]> git.proxmox.com Git - mirror_edk2.git/commitdiff
Add security package to repository.
authorgdong1 <gdong1@6f19259b-4bc3-4df7-8a09-765794883524>
Fri, 2 Sep 2011 07:49:32 +0000 (07:49 +0000)
committergdong1 <gdong1@6f19259b-4bc3-4df7-8a09-765794883524>
Fri, 2 Sep 2011 07:49:32 +0000 (07:49 +0000)
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@12261 6f19259b-4bc3-4df7-8a09-765794883524

102 files changed:
SecurityPkg/Application/VariableInfo/VariableInfo.c [new file with mode: 0644]
SecurityPkg/Application/VariableInfo/VariableInfo.inf [new file with mode: 0644]
SecurityPkg/Include/Guid/AuthenticatedVariableFormat.h [new file with mode: 0644]
SecurityPkg/Include/Guid/PhysicalPresenceData.h [new file with mode: 0644]
SecurityPkg/Include/Guid/SecurityPkgTokenSpace.h [new file with mode: 0644]
SecurityPkg/Include/Guid/TcgEventHob.h [new file with mode: 0644]
SecurityPkg/Include/Library/PlatformSecureLib.h [new file with mode: 0644]
SecurityPkg/Include/Library/TpmCommLib.h [new file with mode: 0644]
SecurityPkg/Include/Ppi/LockPhysicalPresence.h [new file with mode: 0644]
SecurityPkg/Include/Ppi/TpmInitialized.h [new file with mode: 0644]
SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.c [new file with mode: 0644]
SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.h [new file with mode: 0644]
SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.inf [new file with mode: 0644]
SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c [new file with mode: 0644]
SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.h [new file with mode: 0644]
SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.inf [new file with mode: 0644]
SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c [new file with mode: 0644]
SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.inf [new file with mode: 0644]
SecurityPkg/Library/PlatformSecureLibNull/PlatformSecureLibNull.c [new file with mode: 0644]
SecurityPkg/Library/PlatformSecureLibNull/PlatformSecureLibNull.inf [new file with mode: 0644]
SecurityPkg/Library/TpmCommLib/CommonHeader.h [new file with mode: 0644]
SecurityPkg/Library/TpmCommLib/TisPc.c [new file with mode: 0644]
SecurityPkg/Library/TpmCommLib/TpmComm.c [new file with mode: 0644]
SecurityPkg/Library/TpmCommLib/TpmCommLib.inf [new file with mode: 0644]
SecurityPkg/SecurityPkg.dec [new file with mode: 0644]
SecurityPkg/SecurityPkg.dsc [new file with mode: 0644]
SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.c [new file with mode: 0644]
SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.h [new file with mode: 0644]
SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.inf [new file with mode: 0644]
SecurityPkg/Tcg/PhysicalPresenceDxe/PhysicalPresence.c [new file with mode: 0644]
SecurityPkg/Tcg/PhysicalPresenceDxe/PhysicalPresence.h [new file with mode: 0644]
SecurityPkg/Tcg/PhysicalPresenceDxe/PhysicalPresenceDxe.inf [new file with mode: 0644]
SecurityPkg/Tcg/PhysicalPresenceDxe/PhysicalPresenceStrings.uni [new file with mode: 0644]
SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePei.c [new file with mode: 0644]
SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePei.inf [new file with mode: 0644]
SecurityPkg/Tcg/TcgConfigDxe/TcgConfig.vfr [new file with mode: 0644]
SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDriver.c [new file with mode: 0644]
SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDxe.inf [new file with mode: 0644]
SecurityPkg/Tcg/TcgConfigDxe/TcgConfigImpl.c [new file with mode: 0644]
SecurityPkg/Tcg/TcgConfigDxe/TcgConfigImpl.h [new file with mode: 0644]
SecurityPkg/Tcg/TcgConfigDxe/TcgConfigNvData.h [new file with mode: 0644]
SecurityPkg/Tcg/TcgConfigDxe/TcgConfigStrings.uni [new file with mode: 0644]
SecurityPkg/Tcg/TcgDxe/TcgDxe.c [new file with mode: 0644]
SecurityPkg/Tcg/TcgDxe/TcgDxe.inf [new file with mode: 0644]
SecurityPkg/Tcg/TcgDxe/TisDxe.c [new file with mode: 0644]
SecurityPkg/Tcg/TcgDxe/TpmComm.c [new file with mode: 0644]
SecurityPkg/Tcg/TcgDxe/TpmComm.h [new file with mode: 0644]
SecurityPkg/Tcg/TcgPei/TcgPei.c [new file with mode: 0644]
SecurityPkg/Tcg/TcgPei/TcgPei.inf [new file with mode: 0644]
SecurityPkg/Tcg/TcgPei/TisPei.c [new file with mode: 0644]
SecurityPkg/Tcg/TcgPei/TpmComm.c [new file with mode: 0644]
SecurityPkg/Tcg/TcgPei/TpmComm.h [new file with mode: 0644]
SecurityPkg/Tcg/TcgSmm/TcgSmm.c [new file with mode: 0644]
SecurityPkg/Tcg/TcgSmm/TcgSmm.inf [new file with mode: 0644]
SecurityPkg/Tcg/TcgSmm/Tpm.asl [new file with mode: 0644]
SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProvider.c [new file with mode: 0644]
SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProvider.h [new file with mode: 0644]
SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderData.h [new file with mode: 0644]
SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderDxe.inf [new file with mode: 0644]
SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderStrings.uni [new file with mode: 0644]
SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderVfr.Vfr [new file with mode: 0644]
SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProvider.c [new file with mode: 0644]
SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProvider.h [new file with mode: 0644]
SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProviderDxe.inf [new file with mode: 0644]
SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProviderStrings.uni [new file with mode: 0644]
SecurityPkg/UserIdentification/UserIdentifyManagerDxe/LoadDeferredImage.c [new file with mode: 0644]
SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManager.c [new file with mode: 0644]
SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManager.h [new file with mode: 0644]
SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManagerData.h [new file with mode: 0644]
SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManagerDxe.inf [new file with mode: 0644]
SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManagerStrings.uni [new file with mode: 0644]
SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManagerVfr.Vfr [new file with mode: 0644]
SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileAdd.c [new file with mode: 0644]
SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileDelete.c [new file with mode: 0644]
SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManager.c [new file with mode: 0644]
SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManager.h [new file with mode: 0644]
SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManagerData.h [new file with mode: 0644]
SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManagerDxe.inf [new file with mode: 0644]
SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManagerStrings.uni [new file with mode: 0644]
SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManagerVfr.Vfr [new file with mode: 0644]
SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileModify.c [new file with mode: 0644]
SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/AuthService.c [new file with mode: 0644]
SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/AuthService.h [new file with mode: 0644]
SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/EsalVariableDxeSal.inf [new file with mode: 0644]
SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/InitVariable.c [new file with mode: 0644]
SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/Reclaim.c [new file with mode: 0644]
SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/Variable.c [new file with mode: 0644]
SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/Variable.h [new file with mode: 0644]
SecurityPkg/VariableAuthenticated/Pei/Variable.c [new file with mode: 0644]
SecurityPkg/VariableAuthenticated/Pei/Variable.h [new file with mode: 0644]
SecurityPkg/VariableAuthenticated/Pei/VariablePei.inf [new file with mode: 0644]
SecurityPkg/VariableAuthenticated/RuntimeDxe/AuthService.c [new file with mode: 0644]
SecurityPkg/VariableAuthenticated/RuntimeDxe/AuthService.h [new file with mode: 0644]
SecurityPkg/VariableAuthenticated/RuntimeDxe/Reclaim.c [new file with mode: 0644]
SecurityPkg/VariableAuthenticated/RuntimeDxe/Variable.c [new file with mode: 0644]
SecurityPkg/VariableAuthenticated/RuntimeDxe/Variable.h [new file with mode: 0644]
SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableDxe.c [new file with mode: 0644]
SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableRuntimeDxe.inf [new file with mode: 0644]
SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmm.c [new file with mode: 0644]
SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmm.inf [new file with mode: 0644]
SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmmRuntimeDxe.c [new file with mode: 0644]
SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmmRuntimeDxe.inf [new file with mode: 0644]

diff --git a/SecurityPkg/Application/VariableInfo/VariableInfo.c b/SecurityPkg/Application/VariableInfo/VariableInfo.c
new file mode 100644 (file)
index 0000000..418cec3
--- /dev/null
@@ -0,0 +1,268 @@
+/** @file\r
+  If the Variable services have PcdVariableCollectStatistics set to TRUE then \r
+  this utility will print out the statistics information. You can use console \r
+  redirection to capture the data.\r
+  \r
+Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include <Uefi.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/UefiApplicationEntryPoint.h>\r
+#include <Library/BaseMemoryLib.h>\r
+\r
+#include <Library/BaseLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+\r
+#include <Guid/AuthenticatedVariableFormat.h>\r
+#include <Guid/SmmVariableCommon.h>\r
+#include <Protocol/SmmCommunication.h>\r
+#include <Protocol/SmmVariable.h>\r
+\r
+#define EFI_VARIABLE_GUID \\r
+  { 0xddcf3616, 0x3275, 0x4164, { 0x98, 0xb6, 0xfe, 0x85, 0x70, 0x7f, 0xfe, 0x7d } }\r
+\r
+EFI_GUID                        mEfiVariableGuid   = EFI_VARIABLE_GUID;\r
+EFI_SMM_COMMUNICATION_PROTOCOL  *mSmmCommunication = NULL;\r
+\r
+/**\r
+\r
+  This function get the variable statistics data from SMM variable driver. \r
+\r
+  @param[in, out] SmmCommunicateHeader In input, a pointer to a collection of data that will\r
+                                       be passed into an SMM environment. In output, a pointer \r
+                                       to a collection of data that comes from an SMM environment.\r
+  @param[in, out] SmmCommunicateSize   The size of the SmmCommunicateHeader.\r
+                      \r
+  @retval EFI_SUCCESS               Get the statistics data information.\r
+  @retval EFI_NOT_FOUND             Not found.\r
+  @retval EFI_BUFFER_TO_SMALL       DataSize is too small for the result.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+GetVariableStatisticsData (\r
+  IN OUT  EFI_SMM_COMMUNICATE_HEADER  *SmmCommunicateHeader,\r
+  IN OUT  UINTN                       *SmmCommunicateSize\r
+  )\r
+{\r
+  EFI_STATUS                          Status;\r
+  SMM_VARIABLE_COMMUNICATE_HEADER     *SmmVariableFunctionHeader;\r
+\r
+  CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmVariableProtocolGuid);\r
+  SmmCommunicateHeader->MessageLength = *SmmCommunicateSize - OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data);\r
+\r
+  SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) &SmmCommunicateHeader->Data[0];\r
+  SmmVariableFunctionHeader->Function = SMM_VARIABLE_FUNCTION_GET_STATISTICS;\r
+  \r
+  Status = mSmmCommunication->Communicate (mSmmCommunication, SmmCommunicateHeader, SmmCommunicateSize);\r
+  ASSERT_EFI_ERROR (Status);\r
+  \r
+  Status = SmmVariableFunctionHeader->ReturnStatus; \r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+\r
+  This function get and print the variable statistics data from SMM variable driver. \r
+                     \r
+  @retval EFI_SUCCESS               Print the statistics information successfully.\r
+  @retval EFI_NOT_FOUND             Not found the statistics information.\r
+\r
+**/\r
+EFI_STATUS\r
+PrintInfoFromSmm (\r
+  VOID  \r
+  )\r
+{\r
+  EFI_STATUS                                     Status;\r
+  VARIABLE_INFO_ENTRY                            *VariableInfo;\r
+  EFI_SMM_COMMUNICATE_HEADER                     *CommBuffer;\r
+  UINTN                                          RealCommSize;\r
+  UINTN                                          CommSize;\r
+  SMM_VARIABLE_COMMUNICATE_HEADER                *FunctionHeader;\r
+  EFI_SMM_VARIABLE_PROTOCOL                      *Smmvariable;\r
+  \r
+\r
+  Status = gBS->LocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID **) &Smmvariable);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = gBS->LocateProtocol (&gEfiSmmCommunicationProtocolGuid, NULL, (VOID **) &mSmmCommunication);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }  \r
+\r
+  CommSize  = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;\r
+  RealCommSize = CommSize;\r
+  CommBuffer = AllocateZeroPool (CommSize);\r
+  ASSERT (CommBuffer != NULL);\r
+  \r
+  Print (L"Non-Volatile SMM Variables:\n");\r
+  do {\r
+    Status = GetVariableStatisticsData (CommBuffer, &CommSize);\r
+    if (Status == EFI_BUFFER_TOO_SMALL) {\r
+      FreePool (CommBuffer);\r
+      CommBuffer = AllocateZeroPool (CommSize);\r
+      ASSERT (CommBuffer != NULL);\r
+      RealCommSize = CommSize;\r
+      Status = GetVariableStatisticsData (CommBuffer, &CommSize);\r
+    }\r
+\r
+    if (EFI_ERROR (Status) || (CommSize <= SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE)) { \r
+      break;\r
+    }\r
+\r
+    if (CommSize < RealCommSize) {\r
+      CommSize = RealCommSize;\r
+    }\r
+\r
+    FunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) CommBuffer->Data;\r
+    VariableInfo   = (VARIABLE_INFO_ENTRY *) FunctionHeader->Data;\r
+\r
+    if (!VariableInfo->Volatile) {\r
+      Print (\r
+          L"%g R%03d(%03d) W%03d D%03d:%s\n", \r
+          &VariableInfo->VendorGuid,  \r
+          VariableInfo->ReadCount,\r
+          VariableInfo->CacheCount,\r
+          VariableInfo->WriteCount,\r
+          VariableInfo->DeleteCount,\r
+          (CHAR16 *)(VariableInfo + 1)\r
+          );\r
+    }\r
+  } while (TRUE);\r
+  \r
+  Print (L"Volatile SMM Variables:\n");\r
+  ZeroMem (CommBuffer, CommSize);\r
+  do {\r
+    Status = GetVariableStatisticsData (CommBuffer, &CommSize);\r
+    if (Status == EFI_BUFFER_TOO_SMALL) {\r
+      FreePool (CommBuffer);\r
+      CommBuffer = AllocateZeroPool (CommSize);\r
+      ASSERT (CommBuffer != NULL);\r
+      RealCommSize = CommSize;\r
+      Status = GetVariableStatisticsData (CommBuffer, &CommSize);\r
+    }\r
+\r
+    if (EFI_ERROR (Status) || (CommSize <= SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE)) { \r
+      break;\r
+    }\r
+\r
+    if (CommSize < RealCommSize) {\r
+      CommSize = RealCommSize;\r
+    }\r
+\r
+    FunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) CommBuffer->Data;\r
+    VariableInfo   = (VARIABLE_INFO_ENTRY *) FunctionHeader->Data;\r
+\r
+    if (VariableInfo->Volatile) {\r
+      Print (\r
+          L"%g R%03d(%03d) W%03d D%03d:%s\n", \r
+          &VariableInfo->VendorGuid,  \r
+          VariableInfo->ReadCount,\r
+          VariableInfo->CacheCount,\r
+          VariableInfo->WriteCount,\r
+          VariableInfo->DeleteCount,\r
+          (CHAR16 *)(VariableInfo + 1)\r
+          );\r
+    }\r
+  } while (TRUE);\r
+\r
+  FreePool (CommBuffer);  \r
+  return Status;\r
+}\r
+\r
+/**\r
+  The user Entry Point for Application. The user code starts with this function\r
+  as the real entry point for the image goes into a library that calls this \r
+  function.\r
+\r
+  @param[in] ImageHandle    The firmware allocated handle for the EFI image.  \r
+  @param[in] SystemTable    A pointer to the EFI System Table.\r
+  \r
+  @retval EFI_SUCCESS       The entry point is executed successfully.\r
+  @retval other             Some error occurs when executing this entry point.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UefiMain (\r
+  IN EFI_HANDLE        ImageHandle,\r
+  IN EFI_SYSTEM_TABLE  *SystemTable\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  VARIABLE_INFO_ENTRY   *VariableInfo;\r
+  VARIABLE_INFO_ENTRY   *Entry;\r
+\r
+  Status = EfiGetSystemConfigurationTable (&mEfiVariableGuid, (VOID **)&Entry);\r
+  if (EFI_ERROR (Status) || (Entry == NULL)) {\r
+    Status = EfiGetSystemConfigurationTable (&gEfiAuthenticatedVariableGuid, (VOID **)&Entry);\r
+  }\r
+\r
+  if (EFI_ERROR (Status) || (Entry == NULL)) {\r
+    Status = PrintInfoFromSmm ();\r
+    if (!EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }  \r
+\r
+  if (!EFI_ERROR (Status) && (Entry != NULL)) {\r
+    Print (L"Non-Volatile EFI Variables:\n");\r
+    VariableInfo = Entry;\r
+    do {\r
+      if (!VariableInfo->Volatile) {\r
+        Print (\r
+          L"%g R%03d(%03d) W%03d D%03d:%s\n", \r
+          &VariableInfo->VendorGuid,  \r
+          VariableInfo->ReadCount,\r
+          VariableInfo->CacheCount,\r
+          VariableInfo->WriteCount,\r
+          VariableInfo->DeleteCount,\r
+          VariableInfo->Name\r
+          );\r
+      }\r
+\r
+      VariableInfo = VariableInfo->Next;\r
+    } while (VariableInfo != NULL);\r
+\r
+    Print (L"Volatile EFI Variables:\n");\r
+    VariableInfo = Entry;\r
+    do {\r
+      if (VariableInfo->Volatile) {\r
+        Print (\r
+          L"%g R%03d(%03d) W%03d D%03d:%s\n", \r
+          &VariableInfo->VendorGuid,  \r
+          VariableInfo->ReadCount,\r
+          VariableInfo->CacheCount,\r
+          VariableInfo->WriteCount,\r
+          VariableInfo->DeleteCount,\r
+          VariableInfo->Name\r
+          );\r
+      }\r
+      VariableInfo = VariableInfo->Next;\r
+    } while (VariableInfo != NULL);\r
+\r
+  } else {\r
+    Print (L"Warning: Variable Dxe driver doesn't enable the feature of statistical information!\n");\r
+    Print (L"If you want to see this info, please:\n");\r
+    Print (L"  1. Set PcdVariableCollectStatistics as TRUE\n");\r
+    Print (L"  2. Rebuild Variable Dxe driver\n");\r
+    Print (L"  3. Run \"VariableInfo\" cmd again\n");\r
+  }\r
+\r
+  return Status;\r
+}\r
diff --git a/SecurityPkg/Application/VariableInfo/VariableInfo.inf b/SecurityPkg/Application/VariableInfo/VariableInfo.inf
new file mode 100644 (file)
index 0000000..a247d53
--- /dev/null
@@ -0,0 +1,54 @@
+## @file\r
+#  This is a shell application that will display statistical information \r
+#  about variable usage.\r
+#  Note that if Variable Dxe driver doesn't enable the feature by setting \r
+#  PcdVariableCollectStatistics as TRUE, The application will not display \r
+#  variable statistical information.\r
+#\r
+# Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = VariableInfo\r
+  FILE_GUID                      = B9EF901F-A2A2-4fc8-8D2B-3A2E07B301CC\r
+  MODULE_TYPE                    = UEFI_APPLICATION\r
+  VERSION_STRING                 = 1.0\r
+  ENTRY_POINT                    = UefiMain\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC\r
+#\r
+\r
+[Sources]\r
+  VariableInfo.c\r
+\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+  SecurityPkg/SecurityPkg.dec\r
+\r
+[LibraryClasses]\r
+  UefiApplicationEntryPoint\r
+  UefiLib\r
+  UefiBootServicesTableLib\r
+  BaseMemoryLib\r
+  MemoryAllocationLib\r
+\r
+[Protocols]\r
+  gEfiSmmCommunicationProtocolGuid\r
+  gEfiSmmVariableProtocolGuid\r
+  \r
+[Guids]\r
+  gEfiAuthenticatedVariableGuid        ## CONSUMES ## Configuration Table Guid\r
+  \r
diff --git a/SecurityPkg/Include/Guid/AuthenticatedVariableFormat.h b/SecurityPkg/Include/Guid/AuthenticatedVariableFormat.h
new file mode 100644 (file)
index 0000000..245339c
--- /dev/null
@@ -0,0 +1,174 @@
+/** @file\r
+  The variable data structures are related to EDKII-specific \r
+  implementation of UEFI authenticated variables.\r
+  AuthenticatedVariableFormat.h defines variable data headers \r
+  and variable storage region headers.\r
+\r
+Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef __AUTHENTICATED_VARIABLE_FORMAT_H__\r
+#define __AUTHENTICATED_VARIABLE_FORMAT_H__\r
+\r
+#define EFI_AUTHENTICATED_VARIABLE_GUID \\r
+  { 0xaaf32c78, 0x947b, 0x439a, { 0xa1, 0x80, 0x2e, 0x14, 0x4e, 0xc3, 0x77, 0x92 } }\r
+\r
+extern EFI_GUID gEfiAuthenticatedVariableGuid;\r
+\r
+///\r
+/// Alignment of variable name and data, according to the architecture:\r
+/// * For IA-32 and Intel(R) 64 architectures: 1.\r
+/// * For IA-64 architecture: 8.\r
+///\r
+#if defined (MDE_CPU_IPF)\r
+#define ALIGNMENT         8\r
+#else\r
+#define ALIGNMENT         1\r
+#endif\r
+\r
+//\r
+// GET_PAD_SIZE calculates the miminal pad bytes needed to make the current pad size satisfy the alignment requirement.\r
+//\r
+#if (ALIGNMENT == 1)\r
+#define GET_PAD_SIZE(a) (0)\r
+#else\r
+#define GET_PAD_SIZE(a) (((~a) + 1) & (ALIGNMENT - 1))\r
+#endif\r
+\r
+///\r
+/// Alignment of Variable Data Header in Variable Store region.\r
+///\r
+#define HEADER_ALIGNMENT  4\r
+#define HEADER_ALIGN(Header)  (((UINTN) (Header) + HEADER_ALIGNMENT - 1) & (~(HEADER_ALIGNMENT - 1)))\r
+\r
+///\r
+/// Status of Variable Store Region.\r
+///\r
+typedef enum {\r
+  EfiRaw,\r
+  EfiValid,\r
+  EfiInvalid,\r
+  EfiUnknown\r
+} VARIABLE_STORE_STATUS;\r
+\r
+#pragma pack(1)\r
+\r
+#define VARIABLE_STORE_SIGNATURE  EFI_AUTHENTICATED_VARIABLE_GUID\r
+\r
+///\r
+/// Variable Store Header Format and State.\r
+///\r
+#define VARIABLE_STORE_FORMATTED          0x5a\r
+#define VARIABLE_STORE_HEALTHY            0xfe\r
+\r
+///\r
+/// Variable Store region header.\r
+///\r
+typedef struct {\r
+  ///\r
+  /// Variable store region signature.\r
+  ///\r
+  EFI_GUID  Signature;\r
+  ///\r
+  /// Size of entire variable store, \r
+  /// including size of variable store header but not including the size of FvHeader.\r
+  ///\r
+  UINT32  Size;\r
+  ///\r
+  /// Variable region format state.\r
+  ///\r
+  UINT8   Format;\r
+  ///\r
+  /// Variable region healthy state.\r
+  ///\r
+  UINT8   State;\r
+  UINT16  Reserved;\r
+  UINT32  Reserved1;\r
+} VARIABLE_STORE_HEADER;\r
+\r
+///\r
+/// Variable data start flag.\r
+///\r
+#define VARIABLE_DATA                     0x55AA\r
+\r
+///\r
+/// Variable State flags.\r
+///\r
+#define VAR_IN_DELETED_TRANSITION     0xfe  ///< Variable is in obsolete transition.\r
+#define VAR_DELETED                   0xfd  ///< Variable is obsolete.\r
+#define VAR_HEADER_VALID_ONLY         0x7f  ///< Variable header has been valid.\r
+#define VAR_ADDED                     0x3f  ///< Variable has been completely added.\r
+\r
+///\r
+/// Single Variable Data Header Structure.\r
+///\r
+typedef struct {\r
+  ///\r
+  /// Variable Data Start Flag.\r
+  ///\r
+  UINT16      StartId;\r
+  ///\r
+  /// Variable State defined above.\r
+  ///\r
+  UINT8       State;\r
+  UINT8       Reserved;\r
+  ///\r
+  /// Attributes of variable defined in UEFI specification.\r
+  ///\r
+  UINT32      Attributes;\r
+  ///\r
+  /// Associated monotonic count value against replay attack.\r
+  ///\r
+  UINT64      MonotonicCount;\r
+  ///\r
+  /// Associated TimeStamp value against replay attack. \r
+  ///\r
+  EFI_TIME    TimeStamp;\r
+  ///\r
+  /// Index of associated public key in database.\r
+  ///\r
+  UINT32      PubKeyIndex;\r
+  ///\r
+  /// Size of variable null-terminated Unicode string name.\r
+  ///\r
+  UINT32      NameSize;\r
+  ///\r
+  /// Size of the variable data without this header.\r
+  ///\r
+  UINT32      DataSize;\r
+  ///\r
+  /// A unique identifier for the vendor that produces and consumes this varaible.\r
+  ///\r
+  EFI_GUID    VendorGuid;\r
+} VARIABLE_HEADER;\r
+\r
+#pragma pack()\r
+\r
+typedef struct _VARIABLE_INFO_ENTRY  VARIABLE_INFO_ENTRY;\r
+\r
+///\r
+/// This structure contains the variable list that is put in EFI system table.\r
+/// The variable driver collects all variables that were used at boot service time and produces this list.\r
+/// This is an optional feature to dump all used variables in shell environment. \r
+///\r
+struct _VARIABLE_INFO_ENTRY {\r
+  VARIABLE_INFO_ENTRY *Next;       ///< Pointer to next entry.\r
+  EFI_GUID            VendorGuid;  ///< Guid of Variable.\r
+  CHAR16              *Name;       ///< Name of Variable. \r
+  UINT32              Attributes;  ///< Attributes of variable defined in UEFI spec.\r
+  UINT32              ReadCount;   ///< Number of times to read this variable.\r
+  UINT32              WriteCount;  ///< Number of times to write this variable.\r
+  UINT32              DeleteCount; ///< Number of times to delete this variable.\r
+  UINT32              CacheCount;  ///< Number of times that cache hits this variable.\r
+  BOOLEAN             Volatile;    ///< TRUE if volatile, FALSE if non-volatile.\r
+};\r
+\r
+#endif // __AUTHENTICATED_VARIABLE_FORMAT_H__\r
diff --git a/SecurityPkg/Include/Guid/PhysicalPresenceData.h b/SecurityPkg/Include/Guid/PhysicalPresenceData.h
new file mode 100644 (file)
index 0000000..1ae8095
--- /dev/null
@@ -0,0 +1,76 @@
+/** @file\r
+  Define the variable data structures used for TCG physical presence.\r
+  The TPM request from firmware or OS is saved to variable. And it is\r
+  cleared after it is processed in the next boot cycle. The TPM response \r
+  is saved to variable.\r
+\r
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef __PHYSICAL_PRESENCE_DATA_GUID_H__\r
+#define __PHYSICAL_PRESENCE_DATA_GUID_H__\r
+\r
+#define EFI_PHYSICAL_PRESENCE_DATA_GUID \\r
+  { \\r
+    0xf6499b1, 0xe9ad, 0x493d, { 0xb9, 0xc2, 0x2f, 0x90, 0x81, 0x5c, 0x6c, 0xbc }\\r
+  }\r
+\r
+#define PHYSICAL_PRESENCE_VARIABLE  L"PhysicalPresence"\r
+\r
+typedef struct {\r
+  UINT8   PPRequest;      ///< Physical Presence request command.\r
+  UINT8   LastPPRequest;\r
+  UINT32  PPResponse;\r
+  UINT8   Flags;\r
+} EFI_PHYSICAL_PRESENCE;\r
+\r
+//\r
+// The definition bit of the flags\r
+//\r
+#define FLAG_NO_PPI_PROVISION                    BIT0\r
+#define FLAG_NO_PPI_CLEAR                        BIT1\r
+#define FLAG_NO_PPI_MAINTENANCE                  BIT2\r
+#define FLAG_RESET_TRACK                         BIT3\r
+\r
+#define H2NS(x)        ((((x) << 8) | ((x) >> 8)) & 0xffff)\r
+#define H2NL(x)        (H2NS ((x) >> 16) | (H2NS ((x) & 0xffff) << 16))\r
+\r
+//\r
+// The definition of physical presence operation actions\r
+//\r
+#define NO_ACTION                               0\r
+#define ENABLE                                  1\r
+#define DISABLE                                 2\r
+#define ACTIVATE                                3\r
+#define DEACTIVATE                              4 \r
+#define CLEAR                                   5\r
+#define ENABLE_ACTIVATE                         6\r
+#define DEACTIVATE_DISABLE                      7\r
+#define SET_OWNER_INSTALL_TRUE                  8\r
+#define SET_OWNER_INSTALL_FALSE                 9\r
+#define ENABLE_ACTIVATE_OWNER_TRUE              10\r
+#define DEACTIVATE_DISABLE_OWNER_FALSE          11\r
+#define DEFERRED_PP_UNOWNERED_FIELD_UPGRADE     12\r
+#define SET_OPERATOR_AUTH                       13\r
+#define CLEAR_ENABLE_ACTIVATE                   14\r
+#define SET_NO_PPI_PROVISION_FALSE              15\r
+#define SET_NO_PPI_PROVISION_TRUE               16\r
+#define SET_NO_PPI_CLEAR_FALSE                  17\r
+#define SET_NO_PPI_CLEAR_TRUE                   18\r
+#define SET_NO_PPI_MAINTENANCE_FALSE            19\r
+#define SET_NO_PPI_MAINTENANCE_TRUE             20\r
+#define ENABLE_ACTIVATE_CLEAR                   21\r
+#define ENABLE_ACTIVATE_CLEAR_ENABLE_ACTIVATE   22\r
+\r
+extern EFI_GUID  gEfiPhysicalPresenceGuid;\r
+\r
+#endif\r
+\r
diff --git a/SecurityPkg/Include/Guid/SecurityPkgTokenSpace.h b/SecurityPkg/Include/Guid/SecurityPkgTokenSpace.h
new file mode 100644 (file)
index 0000000..b1b7666
--- /dev/null
@@ -0,0 +1,25 @@
+/** @file\r
+  GUID for SecurityPkg PCD Token Space.\r
+\r
+Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _SECURITYPKG_TOKEN_SPACE_GUID_H_\r
+#define _SECURITYPKG_TOKEN_SPACE_GUID_H_\r
+\r
+#define SECURITYPKG_TOKEN_SPACE_GUID \\r
+  { \\r
+    0xd3fb176, 0x9569, 0x4d51, { 0xa3, 0xef, 0x7d, 0x61, 0xc6, 0x4f, 0xea, 0xba } \\r
+  }\r
+\r
+extern EFI_GUID gEfiSecurityPkgTokenSpaceGuid;\r
+\r
+#endif\r
diff --git a/SecurityPkg/Include/Guid/TcgEventHob.h b/SecurityPkg/Include/Guid/TcgEventHob.h
new file mode 100644 (file)
index 0000000..e88bd3a
--- /dev/null
@@ -0,0 +1,30 @@
+/** @file\r
+  Defines the HOB GUID used to pass a TCG_PCR_EVENT from a TPM PEIM to \r
+  a TPM DXE Driver. A GUIDed HOB is generated for each measurement \r
+  made in the PEI Phase.\r
+    \r
+Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _TCG_EVENT_HOB_H_\r
+#define _TCG_EVENT_HOB_H_\r
+\r
+///\r
+/// The Global ID of a GUIDed HOB used to pass a TCG_PCR_EVENT from a TPM PEIM to a TPM DXE Driver.\r
+///\r
+#define EFI_TCG_EVENT_HOB_GUID \\r
+  { \\r
+    0x2e3044ac, 0x879f, 0x490f, {0x97, 0x60, 0xbb, 0xdf, 0xaf, 0x69, 0x5f, 0x50 } \\r
+  }\r
+\r
+extern EFI_GUID gTcgEventEntryHobGuid;\r
+\r
+#endif\r
diff --git a/SecurityPkg/Include/Library/PlatformSecureLib.h b/SecurityPkg/Include/Library/PlatformSecureLib.h
new file mode 100644 (file)
index 0000000..c544719
--- /dev/null
@@ -0,0 +1,42 @@
+/** @file\r
+  Provides a secure platform-specific method to clear PK(Platform Key).\r
+\r
+Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef __PLATFORM_SECURE_LIB_H__\r
+#define __PLATFORM_SECURE_LIB_H__\r
+\r
+\r
+/**\r
+\r
+  This function detects whether a secure platform-specific method to clear PK(Platform Key)\r
+  is configured by platform owner. This method is provided for users force to clear PK \r
+  in case incorrect enrollment mis-haps.\r
+  \r
+  UEFI231 spec chapter 27.5.2 stipulates: The platform key may also be cleared using \r
+  a secure platform-specific method. In  this case, the global variable SetupMode \r
+  must also be updated to 1.\r
+\r
+  NOTE THAT: This function cannot depend on any EFI Variable Service since they are\r
+  not available when this function is called in AuthenticateVariable driver.\r
+  \r
+  @retval  TRUE       The Platform owner wants to force clear PK.\r
+  @retval  FALSE      The Platform owner doesn't want to force clear PK. \r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+ForceClearPK (\r
+  VOID\r
+  );\r
+\r
+#endif
\ No newline at end of file
diff --git a/SecurityPkg/Include/Library/TpmCommLib.h b/SecurityPkg/Include/Library/TpmCommLib.h
new file mode 100644 (file)
index 0000000..175dd8d
--- /dev/null
@@ -0,0 +1,286 @@
+/** @file\r
+  Ihis library is only intended to be used by TPM modules.\r
+  It provides basic TPM Interface Specification (TIS) and Command functions.\r
+\r
+Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _TPM_COMM_LIB_H_\r
+#define _TPM_COMM_LIB_H_\r
+\r
+#include <IndustryStandard/Tpm12.h>\r
+\r
+typedef EFI_HANDLE  TIS_TPM_HANDLE;\r
+\r
+///\r
+/// TPM register base address.\r
+///\r
+#define TPM_BASE_ADDRESS            0xfed40000\r
+\r
+//\r
+// Set structure alignment to 1-byte\r
+//\r
+#pragma pack (1)\r
+\r
+//\r
+// Register set map as specified in TIS specification Chapter 10\r
+//\r
+typedef struct {\r
+  ///\r
+  /// Used to gain ownership for this particular port.\r
+  ///\r
+  UINT8                             Access;             // 0\r
+  UINT8                             Reserved1[7];       // 1\r
+  ///\r
+  /// Controls interrupts.\r
+  ///\r
+  UINT32                            IntEnable;          // 8\r
+  ///\r
+  /// SIRQ vector to be used by the TPM.\r
+  ///\r
+  UINT8                             IntVector;          // 0ch\r
+  UINT8                             Reserved2[3];       // 0dh\r
+  ///\r
+  /// What caused interrupt.\r
+  ///\r
+  UINT32                            IntSts;             // 10h\r
+  ///\r
+  /// Shows which interrupts are supported by that particular TPM.\r
+  ///\r
+  UINT32                            IntfCapability;     // 14h\r
+  ///\r
+  /// Status Register. Provides status of the TPM.\r
+  ///\r
+  UINT8                             Status;             // 18h\r
+  ///\r
+  /// Number of consecutive writes that can be done to the TPM.\r
+  ///\r
+  UINT16                            BurstCount;         // 19h\r
+  UINT8                             Reserved3[9];\r
+  ///\r
+  /// Read or write FIFO, depending on transaction.\r
+  ///\r
+  UINT32                            DataFifo;           // 24\r
+  UINT8                             Reserved4[0xed8];   // 28h\r
+  ///\r
+  /// Vendor ID\r
+  ///\r
+  UINT16                            Vid;                // 0f00h\r
+  ///\r
+  /// Device ID\r
+  ///\r
+  UINT16                            Did;                // 0f02h\r
+  ///\r
+  /// Revision ID\r
+  ///\r
+  UINT8                             Rid;                // 0f04h\r
+  ///\r
+  /// TCG defined configuration registers.\r
+  ///\r
+  UINT8                             TcgDefined[0x7b];   // 0f05h\r
+  ///\r
+  /// Alias to I/O legacy space.\r
+  ///\r
+  UINT32                            LegacyAddress1;     // 0f80h\r
+  ///\r
+  /// Additional 8 bits for I/O legacy space extension.\r
+  ///\r
+  UINT32                            LegacyAddress1Ex;   // 0f84h\r
+  ///\r
+  /// Alias to second I/O legacy space.\r
+  ///\r
+  UINT32                            LegacyAddress2;     // 0f88h\r
+  ///\r
+  /// Additional 8 bits for second I/O legacy space extension.\r
+  ///\r
+  UINT32                            LegacyAddress2Ex;   // 0f8ch\r
+  ///\r
+  /// Vendor-defined configuration registers.\r
+  ///\r
+  UINT8                             VendorDefined[0x70];// 0f90h\r
+} TIS_PC_REGISTERS;\r
+\r
+//\r
+// Restore original structure alignment\r
+//\r
+#pragma pack ()\r
+\r
+//\r
+// Define pointer types used to access TIS registers on PC\r
+//\r
+typedef TIS_PC_REGISTERS  *TIS_PC_REGISTERS_PTR;\r
+\r
+//\r
+// TCG Platform Type based on TCG ACPI Specification Version 1.00\r
+//\r
+#define TCG_PLATFORM_TYPE_CLIENT   0\r
+#define TCG_PLATFORM_TYPE_SERVER   1\r
+\r
+//\r
+// Define bits of ACCESS and STATUS registers\r
+//\r
+\r
+///\r
+/// This bit is a 1 to indicate that the other bits in this register are valid.\r
+///\r
+#define TIS_PC_VALID                BIT7\r
+///\r
+/// Indicate that this locality is active.\r
+///\r
+#define TIS_PC_ACC_ACTIVE           BIT5\r
+///\r
+/// Set to 1 to indicate that this locality had the TPM taken away while\r
+/// this locality had the TIS_PC_ACC_ACTIVE bit set.\r
+///\r
+#define TIS_PC_ACC_SEIZED           BIT4\r
+///\r
+/// Set to 1 to indicate that TPM MUST reset the\r
+/// TIS_PC_ACC_ACTIVE bit and remove ownership for localities less than the\r
+/// locality that is writing this bit.\r
+///\r
+#define TIS_PC_ACC_SEIZE            BIT3\r
+///\r
+/// When this bit is 1, another locality is requesting usage of the TPM.\r
+///\r
+#define TIS_PC_ACC_PENDIND          BIT2\r
+///\r
+/// Set to 1 to indicate that this locality is requesting to use TPM.\r
+///\r
+#define TIS_PC_ACC_RQUUSE           BIT1\r
+///\r
+/// A value of 1 indicates that a T/OS has not been established on the platform\r
+///\r
+#define TIS_PC_ACC_ESTABLISH        BIT0\r
+\r
+///\r
+/// When this bit is 1, TPM is in the Ready state, \r
+/// indicating it is ready to receive a new command.\r
+///\r
+#define TIS_PC_STS_READY            BIT6\r
+///\r
+/// Write a 1 to this bit to cause the TPM to execute that command.\r
+///\r
+#define TIS_PC_STS_GO               BIT5\r
+///\r
+/// This bit indicates that the TPM has data available as a response.\r
+///\r
+#define TIS_PC_STS_DATA             BIT4\r
+///\r
+/// The TPM sets this bit to a value of 1 when it expects another byte of data for a command.\r
+///\r
+#define TIS_PC_STS_EXPECT           BIT3\r
+///\r
+/// Writes a 1 to this bit to force the TPM to re-send the response.\r
+///\r
+#define TIS_PC_STS_RETRY            BIT1\r
+\r
+//\r
+// Default TimeOut value\r
+//\r
+#define TIS_TIMEOUT_B               2000 * 1000  // 2s\r
+#define TIS_TIMEOUT_C               750 * 1000   // 750ms\r
+#define TIS_TIMEOUT_D               750 * 1000   // 750ms\r
+\r
+//\r
+// Max TPM command/reponse length\r
+//\r
+#define TPMCMDBUFLENGTH             1024\r
+\r
+/**\r
+  Check whether the value of a TPM chip register satisfies the input BIT setting.\r
+\r
+  @param[in]  Register     Address port of register to be checked.\r
+  @param[in]  BitSet       Check these data bits are set.\r
+  @param[in]  BitClear     Check these data bits are clear.\r
+  @param[in]  TimeOut      The max wait time (unit MicroSecond) when checking register.\r
+\r
+  @retval     EFI_SUCCESS  The register satisfies the check bit.\r
+  @retval     EFI_TIMEOUT  The register can't run into the expected status in time.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TisPcWaitRegisterBits (\r
+  IN UINT8   *Register,\r
+  IN UINT8   BitSet,   \r
+  IN UINT8   BitClear, \r
+  IN UINT32  TimeOut   \r
+  );\r
+\r
+/**\r
+  Get BurstCount by reading the burstCount field of a TIS regiger \r
+  in the time of default TIS_TIMEOUT_D.\r
+\r
+  @param[in]  TisReg                Pointer to TIS register.\r
+  @param[out] BurstCount            Pointer to a buffer to store the got BurstConut.\r
+\r
+  @retval     EFI_SUCCESS           Get BurstCount.\r
+  @retval     EFI_INVALID_PARAMETER TisReg is NULL or BurstCount is NULL.\r
+  @retval     EFI_TIMEOUT           BurstCount can't be got in time.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TisPcReadBurstCount (\r
+  IN  TIS_PC_REGISTERS_PTR  TisReg,\r
+  OUT UINT16                *BurstCount\r
+  );\r
+\r
+/**\r
+  Set TPM chip to ready state by sending ready command TIS_PC_STS_READY \r
+  to Status Register in time.\r
+\r
+  @param[in] TisReg                Pointer to TIS register.\r
+\r
+  @retval    EFI_SUCCESS           TPM chip enters into ready state.\r
+  @retval    EFI_INVALID_PARAMETER TisReg is NULL.\r
+  @retval    EFI_TIMEOUT           TPM chip can't be set to ready state in time.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TisPcPrepareCommand (\r
+  IN TIS_PC_REGISTERS_PTR  TisReg\r
+  );\r
+\r
+/**\r
+  Get the control of TPM chip by sending requestUse command TIS_PC_ACC_RQUUSE \r
+  to ACCESS Register in the time of default TIS_TIMEOUT_D.\r
+\r
+  @param[in] TisReg                Pointer to TIS register.\r
+\r
+  @retval    EFI_SUCCESS           Get the control of TPM chip.\r
+  @retval    EFI_INVALID_PARAMETER TisReg is NULL.\r
+  @retval    EFI_NOT_FOUND         TPM chip doesn't exit.\r
+  @retval    EFI_TIMEOUT           Can't get the TPM control in time.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TisPcRequestUseTpm (\r
+  IN TIS_PC_REGISTERS_PTR  TisReg\r
+  );\r
+\r
+/**\r
+  Single function calculates SHA1 digest value for all raw data. It\r
+  combines Sha1Init(), Sha1Update() and Sha1Final().\r
+\r
+  @param[in]  Data          Raw data to be digested.\r
+  @param[in]  DataLen       Size of the raw data.\r
+  @param[out] Digest        Pointer to a buffer that stores the final digest.\r
+  \r
+  @retval     EFI_SUCCESS   Always successfully calculate the final digest.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TpmCommHashAll (\r
+  IN  CONST UINT8       *Data,\r
+  IN        UINTN       DataLen,\r
+  OUT       TPM_DIGEST  *Digest\r
+  );\r
+\r
+#endif\r
diff --git a/SecurityPkg/Include/Ppi/LockPhysicalPresence.h b/SecurityPkg/Include/Ppi/LockPhysicalPresence.h
new file mode 100644 (file)
index 0000000..0ae3b7b
--- /dev/null
@@ -0,0 +1,60 @@
+/** @file\r
+  This file defines the lock physical Presence PPI. This PPI is \r
+  produced by a platform specific PEIM and consumed by the TPM \r
+  PEIM.\r
+\r
+Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef __PEI_LOCK_PHYSICAL_PRESENCE_H__\r
+#define __PEI_LOCK_PHYSICAL_PRESENCE_H__\r
+\r
+///\r
+/// Global ID for the PEI_LOCK_PHYSICAL_PRESENCE_PPI_GUID.  \r
+///\r
+#define PEI_LOCK_PHYSICAL_PRESENCE_PPI_GUID  \\r
+  { \\r
+    0xef9aefe5, 0x2bd3, 0x4031, { 0xaf, 0x7d, 0x5e, 0xfe, 0x5a, 0xbb, 0x9a, 0xd } \\r
+  }\r
+\r
+///\r
+/// Forward declaration for the PEI_LOCK_PHYSICAL_PRESENCE_PPI\r
+///\r
+typedef struct _PEI_LOCK_PHYSICAL_PRESENCE_PPI PEI_LOCK_PHYSICAL_PRESENCE_PPI;\r
+\r
+/**\r
+  This interface returns whether TPM physical presence needs be locked.\r
+\r
+  @param[in]  PeiServices       The pointer to the PEI Services Table.\r
+\r
+  @retval     TRUE              The TPM physical presence should be locked.\r
+  @retval     FALSE             The TPM physical presence cannot be locked.\r
+\r
+**/\r
+typedef\r
+BOOLEAN\r
+(EFIAPI *PEI_LOCK_PHYSICAL_PRESENCE)(\r
+  IN CONST  EFI_PEI_SERVICES                    **PeiServices\r
+);\r
+\r
+///\r
+/// This service abstracts TPM physical presence lock interface. It is necessary for  \r
+/// safety to convey this information to the TPM driver so that TPM physical presence  \r
+/// can be locked as early as possible. This PPI is produced by a platform specific \r
+/// PEIM and consumed by the TPM PEIM.\r
+///\r
+struct _PEI_LOCK_PHYSICAL_PRESENCE_PPI {\r
+  PEI_LOCK_PHYSICAL_PRESENCE  LockPhysicalPresence;\r
+};\r
+\r
+extern EFI_GUID  gPeiLockPhysicalPresencePpiGuid;\r
+\r
+#endif  //  __PEI_LOCK_PHYSICAL_PRESENCE_H__
\ No newline at end of file
diff --git a/SecurityPkg/Include/Ppi/TpmInitialized.h b/SecurityPkg/Include/Ppi/TpmInitialized.h
new file mode 100644 (file)
index 0000000..dbbd415
--- /dev/null
@@ -0,0 +1,30 @@
+/** @file\r
+  Tag GUID that must be installed by the TPM PEIM after the TPM hardware is\r
+  initialized.  PEIMs that must execute after TPM hardware initialization\r
+  may use this GUID in their dependency expressions.\r
+    \r
+Copyright (c) 2008 - 2010, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _PEI_TPM_INITIALIZED_PPI_H_\r
+#define _PEI_TPM_INITIALIZED_PPI_H_\r
+\r
+///\r
+/// Global ID for the PEI_TPM_INITIALIZED_PPI which always uses a NULL interface. \r
+///\r
+#define PEI_TPM_INITIALIZED_PPI_GUID \\r
+  { \\r
+    0xe9db0d58, 0xd48d, 0x47f6, 0x9c, 0x6e, 0x6f, 0x40, 0xe8, 0x6c, 0x7b, 0x41 \\r
+  }\r
+\r
+extern EFI_GUID gPeiTpmInitializedPpiGuid;\r
+\r
+#endif\r
diff --git a/SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.c b/SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.c
new file mode 100644 (file)
index 0000000..f7fe594
--- /dev/null
@@ -0,0 +1,858 @@
+/** @file\r
+  Implement defer image load services for user identification in UEFI2.2.\r
+\r
+Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "DxeDeferImageLoadLib.h"\r
+\r
+//\r
+// Handle for the Deferred Image Load Protocol instance produced by this driver.\r
+//\r
+EFI_HANDLE                       mDeferredImageHandle = NULL;\r
+BOOLEAN                          mIsProtocolInstalled = FALSE;\r
+EFI_USER_MANAGER_PROTOCOL        *mUserManager        = NULL;\r
+DEFERRED_IMAGE_TABLE             mDeferredImage       = {\r
+  0,       // Deferred image count\r
+  NULL     // The deferred image info\r
+};\r
+\r
+EFI_DEFERRED_IMAGE_LOAD_PROTOCOL gDeferredImageLoad   = {\r
+  GetDefferedImageInfo\r
+};\r
+\r
+/**\r
+  Get the image type.\r
+\r
+  @param[in]    File    This is a pointer to the device path of the file\r
+                        that is being dispatched. \r
+\r
+  @return       UINT32  Image Type             \r
+\r
+**/\r
+UINT32\r
+GetFileType (\r
+  IN  CONST EFI_DEVICE_PATH_PROTOCOL   *File\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  EFI_HANDLE                        DeviceHandle; \r
+  EFI_DEVICE_PATH_PROTOCOL          *TempDevicePath;\r
+  EFI_BLOCK_IO_PROTOCOL             *BlockIo;\r
+\r
+  //\r
+  // First check to see if File is from a Firmware Volume\r
+  //\r
+  DeviceHandle      = NULL;\r
+  TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File;\r
+  Status = gBS->LocateDevicePath (\r
+                  &gEfiFirmwareVolume2ProtocolGuid,\r
+                  &TempDevicePath,\r
+                  &DeviceHandle\r
+                  );\r
+  if (!EFI_ERROR (Status)) {\r
+    Status = gBS->OpenProtocol (\r
+                    DeviceHandle,\r
+                    &gEfiFirmwareVolume2ProtocolGuid,\r
+                    NULL,\r
+                    NULL,\r
+                    NULL,\r
+                    EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+                    );\r
+    if (!EFI_ERROR (Status)) {\r
+      return IMAGE_FROM_FV;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Next check to see if File is from a Block I/O device\r
+  //\r
+  DeviceHandle   = NULL;\r
+  TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File;\r
+  Status = gBS->LocateDevicePath (\r
+                  &gEfiBlockIoProtocolGuid,\r
+                  &TempDevicePath,\r
+                  &DeviceHandle\r
+                  );\r
+  if (!EFI_ERROR (Status)) {\r
+    BlockIo = NULL;\r
+    Status = gBS->OpenProtocol (\r
+                    DeviceHandle,\r
+                    &gEfiBlockIoProtocolGuid,\r
+                    (VOID **) &BlockIo,\r
+                    NULL,\r
+                    NULL,\r
+                    EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                    );\r
+    if (!EFI_ERROR (Status) && BlockIo != NULL) {\r
+      if (BlockIo->Media != NULL) {\r
+        if (BlockIo->Media->RemovableMedia) {\r
+          //\r
+          // Block I/O is present and specifies the media is removable\r
+          //\r
+          return IMAGE_FROM_REMOVABLE_MEDIA;\r
+        } else {\r
+          //\r
+          // Block I/O is present and specifies the media is not removable\r
+          //\r
+          return IMAGE_FROM_FIXED_MEDIA;\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
+  //\r
+  // File is not in a Firmware Volume or on a Block I/O device, so check to see if \r
+  // the device path supports the Simple File System Protocol.\r
+  //\r
+  DeviceHandle   = NULL;\r
+  TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File;\r
+  Status = gBS->LocateDevicePath (\r
+                  &gEfiSimpleFileSystemProtocolGuid,\r
+                  &TempDevicePath,\r
+                  &DeviceHandle\r
+                  );\r
+  if (!EFI_ERROR (Status)) {\r
+    //\r
+    // Simple File System is present without Block I/O, so assume media is fixed.\r
+    //\r
+    return IMAGE_FROM_FIXED_MEDIA;\r
+  }\r
+\r
+  //\r
+  // File is not from an FV, Block I/O or Simple File System, so the only options\r
+  // left are a PCI Option ROM and a Load File Protocol such as a PXE Boot from a NIC.  \r
+  //\r
+  TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File;\r
+  while (!IsDevicePathEndType (TempDevicePath)) {\r
+    switch (DevicePathType (TempDevicePath)) {\r
+    \r
+    case MEDIA_DEVICE_PATH:\r
+      if (DevicePathSubType (TempDevicePath) == MEDIA_RELATIVE_OFFSET_RANGE_DP) {\r
+        return IMAGE_FROM_OPTION_ROM;\r
+      }\r
+      break;\r
+\r
+    case MESSAGING_DEVICE_PATH:\r
+      if (DevicePathSubType(TempDevicePath) == MSG_MAC_ADDR_DP) {\r
+        return IMAGE_FROM_REMOVABLE_MEDIA;\r
+      } \r
+      break;\r
+\r
+    default:\r
+      break;\r
+    }\r
+    TempDevicePath = NextDevicePathNode (TempDevicePath);\r
+  }\r
+  return IMAGE_UNKNOWN; \r
+}\r
+\r
+\r
+/**\r
+  Get current user's access right.\r
+\r
+  @param[out]  AccessControl Points to the user's access control data, the\r
+                             caller should free data buffer.\r
+  @param[in]   AccessType    The type of user access control.\r
+\r
+  @retval      EFI_SUCCESS   Get current user access control successfully\r
+  @retval      others        Fail to get current user access control\r
+\r
+**/\r
+EFI_STATUS\r
+GetAccessControl (\r
+  OUT  EFI_USER_INFO_ACCESS_CONTROL     **AccessControl,\r
+  IN   UINT32                           AccessType\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  EFI_USER_INFO_HANDLE          UserInfo;\r
+  EFI_USER_INFO                 *Info;\r
+  UINTN                         InfoSize;\r
+  EFI_USER_INFO_ACCESS_CONTROL  *Access;\r
+  EFI_USER_PROFILE_HANDLE       CurrentUser;\r
+  UINTN                         CheckLen;\r
+  EFI_USER_MANAGER_PROTOCOL     *UserManager;\r
+\r
+  CurrentUser = NULL;\r
+  Status = gBS->LocateProtocol (\r
+                  &gEfiUserManagerProtocolGuid,\r
+                  NULL,\r
+                  (VOID **) &UserManager\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+  \r
+  //\r
+  // Get current user access information.\r
+  //\r
+  UserManager->Current (UserManager, &CurrentUser);\r
+\r
+  UserInfo = NULL;\r
+  Info     = NULL;\r
+  InfoSize = 0;\r
+  while (TRUE) {\r
+    //\r
+    // Get next user information.\r
+    //\r
+    Status = UserManager->GetNextInfo (UserManager, CurrentUser, &UserInfo);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    Status = UserManager->GetInfo (\r
+                            UserManager,\r
+                            CurrentUser,\r
+                            UserInfo,\r
+                            Info,\r
+                            &InfoSize\r
+                            );\r
+    if (Status == EFI_BUFFER_TOO_SMALL) {\r
+      if (Info != NULL) {\r
+        FreePool (Info);\r
+      }\r
+      Info = AllocateZeroPool (InfoSize);\r
+      ASSERT (Info != NULL);\r
+      Status = UserManager->GetInfo (\r
+                              UserManager,\r
+                              CurrentUser,\r
+                              UserInfo,\r
+                              Info,\r
+                              &InfoSize\r
+                              );\r
+    }\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      break;\r
+    }\r
+    \r
+    ASSERT (Info != NULL);\r
+    if (Info->InfoType != EFI_USER_INFO_ACCESS_POLICY_RECORD) {\r
+      continue;\r
+    }\r
+    \r
+    //\r
+    // Get specified access information.\r
+    //\r
+    CheckLen  = 0;\r
+    while (CheckLen < Info->InfoSize - sizeof (EFI_USER_INFO)) {\r
+      Access = (EFI_USER_INFO_ACCESS_CONTROL *) ((UINT8 *) (Info + 1) + CheckLen);\r
+      if ((Access->Type == AccessType)) {\r
+        *AccessControl = AllocateZeroPool (Access->Size);\r
+        ASSERT (*AccessControl != NULL);\r
+        CopyMem (*AccessControl, Access, Access->Size);\r
+        FreePool (Info);\r
+        return EFI_SUCCESS;\r
+      }\r
+      CheckLen += Access->Size;\r
+    }\r
+  }\r
+  \r
+  if (Info != NULL) {\r
+    FreePool (Info);\r
+  }\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+\r
+/**\r
+  Convert the '/' to '\' in the specified string.\r
+\r
+  @param[in, out]  Str       Points to the string to convert.\r
+\r
+**/\r
+VOID\r
+ConvertDPStr (\r
+  IN OUT EFI_STRING                     Str \r
+  )\r
+{\r
+  INTN                                  Count;\r
+  INTN                                  Index;\r
+  \r
+  Count = StrSize(Str) / 2 - 1;\r
+\r
+  if (Count < 4) {\r
+    return;\r
+  }\r
+  \r
+  //\r
+  // Convert device path string.\r
+  //\r
+  Index = Count - 1;\r
+  while (Index > 0) {\r
+    //\r
+    // Find the last '/'.\r
+    //\r
+    for (Index = Count - 1; Index > 0; Index--) {\r
+      if (Str[Index] == L'/')\r
+        break;\r
+    }\r
+\r
+    //\r
+    // Check next char.\r
+    //\r
+    if (Str[Index + 1] == L'\\')\r
+      return;\r
+    \r
+    Str[Index] = L'\\';\r
+    \r
+    //\r
+    // Check previous char.\r
+    //\r
+    if ((Index > 0) && (Str[Index - 1] == L'\\')) {\r
+      CopyMem (&Str[Index - 1], &Str[Index], (UINTN) ((Count - Index + 1) * sizeof (CHAR16)));\r
+      return;\r
+    }\r
+    Index--;\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Check whether the DevicePath2 is identical with DevicePath1, or identical with\r
+  DevicePath1's child device path.\r
+\r
+  If DevicePath2 is identical with DevicePath1, or with DevicePath1's child device\r
+  path, then TRUE returned. Otherwise, FALSE is returned.\r
+  \r
+  If DevicePath1 is NULL, then ASSERT().\r
+  If DevicePath2 is NULL, then ASSERT().\r
+\r
+  @param[in]  DevicePath1   A pointer to a device path.\r
+  @param[in]  DevicePath2   A pointer to a device path.\r
+\r
+  @retval     TRUE          Two device paths are identical , or DevicePath2 is \r
+                            DevicePath1's child device path.\r
+  @retval     FALSE         Two device paths are not identical, and DevicePath2 \r
+                            is not DevicePath1's child device path.\r
+\r
+**/\r
+BOOLEAN\r
+CheckDevicePath (\r
+  IN  CONST EFI_DEVICE_PATH_PROTOCOL          *DevicePath1,\r
+  IN  CONST EFI_DEVICE_PATH_PROTOCOL          *DevicePath2\r
+  )\r
+{\r
+  EFI_STATUS                            Status;\r
+  EFI_STRING                            DevicePathStr1;\r
+  EFI_STRING                            DevicePathStr2;\r
+  UINTN                                 StrLen1;\r
+  UINTN                                 StrLen2;\r
+  EFI_DEVICE_PATH_TO_TEXT_PROTOCOL      *DevicePathText;\r
+  BOOLEAN                               DevicePathEqual;\r
+\r
+  ASSERT (DevicePath1 != NULL);\r
+  ASSERT (DevicePath2 != NULL);\r
+  \r
+  DevicePathEqual = FALSE;\r
+  DevicePathText  = NULL;\r
+  Status = gBS->LocateProtocol ( \r
+                  &gEfiDevicePathToTextProtocolGuid,\r
+                  NULL,\r
+                  (VOID **) &DevicePathText\r
+                  );\r
+  ASSERT (Status == EFI_SUCCESS);\r
+  \r
+  //\r
+  // Get first device path string.\r
+  //\r
+  DevicePathStr1 = DevicePathText->ConvertDevicePathToText (DevicePath1, TRUE, TRUE);\r
+  ConvertDPStr (DevicePathStr1);\r
+  //\r
+  // Get second device path string.\r
+  //\r
+  DevicePathStr2 = DevicePathText->ConvertDevicePathToText (DevicePath2, TRUE, TRUE);\r
+  ConvertDPStr (DevicePathStr2);\r
+  \r
+  //\r
+  // Compare device path string.\r
+  //\r
+  StrLen1 = StrSize (DevicePathStr1);\r
+  StrLen2 = StrSize (DevicePathStr2);\r
+  if (StrLen1 > StrLen2) {\r
+    DevicePathEqual = FALSE;\r
+    goto Done;\r
+  }\r
+  \r
+  if (CompareMem (DevicePathStr1, DevicePathStr2, StrLen1) == 0) {\r
+    DevicePathEqual = TRUE;\r
+  }\r
+\r
+Done:\r
+  FreePool (DevicePathStr1);\r
+  FreePool (DevicePathStr2);\r
+  return DevicePathEqual;\r
+}\r
+\r
+\r
+/**\r
+  Check whether the image pointed to by DevicePath is in the device path list \r
+  specified by AccessType.  \r
+\r
+  @param[in] DevicePath  Points to device path.\r
+  @param[in] AccessType  The type of user access control.\r
\r
+  @retval    TURE        The DevicePath is in the specified List.\r
+  @retval    FALSE       The DevicePath is not in the specified List.\r
+\r
+**/\r
+BOOLEAN\r
+IsDevicePathInList (\r
+  IN  CONST EFI_DEVICE_PATH_PROTOCOL   *DevicePath,\r
+  IN        UINT32                     AccessType\r
+  )\r
+{\r
+  EFI_STATUS                            Status;\r
+  EFI_USER_INFO_ACCESS_CONTROL          *Access;\r
+  EFI_DEVICE_PATH_PROTOCOL              *Path;\r
+  UINTN                                 OffSet;  \r
+\r
+  Status = GetAccessControl (&Access, AccessType);\r
+  if (EFI_ERROR (Status)) {\r
+    return FALSE;\r
+  }  \r
+\r
+  OffSet = 0;\r
+  while (OffSet < Access->Size - sizeof (EFI_USER_INFO_ACCESS_CONTROL)) {\r
+    Path = (EFI_DEVICE_PATH_PROTOCOL*)((UINT8*)(Access + 1) + OffSet);    \r
+    if (CheckDevicePath (Path, DevicePath)) {\r
+      //\r
+      // The device path is found in list.\r
+      //\r
+      FreePool (Access);\r
+      return TRUE;\r
+    }  \r
+    OffSet += GetDevicePathSize (Path);\r
+  }\r
+  \r
+  FreePool (Access);\r
+  return FALSE; \r
+}\r
+\r
+\r
+/**\r
+  Check whether the image pointed to by DevicePath is permitted to load.  \r
+\r
+  @param[in] DevicePath  Points to device path\r
\r
+  @retval    TURE        The image pointed by DevicePath is permitted to load.\r
+  @retval    FALSE       The image pointed by DevicePath is forbidden to load.\r
+\r
+**/\r
+BOOLEAN\r
+VerifyDevicePath (\r
+  IN  CONST EFI_DEVICE_PATH_PROTOCOL   *DevicePath\r
+  )\r
+{\r
+  if (IsDevicePathInList (DevicePath, EFI_USER_INFO_ACCESS_PERMIT_LOAD)) {\r
+    //\r
+    // This access control overrides any restrictions put in place by the \r
+    // EFI_USER_INFO_ACCESS_FORBID_LOAD record.\r
+    //\r
+    return TRUE;\r
+  }\r
+  \r
+  if (IsDevicePathInList (DevicePath, EFI_USER_INFO_ACCESS_FORBID_LOAD)) {\r
+    //\r
+    // The device path is found in the forbidden list.\r
+    //\r
+    return FALSE;\r
+  }\r
+  \r
+  return TRUE; \r
+}\r
+\r
+\r
+/**\r
+  Check the image pointed by DevicePath is a boot option or not.  \r
+\r
+  @param[in] DevicePath  Points to device path.\r
\r
+  @retval    TURE        The image pointed by DevicePath is a boot option.\r
+  @retval    FALSE       The image pointed by DevicePath is not a boot option.\r
+\r
+**/\r
+BOOLEAN\r
+IsBootOption (\r
+  IN  CONST EFI_DEVICE_PATH_PROTOCOL      *DevicePath\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  UINT16                            *BootOrderList;\r
+  UINTN                             BootOrderListSize;\r
+  UINTN                             Index;\r
+  CHAR16                            StrTemp[20];\r
+  UINT8                             *OptionBuffer;\r
+  UINT8                             *OptionPtr;\r
+  EFI_DEVICE_PATH_PROTOCOL          *OptionDevicePath;\r
+  \r
+  //\r
+  // Get BootOrder\r
+  //\r
+  BootOrderListSize = 0;\r
+  BootOrderList     = NULL;  \r
+  Status = gRT->GetVariable (\r
+                  L"BootOrder", \r
+                  &gEfiGlobalVariableGuid, \r
+                  NULL, \r
+                  &BootOrderListSize, \r
+                  NULL\r
+                  );\r
+  if (Status == EFI_BUFFER_TOO_SMALL) {\r
+    BootOrderList = AllocateZeroPool (BootOrderListSize);\r
+    ASSERT (BootOrderList != NULL);\r
+    Status = gRT->GetVariable (\r
+                    L"BootOrder", \r
+                    &gEfiGlobalVariableGuid, \r
+                    NULL, \r
+                    &BootOrderListSize, \r
+                    BootOrderList\r
+                    );\r
+  }\r
+  \r
+  if (EFI_ERROR (Status)) {\r
+    //\r
+    // No Boot option\r
+    //\r
+    return FALSE;\r
+  }\r
+\r
+  OptionBuffer = NULL;\r
+  for (Index = 0; Index < BootOrderListSize / sizeof (UINT16); Index++) {\r
+    //\r
+    // Try to find the DevicePath in BootOption\r
+    //\r
+    UnicodeSPrint (StrTemp, sizeof (StrTemp), L"Boot%04x", Index);\r
+    OptionBuffer = GetEfiGlobalVariable (StrTemp);\r
+    if (OptionBuffer == NULL) {\r
+      continue;\r
+    }\r
+\r
+    //\r
+    // Check whether the image is forbidden.\r
+    //\r
+    \r
+    OptionPtr = OptionBuffer;\r
+    //\r
+    // Skip attribute.\r
+    //\r
+    OptionPtr += sizeof (UINT32);\r
+\r
+    //\r
+    // Skip device path length.\r
+    //\r
+    OptionPtr += sizeof (UINT16);\r
+\r
+    //\r
+    // Skip descript string\r
+    //\r
+    OptionPtr += StrSize ((UINT16 *) OptionPtr);\r
\r
+    //\r
+    // Now OptionPtr points to Device Path.\r
+    //\r
+    OptionDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) OptionPtr;\r
+\r
+    if (CheckDevicePath (DevicePath, OptionDevicePath)) {\r
+      FreePool (OptionBuffer);\r
+      OptionBuffer = NULL;\r
+      return TRUE;\r
+    }\r
+    FreePool (OptionBuffer);\r
+    OptionBuffer = NULL;\r
+  }\r
+\r
+  if (BootOrderList != NULL) {\r
+    FreePool (BootOrderList);\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+\r
+/**\r
+  Add the image info to a deferred image list.\r
+\r
+  @param[in]  ImageDevicePath  A pointer to the device path of a image.                                \r
+  @param[in]  Image            Points to the first byte of the image, or NULL if the \r
+                               image is not available.\r
+  @param[in]  ImageSize        The size of the image, or 0 if the image is not available.\r
+  \r
+**/\r
+VOID\r
+PutDefferedImageInfo (\r
+  IN  CONST EFI_DEVICE_PATH_PROTOCOL    *ImageDevicePath,\r
+  IN        VOID                        *Image,\r
+  IN        UINTN                       ImageSize\r
+  )\r
+{\r
+  DEFERRED_IMAGE_INFO    *CurImageInfo;\r
+  UINTN                  PathSize;\r
+\r
+  //\r
+  // Expand memory for the new deferred image.\r
+  //\r
+  if (mDeferredImage.Count == 0) {\r
+    mDeferredImage.ImageInfo = AllocatePool (sizeof (DEFERRED_IMAGE_INFO));\r
+    ASSERT (mDeferredImage.ImageInfo != NULL);\r
+  } else {\r
+    CurImageInfo = AllocatePool ((mDeferredImage.Count + 1) * sizeof (DEFERRED_IMAGE_INFO));\r
+    ASSERT (CurImageInfo != NULL);\r
+    \r
+    CopyMem (\r
+      CurImageInfo, \r
+      mDeferredImage.ImageInfo,\r
+      mDeferredImage.Count * sizeof (DEFERRED_IMAGE_INFO)\r
+      );\r
+    FreePool (mDeferredImage.ImageInfo);\r
+    mDeferredImage.ImageInfo = CurImageInfo;\r
+  }\r
+  mDeferredImage.Count++;\r
+  \r
+  //\r
+  // Save the deferred image information.\r
+  //\r
+  CurImageInfo = &mDeferredImage.ImageInfo[mDeferredImage.Count - 1];\r
+  PathSize     = GetDevicePathSize (ImageDevicePath);\r
+  CurImageInfo->ImageDevicePath = AllocateZeroPool (PathSize);\r
+  ASSERT (CurImageInfo->ImageDevicePath != NULL);\r
+  CopyMem (CurImageInfo->ImageDevicePath, ImageDevicePath, PathSize);\r
+\r
+  CurImageInfo->Image      = Image;\r
+  CurImageInfo->ImageSize  = ImageSize;\r
+  CurImageInfo->BootOption = IsBootOption (ImageDevicePath);\r
+}\r
+\r
+\r
+/**\r
+  Returns information about a deferred image.\r
+\r
+  This function returns information about a single deferred image. The deferred images are \r
+  numbered consecutively, starting with 0.  If there is no image which corresponds to \r
+  ImageIndex, then EFI_NOT_FOUND is returned. All deferred images may be returned by \r
+  iteratively calling this function until EFI_NOT_FOUND is returned.\r
+  Image may be NULL and ImageSize set to 0 if the decision to defer execution was made \r
+  because of the location of the executable image, rather than its actual contents.  \r
+\r
+  @param[in]  This             Points to this instance of the EFI_DEFERRED_IMAGE_LOAD_PROTOCOL.\r
+  @param[in]  ImageIndex       Zero-based index of the deferred index.\r
+  @param[out] ImageDevicePath  On return, points to a pointer to the device path of the image. \r
+                               The device path should not be freed by the caller. \r
+  @param[out] Image            On return, points to the first byte of the image or NULL if the \r
+                               image is not available. The image should not be freed by the caller\r
+                               unless LoadImage() has been successfully called.  \r
+  @param[out] ImageSize        On return, the size of the image, or 0 if the image is not available.\r
+  @param[out] BootOption       On return, points to TRUE if the image was intended as a boot option \r
+                               or FALSE if it was not intended as a boot option. \r
\r
+  @retval EFI_SUCCESS           Image information returned successfully.\r
+  @retval EFI_NOT_FOUND         ImageIndex does not refer to a valid image.\r
+  @retval EFI_INVALID_PARAMETER ImageDevicePath is NULL or Image is NULL or ImageSize is NULL or \r
+                                BootOption is NULL.\r
+  \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+GetDefferedImageInfo (\r
+  IN     EFI_DEFERRED_IMAGE_LOAD_PROTOCOL  *This,\r
+  IN     UINTN                             ImageIndex,\r
+     OUT EFI_DEVICE_PATH_PROTOCOL          **ImageDevicePath,\r
+     OUT VOID                              **Image,\r
+     OUT UINTN                             *ImageSize,\r
+     OUT BOOLEAN                           *BootOption\r
+  )\r
+{\r
+  DEFERRED_IMAGE_INFO   *ReqImageInfo;\r
+\r
+  //\r
+  // Check the parameter.\r
+  //\r
+\r
+  if ((This == NULL) || (ImageSize == NULL) || (Image == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  \r
+  if ((ImageDevicePath == NULL) || (BootOption == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (ImageIndex >= mDeferredImage.Count) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+  \r
+  //\r
+  // Get the request deferred image.\r
+  // \r
+  ReqImageInfo = &mDeferredImage.ImageInfo[ImageIndex];\r
+   \r
+  *ImageDevicePath = ReqImageInfo->ImageDevicePath;\r
+  *Image           = ReqImageInfo->Image;\r
+  *ImageSize       = ReqImageInfo->ImageSize;\r
+  *BootOption      = ReqImageInfo->BootOption;\r
+  \r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Provides the service of deferring image load based on platform policy control,\r
+  and installs Deferred Image Load Protocol.\r
+\r
+  @param[in]  AuthenticationStatus  This is the authentication status returned from the \r
+                                    security measurement services for the input file.\r
+  @param[in]  File                  This is a pointer to the device path of the file that\r
+                                    is being dispatched. This will optionally be used for\r
+                                    logging.\r
+  @param[in]  FileBuffer            File buffer matches the input file device path.\r
+  @param[in]  FileSize              Size of File buffer matches the input file device path.\r
+\r
+  @retval EFI_SUCCESS               The file specified by File did authenticate, and the\r
+                                    platform policy dictates that the DXE Core may use File.\r
+  @retval EFI_INVALID_PARAMETER     File is NULL.\r
+  @retval EFI_SECURITY_VIOLATION    The file specified by File did not authenticate, and\r
+                                    the platform policy dictates that File should be placed\r
+                                    in the untrusted state. A file may be promoted from\r
+                                    the untrusted to the trusted state at a future time\r
+                                    with a call to the Trust() DXE Service.\r
+  @retval EFI_ACCESS_DENIED         The file specified by File did not authenticate, and\r
+                                    the platform policy dictates that File should not be\r
+                                    used for any purpose.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DxeDeferImageLoadHandler (\r
+  IN  UINT32                           AuthenticationStatus,\r
+  IN  CONST EFI_DEVICE_PATH_PROTOCOL   *File,\r
+  IN  VOID                             *FileBuffer,\r
+  IN  UINTN                            FileSize\r
+  )\r
+\r
+{\r
+  EFI_STATUS                           Status;\r
+  EFI_USER_PROFILE_HANDLE              CurrentUser;\r
+  UINT32                               Policy;\r
+  UINT32                               FileType;\r
+\r
+  if (File == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Check whether user has a logon.\r
+  // \r
+  CurrentUser = NULL;\r
+  if (mUserManager != NULL) {\r
+    mUserManager->Current (mUserManager, &CurrentUser);\r
+    if (CurrentUser != NULL) {\r
+      //\r
+      // The user is logon; verify the FilePath by current user access policy.\r
+      //\r
+      if (!VerifyDevicePath (File)) {\r
+        DEBUG ((EFI_D_ERROR, "[Security] The image is forbidden to load!\n"));\r
+        return EFI_ACCESS_DENIED;\r
+      }\r
+      return EFI_SUCCESS;\r
+    }\r
+  }\r
+  \r
+  //\r
+  // Still no user logon.\r
+  // Check the file type and get policy setting.\r
+  //\r
+  FileType = GetFileType (File);\r
+  Policy   = PcdGet32 (PcdDeferImageLoadPolicy);\r
+  if ((Policy & FileType) == FileType) {\r
+    //\r
+    // This file type is secure to load.\r
+    //\r
+    return EFI_SUCCESS;\r
+  }\r
\r
+  DEBUG ((EFI_D_ERROR, "[Security] No user identified, the image is deferred to load!\n"));\r
+  PutDefferedImageInfo (File, NULL, 0);\r
+\r
+  //\r
+  // Install the Deferred Image Load Protocol onto a new handle.\r
+  //\r
+  if (!mIsProtocolInstalled) {\r
+    Status = gBS->InstallMultipleProtocolInterfaces (\r
+                    &mDeferredImageHandle,\r
+                    &gEfiDeferredImageLoadProtocolGuid,\r
+                    &gDeferredImageLoad,\r
+                    NULL\r
+                    );\r
+    ASSERT_EFI_ERROR (Status);\r
+    mIsProtocolInstalled = TRUE;\r
+  }\r
+\r
+  return EFI_ACCESS_DENIED;\r
+}\r
+\r
+/**\r
+  Locate user manager protocol when user manager is installed.  \r
+\r
+  @param[in] Event    The Event that is being processed, not used.\r
+  @param[in] Context  Event Context, not used. \r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+FindUserManagerProtocol (\r
+  IN EFI_EVENT    Event,\r
+  IN VOID*        Context\r
+  )\r
+{\r
+  gBS->LocateProtocol (\r
+         &gEfiUserManagerProtocolGuid,\r
+         NULL,\r
+         (VOID **) &mUserManager\r
+         );\r
+  \r
+}\r
+\r
+\r
+/**\r
+  Register security handler for deferred image load.\r
+\r
+  @param[in]  ImageHandle   ImageHandle of the loaded driver.\r
+  @param[in]  SystemTable   Pointer to the EFI System Table.\r
+\r
+  @retval EFI_SUCCESS   The handlers were registered successfully.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DxeDeferImageLoadLibConstructor (\r
+  IN EFI_HANDLE        ImageHandle,\r
+  IN EFI_SYSTEM_TABLE  *SystemTable\r
+  )\r
+{\r
+  VOID                 *Registration;\r
+  \r
+  //\r
+  // Register user manager notification function.\r
+  //\r
+  EfiCreateProtocolNotifyEvent (\r
+    &gEfiUserManagerProtocolGuid, \r
+    TPL_CALLBACK,\r
+    FindUserManagerProtocol,\r
+    NULL,\r
+    &Registration\r
+    );\r
+  \r
+  return RegisterSecurityHandler (\r
+           DxeDeferImageLoadHandler,\r
+           EFI_AUTH_OPERATION_DEFER_IMAGE_LOAD \r
+           );      \r
+}\r
+\r
+\r
diff --git a/SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.h b/SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.h
new file mode 100644 (file)
index 0000000..52eb81b
--- /dev/null
@@ -0,0 +1,106 @@
+/** @file\r
+  The internal header file includes the common header files, defines\r
+  internal structure and functions used by DeferImageLoadLib.\r
+\r
+Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef __DEFER_IMAGE_LOAD_LIB_H__\r
+#define __DEFER_IMAGE_LOAD_LIB_H__\r
+\r
+#include <PiDxe.h>\r
+#include <Library/UefiRuntimeServicesTableLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/SecurityManagementLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/DevicePathLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/PrintLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/PcdLib.h>\r
+\r
+#include <Protocol/FirmwareVolume2.h>\r
+#include <Protocol/BlockIo.h>\r
+#include <Protocol/SimpleFileSystem.h>\r
+#include <Protocol/DeferredImageLoad.h>\r
+#include <Protocol/UserCredential.h>\r
+#include <Protocol/UserManager.h>\r
+#include <Protocol/DevicePathToText.h>\r
+\r
+#include <Guid/GlobalVariable.h>\r
+\r
+//\r
+// Image type definitions.\r
+//\r
+#define IMAGE_UNKNOWN                         0x00000001\r
+#define IMAGE_FROM_FV                         0x00000002\r
+#define IMAGE_FROM_OPTION_ROM                 0x00000004\r
+#define IMAGE_FROM_REMOVABLE_MEDIA            0x00000008\r
+#define IMAGE_FROM_FIXED_MEDIA                0x00000010\r
+\r
+//\r
+// The struct to save the deferred image information.\r
+//\r
+typedef struct {\r
+  EFI_DEVICE_PATH_PROTOCOL          *ImageDevicePath;\r
+  VOID                              *Image;\r
+  UINTN                             ImageSize;\r
+  BOOLEAN                           BootOption;\r
+} DEFERRED_IMAGE_INFO;\r
+\r
+//\r
+// The table to save the deferred image item.\r
+//\r
+typedef struct {\r
+  UINTN                             Count;         ///< deferred image count\r
+  DEFERRED_IMAGE_INFO               *ImageInfo;    ///< deferred image item\r
+} DEFERRED_IMAGE_TABLE;\r
+\r
+/**\r
+  Returns information about a deferred image.\r
+\r
+  This function returns information about a single deferred image. The deferred images are \r
+  numbered consecutively, starting with 0.  If there is no image which corresponds to \r
+  ImageIndex, then EFI_NOT_FOUND is returned. All deferred images may be returned by \r
+  iteratively calling this function until EFI_NOT_FOUND is returned.\r
+  Image may be NULL and ImageSize set to 0 if the decision to defer execution was made \r
+  because of the location of the executable image, rather than its actual contents.  \r
+\r
+  @param[in]  This              Points to this instance of the EFI_DEFERRED_IMAGE_LOAD_PROTOCOL.\r
+  @param[in]  ImageIndex        Zero-based index of the deferred index.\r
+  @param[out] ImageDevicePath   On return, points to a pointer to the device path of the image. \r
+                                The device path should not be freed by the caller. \r
+  @param[out] Image             On return, points to the first byte of the image or NULL if the \r
+                                image is not available. The image should not be freed by the caller\r
+                                unless LoadImage() has been called successfully.  \r
+  @param[out] ImageSize         On return, the size of the image, or 0 if the image is not available.\r
+  @param[out] BootOption        On return, points to TRUE if the image was intended as a boot option \r
+                                or FALSE if it was not intended as a boot option. \r
\r
+  @retval EFI_SUCCESS           Image information returned successfully.\r
+  @retval EFI_NOT_FOUND         ImageIndex does not refer to a valid image.\r
+  @retval EFI_INVALID_PARAMETER ImageDevicePath is NULL or Image is NULL or ImageSize is NULL or \r
+                                BootOption is NULL.\r
+  \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+GetDefferedImageInfo (\r
+  IN     EFI_DEFERRED_IMAGE_LOAD_PROTOCOL  *This,\r
+  IN     UINTN                             ImageIndex,\r
+     OUT EFI_DEVICE_PATH_PROTOCOL          **ImageDevicePath,\r
+     OUT VOID                              **Image,\r
+     OUT UINTN                             *ImageSize,\r
+     OUT BOOLEAN                           *BootOption\r
+  );\r
+  \r
+#endif\r
diff --git a/SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.inf b/SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.inf
new file mode 100644 (file)
index 0000000..e16fe8d
--- /dev/null
@@ -0,0 +1,62 @@
+## @file\r
+#  The library instance provides security service of deferring image load.\r
+#\r
+# Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = DxeDeferImageLoadLib   \r
+  FILE_GUID                      = 5E2FAE1F-41DA-4fbd-BC81-603CE5CD8497\r
+  MODULE_TYPE                    = DXE_DRIVER\r
+  VERSION_STRING                 = 1.0\r
+  LIBRARY_CLASS                  = NULL|DXE_DRIVER UEFI_DRIVER DXE_RUNTIME_DRIVER UEFI_APPLICATION\r
+  CONSTRUCTOR                    = DxeDeferImageLoadLibConstructor\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64 EBC\r
+#\r
+\r
+[Sources]\r
+  DxeDeferImageLoadLib.c\r
+  DxeDeferImageLoadLib.h\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+  SecurityPkg/SecurityPkg.dec\r
+\r
+[LibraryClasses]\r
+  UefiRuntimeServicesTableLib\r
+  UefiBootServicesTableLib\r
+  SecurityManagementLib\r
+  MemoryAllocationLib\r
+  DevicePathLib\r
+  BaseMemoryLib\r
+  PrintLib\r
+  DebugLib \r
+  UefiLib\r
+  PcdLib \r
+\r
+[Protocols]\r
+  gEfiFirmwareVolume2ProtocolGuid\r
+  gEfiBlockIoProtocolGuid\r
+  gEfiSimpleFileSystemProtocolGuid\r
+  gEfiUserManagerProtocolGuid\r
+  gEfiDeferredImageLoadProtocolGuid\r
+  gEfiDevicePathToTextProtocolGuid\r
+  \r
+[Guids]\r
+  gEfiGlobalVariableGuid\r
+  \r
+[Pcd]\r
+  gEfiSecurityPkgTokenSpaceGuid.PcdDeferImageLoadPolicy\r
diff --git a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c
new file mode 100644 (file)
index 0000000..148dbd5
--- /dev/null
@@ -0,0 +1,1368 @@
+/** @file\r
+  Implement image verification services for secure boot service in UEFI2.3.1.\r
+\r
+Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "DxeImageVerificationLib.h"\r
+\r
+EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION mNtHeader;\r
+UINTN                               mImageSize;\r
+UINT32                              mPeCoffHeaderOffset; \r
+UINT8                               mImageDigest[MAX_DIGEST_SIZE];\r
+UINTN                               mImageDigestSize;\r
+EFI_IMAGE_DATA_DIRECTORY            *mSecDataDir      = NULL;\r
+UINT8                               *mImageBase       = NULL;\r
+EFI_GUID                            mCertType;\r
+\r
+//\r
+// Notify string for authorization UI.\r
+//\r
+CHAR16  mNotifyString1[MAX_NOTIFY_STRING_LEN] = L"Image verification pass but not found in authorized database!";\r
+CHAR16  mNotifyString2[MAX_NOTIFY_STRING_LEN] = L"Launch this image anyway? (Yes/Defer/No)";\r
+//\r
+// Public Exponent of RSA Key.\r
+//\r
+CONST UINT8 mRsaE[] = { 0x01, 0x00, 0x01 };\r
+\r
+\r
+//\r
+// OID ASN.1 Value for Hash Algorithms\r
+//\r
+UINT8 mHashOidValue[] = {\r
+  0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05,         // OBJ_md5\r
+  0x2B, 0x0E, 0x03, 0x02, 0x1A,                           // OBJ_sha1\r
+  0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04,   // OBJ_sha224\r
+  0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01,   // OBJ_sha256\r
+  0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02,   // OBJ_sha384\r
+  0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03,   // OBJ_sha512\r
+  };\r
+\r
+HASH_TABLE mHash[] = {\r
+  { L"SHA1",   20, &mHashOidValue[8],  5, Sha1GetContextSize,  Sha1Init,   Sha1Update,    Sha1Final  },\r
+  { L"SHA224", 28, &mHashOidValue[13], 9, NULL,                NULL,       NULL,          NULL       },\r
+  { L"SHA256", 32, &mHashOidValue[22], 9, Sha256GetContextSize,Sha256Init, Sha256Update,  Sha256Final},\r
+  { L"SHA384", 48, &mHashOidValue[31], 9, NULL,                NULL,       NULL,          NULL       },\r
+  { L"SHA512", 64, &mHashOidValue[40], 9, NULL,                NULL,       NULL,          NULL       }\r
+};\r
+\r
+\r
+/**\r
+  Get the image type.\r
+\r
+  @param[in]    File       This is a pointer to the device path of the file that is\r
+                           being dispatched. \r
+\r
+  @return UINT32           Image Type             \r
+\r
+**/\r
+UINT32\r
+GetImageType (\r
+  IN  CONST EFI_DEVICE_PATH_PROTOCOL   *File\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  EFI_HANDLE                        DeviceHandle; \r
+  EFI_DEVICE_PATH_PROTOCOL          *TempDevicePath;\r
+  EFI_BLOCK_IO_PROTOCOL             *BlockIo;\r
+\r
+  //\r
+  // First check to see if File is from a Firmware Volume\r
+  //\r
+  DeviceHandle      = NULL;\r
+  TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File;\r
+  Status = gBS->LocateDevicePath (\r
+                  &gEfiFirmwareVolume2ProtocolGuid,\r
+                  &TempDevicePath,\r
+                  &DeviceHandle\r
+                  );\r
+  if (!EFI_ERROR (Status)) {\r
+    Status = gBS->OpenProtocol (\r
+                    DeviceHandle,\r
+                    &gEfiFirmwareVolume2ProtocolGuid,\r
+                    NULL,\r
+                    NULL,\r
+                    NULL,\r
+                    EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+                    );\r
+    if (!EFI_ERROR (Status)) {\r
+      return IMAGE_FROM_FV;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Next check to see if File is from a Block I/O device\r
+  //\r
+  DeviceHandle   = NULL;\r
+  TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File;\r
+  Status = gBS->LocateDevicePath (\r
+                  &gEfiBlockIoProtocolGuid,\r
+                  &TempDevicePath,\r
+                  &DeviceHandle\r
+                  );\r
+  if (!EFI_ERROR (Status)) {\r
+    BlockIo = NULL;\r
+    Status = gBS->OpenProtocol (\r
+                    DeviceHandle,\r
+                    &gEfiBlockIoProtocolGuid,\r
+                    (VOID **) &BlockIo,\r
+                    NULL,\r
+                    NULL,\r
+                    EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                    );\r
+    if (!EFI_ERROR (Status) && BlockIo != NULL) {\r
+      if (BlockIo->Media != NULL) {\r
+        if (BlockIo->Media->RemovableMedia) {\r
+          //\r
+          // Block I/O is present and specifies the media is removable\r
+          //\r
+          return IMAGE_FROM_REMOVABLE_MEDIA;\r
+        } else {\r
+          //\r
+          // Block I/O is present and specifies the media is not removable\r
+          //\r
+          return IMAGE_FROM_FIXED_MEDIA;\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
+  //\r
+  // File is not in a Firmware Volume or on a Block I/O device, so check to see if \r
+  // the device path supports the Simple File System Protocol.\r
+  //\r
+  DeviceHandle   = NULL;\r
+  TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File;\r
+  Status = gBS->LocateDevicePath (\r
+                  &gEfiSimpleFileSystemProtocolGuid,\r
+                  &TempDevicePath,\r
+                  &DeviceHandle\r
+                  );\r
+  if (!EFI_ERROR (Status)) {\r
+    //\r
+    // Simple File System is present without Block I/O, so assume media is fixed.\r
+    //\r
+    return IMAGE_FROM_FIXED_MEDIA;\r
+  }\r
+\r
+  //\r
+  // File is not from an FV, Block I/O or Simple File System, so the only options\r
+  // left are a PCI Option ROM and a Load File Protocol such as a PXE Boot from a NIC.  \r
+  //\r
+  TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File;\r
+  while (!IsDevicePathEndType (TempDevicePath)) {\r
+    switch (DevicePathType (TempDevicePath)) {\r
+    \r
+    case MEDIA_DEVICE_PATH:\r
+      if (DevicePathSubType (TempDevicePath) == MEDIA_RELATIVE_OFFSET_RANGE_DP) {\r
+        return IMAGE_FROM_OPTION_ROM;\r
+      }\r
+      break;\r
+\r
+    case MESSAGING_DEVICE_PATH:\r
+      if (DevicePathSubType(TempDevicePath) == MSG_MAC_ADDR_DP) {\r
+        return IMAGE_FROM_REMOVABLE_MEDIA;\r
+      } \r
+      break;\r
+\r
+    default:\r
+      break;\r
+    }\r
+    TempDevicePath = NextDevicePathNode (TempDevicePath);\r
+  }\r
+  return IMAGE_UNKNOWN; \r
+}\r
+\r
+/**\r
+  Caculate hash of Pe/Coff image based on the authenticode image hashing in\r
+  PE/COFF Specification 8.0 Appendix A\r
+\r
+  @param[in]    HashAlg   Hash algorithm type.\r
\r
+  @retval TRUE            Successfully hash image.\r
+  @retval FALSE           Fail in hash image.\r
+\r
+**/\r
+BOOLEAN \r
+HashPeImage (\r
+  IN  UINT32              HashAlg\r
+  )\r
+{\r
+  BOOLEAN                   Status;\r
+  UINT16                    Magic;\r
+  EFI_IMAGE_SECTION_HEADER  *Section;\r
+  VOID                      *HashCtx;\r
+  UINTN                     CtxSize;\r
+  UINT8                     *HashBase;\r
+  UINTN                     HashSize;\r
+  UINTN                     SumOfBytesHashed;\r
+  EFI_IMAGE_SECTION_HEADER  *SectionHeader;\r
+  UINTN                     Index;\r
+  UINTN                     Pos;\r
+\r
+  HashCtx       = NULL;\r
+  SectionHeader = NULL;\r
+  Status        = FALSE;\r
+\r
+  if ((HashAlg != HASHALG_SHA1) && (HashAlg != HASHALG_SHA256)) {\r
+    return FALSE;\r
+  }\r
+  \r
+  //\r
+  // Initialize context of hash.\r
+  //\r
+  ZeroMem (mImageDigest, MAX_DIGEST_SIZE);\r
+\r
+  if (HashAlg == HASHALG_SHA1) {\r
+    mImageDigestSize  = SHA1_DIGEST_SIZE;\r
+    mCertType         = gEfiCertSha1Guid;\r
+  } else if (HashAlg == HASHALG_SHA256) {\r
+    mImageDigestSize  = SHA256_DIGEST_SIZE;\r
+    mCertType         = gEfiCertSha256Guid;\r
+  } else {\r
+    return FALSE;\r
+  }\r
+\r
+  CtxSize   = mHash[HashAlg].GetContextSize();\r
+  \r
+  HashCtx = AllocatePool (CtxSize);\r
+  ASSERT (HashCtx != NULL);\r
+\r
+  // 1.  Load the image header into memory.\r
+\r
+  // 2.  Initialize a SHA hash context.\r
+  Status = mHash[HashAlg].HashInit(HashCtx);\r
+  \r
+  if (!Status) {\r
+    goto Done;\r
+  }\r
+  //\r
+  // Measuring PE/COFF Image Header;\r
+  // But CheckSum field and SECURITY data directory (certificate) are excluded\r
+  //\r
+  Magic = mNtHeader.Pe32->OptionalHeader.Magic;\r
+  //\r
+  // 3.  Calculate the distance from the base of the image header to the image checksum address.\r
+  // 4.  Hash the image header from its base to beginning of the image checksum.\r
+  //\r
+  HashBase = mImageBase;\r
+  if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
+    //\r
+    // Use PE32 offset.\r
+    //\r
+    HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32->OptionalHeader.CheckSum) - HashBase);\r
+  } else {\r
+    //\r
+    // Use PE32+ offset.\r
+    //\r
+    HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32Plus->OptionalHeader.CheckSum) - HashBase);\r
+  }\r
+\r
+  Status  = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);\r
+  if (!Status) {\r
+    goto Done;\r
+  }\r
+  //\r
+  // 5.  Skip over the image checksum (it occupies a single ULONG).\r
+  // 6.  Get the address of the beginning of the Cert Directory.\r
+  // 7.  Hash everything from the end of the checksum to the start of the Cert Directory.\r
+  //\r
+  if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
+    //\r
+    // Use PE32 offset.\r
+    //\r
+    HashBase = (UINT8 *) &mNtHeader.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);\r
+    HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase);\r
+  } else {\r
+    //\r
+    // Use PE32+ offset.\r
+    //    \r
+    HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);\r
+    HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase);\r
+  }\r
+\r
+  Status  = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);\r
+  if (!Status) {\r
+    goto Done;\r
+  }\r
+  //\r
+  // 8.  Skip over the Cert Directory. (It is sizeof(IMAGE_DATA_DIRECTORY) bytes.)\r
+  // 9.  Hash everything from the end of the Cert Directory to the end of image header.\r
+  //\r
+  if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
+    //\r
+    // Use PE32 offset\r
+    //\r
+    HashBase = (UINT8 *) &mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];\r
+    HashSize = mNtHeader.Pe32->OptionalHeader.SizeOfHeaders - (UINTN) ((UINT8 *) (&mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]) - mImageBase);\r
+  } else {\r
+    //\r
+    // Use PE32+ offset.\r
+    //\r
+    HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];\r
+    HashSize = mNtHeader.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN) ((UINT8 *) (&mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]) - mImageBase);\r
+  }\r
+\r
+  Status  = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);\r
+  if (!Status) {\r
+    goto Done;\r
+  }\r
+  //\r
+  // 10. Set the SUM_OF_BYTES_HASHED to the size of the header.\r
+  //\r
+  if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
+    //\r
+    // Use PE32 offset.\r
+    //\r
+    SumOfBytesHashed = mNtHeader.Pe32->OptionalHeader.SizeOfHeaders;\r
+  } else {\r
+    //\r
+    // Use PE32+ offset\r
+    //\r
+    SumOfBytesHashed = mNtHeader.Pe32Plus->OptionalHeader.SizeOfHeaders;\r
+  }\r
+\r
+  //\r
+  // 11. Build a temporary table of pointers to all the IMAGE_SECTION_HEADER\r
+  //     structures in the image. The 'NumberOfSections' field of the image\r
+  //     header indicates how big the table should be. Do not include any\r
+  //     IMAGE_SECTION_HEADERs in the table whose 'SizeOfRawData' field is zero.\r
+  //\r
+  SectionHeader = (EFI_IMAGE_SECTION_HEADER *) AllocateZeroPool (sizeof (EFI_IMAGE_SECTION_HEADER) * mNtHeader.Pe32->FileHeader.NumberOfSections);\r
+  ASSERT (SectionHeader != NULL);\r
+  //\r
+  // 12.  Using the 'PointerToRawData' in the referenced section headers as\r
+  //      a key, arrange the elements in the table in ascending order. In other\r
+  //      words, sort the section headers according to the disk-file offset of\r
+  //      the section.\r
+  //\r
+  Section = (EFI_IMAGE_SECTION_HEADER *) (\r
+               mImageBase +\r
+               mPeCoffHeaderOffset +\r
+               sizeof (UINT32) +\r
+               sizeof (EFI_IMAGE_FILE_HEADER) +\r
+               mNtHeader.Pe32->FileHeader.SizeOfOptionalHeader\r
+               );\r
+  for (Index = 0; Index < mNtHeader.Pe32->FileHeader.NumberOfSections; Index++) {\r
+    Pos = Index;\r
+    while ((Pos > 0) && (Section->PointerToRawData < SectionHeader[Pos - 1].PointerToRawData)) {\r
+      CopyMem (&SectionHeader[Pos], &SectionHeader[Pos - 1], sizeof (EFI_IMAGE_SECTION_HEADER));\r
+      Pos--;\r
+    }\r
+    CopyMem (&SectionHeader[Pos], Section, sizeof (EFI_IMAGE_SECTION_HEADER));\r
+    Section += 1;\r
+  }\r
+\r
+  //\r
+  // 13.  Walk through the sorted table, bring the corresponding section\r
+  //      into memory, and hash the entire section (using the 'SizeOfRawData'\r
+  //      field in the section header to determine the amount of data to hash).\r
+  // 14.  Add the section's 'SizeOfRawData' to SUM_OF_BYTES_HASHED .\r
+  // 15.  Repeat steps 13 and 14 for all the sections in the sorted table.\r
+  //\r
+  for (Index = 0; Index < mNtHeader.Pe32->FileHeader.NumberOfSections; Index++) {\r
+    Section = &SectionHeader[Index];\r
+    if (Section->SizeOfRawData == 0) {\r
+      continue;\r
+    }\r
+    HashBase  = mImageBase + Section->PointerToRawData;\r
+    HashSize  = (UINTN) Section->SizeOfRawData;\r
+\r
+    Status  = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);\r
+    if (!Status) {\r
+      goto Done;\r
+    }\r
+\r
+    SumOfBytesHashed += HashSize;\r
+  }\r
+\r
+  //\r
+  // 16.  If the file size is greater than SUM_OF_BYTES_HASHED, there is extra\r
+  //      data in the file that needs to be added to the hash. This data begins\r
+  //      at file offset SUM_OF_BYTES_HASHED and its length is:\r
+  //             FileSize  -  (CertDirectory->Size)\r
+  //\r
+  if (mImageSize > SumOfBytesHashed) {\r
+    HashBase = mImageBase + SumOfBytesHashed;\r
+    if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
+      //\r
+      // Use PE32 offset.\r
+      //\r
+      HashSize = (UINTN)(\r
+                 mImageSize -\r
+                 mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size -\r
+                 SumOfBytesHashed);\r
+    } else {\r
+      //\r
+      // Use PE32+ offset.\r
+      //\r
+      HashSize = (UINTN)(\r
+                 mImageSize -\r
+                 mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size -\r
+                 SumOfBytesHashed);      \r
+    }\r
+\r
+    Status  = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);\r
+    if (!Status) {\r
+      goto Done;\r
+    }\r
+  }\r
+  Status  = mHash[HashAlg].HashFinal(HashCtx, mImageDigest);\r
+\r
+Done:\r
+  if (HashCtx != NULL) {\r
+    FreePool (HashCtx);\r
+  }\r
+  if (SectionHeader != NULL) {\r
+    FreePool (SectionHeader);\r
+  }\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Recognize the Hash algorithm in PE/COFF Authenticode and caculate hash of \r
+  Pe/Coff image based on the authenticode image hashing in PE/COFF Specification \r
+  8.0 Appendix A\r
+\r
+  @retval EFI_UNSUPPORTED             Hash algorithm is not supported.\r
+  @retval EFI_SUCCESS                 Hash successfully.\r
+\r
+**/\r
+EFI_STATUS \r
+HashPeImageByType (\r
+  VOID\r
+  )\r
+{\r
+  UINT8                     Index;\r
+  WIN_CERTIFICATE_EFI_PKCS  *PkcsCertData;\r
+\r
+  PkcsCertData = (WIN_CERTIFICATE_EFI_PKCS *) (mImageBase + mSecDataDir->VirtualAddress);\r
+\r
+  for (Index = 0; Index < HASHALG_MAX; Index++) {  \r
+    //\r
+    // Check the Hash algorithm in PE/COFF Authenticode.\r
+    //    According to PKCS#7 Definition: \r
+    //        SignedData ::= SEQUENCE {\r
+    //            version Version,\r
+    //            digestAlgorithms DigestAlgorithmIdentifiers,\r
+    //            contentInfo ContentInfo,\r
+    //            .... }\r
+    //    The DigestAlgorithmIdentifiers can be used to determine the hash algorithm in PE/COFF hashing\r
+    //    This field has the fixed offset (+32) in final Authenticode ASN.1 data.\r
+    //    \r
+    if (CompareMem (PkcsCertData->CertData + 32, mHash[Index].OidValue, mHash[Index].OidLength) == 0) {\r
+      break;\r
+    }\r
+  }\r
+\r
+  if (Index == HASHALG_MAX) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  //\r
+  // HASH PE Image based on Hash algorithm in PE/COFF Authenticode.\r
+  //\r
+  if (!HashPeImage(Index)) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Returns the size of a given image execution info table in bytes.\r
+\r
+  This function returns the size, in bytes, of the image execution info table specified by\r
+  ImageExeInfoTable. If ImageExeInfoTable is NULL, then 0 is returned.\r
+\r
+  @param  ImageExeInfoTable          A pointer to a image execution info table structure.\r
+  \r
+  @retval 0       If ImageExeInfoTable is NULL.\r
+  @retval Others  The size of a image execution info table in bytes.\r
+\r
+**/\r
+UINTN\r
+GetImageExeInfoTableSize (\r
+  EFI_IMAGE_EXECUTION_INFO_TABLE        *ImageExeInfoTable\r
+  )\r
+{\r
+  UINTN                     Index;\r
+  EFI_IMAGE_EXECUTION_INFO  *ImageExeInfoItem;\r
+  UINTN                     TotalSize;\r
+\r
+  if (ImageExeInfoTable == NULL) {\r
+    return 0;\r
+  }\r
+\r
+  ImageExeInfoItem  = (EFI_IMAGE_EXECUTION_INFO *) ((UINT8 *) ImageExeInfoTable + sizeof (EFI_IMAGE_EXECUTION_INFO_TABLE));\r
+  TotalSize         = sizeof (EFI_IMAGE_EXECUTION_INFO_TABLE);\r
+  for (Index = 0; Index < ImageExeInfoTable->NumberOfImages; Index++) {\r
+    TotalSize += ReadUnaligned32 ((UINT32 *) &ImageExeInfoItem->InfoSize);\r
+    ImageExeInfoItem = (EFI_IMAGE_EXECUTION_INFO *) ((UINT8 *) ImageExeInfoItem + ReadUnaligned32 ((UINT32 *) &ImageExeInfoItem->InfoSize));\r
+  }\r
+\r
+  return TotalSize;\r
+}\r
+\r
+/**\r
+  Create an Image Execution Information Table entry and add it to system configuration table.\r
+\r
+  @param[in]  Action          Describes the action taken by the firmware regarding this image.\r
+  @param[in]  Name            Input a null-terminated, user-friendly name.\r
+  @param[in]  DevicePath      Input device path pointer.\r
+  @param[in]  Signature       Input signature info in EFI_SIGNATURE_LIST data structure.\r
+  @param[in]  SignatureSize   Size of signature.\r
+  \r
+**/\r
+VOID\r
+AddImageExeInfo (\r
+  IN       EFI_IMAGE_EXECUTION_ACTION       Action, \r
+  IN       CHAR16                           *Name OPTIONAL, \r
+  IN CONST EFI_DEVICE_PATH_PROTOCOL         *DevicePath,\r
+  IN       EFI_SIGNATURE_LIST               *Signature OPTIONAL,\r
+  IN       UINTN                            SignatureSize\r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  EFI_IMAGE_EXECUTION_INFO_TABLE  *ImageExeInfoTable;\r
+  EFI_IMAGE_EXECUTION_INFO_TABLE  *NewImageExeInfoTable;\r
+  EFI_IMAGE_EXECUTION_INFO        *ImageExeInfoEntry;\r
+  UINTN                           ImageExeInfoTableSize;\r
+  UINTN                           NewImageExeInfoEntrySize;\r
+  UINTN                           NameStringLen;\r
+  UINTN                           DevicePathSize;\r
+\r
+  ASSERT (DevicePath != NULL);\r
+  ImageExeInfoTable     = NULL;\r
+  NewImageExeInfoTable  = NULL;\r
+  ImageExeInfoEntry     = NULL;\r
+  NameStringLen         = 0;\r
+\r
+  if (Name != NULL) {\r
+    NameStringLen = StrSize (Name);\r
+  }\r
+\r
+  ImageExeInfoTable = NULL;\r
+  EfiGetSystemConfigurationTable (&gEfiImageSecurityDatabaseGuid, (VOID**)&ImageExeInfoTable);\r
+  if (ImageExeInfoTable != NULL) {\r
+    //\r
+    // The table has been found!\r
+    // We must enlarge the table to accmodate the new exe info entry.\r
+    //\r
+    ImageExeInfoTableSize = GetImageExeInfoTableSize (ImageExeInfoTable);\r
+  } else {\r
+    //\r
+    // Not Found!\r
+    // We should create a new table to append to the configuration table.\r
+    //\r
+    ImageExeInfoTableSize = sizeof (EFI_IMAGE_EXECUTION_INFO_TABLE);\r
+  }\r
+\r
+  DevicePathSize            = GetDevicePathSize (DevicePath);\r
+  NewImageExeInfoEntrySize  = sizeof (EFI_IMAGE_EXECUTION_INFO) + NameStringLen + DevicePathSize + SignatureSize;\r
+  NewImageExeInfoTable      = (EFI_IMAGE_EXECUTION_INFO_TABLE *) AllocateRuntimePool (ImageExeInfoTableSize + NewImageExeInfoEntrySize);\r
+  ASSERT (NewImageExeInfoTable != NULL);\r
+\r
+  if (ImageExeInfoTable != NULL) {\r
+    CopyMem (NewImageExeInfoTable, ImageExeInfoTable, ImageExeInfoTableSize);\r
+  } else {\r
+    NewImageExeInfoTable->NumberOfImages = 0;\r
+  }\r
+  NewImageExeInfoTable->NumberOfImages++;\r
+  ImageExeInfoEntry = (EFI_IMAGE_EXECUTION_INFO *) ((UINT8 *) NewImageExeInfoTable + ImageExeInfoTableSize);\r
+  //\r
+  // Update new item's infomation.\r
+  //\r
+  WriteUnaligned32 ((UINT32 *) &ImageExeInfoEntry->Action, Action);\r
+  WriteUnaligned32 ((UINT32 *) &ImageExeInfoEntry->InfoSize, (UINT32) NewImageExeInfoEntrySize);\r
+\r
+  if (Name != NULL) {\r
+    CopyMem ((UINT8 *) &ImageExeInfoEntry->InfoSize + sizeof (UINT32), Name, NameStringLen);\r
+  }\r
+  CopyMem (\r
+    (UINT8 *) &ImageExeInfoEntry->InfoSize + sizeof (UINT32) + NameStringLen,\r
+    DevicePath,\r
+    DevicePathSize\r
+    );\r
+  if (Signature != NULL) {\r
+    CopyMem (\r
+      (UINT8 *) &ImageExeInfoEntry->InfoSize + sizeof (UINT32) + NameStringLen + DevicePathSize,\r
+      Signature,\r
+      SignatureSize\r
+      );\r
+  }\r
+  //\r
+  // Update/replace the image execution table.\r
+  //\r
+  Status = gBS->InstallConfigurationTable (&gEfiImageSecurityDatabaseGuid, (VOID *) NewImageExeInfoTable);\r
+  ASSERT_EFI_ERROR (Status);\r
+  //\r
+  // Free Old table data!\r
+  //\r
+  if (ImageExeInfoTable != NULL) {\r
+    FreePool (ImageExeInfoTable);\r
+  }\r
+}\r
+\r
+/**\r
+  Discover if the UEFI image is authorized by user's policy setting.\r
+\r
+  @param[in]    Policy            Specify platform's policy setting. \r
+\r
+  @retval EFI_ACCESS_DENIED       Image is not allowed to run.\r
+  @retval EFI_SECURITY_VIOLATION  Image is deferred.\r
+  @retval EFI_SUCCESS             Image is authorized to run.\r
+\r
+**/\r
+EFI_STATUS\r
+ImageAuthorization (\r
+  IN UINT32     Policy\r
+  )\r
+{\r
+  EFI_STATUS    Status;\r
+  EFI_INPUT_KEY Key;\r
+\r
+  Status = EFI_ACCESS_DENIED;\r
+\r
+  switch (Policy) {\r
+  \r
+  case QUERY_USER_ON_SECURITY_VIOLATION:\r
+    do {\r
+      CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, mNotifyString1, mNotifyString2, NULL);\r
+      if (Key.UnicodeChar == L'Y' || Key.UnicodeChar == L'y') {\r
+        Status = EFI_SUCCESS;\r
+        break;\r
+      } else if (Key.UnicodeChar == L'N' || Key.UnicodeChar == L'n') {\r
+        Status = EFI_ACCESS_DENIED;\r
+        break;\r
+      } else if (Key.UnicodeChar == L'D' || Key.UnicodeChar == L'd') {\r
+        Status = EFI_SECURITY_VIOLATION;\r
+        break;\r
+      }\r
+    } while (TRUE);\r
+    break;\r
+\r
+  case ALLOW_EXECUTE_ON_SECURITY_VIOLATION:\r
+    Status = EFI_SUCCESS;\r
+    break;\r
+\r
+  case DEFER_EXECUTE_ON_SECURITY_VIOLATION:\r
+    Status = EFI_SECURITY_VIOLATION;\r
+    break;\r
+\r
+  case DENY_EXECUTE_ON_SECURITY_VIOLATION:\r
+    Status = EFI_ACCESS_DENIED;\r
+    break;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Check whether signature is in specified database.\r
+\r
+  @param[in]  VariableName        Name of database variable that is searched in.\r
+  @param[in]  Signature           Pointer to signature that is searched for.\r
+  @param[in]  CertType            Pointer to hash algrithom.\r
+  @param[in]  SignatureSize       Size of Signature.\r
+\r
+  @return TRUE                    Found the signature in the variable database.\r
+  @return FALSE                   Not found the signature in the variable database.\r
+\r
+**/\r
+BOOLEAN\r
+IsSignatureFoundInDatabase (\r
+  IN CHAR16             *VariableName,\r
+  IN UINT8              *Signature, \r
+  IN EFI_GUID           *CertType,\r
+  IN UINTN              SignatureSize\r
+  )\r
+{\r
+  EFI_STATUS          Status;\r
+  EFI_SIGNATURE_LIST  *CertList;\r
+  EFI_SIGNATURE_DATA  *Cert;\r
+  UINTN               DataSize;\r
+  UINT8               *Data;\r
+  UINTN               Index;\r
+  UINTN               CertCount;\r
+  BOOLEAN             IsFound;\r
+  //\r
+  // Read signature database variable.\r
+  //\r
+  IsFound   = FALSE;\r
+  Data      = NULL;\r
+  DataSize  = 0;\r
+  Status    = gRT->GetVariable (VariableName, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, NULL);\r
+  if (Status != EFI_BUFFER_TOO_SMALL) {\r
+    return FALSE;\r
+  }\r
+\r
+  Data = (UINT8 *) AllocateZeroPool (DataSize);\r
+  ASSERT (Data != NULL);\r
+\r
+  Status = gRT->GetVariable (VariableName, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, Data);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+  //\r
+  // Enumerate all signature data in SigDB to check if executable's signature exists.\r
+  //\r
+  CertList = (EFI_SIGNATURE_LIST *) Data;\r
+  while ((DataSize > 0) && (DataSize >= CertList->SignatureListSize)) {\r
+    CertCount = (CertList->SignatureListSize - CertList->SignatureHeaderSize) / CertList->SignatureSize;\r
+    Cert      = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\r
+    if ((CertList->SignatureSize == sizeof(EFI_SIGNATURE_DATA) - 1 + SignatureSize) && (CompareGuid(&CertList->SignatureType, CertType))) {\r
+      for (Index = 0; Index < CertCount; Index++) {\r
+        if (CompareMem (Cert->SignatureData, Signature, SignatureSize) == 0) {\r
+          //\r
+          // Find the signature in database.\r
+          //\r
+          IsFound = TRUE;\r
+          break;\r
+        }\r
+\r
+        Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);\r
+      }\r
+\r
+      if (IsFound) {\r
+        break;\r
+      }\r
+    }\r
+\r
+    DataSize -= CertList->SignatureListSize;\r
+    CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);\r
+  }\r
+\r
+Done:\r
+  if (Data != NULL) {\r
+    FreePool (Data);\r
+  }\r
+\r
+  return IsFound;\r
+}\r
+\r
+/**\r
+  Verify certificate in WIN_CERT_TYPE_PKCS_SIGNED_DATA format .\r
+\r
+  @retval EFI_SUCCESS                 Image pass verification.\r
+  @retval EFI_SECURITY_VIOLATION      Image fail verification.\r
+  @retval other error value\r
+\r
+**/\r
+EFI_STATUS \r
+VerifyCertPkcsSignedData (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  BOOLEAN                   VerifyStatus;\r
+  WIN_CERTIFICATE_EFI_PKCS  *PkcsCertData;\r
+  EFI_SIGNATURE_LIST        *CertList;\r
+  EFI_SIGNATURE_DATA        *Cert;\r
+  UINTN                     DataSize;\r
+  UINT8                     *Data;\r
+  UINT8                     *RootCert;\r
+  UINTN                     RootCertSize;\r
+  UINTN                     Index;\r
+  UINTN                     CertCount;\r
+\r
+  Data                   = NULL;\r
+  CertList               = NULL;\r
+  Cert                   = NULL;\r
+  RootCert               = NULL;\r
+  RootCertSize           = 0;\r
+  VerifyStatus           = FALSE;\r
+  PkcsCertData           = (WIN_CERTIFICATE_EFI_PKCS *) (mImageBase + mSecDataDir->VirtualAddress);\r
+\r
+  //\r
+  // 1: Find certificate from KEK database and try to verify authenticode struct.\r
+  //\r
+  DataSize = 0;\r
+  Status   = gRT->GetVariable (EFI_KEY_EXCHANGE_KEY_NAME, &gEfiGlobalVariableGuid, NULL, &DataSize, NULL);\r
+  if (Status == EFI_BUFFER_TOO_SMALL) {\r
+    Data = (UINT8 *)AllocateZeroPool (DataSize);\r
+    ASSERT (Data != NULL);\r
+\r
+    Status = gRT->GetVariable (EFI_KEY_EXCHANGE_KEY_NAME, &gEfiGlobalVariableGuid, NULL, &DataSize, (VOID *)Data);\r
+    if (EFI_ERROR (Status)) {\r
+      goto Done;\r
+    }\r
+    \r
+    //\r
+    // Find Cert Enrolled in KEK database to verify the signature in pkcs7 signed data.\r
+    // \r
+    CertList = (EFI_SIGNATURE_LIST *) Data;\r
+    while ((DataSize > 0) && (DataSize >= CertList->SignatureListSize)) {\r
+      if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {\r
+        Cert          = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\r
+        CertCount     = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;\r
+        for (Index = 0; Index < CertCount; Index++) {\r
+          //\r
+          // Iterate each Signature Data Node within this CertList for a verify\r
+          //        \r
+          RootCert      = Cert->SignatureData;\r
+          RootCertSize  = CertList->SignatureSize;\r
+  \r
+          //\r
+          // Call AuthenticodeVerify library to Verify Authenticode struct. \r
+          //\r
+          VerifyStatus = AuthenticodeVerify (\r
+                           PkcsCertData->CertData,\r
+                           mSecDataDir->Size - sizeof(PkcsCertData->Hdr),\r
+                           RootCert,\r
+                           RootCertSize,\r
+                           mImageDigest,\r
+                           mImageDigestSize\r
+                           );\r
+  \r
+          if (VerifyStatus) {\r
+            goto Done;\r
+          }\r
+          Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);\r
+        }        \r
+      }\r
+      DataSize -= CertList->SignatureListSize;\r
+      CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);\r
+    }\r
+  }\r
+\r
+  \r
+\r
+  //\r
+  // 2: Find certificate from DB database and try to verify authenticode struct.\r
+  //\r
+  DataSize = 0;\r
+  Status   = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, NULL);\r
+  if (Status == EFI_BUFFER_TOO_SMALL) {\r
+    Data = (UINT8 *)AllocateZeroPool (DataSize);\r
+    ASSERT (Data != NULL);\r
+\r
+    Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, (VOID *)Data);\r
+    if (EFI_ERROR (Status)) {\r
+      goto Done;\r
+    }\r
+\r
+    //\r
+    // Find Cert Enrolled in DB database to verify the signature in pkcs7 signed data.\r
+    // \r
+    CertList = (EFI_SIGNATURE_LIST *) Data;\r
+    while ((DataSize > 0) && (DataSize >= CertList->SignatureListSize)) {\r
+      if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {\r
+        Cert          = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\r
+        CertCount     = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;\r
+        for (Index = 0; Index < CertCount; Index++) {\r
+          //\r
+          // Iterate each Signature Data Node within this CertList for a verify\r
+          //        \r
+          RootCert      = Cert->SignatureData;\r
+          RootCertSize  = CertList->SignatureSize;\r
+  \r
+          //\r
+          // Call AuthenticodeVerify library to Verify Authenticode struct. \r
+          //\r
+          VerifyStatus = AuthenticodeVerify (\r
+                           PkcsCertData->CertData,\r
+                           mSecDataDir->Size - sizeof(PkcsCertData->Hdr),\r
+                           RootCert,\r
+                           RootCertSize,\r
+                           mImageDigest,\r
+                           mImageDigestSize\r
+                           );\r
+  \r
+          if (VerifyStatus) {\r
+            goto Done;\r
+          }\r
+          Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);\r
+        }        \r
+      }\r
+      DataSize -= CertList->SignatureListSize;\r
+      CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);\r
+    }\r
+  }\r
+\r
+Done:\r
+  if (Data != NULL) {\r
+    FreePool (Data);\r
+  }\r
+\r
+  if (VerifyStatus) {\r
+    return EFI_SUCCESS;\r
+  } else {\r
+    return EFI_SECURITY_VIOLATION;\r
+  }\r
+}\r
+\r
+/**\r
+  Verify certificate in WIN_CERTIFICATE_UEFI_GUID format. \r
+\r
+  @retval EFI_SUCCESS                 Image pass verification.\r
+  @retval EFI_SECURITY_VIOLATION      Image fail verification.\r
+  @retval other error value\r
+\r
+**/\r
+EFI_STATUS \r
+VerifyCertUefiGuid (\r
+  VOID\r
+  )\r
+{\r
+  BOOLEAN                         Status;\r
+  WIN_CERTIFICATE_UEFI_GUID       *EfiCert;\r
+  EFI_SIGNATURE_LIST              *KekList;\r
+  EFI_SIGNATURE_DATA              *KekItem;\r
+  EFI_CERT_BLOCK_RSA_2048_SHA256  *CertBlock;\r
+  VOID                            *Rsa;\r
+  UINTN                           KekCount;\r
+  UINTN                           Index;\r
+  UINTN                           KekDataSize;\r
+  BOOLEAN                         IsFound;\r
+  EFI_STATUS                      Result;\r
+\r
+  EfiCert   = NULL;\r
+  KekList   = NULL;\r
+  KekItem   = NULL;\r
+  CertBlock = NULL;\r
+  Rsa       = NULL;\r
+  Status    = FALSE;\r
+  IsFound   = FALSE;\r
+  KekDataSize = 0;\r
+\r
+  EfiCert   = (WIN_CERTIFICATE_UEFI_GUID *) (mImageBase + mSecDataDir->VirtualAddress);\r
+  CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) EfiCert->CertData;\r
+  if (!CompareGuid (&EfiCert->CertType, &gEfiCertTypeRsa2048Sha256Guid)) {\r
+    //\r
+    // Invalid Certificate Data Type.\r
+    //\r
+    return EFI_SECURITY_VIOLATION;\r
+  }\r
+\r
+  //\r
+  // Get KEK database variable data size\r
+  //\r
+  Result = gRT->GetVariable (EFI_KEY_EXCHANGE_KEY_NAME, &gEfiGlobalVariableGuid, NULL, &KekDataSize, NULL);\r
+  if (Result != EFI_BUFFER_TOO_SMALL) {\r
+    return EFI_SECURITY_VIOLATION;\r
+  }\r
+\r
+  //\r
+  // Get KEK database variable.\r
+  //\r
+  KekList = GetEfiGlobalVariable (EFI_KEY_EXCHANGE_KEY_NAME);\r
+  if (KekList == NULL) {\r
+    return EFI_SECURITY_VIOLATION;\r
+  }\r
+  \r
+  //\r
+  // Enumerate all Kek items in this list to verify the variable certificate data.\r
+  // If anyone is authenticated successfully, it means the variable is correct!\r
+  //\r
+  while ((KekDataSize > 0) && (KekDataSize >= KekList->SignatureListSize)) {\r
+    if (CompareGuid (&KekList->SignatureType, &gEfiCertRsa2048Guid)) {\r
+      KekItem   = (EFI_SIGNATURE_DATA *) ((UINT8 *) KekList + sizeof (EFI_SIGNATURE_LIST) + KekList->SignatureHeaderSize);\r
+      KekCount  = (KekList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - KekList->SignatureHeaderSize) / KekList->SignatureSize;\r
+      for (Index = 0; Index < KekCount; Index++) {\r
+        if (CompareMem (KekItem->SignatureData, CertBlock->PublicKey, EFI_CERT_TYPE_RSA2048_SIZE) == 0) {\r
+          IsFound = TRUE;\r
+          break;\r
+        }\r
+        KekItem = (EFI_SIGNATURE_DATA *) ((UINT8 *) KekItem + KekList->SignatureSize);\r
+      }\r
+    }\r
+    KekDataSize -= KekList->SignatureListSize;\r
+    KekList = (EFI_SIGNATURE_LIST *) ((UINT8 *) KekList + KekList->SignatureListSize);\r
+  }\r
+  \r
+  if (!IsFound) {\r
+    //\r
+    // Signed key is not a trust one.\r
+    //\r
+    goto Done;\r
+  }\r
+\r
+  //\r
+  // Now, we found the corresponding security policy.\r
+  // Verify the data payload.\r
+  //\r
+  Rsa = RsaNew ();\r
+  ASSERT (Rsa != NULL);\r
+  // \r
+  // Set RSA Key Components.\r
+  // NOTE: Only N and E are needed to be set as RSA public key for signature verification.\r
+  //\r
+  Status = RsaSetKey (Rsa, RsaKeyN, CertBlock->PublicKey, EFI_CERT_TYPE_RSA2048_SIZE);\r
+  if (!Status) {\r
+    goto Done;\r
+  }\r
+  Status = RsaSetKey (Rsa, RsaKeyE, mRsaE, sizeof (mRsaE));\r
+  if (!Status) {\r
+    goto Done;\r
+  }\r
+  //\r
+  // Verify the signature.\r
+  //\r
+  Status = RsaPkcs1Verify (\r
+             Rsa, \r
+             mImageDigest, \r
+             mImageDigestSize, \r
+             CertBlock->Signature, \r
+             EFI_CERT_TYPE_RSA2048_SHA256_SIZE\r
+             );\r
\r
+Done:\r
+  if (KekList != NULL) {\r
+    FreePool (KekList);\r
+  }\r
+  if (Rsa != NULL ) {\r
+    RsaFree (Rsa);\r
+  }\r
+  if (Status) {\r
+    return EFI_SUCCESS;\r
+  } else {\r
+    return EFI_SECURITY_VIOLATION;\r
+  }\r
+}\r
+\r
+/**\r
+  Provide verification service for signed images, which include both signature validation\r
+  and platform policy control. For signature types, both UEFI WIN_CERTIFICATE_UEFI_GUID and \r
+  MSFT Authenticode type signatures are supported.\r
+  \r
+  In this implementation, only verify external executables when in USER MODE.\r
+  Executables from FV is bypass, so pass in AuthenticationStatus is ignored. \r
+\r
+  @param[in]    AuthenticationStatus \r
+                           This is the authentication status returned from the security\r
+                           measurement services for the input file.\r
+  @param[in]    File       This is a pointer to the device path of the file that is\r
+                           being dispatched. This will optionally be used for logging.\r
+  @param[in]    FileBuffer File buffer matches the input file device path.\r
+  @param[in]    FileSize   Size of File buffer matches the input file device path.\r
+\r
+  @retval EFI_SUCCESS            The file specified by File did authenticate, and the\r
+                                 platform policy dictates that the DXE Core may use File.\r
+  @retval EFI_INVALID_PARAMETER  File is NULL.\r
+  @retval EFI_SECURITY_VIOLATION The file specified by File did not authenticate, and\r
+                                 the platform policy dictates that File should be placed\r
+                                 in the untrusted state. A file may be promoted from\r
+                                 the untrusted to the trusted state at a future time\r
+                                 with a call to the Trust() DXE Service.\r
+  @retval EFI_ACCESS_DENIED      The file specified by File did not authenticate, and\r
+                                 the platform policy dictates that File should not be\r
+                                 used for any purpose.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DxeImageVerificationHandler (\r
+  IN  UINT32                           AuthenticationStatus,\r
+  IN  CONST EFI_DEVICE_PATH_PROTOCOL   *File,\r
+  IN  VOID                             *FileBuffer,\r
+  IN  UINTN                            FileSize\r
+  )\r
+\r
+{\r
+  EFI_STATUS                  Status;\r
+  UINT16                      Magic;\r
+  EFI_IMAGE_DOS_HEADER        *DosHdr;\r
+  EFI_STATUS                  VerifyStatus;\r
+  UINT8                       *SetupMode;\r
+  EFI_SIGNATURE_LIST          *SignatureList;\r
+  UINTN                       SignatureListSize;\r
+  EFI_SIGNATURE_DATA          *Signature;\r
+  EFI_IMAGE_EXECUTION_ACTION  Action;\r
+  WIN_CERTIFICATE             *WinCertificate;\r
+  UINT32                      Policy;\r
+\r
+  if (File == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  SignatureList     = NULL;\r
+  SignatureListSize = 0;\r
+  WinCertificate    = NULL;\r
+  Action            = EFI_IMAGE_EXECUTION_AUTH_UNTESTED;\r
+  Status            = EFI_ACCESS_DENIED;\r
+  //\r
+  // Check the image type and get policy setting.\r
+  //\r
+  switch (GetImageType (File)) {\r
+  \r
+  case IMAGE_FROM_FV:\r
+    Policy = ALWAYS_EXECUTE;\r
+    break;\r
+\r
+  case IMAGE_FROM_OPTION_ROM:\r
+    Policy = PcdGet32 (PcdOptionRomImageVerificationPolicy);\r
+    break;\r
+\r
+  case IMAGE_FROM_REMOVABLE_MEDIA:\r
+    Policy = PcdGet32 (PcdRemovableMediaImageVerificationPolicy);\r
+    break;\r
+\r
+  case IMAGE_FROM_FIXED_MEDIA:\r
+    Policy = PcdGet32 (PcdFixedMediaImageVerificationPolicy);\r
+    break;\r
+\r
+  default:\r
+    Policy = DENY_EXECUTE_ON_SECURITY_VIOLATION; \r
+    break;\r
+  }\r
+  //\r
+  // If policy is always/never execute, return directly.\r
+  //\r
+  if (Policy == ALWAYS_EXECUTE) {\r
+    return EFI_SUCCESS;\r
+  } else if (Policy == NEVER_EXECUTE) {\r
+    return EFI_ACCESS_DENIED;\r
+  }\r
+  SetupMode = GetEfiGlobalVariable (EFI_SETUP_MODE_NAME);\r
+\r
+  //\r
+  // SetupMode doesn't exist means no AuthVar driver is dispatched,\r
+  // skip verification.\r
+  //\r
+  if (SetupMode == NULL) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // If platform is in SETUP MODE, skip verification.\r
+  //\r
+  if (*SetupMode == SETUP_MODE) {\r
+    FreePool (SetupMode);\r
+    return EFI_SUCCESS;\r
+  }\r
+  //\r
+  // Read the Dos header.\r
+  //\r
+  ASSERT (FileBuffer != NULL);\r
+  mImageBase  = (UINT8 *) FileBuffer;\r
+  mImageSize  = FileSize;\r
+  DosHdr      = (EFI_IMAGE_DOS_HEADER *) (mImageBase);\r
+  if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {\r
+    //\r
+    // DOS image header is present, \r
+    // so read the PE header after the DOS image header.\r
+    //\r
+    mPeCoffHeaderOffset = DosHdr->e_lfanew;\r
+  } else {\r
+    mPeCoffHeaderOffset = 0;\r
+  }\r
+  //\r
+  // Check PE/COFF image.\r
+  //\r
+  mNtHeader.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) (mImageBase + mPeCoffHeaderOffset);\r
+  if (mNtHeader.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {\r
+    //\r
+    // It is not a valid Pe/Coff file.\r
+    //\r
+    return EFI_ACCESS_DENIED;\r
+  }\r
+\r
+  Magic = mNtHeader.Pe32->OptionalHeader.Magic;\r
+  if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
+    //\r
+    // Use PE32 offset.\r
+    //\r
+    mSecDataDir = (EFI_IMAGE_DATA_DIRECTORY *)&mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];\r
+  } else {\r
+    //\r
+    // Use PE32+ offset.\r
+    //\r
+    mSecDataDir = (EFI_IMAGE_DATA_DIRECTORY *)&mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];\r
+  }\r
+\r
+  if (mSecDataDir->Size == 0) {\r
+    //\r
+    // This image is not signed.\r
+    //\r
+    Action = EFI_IMAGE_EXECUTION_AUTH_UNTESTED;\r
+    Status = EFI_ACCESS_DENIED;  \r
+    goto Done; \r
+  }\r
+  //\r
+  // Verify signature of executables.\r
+  //\r
+  WinCertificate = (WIN_CERTIFICATE *) (mImageBase + mSecDataDir->VirtualAddress);\r
+\r
+  switch (WinCertificate->wCertificateType) {\r
+  \r
+  case WIN_CERT_TYPE_EFI_GUID:\r
+    //\r
+    // Verify UEFI GUID type.\r
+    //   \r
+    if (!HashPeImage (HASHALG_SHA256)) {\r
+      goto Done;\r
+    }\r
+\r
+    VerifyStatus = VerifyCertUefiGuid ();\r
+    break;\r
+\r
+  case WIN_CERT_TYPE_PKCS_SIGNED_DATA:\r
+    //\r
+    // Verify Pkcs signed data type.\r
+    //\r
+    Status    = HashPeImageByType();\r
+    if (EFI_ERROR(Status)) {\r
+      goto Done;\r
+    }\r
+\r
+    VerifyStatus = VerifyCertPkcsSignedData ();\r
+\r
+    //\r
+    // For image verification against enrolled certificate(root or intermediate),\r
+    // no need to check image's hash in the allowed database.\r
+    //\r
+    if (!EFI_ERROR (VerifyStatus)) {\r
+      return EFI_SUCCESS;\r
+    }\r
+\r
+  default:\r
+    return EFI_ACCESS_DENIED;\r
+  }\r
+  //\r
+  // Get image hash value as executable's signature.\r
+  //\r
+  SignatureListSize = sizeof (EFI_SIGNATURE_LIST) + sizeof (EFI_SIGNATURE_DATA) - 1 + mImageDigestSize;\r
+  SignatureList     = (EFI_SIGNATURE_LIST *) AllocateZeroPool (SignatureListSize);\r
+  ASSERT (SignatureList != NULL);\r
+  SignatureList->SignatureHeaderSize  = 0;\r
+  SignatureList->SignatureListSize    = (UINT32) SignatureListSize;\r
+  SignatureList->SignatureSize        = (UINT32) mImageDigestSize;\r
+  CopyMem (&SignatureList->SignatureType, &mCertType, sizeof (EFI_GUID));\r
+  Signature = (EFI_SIGNATURE_DATA *) ((UINT8 *) SignatureList + sizeof (EFI_SIGNATURE_LIST));\r
+  CopyMem (Signature->SignatureData, mImageDigest, mImageDigestSize);\r
+  //\r
+  // Signature database check after verification.\r
+  //\r
+  if (EFI_ERROR (VerifyStatus)) {\r
+    //\r
+    // Verification failure.\r
+    //\r
+    Action = EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED;\r
+    Status = EFI_ACCESS_DENIED;\r
+  } else if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE1, Signature->SignatureData, &mCertType, mImageDigestSize)) {\r
+    //\r
+    // Executable signature verification passes, but is found in forbidden signature database.\r
+    //\r
+    Action = EFI_IMAGE_EXECUTION_AUTH_SIG_FOUND;\r
+    Status = EFI_ACCESS_DENIED;\r
+  } else if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE, Signature->SignatureData, &mCertType, mImageDigestSize)) {\r
+    //\r
+    // Executable signature is found in authorized signature database.\r
+    //\r
+    Status = EFI_SUCCESS;\r
+  } else {\r
+    //\r
+    // Executable signature verification passes, but cannot be found in authorized signature database.\r
+    // Get platform policy to determine the action.\r
+    //\r
+    Action = EFI_IMAGE_EXECUTION_AUTH_SIG_PASSED;\r
+    Status = ImageAuthorization (Policy);\r
+  }\r
+\r
+Done:\r
+  if (Status != EFI_SUCCESS) {\r
+    //\r
+    // Policy decides to defer or reject the image; add its information in image executable information table.\r
+    //\r
+    AddImageExeInfo (Action, NULL, File, SignatureList, SignatureListSize);\r
+  }\r
+\r
+  if (SignatureList != NULL) {\r
+    FreePool (SignatureList);\r
+  }\r
+\r
+  FreePool (SetupMode);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  When VariableWriteArchProtocol install, create "SecureBoot" variable.\r
+  \r
+  @param[in] Event    Event whose notification function is being invoked.\r
+  @param[in] Context  Pointer to the notification function's context.\r
+  \r
+**/\r
+VOID\r
+EFIAPI\r
+VariableWriteCallBack (\r
+  IN  EFI_EVENT                           Event,\r
+  IN  VOID                                *Context\r
+  )\r
+{\r
+  UINT8                       SecureBootMode;\r
+  UINT8                       *SecureBootModePtr;\r
+  EFI_STATUS                  Status;\r
+  VOID                        *ProtocolPointer;\r
+\r
+  Status = gBS->LocateProtocol (&gEfiVariableWriteArchProtocolGuid, NULL, &ProtocolPointer);\r
+  if (EFI_ERROR (Status)) {\r
+    return;\r
+  }\r
+  \r
+  //\r
+  // Check whether "SecureBoot" variable exists.\r
+  // If this library is built-in, it means firmware has capability to perform\r
+  // driver signing verification.\r
+  //\r
+  SecureBootModePtr = GetEfiGlobalVariable (EFI_SECURE_BOOT_MODE_NAME);\r
+  if (SecureBootModePtr == NULL) {\r
+    SecureBootMode   = SECURE_BOOT_MODE_DISABLE;\r
+    //\r
+    // Authenticated variable driver will update "SecureBoot" depending on SetupMode variable.\r
+    //\r
+    gRT->SetVariable (\r
+           EFI_SECURE_BOOT_MODE_NAME,\r
+           &gEfiGlobalVariableGuid,\r
+           EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
+           sizeof (UINT8),\r
+           &SecureBootMode\r
+           );\r
+  } else {\r
+    FreePool (SecureBootModePtr);\r
+  }\r
+}  \r
+\r
+/**\r
+  Register security measurement handler.\r
+\r
+  @param  ImageHandle   ImageHandle of the loaded driver.\r
+  @param  SystemTable   Pointer to the EFI System Table.\r
+\r
+  @retval EFI_SUCCESS   The handlers were registered successfully.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DxeImageVerificationLibConstructor (\r
+  IN EFI_HANDLE        ImageHandle,\r
+  IN EFI_SYSTEM_TABLE  *SystemTable\r
+  )\r
+{\r
+  VOID                *Registration;\r
+\r
+  //\r
+  // Register callback function upon VariableWriteArchProtocol.\r
+  // \r
+  EfiCreateProtocolNotifyEvent (\r
+    &gEfiVariableWriteArchProtocolGuid,\r
+    TPL_CALLBACK,\r
+    VariableWriteCallBack,\r
+    NULL,\r
+    &Registration\r
+    );\r
+\r
+  return RegisterSecurityHandler (\r
+          DxeImageVerificationHandler,\r
+          EFI_AUTH_OPERATION_VERIFY_IMAGE | EFI_AUTH_OPERATION_IMAGE_REQUIRED\r
+          );      \r
+}\r
diff --git a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.h b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.h
new file mode 100644 (file)
index 0000000..34ed0c8
--- /dev/null
@@ -0,0 +1,201 @@
+/** @file\r
+  The internal header file includes the common header files, defines\r
+  internal structure and functions used by ImageVerificationLib.\r
+\r
+Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef __IMAGEVERIFICATIONLIB_H__\r
+#define __IMAGEVERIFICATIONLIB_H__\r
+\r
+#include <Library/UefiDriverEntryPoint.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiRuntimeServicesTableLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/BaseCryptLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/DevicePathLib.h>\r
+#include <Library/SecurityManagementLib.h>\r
+#include <Protocol/FirmwareVolume2.h>\r
+#include <Protocol/DevicePath.h>\r
+#include <Protocol/BlockIo.h>\r
+#include <Protocol/SimpleFileSystem.h>\r
+#include <Protocol/VariableWrite.h>\r
+#include <Guid/ImageAuthentication.h>\r
+#include <IndustryStandard/PeImage.h>\r
+\r
+#define EFI_CERT_TYPE_RSA2048_SHA256_SIZE 256\r
+#define EFI_CERT_TYPE_RSA2048_SIZE        256\r
+#define MAX_NOTIFY_STRING_LEN             64\r
+\r
+//\r
+// Image type definitions\r
+//\r
+#define IMAGE_UNKNOWN                         0x00000000\r
+#define IMAGE_FROM_FV                         0x00000001\r
+#define IMAGE_FROM_OPTION_ROM                 0x00000002\r
+#define IMAGE_FROM_REMOVABLE_MEDIA            0x00000003\r
+#define IMAGE_FROM_FIXED_MEDIA                0x00000004\r
+\r
+//\r
+// Authorization policy bit definition\r
+//\r
+#define ALWAYS_EXECUTE                         0x00000000\r
+#define NEVER_EXECUTE                          0x00000001\r
+#define ALLOW_EXECUTE_ON_SECURITY_VIOLATION    0x00000002\r
+#define DEFER_EXECUTE_ON_SECURITY_VIOLATION    0x00000003\r
+#define DENY_EXECUTE_ON_SECURITY_VIOLATION     0x00000004\r
+#define QUERY_USER_ON_SECURITY_VIOLATION       0x00000005\r
+\r
+//\r
+// Support hash types\r
+//\r
+#define HASHALG_SHA1                           0x00000000\r
+#define HASHALG_SHA224                         0x00000001\r
+#define HASHALG_SHA256                         0x00000002\r
+#define HASHALG_SHA384                         0x00000003\r
+#define HASHALG_SHA512                         0x00000004\r
+#define HASHALG_MAX                            0x00000005\r
+\r
+//\r
+// Set max digest size as SHA256 Output (32 bytes) by far\r
+//\r
+#define MAX_DIGEST_SIZE    SHA256_DIGEST_SIZE      \r
+//\r
+//\r
+// PKCS7 Certificate definition\r
+//\r
+typedef struct {\r
+  WIN_CERTIFICATE Hdr;\r
+  UINT8           CertData[1];\r
+} WIN_CERTIFICATE_EFI_PKCS;\r
+\r
+\r
+/**\r
+  Retrieves the size, in bytes, of the context buffer required for hash operations.\r
+\r
+  @return  The size, in bytes, of the context buffer required for hash operations.\r
+\r
+**/\r
+typedef\r
+UINTN\r
+(EFIAPI *HASH_GET_CONTEXT_SIZE)(\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Initializes user-supplied memory pointed by HashContext as hash context for\r
+  subsequent use.\r
+\r
+  If HashContext is NULL, then ASSERT().\r
+\r
+  @param[in, out]  HashContext  Pointer to  Context being initialized.\r
+\r
+  @retval TRUE   HASH context initialization succeeded.\r
+  @retval FALSE  HASH context initialization failed.\r
+\r
+**/\r
+typedef\r
+BOOLEAN\r
+(EFIAPI *HASH_INIT)(\r
+  IN OUT  VOID  *HashContext\r
+  );\r
+\r
+\r
+/**\r
+  Performs digest on a data buffer of the specified length. This function can\r
+  be called multiple times to compute the digest of long or discontinuous data streams.\r
+\r
+  If HashContext is NULL, then ASSERT().\r
+\r
+  @param[in, out]  HashContext  Pointer to the MD5 context.\r
+  @param[in]       Data         Pointer to the buffer containing the data to be hashed.\r
+  @param[in]       DataLength   Length of Data buffer in bytes.\r
+\r
+  @retval TRUE     HASH data digest succeeded.\r
+  @retval FALSE    Invalid HASH context. After HashFinal function has been called, the\r
+                   HASH context cannot be reused.\r
+\r
+**/\r
+typedef\r
+BOOLEAN\r
+(EFIAPI *HASH_UPDATE)(\r
+  IN OUT  VOID        *HashContext,\r
+  IN      CONST VOID  *Data,\r
+  IN      UINTN       DataLength\r
+  );\r
+\r
+/**\r
+  Completes hash computation and retrieves the digest value into the specified\r
+  memory. After this function has been called, the context cannot be used again.\r
+\r
+  If HashContext is NULL, then ASSERT().\r
+  If HashValue is NULL, then ASSERT().\r
+\r
+  @param[in, out]  HashContext  Pointer to the MD5 context\r
+  @param[out]      HashValue    Pointer to a buffer that receives the HASH digest\r
+                                value.\r
+\r
+  @retval TRUE   HASH digest computation succeeded.\r
+  @retval FALSE  HASH digest computation failed.\r
+\r
+**/\r
+typedef\r
+BOOLEAN\r
+(EFIAPI *HASH_FINAL)(\r
+  IN OUT  VOID   *HashContext,\r
+  OUT     UINT8  *HashValue\r
+  );\r
+\r
+\r
+//\r
+// Hash Algorithm Table\r
+//\r
+typedef struct {\r
+  //\r
+  // Name for Hash Algorithm\r
+  //\r
+  CHAR16                   *Name;\r
+  //\r
+  // Digest Length\r
+  //\r
+  UINTN                    DigestLength;\r
+  //\r
+  // Hash Algorithm OID ASN.1 Value\r
+  //\r
+  UINT8                    *OidValue;\r
+  //\r
+  // Length of Hash OID Value\r
+  //\r
+  UINTN                    OidLength;\r
+  //\r
+  // Pointer to Hash GetContentSize function\r
+  //\r
+  HASH_GET_CONTEXT_SIZE    GetContextSize;\r
+  //\r
+  // Pointer to Hash Init function\r
+  //\r
+  HASH_INIT                HashInit;\r
+  //\r
+  // Pointer to Hash Update function\r
+  //\r
+  HASH_UPDATE              HashUpdate;\r
+  //\r
+  // Pointer to Hash Final function\r
+  //\r
+  HASH_FINAL               HashFinal;\r
+} HASH_TABLE;\r
+\r
+#endif\r
diff --git a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.inf b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.inf
new file mode 100644 (file)
index 0000000..5874d6b
--- /dev/null
@@ -0,0 +1,73 @@
+## @file\r
+#  The library instance provides security service of image verification.\r
+#  Image verification Library module supports UEFI2.3.1\r
+#\r
+# Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = DxeImageVerificationLib   \r
+  FILE_GUID                      = 0CA970E1-43FA-4402-BC0A-81AF336BFFD6\r
+  MODULE_TYPE                    = DXE_DRIVER\r
+  VERSION_STRING                 = 1.0\r
+  LIBRARY_CLASS                  = NULL|DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SAL_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER \r
+  CONSTRUCTOR                    = DxeImageVerificationLibConstructor\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC\r
+#\r
+\r
+[Sources]\r
+  DxeImageVerificationLib.c\r
+  DxeImageVerificationLib.h\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+  CryptoPkg/CryptoPkg.dec\r
+  SecurityPkg/SecurityPkg.dec\r
+\r
+[LibraryClasses]\r
+  MemoryAllocationLib\r
+  BaseLib\r
+  UefiLib\r
+  UefiBootServicesTableLib\r
+  UefiRuntimeServicesTableLib\r
+  BaseMemoryLib\r
+  DebugLib\r
+  DevicePathLib\r
+  BaseCryptLib\r
+  SecurityManagementLib\r
+\r
+[Protocols]\r
+  gEfiFirmwareVolume2ProtocolGuid\r
+  gEfiBlockIoProtocolGuid\r
+  gEfiSimpleFileSystemProtocolGuid\r
+  gEfiVariableWriteArchProtocolGuid\r
+  \r
+[Guids]\r
+  gEfiCertTypeRsa2048Sha256Guid\r
+  gEfiImageSecurityDatabaseGuid\r
+  gEfiCertSha1Guid\r
+  gEfiCertSha256Guid\r
+  gEfiCertX509Guid\r
+  gEfiCertRsa2048Guid\r
+  \r
+[Pcd]\r
+  gEfiSecurityPkgTokenSpaceGuid.PcdOptionRomImageVerificationPolicy\r
+  gEfiSecurityPkgTokenSpaceGuid.PcdRemovableMediaImageVerificationPolicy\r
+  gEfiSecurityPkgTokenSpaceGuid.PcdFixedMediaImageVerificationPolicy\r
+\r
+  \r
+\r
+\r
diff --git a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c
new file mode 100644 (file)
index 0000000..c012f13
--- /dev/null
@@ -0,0 +1,830 @@
+/** @file\r
+  The library instance provides security service of TPM measure boot.  \r
+\r
+Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include <PiDxe.h>\r
+\r
+#include <Protocol/TcgService.h>\r
+#include <Protocol/FirmwareVolume2.h>\r
+#include <Protocol/BlockIo.h>\r
+#include <Protocol/DiskIo.h>\r
+#include <Protocol/DevicePathToText.h>\r
+\r
+#include <Library/BaseLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/DevicePathLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/BaseCryptLib.h>\r
+#include <Library/PeCoffLib.h>\r
+#include <Library/SecurityManagementLib.h>\r
+\r
+//\r
+// Flag to check GPT partition. It only need be measured once.\r
+//\r
+BOOLEAN                           mMeasureGptTableFlag = FALSE;\r
+EFI_GUID                          mZeroGuid = {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}};\r
+UINTN                             mMeasureGptCount = 0;\r
+\r
+/**\r
+  Reads contents of a PE/COFF image in memory buffer.\r
+\r
+  @param  FileHandle      Pointer to the file handle to read the PE/COFF image.\r
+  @param  FileOffset      Offset into the PE/COFF image to begin the read operation.\r
+  @param  ReadSize        On input, the size in bytes of the requested read operation.  \r
+                          On output, the number of bytes actually read.\r
+  @param  Buffer          Output buffer that contains the data read from the PE/COFF image.\r
+  \r
+  @retval EFI_SUCCESS     The specified portion of the PE/COFF image was read and the size \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ImageRead (\r
+  IN     VOID    *FileHandle,\r
+  IN     UINTN   FileOffset,\r
+  IN OUT UINTN   *ReadSize,\r
+  OUT    VOID    *Buffer\r
+  )\r
+{\r
+  CopyMem (Buffer, (UINT8 *)((UINTN) FileHandle + FileOffset), *ReadSize);\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Measure GPT table data into TPM log.\r
+\r
+  @param TcgProtocol             Pointer to the located TCG protocol instance.\r
+  @param GptHandle               Handle that GPT partition was installed.\r
+\r
+  @retval EFI_SUCCESS            Successfully measure GPT table.\r
+  @retval EFI_UNSUPPORTED        Not support GPT table on the given handle.\r
+  @retval EFI_DEVICE_ERROR       Can't get GPT table because device error.\r
+  @retval EFI_OUT_OF_RESOURCES   No enough resource to measure GPT table.\r
+  @retval other error value\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TcgMeasureGptTable (\r
+  IN  EFI_TCG_PROTOCOL   *TcgProtocol,\r
+  IN  EFI_HANDLE         GptHandle\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  EFI_BLOCK_IO_PROTOCOL             *BlockIo;\r
+  EFI_DISK_IO_PROTOCOL              *DiskIo;\r
+  EFI_PARTITION_TABLE_HEADER        *PrimaryHeader;\r
+  EFI_PARTITION_ENTRY               *PartitionEntry;\r
+  UINT8                             *EntryPtr;\r
+  UINTN                             NumberOfPartition;\r
+  UINT32                            Index;\r
+  TCG_PCR_EVENT                     *TcgEvent;\r
+  EFI_GPT_DATA                      *GptData;\r
+  UINT32                            EventSize;\r
+  UINT32                            EventNumber;\r
+  EFI_PHYSICAL_ADDRESS              EventLogLastEntry;\r
+\r
+  if (mMeasureGptCount > 0) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  Status = gBS->HandleProtocol (GptHandle, &gEfiBlockIoProtocolGuid, (VOID**)&BlockIo);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+  Status = gBS->HandleProtocol (GptHandle, &gEfiDiskIoProtocolGuid, (VOID**)&DiskIo);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+  //\r
+  // Read the EFI Partition Table Header\r
+  //  \r
+  PrimaryHeader = (EFI_PARTITION_TABLE_HEADER *) AllocatePool (BlockIo->Media->BlockSize);\r
+  if (PrimaryHeader == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }  \r
+  Status = DiskIo->ReadDisk (\r
+                     DiskIo,\r
+                     BlockIo->Media->MediaId,\r
+                     1 * BlockIo->Media->BlockSize,\r
+                     BlockIo->Media->BlockSize,\r
+                     (UINT8 *)PrimaryHeader\r
+                     );\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "Failed to Read Partition Table Header!\n"));\r
+    FreePool (PrimaryHeader);\r
+    return EFI_DEVICE_ERROR;\r
+  }  \r
+  //\r
+  // Read the partition entry.\r
+  //\r
+  EntryPtr = (UINT8 *)AllocatePool (PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry);\r
+  if (EntryPtr == NULL) {\r
+    FreePool (PrimaryHeader);\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  Status = DiskIo->ReadDisk (\r
+                     DiskIo,\r
+                     BlockIo->Media->MediaId,\r
+                     MultU64x32(PrimaryHeader->PartitionEntryLBA, BlockIo->Media->BlockSize),\r
+                     PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry,\r
+                     EntryPtr\r
+                     );\r
+  if (EFI_ERROR (Status)) {\r
+    FreePool (PrimaryHeader);\r
+    FreePool (EntryPtr);\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  \r
+  //\r
+  // Count the valid partition\r
+  //\r
+  PartitionEntry    = (EFI_PARTITION_ENTRY *)EntryPtr;\r
+  NumberOfPartition = 0;\r
+  for (Index = 0; Index < PrimaryHeader->NumberOfPartitionEntries; Index++) {\r
+    if (!CompareGuid (&PartitionEntry->PartitionTypeGUID, &mZeroGuid)) {\r
+      NumberOfPartition++;  \r
+    }\r
+    PartitionEntry++;\r
+  }\r
+\r
+  //\r
+  // Parepare Data for Measurement\r
+  // \r
+  EventSize = (UINT32)(sizeof (EFI_GPT_DATA) - sizeof (GptData->Partitions) \r
+                        + NumberOfPartition * PrimaryHeader->SizeOfPartitionEntry);\r
+  TcgEvent = (TCG_PCR_EVENT *) AllocateZeroPool (EventSize + sizeof (TCG_PCR_EVENT));\r
+  if (TcgEvent == NULL) {\r
+    FreePool (PrimaryHeader);\r
+    FreePool (EntryPtr);\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  TcgEvent->PCRIndex   = 5;\r
+  TcgEvent->EventType  = EV_EFI_GPT_EVENT;\r
+  TcgEvent->EventSize  = EventSize;\r
+  GptData = (EFI_GPT_DATA *) TcgEvent->Event;  \r
+\r
+  //\r
+  // Copy the EFI_PARTITION_TABLE_HEADER and NumberOfPartition\r
+  //  \r
+  CopyMem ((UINT8 *)GptData, (UINT8*)PrimaryHeader, sizeof (EFI_PARTITION_TABLE_HEADER));\r
+  GptData->NumberOfPartitions = NumberOfPartition;\r
+  //\r
+  // Copy the valid partition entry\r
+  //\r
+  PartitionEntry    = (EFI_PARTITION_ENTRY*)EntryPtr;\r
+  NumberOfPartition = 0;\r
+  for (Index = 0; Index < PrimaryHeader->NumberOfPartitionEntries; Index++) {\r
+    if (!CompareGuid (&PartitionEntry->PartitionTypeGUID, &mZeroGuid)) {\r
+      CopyMem (\r
+        (UINT8 *)&GptData->Partitions + NumberOfPartition * sizeof (EFI_PARTITION_ENTRY),\r
+        (UINT8 *)PartitionEntry,\r
+        sizeof (EFI_PARTITION_ENTRY)\r
+        );\r
+      NumberOfPartition++;\r
+    }\r
+    PartitionEntry++;\r
+  }\r
+\r
+  //\r
+  // Measure the GPT data\r
+  //\r
+  EventNumber = 1;\r
+  Status = TcgProtocol->HashLogExtendEvent (\r
+             TcgProtocol,\r
+             (EFI_PHYSICAL_ADDRESS) (UINTN) (VOID *) GptData,\r
+             (UINT64) TcgEvent->EventSize,\r
+             TPM_ALG_SHA,\r
+             TcgEvent,\r
+             &EventNumber,\r
+             &EventLogLastEntry\r
+             );\r
+  if (!EFI_ERROR (Status)) {\r
+    mMeasureGptCount++;\r
+  }\r
+\r
+  FreePool (PrimaryHeader);\r
+  FreePool (EntryPtr);\r
+  FreePool (TcgEvent);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Measure PE image into TPM log based on the authenticode image hashing in\r
+  PE/COFF Specification 8.0 Appendix A.\r
+\r
+  @param[in] TcgProtocol    Pointer to the located TCG protocol instance.\r
+  @param[in] ImageAddress   Start address of image buffer.\r
+  @param[in] ImageSize      Image size\r
+  @param[in] LinkTimeBase   Address that the image is loaded into memory.\r
+  @param[in] ImageType      Image subsystem type.\r
+  @param[in] FilePath       File path is corresponding to the input image.\r
+\r
+  @retval EFI_SUCCESS            Successfully measure image.\r
+  @retval EFI_OUT_OF_RESOURCES   No enough resource to measure image.\r
+  @retval other error value\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TcgMeasurePeImage (\r
+  IN  EFI_TCG_PROTOCOL          *TcgProtocol,\r
+  IN  EFI_PHYSICAL_ADDRESS      ImageAddress,\r
+  IN  UINTN                     ImageSize,\r
+  IN  UINTN                     LinkTimeBase,\r
+  IN  UINT16                    ImageType,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL  *FilePath\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  TCG_PCR_EVENT                     *TcgEvent;\r
+  EFI_IMAGE_LOAD_EVENT              *ImageLoad;\r
+  UINT32                            FilePathSize;\r
+  VOID                              *Sha1Ctx;\r
+  UINTN                             CtxSize;\r
+  EFI_IMAGE_DOS_HEADER              *DosHdr;\r
+  UINT32                            PeCoffHeaderOffset;\r
+  EFI_IMAGE_SECTION_HEADER          *Section;\r
+  UINT8                             *HashBase;\r
+  UINTN                             HashSize;\r
+  UINTN                             SumOfBytesHashed;\r
+  EFI_IMAGE_SECTION_HEADER          *SectionHeader;\r
+  UINTN                             Index, Pos;\r
+  UINT16                            Magic;\r
+  UINT32                            EventSize;\r
+  UINT32                            EventNumber;\r
+  EFI_PHYSICAL_ADDRESS              EventLogLastEntry;\r
+  EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION  Hdr;\r
+\r
+  Status        = EFI_SUCCESS;\r
+  ImageLoad     = NULL;\r
+  SectionHeader = NULL;\r
+  Sha1Ctx       = NULL;\r
+  FilePathSize  = (UINT32) GetDevicePathSize (FilePath);\r
+\r
+  //\r
+  // Determine destination PCR by BootPolicy\r
+  //\r
+  EventSize = sizeof (*ImageLoad) - sizeof (ImageLoad->DevicePath) + FilePathSize;\r
+  TcgEvent = AllocateZeroPool (EventSize + sizeof (TCG_PCR_EVENT));\r
+  if (TcgEvent == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  TcgEvent->EventSize = EventSize;\r
+  ImageLoad           = (EFI_IMAGE_LOAD_EVENT *) TcgEvent->Event;\r
+\r
+  switch (ImageType) {\r
+    case EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION:\r
+      TcgEvent->EventType = EV_EFI_BOOT_SERVICES_APPLICATION;\r
+      TcgEvent->PCRIndex  = 4;\r
+      break;\r
+    case EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER:\r
+      TcgEvent->EventType = EV_EFI_BOOT_SERVICES_DRIVER;\r
+      TcgEvent->PCRIndex  = 2;\r
+      break;\r
+    case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER:\r
+      TcgEvent->EventType = EV_EFI_RUNTIME_SERVICES_DRIVER;\r
+      TcgEvent->PCRIndex  = 2;\r
+      break;\r
+    default:\r
+      DEBUG ((\r
+        EFI_D_ERROR,\r
+        "TcgMeasurePeImage: Unknown subsystem type %d",\r
+        ImageType\r
+        ));\r
+      ASSERT (FALSE);\r
+      TcgEvent->EventType = ImageType;\r
+      Status = EFI_UNSUPPORTED;\r
+      goto Finish;\r
+  }\r
+\r
+  ImageLoad->ImageLocationInMemory = ImageAddress;\r
+  ImageLoad->ImageLengthInMemory   = ImageSize;\r
+  ImageLoad->ImageLinkTimeAddress  = LinkTimeBase;\r
+  ImageLoad->LengthOfDevicePath    = FilePathSize;\r
+  CopyMem (ImageLoad->DevicePath, FilePath, FilePathSize);\r
+\r
+  //\r
+  // Check PE/COFF image\r
+  //\r
+  DosHdr = (EFI_IMAGE_DOS_HEADER *) (UINTN) ImageAddress;\r
+  PeCoffHeaderOffset = 0;\r
+  if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {\r
+    PeCoffHeaderOffset = DosHdr->e_lfanew;\r
+  }\r
+  if (((EFI_TE_IMAGE_HEADER *)((UINT8 *) (UINTN) ImageAddress + PeCoffHeaderOffset))->Signature\r
+       == EFI_TE_IMAGE_HEADER_SIGNATURE) {\r
+    goto Finish;\r
+  }\r
+\r
+  //\r
+  // PE/COFF Image Measurement\r
+  //\r
+  //    NOTE: The following codes/steps are based upon the authenticode image hashing in\r
+  //      PE/COFF Specification 8.0 Appendix A.\r
+  //\r
+  //\r
+\r
+  // 1.  Load the image header into memory.\r
+\r
+  // 2.  Initialize a SHA hash context.\r
+  CtxSize = Sha1GetContextSize ();\r
+  Sha1Ctx = AllocatePool (CtxSize);\r
+  if (Sha1Ctx == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto Finish;\r
+  }\r
+\r
+  Sha1Init (Sha1Ctx);\r
+\r
+  //\r
+  // Measuring PE/COFF Image Header;\r
+  // But CheckSum field and SECURITY data directory (certificate) are excluded\r
+  //\r
+  Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINT8 *) (UINTN) ImageAddress + PeCoffHeaderOffset);\r
+  Magic    = Hdr.Pe32->OptionalHeader.Magic;\r
+  \r
+  //\r
+  // 3.  Calculate the distance from the base of the image header to the image checksum address.\r
+  // 4.  Hash the image header from its base to beginning of the image checksum.\r
+  //\r
+  HashBase = (UINT8 *) (UINTN) ImageAddress;\r
+  if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
+    //\r
+    // Use PE32 offset\r
+    //\r
+    HashSize = (UINTN) ((UINT8 *)(&Hdr.Pe32->OptionalHeader.CheckSum) - HashBase);\r
+  } else {\r
+    //\r
+    // Use PE32+ offset\r
+    //\r
+    HashSize = (UINTN) ((UINT8 *)(&Hdr.Pe32Plus->OptionalHeader.CheckSum) - HashBase);\r
+  }\r
+\r
+  Sha1Update (Sha1Ctx, HashBase, HashSize);\r
+\r
+  //\r
+  // 5.  Skip over the image checksum (it occupies a single ULONG).\r
+  // 6.  Get the address of the beginning of the Cert Directory.\r
+  // 7.  Hash everything from the end of the checksum to the start of the Cert Directory.\r
+  //\r
+  if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
+    //\r
+    // Use PE32 offset\r
+    //\r
+    HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);\r
+    HashSize = (UINTN) ((UINT8 *)(&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase);\r
+  } else {\r
+    //\r
+    // Use PE32+ offset\r
+    //    \r
+    HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);\r
+    HashSize = (UINTN) ((UINT8 *)(&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase);\r
+  }\r
+\r
+  Sha1Update (Sha1Ctx, HashBase, HashSize);\r
+\r
+  //\r
+  // 8.  Skip over the Cert Directory. (It is sizeof(IMAGE_DATA_DIRECTORY) bytes.)\r
+  // 9.  Hash everything from the end of the Cert Directory to the end of image header.\r
+  //\r
+  if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
+    //\r
+    // Use PE32 offset\r
+    //\r
+    HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];\r
+    HashSize = Hdr.Pe32->OptionalHeader.SizeOfHeaders -\r
+             (UINTN) ((UINT8 *)(&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]) - (UINT8 *) (UINTN) ImageAddress);\r
+  } else {\r
+    //\r
+    // Use PE32+ offset\r
+    //\r
+    HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];\r
+    HashSize = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders -\r
+             (UINTN) ((UINT8 *)(&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]) - (UINT8 *) (UINTN) ImageAddress);\r
+  }\r
+  \r
+  Sha1Update (Sha1Ctx, HashBase, HashSize);\r
+\r
+  //\r
+  // 10. Set the SUM_OF_BYTES_HASHED to the size of the header\r
+  //\r
+  if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
+    //\r
+    // Use PE32 offset\r
+    //\r
+    SumOfBytesHashed = Hdr.Pe32->OptionalHeader.SizeOfHeaders;\r
+  } else {\r
+    //\r
+    // Use PE32+ offset\r
+    //\r
+    SumOfBytesHashed = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders;\r
+  }\r
+\r
+  //\r
+  // 11. Build a temporary table of pointers to all the IMAGE_SECTION_HEADER\r
+  //     structures in the image. The 'NumberOfSections' field of the image\r
+  //     header indicates how big the table should be. Do not include any\r
+  //     IMAGE_SECTION_HEADERs in the table whose 'SizeOfRawData' field is zero.\r
+  //\r
+  SectionHeader = (EFI_IMAGE_SECTION_HEADER *)AllocateZeroPool (sizeof (EFI_IMAGE_SECTION_HEADER) * Hdr.Pe32->FileHeader.NumberOfSections);\r
+  if (SectionHeader == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto Finish;\r
+  }\r
+\r
+  //\r
+  // 12.  Using the 'PointerToRawData' in the referenced section headers as\r
+  //      a key, arrange the elements in the table in ascending order. In other\r
+  //      words, sort the section headers according to the disk-file offset of\r
+  //      the section.\r
+  //\r
+  Section = (EFI_IMAGE_SECTION_HEADER *) (\r
+               (UINT8 *) (UINTN) ImageAddress +\r
+               PeCoffHeaderOffset +\r
+               sizeof(UINT32) +\r
+               sizeof(EFI_IMAGE_FILE_HEADER) +\r
+               Hdr.Pe32->FileHeader.SizeOfOptionalHeader\r
+               );\r
+  for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {\r
+    Pos = Index;\r
+    while ((Pos > 0) && (Section->PointerToRawData < SectionHeader[Pos - 1].PointerToRawData)) {\r
+      CopyMem (&SectionHeader[Pos], &SectionHeader[Pos - 1], sizeof(EFI_IMAGE_SECTION_HEADER));\r
+      Pos--;\r
+    }\r
+    CopyMem (&SectionHeader[Pos], Section, sizeof(EFI_IMAGE_SECTION_HEADER));\r
+    Section += 1;\r
+  }\r
+\r
+  //\r
+  // 13.  Walk through the sorted table, bring the corresponding section\r
+  //      into memory, and hash the entire section (using the 'SizeOfRawData'\r
+  //      field in the section header to determine the amount of data to hash).\r
+  // 14.  Add the section's 'SizeOfRawData' to SUM_OF_BYTES_HASHED .\r
+  // 15.  Repeat steps 13 and 14 for all the sections in the sorted table.\r
+  //\r
+  for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {\r
+    Section  = (EFI_IMAGE_SECTION_HEADER *) &SectionHeader[Index];\r
+    if (Section->SizeOfRawData == 0) {\r
+      continue;\r
+    }\r
+    HashBase = (UINT8 *) (UINTN) ImageAddress + Section->PointerToRawData;\r
+    HashSize = (UINTN) Section->SizeOfRawData;\r
+\r
+    Sha1Update (Sha1Ctx, HashBase, HashSize);\r
+\r
+    SumOfBytesHashed += HashSize;\r
+  }\r
+\r
+  //\r
+  // 16.  If the file size is greater than SUM_OF_BYTES_HASHED, there is extra\r
+  //      data in the file that needs to be added to the hash. This data begins\r
+  //      at file offset SUM_OF_BYTES_HASHED and its length is:\r
+  //             FileSize  -  (CertDirectory->Size)\r
+  //\r
+  if (ImageSize > SumOfBytesHashed) {\r
+    HashBase = (UINT8 *) (UINTN) ImageAddress + SumOfBytesHashed;\r
+    if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
+      //\r
+      // Use PE32 offset\r
+      //\r
+      HashSize = (UINTN)(ImageSize -\r
+                 Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size -\r
+                 SumOfBytesHashed);\r
+    } else {\r
+      //\r
+      // Use PE32+ offset\r
+      //\r
+      HashSize = (UINTN)(ImageSize -\r
+                 Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size -\r
+                 SumOfBytesHashed);      \r
+    }\r
+\r
+    Sha1Update (Sha1Ctx, HashBase, HashSize);\r
+  }\r
+\r
+  //\r
+  // 17.  Finalize the SHA hash.\r
+  //\r
+  Sha1Final (Sha1Ctx, (UINT8 *)&TcgEvent->Digest);\r
+\r
+  //\r
+  // Log the PE data\r
+  //\r
+  EventNumber = 1;\r
+  Status = TcgProtocol->HashLogExtendEvent (\r
+             TcgProtocol,\r
+             (EFI_PHYSICAL_ADDRESS) (UINTN) (VOID *) NULL,\r
+             0,\r
+             TPM_ALG_SHA,\r
+             TcgEvent,\r
+             &EventNumber,\r
+             &EventLogLastEntry\r
+             );\r
+\r
+Finish:\r
+  FreePool (TcgEvent);\r
+\r
+  if (SectionHeader != NULL) {\r
+    FreePool (SectionHeader);\r
+  }\r
+\r
+  if (Sha1Ctx != NULL ) {\r
+    FreePool (Sha1Ctx);\r
+  }\r
+  return Status;\r
+}\r
+\r
+/**\r
+  The security handler is used to abstract platform-specific policy \r
+  from the DXE core response to an attempt to use a file that returns a \r
+  given status for the authentication check from the section extraction protocol.  \r
+\r
+  The possible responses in a given SAP implementation may include locking \r
+  flash upon failure to authenticate, attestation logging for all signed drivers, \r
+  and other exception operations.  The File parameter allows for possible logging \r
+  within the SAP of the driver.\r
+\r
+  If File is NULL, then EFI_INVALID_PARAMETER is returned.\r
+\r
+  If the file specified by File with an authentication status specified by \r
+  AuthenticationStatus is safe for the DXE Core to use, then EFI_SUCCESS is returned.\r
+\r
+  If the file specified by File with an authentication status specified by \r
+  AuthenticationStatus is not safe for the DXE Core to use under any circumstances, \r
+  then EFI_ACCESS_DENIED is returned.\r
+\r
+  If the file specified by File with an authentication status specified by \r
+  AuthenticationStatus is not safe for the DXE Core to use right now, but it \r
+  might be possible to use it at a future time, then EFI_SECURITY_VIOLATION is \r
+  returned.\r
+\r
+  @param[in, out] AuthenticationStatus  This is the authentication status returned\r
+                                        from the securitymeasurement services for the\r
+                                        input file.\r
+  @param[in]      File       This is a pointer to the device path of the file that is\r
+                             being dispatched. This will optionally be used for logging.\r
+  @param[in]      FileBuffer File buffer matches the input file device path.\r
+  @param[in]      FileSize   Size of File buffer matches the input file device path.\r
+\r
+  @retval EFI_SUCCESS            The file specified by File did authenticate, and the\r
+                                 platform policy dictates that the DXE Core may use File.\r
+  @retval EFI_INVALID_PARAMETER  File is NULL.\r
+  @retval EFI_SECURITY_VIOLATION The file specified by File did not authenticate, and\r
+                                 the platform policy dictates that File should be placed\r
+                                 in the untrusted state. A file may be promoted from\r
+                                 the untrusted to the trusted state at a future time\r
+                                 with a call to the Trust() DXE Service.\r
+  @retval EFI_ACCESS_DENIED      The file specified by File did not authenticate, and\r
+                                 the platform policy dictates that File should not be\r
+                                 used for any purpose.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DxeTpmMeasureBootHandler (\r
+  IN  OUT   UINT32                     AuthenticationStatus,\r
+  IN  CONST EFI_DEVICE_PATH_PROTOCOL   *File,\r
+  IN  VOID                             *FileBuffer OPTIONAL,\r
+  IN  UINTN                            FileSize OPTIONAL\r
+  )\r
+{\r
+  EFI_TCG_PROTOCOL                  *TcgProtocol;\r
+  EFI_STATUS                        Status;\r
+  TCG_EFI_BOOT_SERVICE_CAPABILITY   ProtocolCapability;\r
+  UINT32                            TCGFeatureFlags;\r
+  EFI_PHYSICAL_ADDRESS              EventLogLocation;\r
+  EFI_PHYSICAL_ADDRESS              EventLogLastEntry;\r
+  EFI_DEVICE_PATH_PROTOCOL          *DevicePathNode;\r
+  EFI_DEVICE_PATH_PROTOCOL          *OrigDevicePathNode;\r
+  EFI_HANDLE                        Handle;\r
+  BOOLEAN                           ApplicationRequired;\r
+  PE_COFF_LOADER_IMAGE_CONTEXT      ImageContext;\r
+\r
+  if (File == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Status = gBS->LocateProtocol (&gEfiTcgProtocolGuid, NULL, (VOID **) &TcgProtocol);\r
+  if (EFI_ERROR (Status)) {\r
+    //\r
+    // TCG protocol is not installed. So, TPM is not present.\r
+    // Don't do any measurement, and directly return EFI_SUCCESS.\r
+    //\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  ProtocolCapability.Size = (UINT8) sizeof (ProtocolCapability);\r
+  Status = TcgProtocol->StatusCheck (\r
+             TcgProtocol, \r
+             &ProtocolCapability,\r
+             &TCGFeatureFlags,\r
+             &EventLogLocation,\r
+             &EventLogLastEntry\r
+           );\r
+  if (EFI_ERROR (Status) || ProtocolCapability.TPMDeactivatedFlag) {\r
+    //\r
+    // TPM device doesn't work or activate.\r
+    //\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // Copy File Device Path\r
+  //\r
+  OrigDevicePathNode = DuplicateDevicePath (File);\r
+  ASSERT (OrigDevicePathNode != NULL);\r
+  \r
+  //\r
+  // 1. Check whether this device path support BlockIo protocol.\r
+  // Is so, this device path may be a GPT device path.\r
+  //\r
+  DevicePathNode = OrigDevicePathNode;\r
+  Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &DevicePathNode, &Handle);\r
+  if (!EFI_ERROR (Status) && !mMeasureGptTableFlag) {\r
+    //\r
+    // Find the gpt partion on the given devicepath\r
+    //\r
+    DevicePathNode = OrigDevicePathNode;\r
+    while (!IsDevicePathEnd (DevicePathNode)) {\r
+      //\r
+      // Find the Gpt partition\r
+      //\r
+      if (DevicePathType (DevicePathNode) == MEDIA_DEVICE_PATH &&\r
+            DevicePathSubType (DevicePathNode) == MEDIA_HARDDRIVE_DP) {\r
+        //\r
+        // Check whether it is a gpt partition or not\r
+        //                           \r
+        if (((HARDDRIVE_DEVICE_PATH *) DevicePathNode)->MBRType == MBR_TYPE_EFI_PARTITION_TABLE_HEADER && \r
+            ((HARDDRIVE_DEVICE_PATH *) DevicePathNode)->SignatureType == SIGNATURE_TYPE_GUID) {\r
+\r
+          //\r
+          // Change the partition device path to its parent device path (disk) and get the handle.\r
+          //\r
+          DevicePathNode->Type    = END_DEVICE_PATH_TYPE;\r
+          DevicePathNode->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE;\r
+          DevicePathNode          = OrigDevicePathNode;\r
+          Status = gBS->LocateDevicePath (\r
+                         &gEfiDiskIoProtocolGuid,\r
+                         &DevicePathNode,\r
+                         &Handle\r
+                         );\r
+          if (!EFI_ERROR (Status)) {\r
+            //\r
+            // Measure GPT disk.\r
+            //\r
+            Status = TcgMeasureGptTable (TcgProtocol, Handle);\r
+            if (!EFI_ERROR (Status)) {\r
+              //\r
+              // GPT disk check done.\r
+              //\r
+              mMeasureGptTableFlag = TRUE;\r
+            }\r
+          }\r
+          FreePool (OrigDevicePathNode);\r
+          OrigDevicePathNode = DuplicateDevicePath (File);\r
+          ASSERT (OrigDevicePathNode != NULL);\r
+          break;\r
+        }\r
+      }\r
+      DevicePathNode    = NextDevicePathNode (DevicePathNode);\r
+    }\r
+  }\r
+  \r
+  //\r
+  // 2. Measure PE image.\r
+  //\r
+  ApplicationRequired = FALSE;\r
+\r
+  //\r
+  // Check whether this device path support FV2 protocol.\r
+  //\r
+  DevicePathNode = OrigDevicePathNode;\r
+  Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &DevicePathNode, &Handle);\r
+  if (!EFI_ERROR (Status)) {\r
+    //\r
+    // Don't check FV image, and directly return EFI_SUCCESS.\r
+    // It can be extended to the specific FV authentication according to the different requirement.\r
+    //\r
+    if (IsDevicePathEnd (DevicePathNode)) {\r
+      return EFI_SUCCESS;\r
+    }\r
+    //\r
+    // The image from Firmware image will not be mearsured.\r
+    // Current policy doesn't measure PeImage from Firmware if it is driver\r
+    // If the got PeImage is application, it will be still be measured.\r
+    //\r
+    ApplicationRequired = TRUE;\r
+  }\r
+  \r
+  //\r
+  // File is not found.\r
+  //\r
+  if (FileBuffer == NULL) {\r
+    Status = EFI_SECURITY_VIOLATION;\r
+    goto Finish;\r
+  }\r
+\r
+  //\r
+  // Measure PE Image\r
+  //\r
+  DevicePathNode = OrigDevicePathNode;\r
+  ZeroMem (&ImageContext, sizeof (ImageContext));\r
+  ImageContext.Handle    = (VOID *) FileBuffer;\r
+  ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) ImageRead;\r
+\r
+  //\r
+  // Get information about the image being loaded\r
+  //\r
+  Status = PeCoffLoaderGetImageInfo (&ImageContext);\r
+  if (EFI_ERROR (Status)) {\r
+    //\r
+    // The information can't be got from the invalid PeImage\r
+    //\r
+    goto Finish;\r
+  }\r
+  \r
+  //\r
+  // Measure only application if Application flag is set\r
+  // Measure drivers and applications if Application flag is not set\r
+  //\r
+  if ((!ApplicationRequired) || \r
+        (ApplicationRequired && ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION)) {  \r
+    //\r
+    // Print the image path to be measured.\r
+    //    \r
+    DEBUG_CODE_BEGIN ();\r
+      CHAR16                            *ToText;\r
+      EFI_DEVICE_PATH_TO_TEXT_PROTOCOL  *DevPathToText;\r
+      Status = gBS->LocateProtocol (\r
+                      &gEfiDevicePathToTextProtocolGuid,\r
+                      NULL,\r
+                      (VOID **) &DevPathToText\r
+                      );\r
+      if (!EFI_ERROR (Status)) {\r
+        ToText = DevPathToText->ConvertDevicePathToText (\r
+                                  DevicePathNode,\r
+                                  FALSE,\r
+                                  TRUE\r
+                                  );\r
+        if (ToText != NULL) {\r
+          DEBUG ((DEBUG_INFO, "The measured image path is %s.\n", ToText));\r
+        }\r
+      }\r
+    DEBUG_CODE_END ();\r
+\r
+    //\r
+    // Measure PE image into TPM log.\r
+    //\r
+    Status = TcgMeasurePeImage (\r
+               TcgProtocol,\r
+               (EFI_PHYSICAL_ADDRESS) (UINTN) FileBuffer, \r
+               FileSize, \r
+               (UINTN) ImageContext.ImageAddress, \r
+               ImageContext.ImageType, \r
+               DevicePathNode\r
+               );\r
+  }\r
+\r
+  //\r
+  // Done, free the allocated resource.\r
+  //\r
+Finish:\r
+  FreePool (OrigDevicePathNode);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Register the security handler to provide TPM measure boot service.\r
+\r
+  @param  ImageHandle  ImageHandle of the loaded driver.\r
+  @param  SystemTable  Pointer to the EFI System Table.\r
+\r
+  @retval  EFI_SUCCESS            Register successfully.\r
+  @retval  EFI_OUT_OF_RESOURCES   No enough memory to register this handler.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DxeTpmMeasureBootLibConstructor (\r
+  IN EFI_HANDLE        ImageHandle,\r
+  IN EFI_SYSTEM_TABLE  *SystemTable\r
+  )\r
+{\r
+  return RegisterSecurityHandler (\r
+          DxeTpmMeasureBootHandler,\r
+          EFI_AUTH_OPERATION_MEASURE_IMAGE | EFI_AUTH_OPERATION_IMAGE_REQUIRED\r
+          );\r
+}\r
diff --git a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.inf b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.inf
new file mode 100644 (file)
index 0000000..bf83bf1
--- /dev/null
@@ -0,0 +1,54 @@
+## @file\r
+#  The library instance provides security service of TPM measure boot.\r
+#\r
+# Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = DxeTpmMeasureBootLib\r
+  FILE_GUID                      = 6C60C7D0-922A-4b7c-87D7-E503EDD73BBF\r
+  MODULE_TYPE                    = DXE_DRIVER\r
+  VERSION_STRING                 = 1.0\r
+  LIBRARY_CLASS                  = NULL|DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SAL_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER \r
+  CONSTRUCTOR                    = DxeTpmMeasureBootLibConstructor\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC\r
+#\r
+\r
+[Sources]\r
+  DxeTpmMeasureBootLib.c\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+  SecurityPkg/SecurityPkg.dec\r
+  CryptoPkg/CryptoPkg.dec\r
+\r
+[LibraryClasses]\r
+  BaseMemoryLib\r
+  DebugLib\r
+  MemoryAllocationLib\r
+  DevicePathLib\r
+  UefiBootServicesTableLib\r
+  BaseCryptLib\r
+  PeCoffLib\r
+  BaseLib\r
+  SecurityManagementLib\r
+\r
+[Protocols]\r
+  gEfiTcgProtocolGuid                   ## CONSUMES\r
+  gEfiFirmwareVolume2ProtocolGuid       ## CONSUMES\r
+  gEfiBlockIoProtocolGuid               ## CONSUMES\r
+  gEfiDiskIoProtocolGuid                ## CONSUMES\r
+  gEfiDevicePathToTextProtocolGuid      ## SOMETIMES_CONSUMES (Only used in debug mode)\r
diff --git a/SecurityPkg/Library/PlatformSecureLibNull/PlatformSecureLibNull.c b/SecurityPkg/Library/PlatformSecureLibNull/PlatformSecureLibNull.c
new file mode 100644 (file)
index 0000000..f085d62
--- /dev/null
@@ -0,0 +1,39 @@
+/** @file\r
+  Provides a secure platform-specific method to clear PK(Platform Key).\r
+\r
+Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+/**\r
+\r
+  This function detects whether a secure platform-specific method to clear PK(Platform Key)\r
+  is configured by platform owner. This method is provided for users force to clear PK \r
+  in case incorrect enrollment mis-haps.\r
+  \r
+  UEFI231 spec chapter 27.5.2 stipulates: The platform key may also be cleared using \r
+  a secure platform-specific method. In  this case, the global variable SetupMode \r
+  must also be updated to 1.\r
+  \r
+  NOTE THAT: This function cannot depend on any EFI Variable Service since they are\r
+  not available when this function is called in AuthenticateVariable driver.\r
+\r
+  @retval  TRUE       The Platform owner wants to force clear PK.\r
+  @retval  FALSE      The Platform owner doesn't want to force clear PK. \r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+ForceClearPK (\r
+  VOID\r
+  )\r
+{\r
+  return FALSE;\r
+}\r
diff --git a/SecurityPkg/Library/PlatformSecureLibNull/PlatformSecureLibNull.inf b/SecurityPkg/Library/PlatformSecureLibNull/PlatformSecureLibNull.inf
new file mode 100644 (file)
index 0000000..5750198
--- /dev/null
@@ -0,0 +1,33 @@
+## @file\r
+#  Provides a secure platform-specific method to clear PK(Platform Key).\r
+#\r
+# Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = PlatformSecureLibNull\r
+  FILE_GUID                      = 7FA68D82-10A4-4e71-9524-D3D9500D3CDF\r
+  MODULE_TYPE                    = DXE_DRIVER\r
+  VERSION_STRING                 = 1.0\r
+  LIBRARY_CLASS                  = PlatformSecureLib|DXE_RUNTIME_DRIVER DXE_SMM_DRIVER\r
+\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC\r
+#\r
+\r
+[Sources]\r
+  PlatformSecureLibNull.c\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
diff --git a/SecurityPkg/Library/TpmCommLib/CommonHeader.h b/SecurityPkg/Library/TpmCommLib/CommonHeader.h
new file mode 100644 (file)
index 0000000..b8496c7
--- /dev/null
@@ -0,0 +1,29 @@
+/** @file\r
+  The intenal header file for TpmCommLib.\r
+\r
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _TPMCOMMLIB_COMMON_HEADER_H_\r
+#define _TPMCOMMLIB_COMMON_HEADER_H_\r
+\r
+#include <PiPei.h>\r
+#include <IndustryStandard/Tpm12.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/IoLib.h>\r
+#include <Library/TimerLib.h>\r
+#include <Library/TpmCommLib.h>\r
+#include <Library/BaseCryptLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/DebugLib.h>\r
+\r
+#endif\r
diff --git a/SecurityPkg/Library/TpmCommLib/TisPc.c b/SecurityPkg/Library/TpmCommLib/TisPc.c
new file mode 100644 (file)
index 0000000..3d74a01
--- /dev/null
@@ -0,0 +1,180 @@
+/** @file\r
+  Basic TIS (TPM Interface Specification) functions.\r
+\r
+Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "CommonHeader.h"\r
+\r
+/**\r
+  Check whether TPM chip exist.\r
+\r
+  @param[in] TisReg  Pointer to TIS register.\r
+\r
+  @retval    TRUE    TPM chip exists.\r
+  @retval    FALSE   TPM chip is not found.\r
+**/\r
+BOOLEAN\r
+TisPcPresenceCheck (\r
+  IN      TIS_PC_REGISTERS_PTR      TisReg\r
+  )\r
+{\r
+  UINT8                             RegRead;\r
+  \r
+  RegRead = MmioRead8 ((UINTN)&TisReg->Access);\r
+  return (BOOLEAN)(RegRead != (UINT8)-1);\r
+}\r
+\r
+/**\r
+  Check whether the value of a TPM chip register satisfies the input BIT setting.\r
+\r
+  @param[in]  Register     Address port of register to be checked.\r
+  @param[in]  BitSet       Check these data bits are set.\r
+  @param[in]  BitClear     Check these data bits are clear.\r
+  @param[in]  TimeOut      The max wait time (unit MicroSecond) when checking register.\r
+\r
+  @retval     EFI_SUCCESS  The register satisfies the check bit.\r
+  @retval     EFI_TIMEOUT  The register can't run into the expected status in time.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TisPcWaitRegisterBits (\r
+  IN      UINT8                     *Register,\r
+  IN      UINT8                     BitSet,\r
+  IN      UINT8                     BitClear,\r
+  IN      UINT32                    TimeOut\r
+  )\r
+{\r
+  UINT8                             RegRead;\r
+  UINT32                            WaitTime;\r
+\r
+  for (WaitTime = 0; WaitTime < TimeOut; WaitTime += 30){\r
+    RegRead = MmioRead8 ((UINTN)Register);\r
+    if ((RegRead & BitSet) == BitSet && (RegRead & BitClear) == 0)\r
+      return EFI_SUCCESS;\r
+    MicroSecondDelay (30);\r
+  }\r
+  return EFI_TIMEOUT;\r
+}\r
+\r
+/**\r
+  Get BurstCount by reading the burstCount field of a TIS regiger \r
+  in the time of default TIS_TIMEOUT_D.\r
+\r
+  @param[in]  TisReg                Pointer to TIS register.\r
+  @param[out] BurstCount            Pointer to a buffer to store the got BurstConut.\r
+\r
+  @retval     EFI_SUCCESS           Get BurstCount.\r
+  @retval     EFI_INVALID_PARAMETER TisReg is NULL or BurstCount is NULL.\r
+  @retval     EFI_TIMEOUT           BurstCount can't be got in time.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TisPcReadBurstCount (\r
+  IN      TIS_PC_REGISTERS_PTR      TisReg,\r
+     OUT  UINT16                    *BurstCount\r
+  )\r
+{\r
+  UINT32                            WaitTime;\r
+  UINT8                             DataByte0;\r
+  UINT8                             DataByte1;\r
+\r
+  if (BurstCount == NULL || TisReg == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  WaitTime = 0;\r
+  do {\r
+    //\r
+    // TIS_PC_REGISTERS_PTR->burstCount is UINT16, but it is not 2bytes aligned,\r
+    // so it needs to use MmioRead8 to read two times\r
+    //\r
+    DataByte0   = MmioRead8 ((UINTN)&TisReg->BurstCount);\r
+    DataByte1   = MmioRead8 ((UINTN)&TisReg->BurstCount + 1);\r
+    *BurstCount = (UINT16)((DataByte1 << 8) + DataByte0);\r
+    if (*BurstCount != 0) {\r
+      return EFI_SUCCESS;\r
+    }\r
+    MicroSecondDelay (30);\r
+    WaitTime += 30;\r
+  } while (WaitTime < TIS_TIMEOUT_D);\r
+\r
+  return EFI_TIMEOUT;\r
+}\r
+\r
+/**\r
+  Set TPM chip to ready state by sending ready command TIS_PC_STS_READY \r
+  to Status Register in time.\r
+\r
+  @param[in] TisReg                Pointer to TIS register.\r
+\r
+  @retval    EFI_SUCCESS           TPM chip enters into ready state.\r
+  @retval    EFI_INVALID_PARAMETER TisReg is NULL.\r
+  @retval    EFI_TIMEOUT           TPM chip can't be set to ready state in time.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TisPcPrepareCommand (\r
+  IN      TIS_PC_REGISTERS_PTR      TisReg\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+\r
+  if (TisReg == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  MmioWrite8((UINTN)&TisReg->Status, TIS_PC_STS_READY);\r
+  Status = TisPcWaitRegisterBits (\r
+             &TisReg->Status,\r
+             TIS_PC_STS_READY,\r
+             0,\r
+             TIS_TIMEOUT_B\r
+             );\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Get the control of TPM chip by sending requestUse command TIS_PC_ACC_RQUUSE \r
+  to ACCESS Register in the time of default TIS_TIMEOUT_D.\r
+\r
+  @param[in] TisReg                Pointer to TIS register.\r
+\r
+  @retval    EFI_SUCCESS           Get the control of TPM chip.\r
+  @retval    EFI_INVALID_PARAMETER TisReg is NULL.\r
+  @retval    EFI_NOT_FOUND         TPM chip doesn't exit.\r
+  @retval    EFI_TIMEOUT           Can't get the TPM control in time.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TisPcRequestUseTpm (\r
+  IN      TIS_PC_REGISTERS_PTR      TisReg\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  \r
+  if (TisReg == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  \r
+  if (!TisPcPresenceCheck (TisReg)) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  MmioWrite8((UINTN)&TisReg->Access, TIS_PC_ACC_RQUUSE);\r
+  Status = TisPcWaitRegisterBits (\r
+             &TisReg->Access,\r
+             (UINT8)(TIS_PC_ACC_ACTIVE |TIS_PC_VALID),\r
+             0,\r
+             TIS_TIMEOUT_D\r
+             );\r
+  return Status;\r
+}\r
diff --git a/SecurityPkg/Library/TpmCommLib/TpmComm.c b/SecurityPkg/Library/TpmCommLib/TpmComm.c
new file mode 100644 (file)
index 0000000..3197f96
--- /dev/null
@@ -0,0 +1,50 @@
+/** @file\r
+  Basic TPM command functions.\r
+\r
+Copyright (c) 2005 - 2010, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "CommonHeader.h"\r
+\r
+/**\r
+  Single function calculates SHA1 digest value for all raw data. It\r
+  combines Sha1Init(), Sha1Update() and Sha1Final().\r
+\r
+  @param[in]  Data          Raw data to be digested.\r
+  @param[in]  DataLen       Size of the raw data.\r
+  @param[out] Digest        Pointer to a buffer that stores the final digest.\r
+  \r
+  @retval     EFI_SUCCESS   Always successfully calculate the final digest.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TpmCommHashAll (\r
+  IN  CONST UINT8                   *Data,\r
+  IN        UINTN                   DataLen,\r
+  OUT       TPM_DIGEST              *Digest\r
+  )\r
+{\r
+  VOID     *Sha1Ctx;\r
+  UINTN    CtxSize;\r
+\r
+  CtxSize = Sha1GetContextSize ();\r
+  Sha1Ctx = AllocatePool (CtxSize);\r
+  ASSERT (Sha1Ctx != NULL);\r
+\r
+  Sha1Init (Sha1Ctx);\r
+  Sha1Update (Sha1Ctx, Data, DataLen);\r
+  Sha1Final (Sha1Ctx, (UINT8 *)Digest);\r
+\r
+  FreePool (Sha1Ctx);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
diff --git a/SecurityPkg/Library/TpmCommLib/TpmCommLib.inf b/SecurityPkg/Library/TpmCommLib/TpmCommLib.inf
new file mode 100644 (file)
index 0000000..7188a3b
--- /dev/null
@@ -0,0 +1,46 @@
+## @file\r
+#  TpmCommLib instance implements basis TPM Interface Specification (TIS) and TPM command functions.\r
+#\r
+# Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = TpmCommLib\r
+  FILE_GUID                      = 7d9fe32e-a6a9-4cdf-abff-10cc7f22e1c9\r
+  MODULE_TYPE                    = PEIM\r
+  VERSION_STRING                 = 1.0\r
+  LIBRARY_CLASS                  = TpmCommLib|DXE_DRIVER UEFI_DRIVER PEIM DXE_SMM_DRIVER\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64 IPF\r
+#\r
+\r
+[Sources]\r
+  TisPc.c\r
+  TpmComm.c\r
+  CommonHeader.h\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  SecurityPkg/SecurityPkg.dec\r
+  CryptoPkg/CryptoPkg.dec\r
+\r
+[LibraryClasses]\r
+  BaseLib\r
+  BaseMemoryLib\r
+  IoLib\r
+  TimerLib\r
+  BaseCryptLib\r
+  MemoryAllocationLib\r
+  DebugLib\r
+\r
diff --git a/SecurityPkg/SecurityPkg.dec b/SecurityPkg/SecurityPkg.dec
new file mode 100644 (file)
index 0000000..8121f39
--- /dev/null
@@ -0,0 +1,122 @@
+## @file  SecurityPkg.dec\r
+#  This package includes the security drivers, defintions(including PPIs/PROTOCOLs/GUIDs  \r
+#  and library classes) and libraries instances.\r
+#\r
+# Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
+# This program and the accompanying materials are licensed and made available under\r
+# the terms and conditions of the BSD License which accompanies this distribution.\r
+# The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+  DEC_SPECIFICATION              = 0x00010005\r
+  PACKAGE_NAME                   = SecurityPkg\r
+  PACKAGE_GUID                   = 24369CAC-6AA6-4fb8-88DB-90BF061668AD\r
+  PACKAGE_VERSION                = 0.91\r
+\r
+[Includes]\r
+  Include\r
+\r
+[LibraryClasses]\r
+  ##  @libraryclass  Definitions for common TPM commands as library API for TPM\r
+  #                  module use.\r
+  TpmCommLib|Include/Library/TpmCommLib.h\r
+\r
+[Guids]\r
+  ## Security package token space guid\r
+  # Include/Guid/SecurityPkgTokenSpace.h\r
+  gEfiSecurityPkgTokenSpaceGuid  = { 0xd3fb176, 0x9569, 0x4d51, { 0xa3, 0xef, 0x7d, 0x61, 0xc6, 0x4f, 0xea, 0xba }}\r
+  ## Guid acted as the authenticated variable store header's signature, and to specify the variable list entries put in the EFI system table.\r
+  #  Include/Guid/AuthenticatedVariableFormat.h\r
+  gEfiAuthenticatedVariableGuid  = { 0xaaf32c78, 0x947b, 0x439a, { 0xa1, 0x80, 0x2e, 0x14, 0x4e, 0xc3, 0x77, 0x92 } }\r
+\r
+  ## Include/Guid/TcgEventHob.h\r
+  gTcgEventEntryHobGuid              = { 0x2e3044ac, 0x879f, 0x490f, {0x97, 0x60, 0xbb, 0xdf, 0xaf, 0x69, 0x5f, 0x50 }}\r
+\r
+  ## Include/Guid/PhysicalPresenceData.h\r
+  gEfiPhysicalPresenceGuid           = { 0xf6499b1, 0xe9ad, 0x493d, { 0xb9, 0xc2, 0x2f, 0x90, 0x81, 0x5c, 0x6c, 0xbc }}\r
+\r
+[Ppis]\r
+  ## Include/Ppi/LockPhysicalPresence.h\r
+  gPeiLockPhysicalPresencePpiGuid    = { 0xef9aefe5, 0x2bd3, 0x4031, { 0xaf, 0x7d, 0x5e, 0xfe, 0x5a, 0xbb, 0x9a, 0xd } }\r
+\r
+  ## Include/Ppi/TpmInitialized.h\r
+  gPeiTpmInitializedPpiGuid      = { 0xe9db0d58, 0xd48d, 0x47f6, { 0x9c, 0x6e, 0x6f, 0x40, 0xe8, 0x6c, 0x7b, 0x41 }}\r
+\r
+[PcdsFixedAtBuild]\r
+  ## Pcd for OptionRom.\r
+  #  Image verification policy settings:\r
+  #  ALWAYS_EXECUTE                         0x00000000\r
+  #  NEVER_EXECUTE                          0x00000001\r
+  #  ALLOW_EXECUTE_ON_SECURITY_VIOLATION    0x00000002\r
+  #  DEFER_EXECUTE_ON_SECURITY_VIOLATION    0x00000003\r
+  #  DENY_EXECUTE_ON_SECURITY_VIOLATION     0x00000004\r
+  #  QUERY_USER_ON_SECURITY_VIOLATION       0x00000005 \r
+  gEfiSecurityPkgTokenSpaceGuid.PcdOptionRomImageVerificationPolicy|0x00|UINT32|0x00000001\r
+  \r
+  ## Pcd for removable media.\r
+  #  Removable media include CD-ROM, Floppy, USB and network.\r
+  #  Image verification policy settings:\r
+  #  ALWAYS_EXECUTE                         0x00000000\r
+  #  NEVER_EXECUTE                          0x00000001\r
+  #  ALLOW_EXECUTE_ON_SECURITY_VIOLATION    0x00000002\r
+  #  DEFER_EXECUTE_ON_SECURITY_VIOLATION    0x00000003\r
+  #  DENY_EXECUTE_ON_SECURITY_VIOLATION     0x00000004\r
+  #  QUERY_USER_ON_SECURITY_VIOLATION       0x00000005\r
+  gEfiSecurityPkgTokenSpaceGuid.PcdRemovableMediaImageVerificationPolicy|0x05|UINT32|0x00000002\r
+  \r
+  ## Pcd for fixed media.\r
+  #  Fixed media include hard disk.\r
+  #  Image verification policy settings:\r
+  #  ALWAYS_EXECUTE                         0x00000000\r
+  #  NEVER_EXECUTE                          0x00000001\r
+  #  ALLOW_EXECUTE_ON_SECURITY_VIOLATION    0x00000002\r
+  #  DEFER_EXECUTE_ON_SECURITY_VIOLATION    0x00000003\r
+  #  DENY_EXECUTE_ON_SECURITY_VIOLATION     0x00000004\r
+  #  QUERY_USER_ON_SECURITY_VIOLATION       0x00000005  \r
+  gEfiSecurityPkgTokenSpaceGuid.PcdFixedMediaImageVerificationPolicy|0x05|UINT32|0x00000003\r
+  \r
+  ## Defer Image Load policy settings.\r
+  #  The policy is bitwise. \r
+  #  If bit is set, the image from corresponding device will be trust when loading.\r
+  #\r
+  # IMAGE_UNKNOWN                         0x00000001\r
+  # IMAGE_FROM_FV                         0x00000002\r
+  # IMAGE_FROM_OPTION_ROM                 0x00000004\r
+  # IMAGE_FROM_REMOVABLE_MEDIA            0x00000008\r
+  # IMAGE_FROM_FIXED_MEDIA                0x00000010\r
+  gEfiSecurityPkgTokenSpaceGuid.PcdDeferImageLoadPolicy|0x0000001F|UINT32|0x0000004\r
+  \r
+  ## The token file name used to save credential in USB credential provider driver.\r
+  #  The specified file should be saved at the root directory of USB storage disk.\r
+  gEfiSecurityPkgTokenSpaceGuid.PcdFixedUsbCredentialProviderTokenFileName|L"Token.bin"|VOID*|0x00000005\r
+\r
+  ## The size of Append variable buffer. This buffer is reserved for runtime use, OS can append data into one existing variable.\r
+  gEfiSecurityPkgTokenSpaceGuid.PcdMaxAppendVariableSize|0x2000|UINT32|0x30000005  \r
+\r
+  ## This PCD specifies the type of TCG platform that contains TPM chip. \r
+  #  This PCD is only avaiable when PcdTpmPhysicalPresence is TRUE.\r
+  #  If 0, TCG platform type is PC client.\r
+  #  If 1, TCG platform type is server.\r
+  gEfiSecurityPkgTokenSpaceGuid.PcdTpmPlatformClass|0|UINT8|0x00000006\r
+\r
+  ## The PCD is used to control whether to support hiding the TPM.\r
+  #  If TRUE, PcdHideTpm controls whether to hide the TPM.\r
+  gEfiSecurityPkgTokenSpaceGuid.PcdHideTpmSupport|FALSE|BOOLEAN|0x00000007\r
+  \r
+[PcdsDynamic, PcdsDynamicEx]\r
+  ## The PCD is used to control whether to hide the TPM.\r
+  gEfiSecurityPkgTokenSpaceGuid.PcdHideTpm|FALSE|BOOLEAN|0x00010002\r
+\r
+  ## The PCD is used to specify whether or not MOR (MemoryOverwriteControl) feature is enabled.\r
+  gEfiSecurityPkgTokenSpaceGuid.PcdMorEnable|FALSE|BOOLEAN|0x00010000\r
+\r
+[PcdsFixedAtBuild, PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx]\r
+  ## This PCD indicates the presence or absence of the platform operator.\r
+  gEfiSecurityPkgTokenSpaceGuid.PcdTpmPhysicalPresence|TRUE|BOOLEAN|0x00010001\r
+\r
diff --git a/SecurityPkg/SecurityPkg.dsc b/SecurityPkg/SecurityPkg.dsc
new file mode 100644 (file)
index 0000000..09aa8fc
--- /dev/null
@@ -0,0 +1,125 @@
+## @file\r
+#  Security Module Package for All Architectures.\r
+#\r
+# Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+  PLATFORM_NAME                  = SecurityPkg\r
+  PLATFORM_GUID                  = B2C4614D-AE76-47ba-B876-5988BFED064F\r
+  PLATFORM_VERSION               = 0.91\r
+  DSC_SPECIFICATION              = 0x00010005\r
+  OUTPUT_DIRECTORY               = Build/SecurityPkg\r
+  SUPPORTED_ARCHITECTURES        = IA32|IPF|X64|EBC\r
+  BUILD_TARGETS                  = DEBUG|RELEASE\r
+  SKUID_IDENTIFIER               = DEFAULT\r
+\r
+[LibraryClasses]\r
+  DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf\r
+  DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf  \r
+  BaseLib|MdePkg/Library/BaseLib/BaseLib.inf\r
+  SynchronizationLib|MdePkg/Library/BaseSynchronizationLib/BaseSynchronizationLib.inf\r
+  TimerLib|MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTemplate.inf\r
+  BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf\r
+  MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf\r
+  PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf\r
+  UefiApplicationEntryPoint|MdePkg/Library/UefiApplicationEntryPoint/UefiApplicationEntryPoint.inf\r
+\r
+  DxeServicesLib|MdePkg/Library/DxeServicesLib/DxeServicesLib.inf\r
+  UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf\r
+  UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf\r
+  DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf\r
+  UefiLib|MdePkg/Library/UefiLib/UefiLib.inf\r
+  DxeServicesTableLib|MdePkg/Library/DxeServicesTableLib/DxeServicesTableLib.inf\r
+  UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf\r
+  UefiRuntimeLib|MdePkg/Library/UefiRuntimeLib/UefiRuntimeLib.inf\r
+  HiiLib|MdeModulePkg/Library/UefiHiiLib/UefiHiiLib.inf\r
+  UefiHiiServicesLib|MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.inf\r
+  PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf\r
+  BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf\r
+  IntrinsicLib|CryptoPkg/Library/IntrinsicLib/IntrinsicLib.inf\r
+  OpensslLib|CryptoPkg/Library/OpensslLib/OpensslLib.inf\r
+  IoLib|MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf\r
+  TpmCommLib|SecurityPkg/Library/TpmCommLib/TpmCommLib.inf\r
+  PlatformSecureLib|SecurityPkg/Library/PlatformSecureLibNull/PlatformSecureLibNull.inf    \r
+\r
+[LibraryClasses.common.PEIM]\r
+  PeimEntryPoint|MdePkg/Library/PeimEntryPoint/PeimEntryPoint.inf\r
+  PeiServicesLib|MdePkg/Library/PeiServicesLib/PeiServicesLib.inf\r
+  PeiServicesTablePointerLib|MdePkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointerLib.inf\r
+  HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf\r
+  MemoryAllocationLib|MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllocationLib.inf\r
+\r
+[LibraryClasses.common.DXE_DRIVER]\r
+  HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf\r
+  ReportStatusCodeLib|MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf\r
+\r
+[LibraryClasses.common.UEFI_DRIVER, LibraryClasses.common.DXE_RUNTIME_DRIVER, LibraryClasses.common.DXE_SAL_DRIVER,]\r
+  MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf\r
+  DebugLib|MdePkg/Library/UefiDebugLibConOut/UefiDebugLibConOut.inf\r
+\r
+[LibraryClasses.IPF.DXE_SAL_DRIVER]\r
+  ExtendedSalLib|MdePkg/Library/DxeRuntimeExtendedSalLib/DxeRuntimeExtendedSalLib.inf\r
+\r
+[LibraryClasses.common.DXE_SMM_DRIVER]\r
+  SmmServicesTableLib|MdePkg/Library/SmmServicesTableLib/SmmServicesTableLib.inf\r
+  MemoryAllocationLib|MdePkg/Library/SmmMemoryAllocationLib/SmmMemoryAllocationLib.inf\r
+  BaseCryptLib|CryptoPkg/Library/BaseCryptLib/SmmCryptLib.inf\r
+    \r
+[Components]\r
+  SecurityPkg/VariableAuthenticated/Pei/VariablePei.inf\r
+  SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.inf\r
+  SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.inf\r
+  SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManagerDxe.inf\r
+  SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManagerDxe.inf\r
+  SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderDxe.inf\r
+  SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProviderDxe.inf\r
+\r
+  #\r
+  # Application\r
+  #\r
+  SecurityPkg/Application/VariableInfo/VariableInfo.inf\r
+\r
+  #\r
+  # TPM\r
+  #\r
+  SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.inf\r
+  SecurityPkg/Tcg/TcgPei/TcgPei.inf\r
+  SecurityPkg/Tcg/TcgDxe/TcgDxe.inf\r
+  SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePei.inf\r
+  SecurityPkg/Tcg/PhysicalPresenceDxe/PhysicalPresenceDxe.inf\r
+  SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.inf\r
+  SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDxe.inf {\r
+    <LibraryClasses>\r
+      PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf\r
+  }\r
+  SecurityPkg/Tcg/TcgSmm/TcgSmm.inf\r
+\r
+[Components.IA32, Components.X64]\r
+  SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableRuntimeDxe.inf {\r
+    <LibraryClasses>\r
+      BaseCryptLib|CryptoPkg/Library/BaseCryptLib/RuntimeCryptLib.inf\r
+  }\r
+\r
+  SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmm.inf\r
+  SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmmRuntimeDxe.inf\r
+\r
+[Components.IPF]\r
+  SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/EsalVariableDxeSal.inf \r
+\r
+[Components.EBC]\r
+# Build only\r
+  SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableRuntimeDxe.inf \r
+\r
+[BuildOptions]\r
+   MSFT:*_*_IA32_DLINK_FLAGS = /ALIGN:256\r
+  INTEL:*_*_IA32_DLINK_FLAGS = /ALIGN:256\r
+\r
diff --git a/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.c b/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.c
new file mode 100644 (file)
index 0000000..ce53112
--- /dev/null
@@ -0,0 +1,82 @@
+/** @file\r
+  TCG MOR (Memory Overwrite Request) Control Driver.\r
+\r
+  This driver initilize MemoryOverwriteRequestControl variable. It \r
+  will clear MOR_CLEAR_MEMORY_BIT bit if it is set.\r
+\r
+Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "TcgMor.h"\r
+\r
+/**\r
+  Entry Point for TCG MOR Control driver.\r
+\r
+  @param[in] ImageHandle  Image handle of this driver.\r
+  @param[in] SystemTable  A Pointer to the EFI System Table.\r
+\r
+  @retval EFI_SUCEESS     \r
+  @return Others          Some error occurs.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MorDriverEntryPoint (\r
+  IN EFI_HANDLE        ImageHandle,\r
+  IN EFI_SYSTEM_TABLE  *SystemTable\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  UINT8       MorControl;\r
+  UINTN       DataSize;\r
+\r
+  ///\r
+  /// The firmware is required to create the MemoryOverwriteRequestControl UEFI variable.\r
+  ///\r
+\r
+  DataSize = sizeof (MorControl);\r
+  Status = gRT->GetVariable (\r
+                  MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME, \r
+                  &gEfiMemoryOverwriteControlDataGuid, \r
+                  NULL, \r
+                  &DataSize, \r
+                  &MorControl\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    //\r
+    // Set default value to 0\r
+    //\r
+    MorControl = 0;\r
+  } else {\r
+    if (MOR_CLEAR_MEMORY_VALUE (MorControl) == 0x0) {\r
+      //\r
+      // MorControl is expected, directly return to avoid unnecessary variable operation\r
+      //\r
+      return EFI_SUCCESS;\r
+    }\r
+    //\r
+    // Clear MOR_CLEAR_MEMORY_BIT\r
+    //\r
+    DEBUG ((EFI_D_INFO, "TcgMor: Clear MorClearMemory bit\n"));\r
+    MorControl &= 0xFE;\r
+  }\r
+  \r
+  Status = gRT->SetVariable (\r
+                  MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME, \r
+                  &gEfiMemoryOverwriteControlDataGuid, \r
+                  EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
+                  DataSize, \r
+                  &MorControl\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+  return Status;\r
+}\r
+\r
+\r
diff --git a/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.h b/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.h
new file mode 100644 (file)
index 0000000..bfad2cf
--- /dev/null
@@ -0,0 +1,27 @@
+/** @file\r
+  The header file for TcgMor.\r
+\r
+Copyright (c) 2009, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef __TCG_MOR_H__\r
+#define __TCG_MOR_H__\r
+\r
+#include <PiDxe.h>\r
+\r
+#include <Guid/MemoryOverwriteControl.h>\r
+\r
+#include <Library/UefiDriverEntryPoint.h>\r
+#include <Library/UefiRuntimeServicesTableLib.h>\r
+#include <Library/DebugLib.h>\r
+\r
+#endif\r
+\r
diff --git a/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.inf b/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.inf
new file mode 100644 (file)
index 0000000..e62a904
--- /dev/null
@@ -0,0 +1,50 @@
+## @file\r
+#  Component description file for Memory Overwrite Control driver.\r
+#\r
+# Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = TcgMor\r
+  FILE_GUID                      = AD416CE3-A483-45b1-94C2-4B4E4D575562\r
+  MODULE_TYPE                    = DXE_DRIVER\r
+  VERSION_STRING                 = 1.0\r
+\r
+  ENTRY_POINT                    = MorDriverEntryPoint\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC\r
+#\r
+\r
+[Sources]\r
+  TcgMor.c\r
+  TcgMor.h\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  SecurityPkg/SecurityPkg.dec\r
+\r
+[LibraryClasses]\r
+  UefiDriverEntryPoint\r
+  UefiRuntimeServicesTableLib\r
+  ReportStatusCodeLib\r
+  DebugLib\r
+\r
+[Guids]\r
+  gEfiMemoryOverwriteControlDataGuid            # GUID ALWAYS_CONSUMED\r
+\r
+[Depex]\r
+  gEfiVariableArchProtocolGuid AND\r
+  gEfiVariableWriteArchProtocolGuid AND\r
+  gEfiTcgProtocolGuid\r
+\r
diff --git a/SecurityPkg/Tcg/PhysicalPresenceDxe/PhysicalPresence.c b/SecurityPkg/Tcg/PhysicalPresenceDxe/PhysicalPresence.c
new file mode 100644 (file)
index 0000000..187c3ca
--- /dev/null
@@ -0,0 +1,1115 @@
+/** @file\r
+  This driver checks whether there is pending TPM request. If yes, \r
+  it will display TPM request information and ask for user confirmation.\r
+  The TPM request will be cleared after it is processed.  \r
+  \r
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "PhysicalPresence.h"\r
+\r
+EFI_HII_HANDLE mPpStringPackHandle;\r
+\r
+/**\r
+  Get TPM physical presence permanent flags.\r
+\r
+  @param[out] LifetimeLock  Returns physicalPresenceLifetimeLock permanent flag.  \r
+  @param[out] CmdEnable     Returns physicalPresenceCMDEnable permanent flag.\r
+  \r
+  @retval EFI_SUCCESS       Flags were returns successfully.\r
+  @retval other             Failed to locate EFI TCG Protocol.\r
+\r
+**/\r
+EFI_STATUS\r
+GetTpmCapability (\r
+  OUT  BOOLEAN                      *LifetimeLock,\r
+  OUT  BOOLEAN                      *CmdEnable\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  EFI_TCG_PROTOCOL                  *TcgProtocol;\r
+  TPM_RQU_COMMAND_HDR               *TpmRqu;\r
+  TPM_RSP_COMMAND_HDR               *TpmRsp;\r
+  UINT32                            *SendBufPtr;\r
+  UINT8                             SendBuffer[sizeof (*TpmRqu) + sizeof (UINT32) * 3];\r
+  TPM_PERMANENT_FLAGS               *TpmPermanentFlags;\r
+  UINT8                             RecvBuffer[40];\r
+  \r
+  Status = gBS->LocateProtocol (&gEfiTcgProtocolGuid, NULL, (VOID **)&TcgProtocol);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Fill request header\r
+  //\r
+  TpmRsp = (TPM_RSP_COMMAND_HDR*)RecvBuffer;\r
+  TpmRqu = (TPM_RQU_COMMAND_HDR*)SendBuffer;\r
+  \r
+  TpmRqu->tag       = H2NS (TPM_TAG_RQU_COMMAND);\r
+  TpmRqu->paramSize = H2NL (sizeof (SendBuffer));\r
+  TpmRqu->ordinal   = H2NL (TPM_ORD_GetCapability);\r
+\r
+  //\r
+  // Set request parameter\r
+  //\r
+  SendBufPtr      = (UINT32*)(TpmRqu + 1);\r
+  WriteUnaligned32 (SendBufPtr++, H2NL (TPM_CAP_FLAG));\r
+  WriteUnaligned32 (SendBufPtr++, H2NL (sizeof (TPM_CAP_FLAG_PERMANENT)));\r
+  WriteUnaligned32 (SendBufPtr, H2NL (TPM_CAP_FLAG_PERMANENT));  \r
+  \r
+  Status = TcgProtocol->PassThroughToTpm (\r
+                          TcgProtocol,\r
+                          sizeof (SendBuffer),\r
+                          (UINT8*)TpmRqu,\r
+                          sizeof (RecvBuffer),\r
+                          (UINT8*)&RecvBuffer\r
+                          );\r
+  ASSERT_EFI_ERROR (Status);\r
+  ASSERT (TpmRsp->tag == H2NS (TPM_TAG_RSP_COMMAND));\r
+  ASSERT (TpmRsp->returnCode == 0);\r
+  \r
+  TpmPermanentFlags = (TPM_PERMANENT_FLAGS *)&RecvBuffer[sizeof (TPM_RSP_COMMAND_HDR) + sizeof (UINT32)];\r
+  \r
+  if (LifetimeLock != NULL) {\r
+    *LifetimeLock = TpmPermanentFlags->physicalPresenceLifetimeLock;\r
+  }\r
+\r
+  if (CmdEnable != NULL) {\r
+    *CmdEnable = TpmPermanentFlags->physicalPresenceCMDEnable;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Issue TSC_PhysicalPresence command to TPM.\r
+\r
+  @param[in] PhysicalPresence     The state to set the TPM's Physical Presence flags.  \r
+  \r
+  @retval EFI_SUCCESS             TPM executed the command successfully.\r
+  @retval EFI_SECURITY_VIOLATION  TPM returned error when executing the command.\r
+  @retval other                   Failed to locate EFI TCG Protocol.\r
+\r
+**/\r
+EFI_STATUS\r
+TpmPhysicalPresence (\r
+  IN      TPM_PHYSICAL_PRESENCE     PhysicalPresence\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  EFI_TCG_PROTOCOL                  *TcgProtocol;\r
+  TPM_RQU_COMMAND_HDR               *TpmRqu;\r
+  TPM_PHYSICAL_PRESENCE             *TpmPp;\r
+  TPM_RSP_COMMAND_HDR               TpmRsp;\r
+  UINT8                             Buffer[sizeof (*TpmRqu) + sizeof (*TpmPp)];\r
+\r
+  Status = gBS->LocateProtocol (&gEfiTcgProtocolGuid, NULL, (VOID **)&TcgProtocol);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  TpmRqu = (TPM_RQU_COMMAND_HDR*)Buffer;\r
+  TpmPp = (TPM_PHYSICAL_PRESENCE*)(TpmRqu + 1);\r
+\r
+  TpmRqu->tag = H2NS (TPM_TAG_RQU_COMMAND);\r
+  TpmRqu->paramSize = H2NL (sizeof (Buffer));\r
+  TpmRqu->ordinal = H2NL (TSC_ORD_PhysicalPresence);\r
+  WriteUnaligned16 (TpmPp, (TPM_PHYSICAL_PRESENCE) H2NS (PhysicalPresence));  \r
+\r
+  Status = TcgProtocol->PassThroughToTpm (\r
+                          TcgProtocol,\r
+                          sizeof (Buffer),\r
+                          (UINT8*)TpmRqu,\r
+                          sizeof (TpmRsp),\r
+                          (UINT8*)&TpmRsp\r
+                          );\r
+  ASSERT_EFI_ERROR (Status);\r
+  ASSERT (TpmRsp.tag == H2NS (TPM_TAG_RSP_COMMAND));\r
+  if (TpmRsp.returnCode != 0) {\r
+    //\r
+    // If it fails, some requirements may be needed for this command.\r
+    //\r
+    return EFI_SECURITY_VIOLATION;\r
+  }\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Issue a TPM command for which no additional output data will be returned.\r
+\r
+  @param[in] TcgProtocol              EFI TCG Protocol instance.  \r
+  @param[in] Ordinal                  TPM command code.  \r
+  @param[in] AdditionalParameterSize  Additional parameter size.  \r
+  @param[in] AdditionalParameters     Pointer to the Additional paramaters.  \r
+  \r
+  @retval TPM_PP_BIOS_FAILURE         Error occurred during sending command to TPM or \r
+                                      receiving response from TPM.\r
+  @retval Others                      Return code from the TPM device after command execution.\r
+\r
+**/\r
+TPM_RESULT\r
+TpmCommandNoReturnData (\r
+  IN      EFI_TCG_PROTOCOL          *TcgProtocol,\r
+  IN      TPM_COMMAND_CODE          Ordinal,\r
+  IN      UINTN                     AdditionalParameterSize,\r
+  IN      VOID                      *AdditionalParameters\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  TPM_RQU_COMMAND_HDR               *TpmRqu;\r
+  TPM_RSP_COMMAND_HDR               TpmRsp;\r
+  UINT32                            Size;\r
+\r
+  TpmRqu = (TPM_RQU_COMMAND_HDR*)AllocatePool (\r
+                                   sizeof (*TpmRqu) + AdditionalParameterSize\r
+                                   );\r
+  if (TpmRqu == NULL) {\r
+    return TPM_PP_BIOS_FAILURE;\r
+  }\r
+\r
+  TpmRqu->tag       = H2NS (TPM_TAG_RQU_COMMAND);\r
+  Size              = (UINT32)(sizeof (*TpmRqu) + AdditionalParameterSize);\r
+  TpmRqu->paramSize = H2NL (Size);\r
+  TpmRqu->ordinal   = H2NL (Ordinal);\r
+  gBS->CopyMem (TpmRqu + 1, AdditionalParameters, AdditionalParameterSize);\r
+\r
+  Status = TcgProtocol->PassThroughToTpm (\r
+                          TcgProtocol,\r
+                          Size,\r
+                          (UINT8*)TpmRqu,\r
+                          (UINT32)sizeof (TpmRsp),\r
+                          (UINT8*)&TpmRsp\r
+                          );\r
+  FreePool (TpmRqu);\r
+  if (EFI_ERROR (Status) || (TpmRsp.tag != H2NS (TPM_TAG_RSP_COMMAND))) {\r
+    return TPM_PP_BIOS_FAILURE;\r
+  }\r
+  return H2NL (TpmRsp.returnCode);\r
+}\r
+\r
+/**\r
+  Execute physical presence operation requested by the OS.\r
+\r
+  @param[in]      TcgProtocol         EFI TCG Protocol instance.  \r
+  @param[in]      CommandCode         Physical presence operation value.  \r
+  @param[in, out] PpiFlags            The physical presence interface flags. \r
+  \r
+  @retval TPM_PP_BIOS_FAILURE         Unknown physical presence operation.\r
+  @retval TPM_PP_BIOS_FAILURE         Error occurred during sending command to TPM or \r
+                                      receiving response from TPM.\r
+  @retval Others                      Return code from the TPM device after command execution.\r
+\r
+**/\r
+TPM_RESULT\r
+ExecutePhysicalPresence (\r
+  IN      EFI_TCG_PROTOCOL          *TcgProtocol,\r
+  IN      UINT8                     CommandCode,\r
+  IN OUT  UINT8                     *PpiFlags\r
+  )\r
+{\r
+  BOOLEAN                           BoolVal;\r
+  TPM_RESULT                        TpmResponse;\r
+  UINT32                            InData[5];\r
+\r
+  switch (CommandCode) {\r
+    case ENABLE:\r
+      return TpmCommandNoReturnData (\r
+               TcgProtocol,\r
+               TPM_ORD_PhysicalEnable,\r
+               0,\r
+               NULL\r
+               );\r
+\r
+    case DISABLE:\r
+      return TpmCommandNoReturnData (\r
+               TcgProtocol,\r
+               TPM_ORD_PhysicalDisable,\r
+               0,\r
+               NULL\r
+               );\r
+\r
+    case ACTIVATE:\r
+      BoolVal = FALSE;\r
+      return TpmCommandNoReturnData (\r
+               TcgProtocol,\r
+               TPM_ORD_PhysicalSetDeactivated,\r
+               sizeof (BoolVal),\r
+               &BoolVal\r
+               );\r
+\r
+    case DEACTIVATE:\r
+      BoolVal = TRUE;\r
+      return TpmCommandNoReturnData (\r
+               TcgProtocol,\r
+               TPM_ORD_PhysicalSetDeactivated,\r
+               sizeof (BoolVal),\r
+               &BoolVal\r
+               );\r
+\r
+    case CLEAR:\r
+      return TpmCommandNoReturnData (\r
+               TcgProtocol,\r
+               TPM_ORD_ForceClear,\r
+               0,\r
+               NULL\r
+               );\r
+\r
+    case ENABLE_ACTIVATE:\r
+      TpmResponse = ExecutePhysicalPresence (TcgProtocol, ENABLE, PpiFlags);\r
+      if (TpmResponse == 0) {\r
+        TpmResponse = ExecutePhysicalPresence (TcgProtocol, ACTIVATE, PpiFlags);\r
+      }\r
+      return TpmResponse;\r
+\r
+    case DEACTIVATE_DISABLE:\r
+      TpmResponse = ExecutePhysicalPresence (TcgProtocol, DEACTIVATE, PpiFlags);\r
+      if (TpmResponse == 0) {\r
+        TpmResponse = ExecutePhysicalPresence (TcgProtocol, DISABLE, PpiFlags);\r
+      }\r
+      return TpmResponse;\r
+\r
+    case SET_OWNER_INSTALL_TRUE:\r
+      BoolVal = TRUE;\r
+      return TpmCommandNoReturnData (\r
+               TcgProtocol,\r
+               TPM_ORD_SetOwnerInstall,\r
+               sizeof (BoolVal),\r
+               &BoolVal\r
+               );\r
+\r
+    case SET_OWNER_INSTALL_FALSE:\r
+      BoolVal = FALSE;\r
+      return TpmCommandNoReturnData (\r
+               TcgProtocol,\r
+               TPM_ORD_SetOwnerInstall,\r
+               sizeof (BoolVal),\r
+               &BoolVal\r
+               );\r
+\r
+    case ENABLE_ACTIVATE_OWNER_TRUE:\r
+      //\r
+      // ENABLE_ACTIVATE + SET_OWNER_INSTALL_TRUE\r
+      // SET_OWNER_INSTALL_TRUE will be executed atfer reboot\r
+      //\r
+      if ((*PpiFlags & FLAG_RESET_TRACK) == 0) {\r
+        TpmResponse = ExecutePhysicalPresence (TcgProtocol, ENABLE_ACTIVATE, PpiFlags);\r
+        *PpiFlags |= FLAG_RESET_TRACK;\r
+      } else {\r
+        TpmResponse = ExecutePhysicalPresence (TcgProtocol, SET_OWNER_INSTALL_TRUE, PpiFlags);\r
+        *PpiFlags &= ~FLAG_RESET_TRACK;\r
+      }\r
+      return TpmResponse;\r
+\r
+    case DEACTIVATE_DISABLE_OWNER_FALSE:\r
+      TpmResponse = ExecutePhysicalPresence (TcgProtocol, SET_OWNER_INSTALL_FALSE, PpiFlags);\r
+      if (TpmResponse == 0) {\r
+        TpmResponse = ExecutePhysicalPresence (TcgProtocol, DEACTIVATE_DISABLE, PpiFlags);\r
+      }\r
+      return TpmResponse;\r
+\r
+    case DEFERRED_PP_UNOWNERED_FIELD_UPGRADE:\r
+      InData[0] = H2NL (TPM_SET_STCLEAR_DATA);            // CapabilityArea\r
+      InData[1] = H2NL (sizeof(UINT32));                  // SubCapSize\r
+      InData[2] = H2NL (TPM_SD_DEFERREDPHYSICALPRESENCE); // SubCap\r
+      InData[3] = H2NL (sizeof(UINT32));                  // SetValueSize\r
+      InData[4] = H2NL (1);                               // UnownedFieldUpgrade; bit0\r
+      return TpmCommandNoReturnData (\r
+               TcgProtocol,\r
+               TPM_ORD_SetCapability,\r
+               sizeof (UINT32) * 5,\r
+               InData\r
+               );\r
+\r
+    case SET_OPERATOR_AUTH:\r
+      //\r
+      // TPM_SetOperatorAuth\r
+      // This command requires UI to prompt user for Auth data\r
+      // Here it is NOT implemented\r
+      //\r
+      return TPM_PP_BIOS_FAILURE;\r
+\r
+    case CLEAR_ENABLE_ACTIVATE:\r
+      TpmResponse = ExecutePhysicalPresence (TcgProtocol, CLEAR, PpiFlags);\r
+      if (TpmResponse == 0) {\r
+        TpmResponse = ExecutePhysicalPresence (TcgProtocol, ENABLE_ACTIVATE, PpiFlags);\r
+      }\r
+      return TpmResponse;\r
+\r
+    case SET_NO_PPI_PROVISION_FALSE:\r
+      *PpiFlags &= ~FLAG_NO_PPI_PROVISION;\r
+      return 0;\r
+\r
+    case SET_NO_PPI_PROVISION_TRUE:\r
+      *PpiFlags |= FLAG_NO_PPI_PROVISION;\r
+      return 0;\r
+\r
+    case SET_NO_PPI_CLEAR_FALSE:\r
+      *PpiFlags &= ~FLAG_NO_PPI_CLEAR;\r
+      return 0;\r
+\r
+    case SET_NO_PPI_CLEAR_TRUE:\r
+      *PpiFlags |= FLAG_NO_PPI_CLEAR;\r
+      return 0;\r
+\r
+    case SET_NO_PPI_MAINTENANCE_FALSE:\r
+      *PpiFlags &= ~FLAG_NO_PPI_MAINTENANCE;\r
+      return 0;\r
+\r
+    case SET_NO_PPI_MAINTENANCE_TRUE:\r
+      *PpiFlags |= FLAG_NO_PPI_MAINTENANCE;\r
+      return 0;\r
+  \r
+    case ENABLE_ACTIVATE_CLEAR:\r
+      TpmResponse = ExecutePhysicalPresence (TcgProtocol, ENABLE_ACTIVATE, PpiFlags);\r
+      if (TpmResponse == 0) {\r
+        TpmResponse = ExecutePhysicalPresence (TcgProtocol, CLEAR, PpiFlags);\r
+      }\r
+      return TpmResponse;\r
+\r
+    case ENABLE_ACTIVATE_CLEAR_ENABLE_ACTIVATE:\r
+      //\r
+      // ENABLE_ACTIVATE + CLEAR_ENABLE_ACTIVATE\r
+      // CLEAR_ENABLE_ACTIVATE will be executed atfer reboot.\r
+      //\r
+      if ((*PpiFlags & FLAG_RESET_TRACK) == 0) {\r
+        TpmResponse = ExecutePhysicalPresence (TcgProtocol, ENABLE_ACTIVATE, PpiFlags);\r
+        *PpiFlags |= FLAG_RESET_TRACK;\r
+      } else {\r
+        TpmResponse = ExecutePhysicalPresence (TcgProtocol, CLEAR_ENABLE_ACTIVATE, PpiFlags);\r
+        *PpiFlags &= ~FLAG_RESET_TRACK;\r
+      } \r
+      return TpmResponse;\r
+\r
+    default:\r
+      ;\r
+  }\r
+  return TPM_PP_BIOS_FAILURE;\r
+}\r
+\r
+\r
+/**\r
+  Read the specified key for user confirmation.\r
+\r
+  @param[in]  CautionKey  If true,  F12 is used as confirm key;\r
+                          If false, F10 is used as confirm key.\r
+\r
+  @retval     TRUE        User confirmed the changes by input.\r
+  @retval     FALSE       User discarded the changes.\r
+\r
+**/\r
+BOOLEAN\r
+ReadUserKey (\r
+  IN     BOOLEAN                    CautionKey\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  EFI_INPUT_KEY                     Key;\r
+  UINT16                            InputKey;\r
+  EFI_TPL                           OldTpl;\r
+\r
+  OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL); \r
+  gBS->RestoreTPL (TPL_APPLICATION);\r
+      \r
+  InputKey = 0; \r
+  do {\r
+    Status = gBS->CheckEvent (gST->ConIn->WaitForKey);\r
+    if (!EFI_ERROR (Status)) {\r
+      Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
+      if (Key.ScanCode == SCAN_ESC) {\r
+        InputKey = Key.ScanCode;\r
+      }\r
+      if ((Key.ScanCode == SCAN_F10) && !CautionKey) {\r
+        InputKey = Key.ScanCode;\r
+      }\r
+      if ((Key.ScanCode == SCAN_F12) && CautionKey) {\r
+        InputKey = Key.ScanCode;\r
+      }\r
+    }      \r
+  } while (InputKey == 0);\r
+\r
+  gBS->RaiseTPL (OldTpl); \r
+\r
+  if (InputKey != SCAN_ESC) {\r
+    return TRUE;\r
+  }\r
+  \r
+  return FALSE;\r
+}\r
+\r
+/**\r
+  Display the confirm text and get user confirmation.\r
+\r
+  @param[in] TpmPpCommand  The requested TPM physical presence command.\r
+\r
+  @retval  TRUE            The user has confirmed the changes.\r
+  @retval  FALSE           The user doesn't confirm the changes.\r
+**/\r
+BOOLEAN\r
+UserConfirm (\r
+  IN      UINT8                     TpmPpCommand\r
+  )\r
+{\r
+  CHAR16                            *ConfirmText;\r
+  CHAR16                            *TmpStr1;\r
+  CHAR16                            *TmpStr2; \r
+  UINTN                             BufSize;\r
+  BOOLEAN                           CautionKey;\r
+  UINT16                            Index;\r
+  CHAR16                            DstStr[81];\r
+    \r
+  TmpStr2     = NULL;\r
+  CautionKey  = FALSE;\r
+  BufSize     = CONFIRM_BUFFER_SIZE;\r
+  ConfirmText = AllocateZeroPool (BufSize);\r
+  ASSERT (ConfirmText != NULL);\r
+\r
+  mPpStringPackHandle = HiiAddPackages (\r
+                          &gEfiPhysicalPresenceGuid,\r
+                          NULL,\r
+                          PhysicalPresenceDxeStrings,\r
+                          NULL\r
+                          );\r
+  ASSERT (mPpStringPackHandle != NULL);\r
+\r
+  switch (TpmPpCommand) {\r
+    case ENABLE:\r
+      TmpStr2 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_ENABLE), NULL);\r
+      \r
+      TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_HEAD_STR), NULL);      \r
+      UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);\r
+      FreePool (TmpStr1);\r
+\r
+      TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_ACCEPT_KEY), NULL);\r
+      StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);\r
+      FreePool (TmpStr1);\r
+      break;\r
+\r
+    case DISABLE:\r
+      TmpStr2 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_DISABLE), NULL);\r
+      \r
+      TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_HEAD_STR), NULL);\r
+      UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);\r
+      FreePool (TmpStr1);\r
+\r
+      TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_WARNING), NULL);\r
+      StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);\r
+      FreePool (TmpStr1);\r
+\r
+      TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_ACCEPT_KEY), NULL);\r
+      StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);\r
+      FreePool (TmpStr1);\r
+      break;\r
+      \r
+    case ACTIVATE:\r
+      TmpStr2 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_ACTIVATE), NULL);\r
+      \r
+      TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_HEAD_STR), NULL);\r
+      UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);\r
+      FreePool (TmpStr1);\r
+\r
+      TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_ACCEPT_KEY), NULL);\r
+      StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);\r
+      FreePool (TmpStr1);\r
+      break;\r
+\r
+    case DEACTIVATE:\r
+      TmpStr2 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_DEACTIVATE), NULL);\r
+\r
+      TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_HEAD_STR), NULL);\r
+      UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);\r
+      FreePool (TmpStr1);\r
+\r
+      TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_WARNING), NULL);\r
+      StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);\r
+      FreePool (TmpStr1);\r
+\r
+      TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_ACCEPT_KEY), NULL);\r
+      StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);\r
+      FreePool (TmpStr1); \r
+      break;\r
+\r
+    case CLEAR:\r
+      CautionKey = TRUE;\r
+      TmpStr2 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_CLEAR), NULL);\r
+\r
+      TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_HEAD_STR), NULL);\r
+      UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);\r
+      FreePool (TmpStr1);\r
+\r
+      TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_WARNING_CLEAR), NULL);\r
+      StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);\r
+      StrnCat (ConfirmText, L" \n\n", (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);\r
+      FreePool (TmpStr1);      \r
+\r
+      TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_CAUTION_KEY), NULL);\r
+      StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);\r
+      FreePool (TmpStr1);\r
+      break;\r
+\r
+    case ENABLE_ACTIVATE:\r
+      TmpStr2 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_ENABLE_ACTIVATE), NULL);\r
+\r
+      TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_HEAD_STR), NULL);\r
+      UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);\r
+      FreePool (TmpStr1);\r
+\r
+      TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_NOTE_ON), NULL);\r
+      StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);\r
+      FreePool (TmpStr1);\r
+\r
+      TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_ACCEPT_KEY), NULL);\r
+      StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);\r
+      FreePool (TmpStr1);\r
+      break;\r
+\r
+    case DEACTIVATE_DISABLE:\r
+      TmpStr2 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_DEACTIVATE_DISABLE), NULL);\r
+      \r
+      TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_HEAD_STR), NULL);      \r
+      UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);\r
+      FreePool (TmpStr1);\r
+\r
+      TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_NOTE_OFF), NULL);\r
+      StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);\r
+      FreePool (TmpStr1);\r
+      \r
+      TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_WARNING), NULL);\r
+      StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);\r
+      FreePool (TmpStr1);\r
+\r
+      TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_ACCEPT_KEY), NULL);\r
+      StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);\r
+      FreePool (TmpStr1);\r
+      break;\r
+\r
+    case SET_OWNER_INSTALL_TRUE:\r
+      TmpStr2 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_ALLOW_TAKE_OWNERSHIP), NULL);\r
+      \r
+      TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_HEAD_STR), NULL);      \r
+      UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);\r
+      FreePool (TmpStr1);\r
+\r
+      TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_ACCEPT_KEY), NULL);\r
+      StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);\r
+      FreePool (TmpStr1);\r
+      break;\r
+\r
+    case SET_OWNER_INSTALL_FALSE:\r
+      TmpStr2 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_DISALLOW_TAKE_OWNERSHIP), NULL);\r
+      \r
+      TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_HEAD_STR), NULL);      \r
+      UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);\r
+      FreePool (TmpStr1);\r
+\r
+      TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_ACCEPT_KEY), NULL);\r
+      StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);\r
+      FreePool (TmpStr1);\r
+      break;\r
+\r
+    case ENABLE_ACTIVATE_OWNER_TRUE:\r
+      TmpStr2 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_TURN_ON), NULL);\r
+\r
+      TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_HEAD_STR), NULL);\r
+      UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);\r
+      FreePool (TmpStr1);\r
+\r
+      TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_NOTE_ON), NULL);\r
+      StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);\r
+      FreePool (TmpStr1);\r
+\r
+      TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_ACCEPT_KEY), NULL);\r
+      StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);\r
+      FreePool (TmpStr1);\r
+      break;\r
+\r
+    case DEACTIVATE_DISABLE_OWNER_FALSE:\r
+      TmpStr2 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_TURN_OFF), NULL);\r
+      \r
+      TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_HEAD_STR), NULL);      \r
+      UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);\r
+      FreePool (TmpStr1);\r
+\r
+      TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_NOTE_OFF), NULL);\r
+      StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);\r
+      FreePool (TmpStr1);\r
+      \r
+      TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_WARNING), NULL);\r
+      StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);\r
+      FreePool (TmpStr1);\r
+\r
+      TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_ACCEPT_KEY), NULL);\r
+      StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);\r
+      FreePool (TmpStr1);\r
+      break;\r
+\r
+    case DEFERRED_PP_UNOWNERED_FIELD_UPGRADE:\r
+      CautionKey = TRUE;\r
+      TmpStr2 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_UNOWNED_FIELD_UPGRADE), NULL);\r
+      \r
+      TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_UPGRADE_HEAD_STR), NULL);      \r
+      UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);\r
+      FreePool (TmpStr1);\r
+      \r
+      TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_WARNING_MAINTAIN), NULL);\r
+      StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);\r
+      FreePool (TmpStr1);\r
+\r
+      TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_CAUTION_KEY), NULL);\r
+      StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);\r
+      FreePool (TmpStr1);\r
+      break;\r
+\r
+    case SET_OPERATOR_AUTH:\r
+      //\r
+      // TPM_SetOperatorAuth\r
+      // This command requires UI to prompt user for Auth data\r
+      // Here it is NOT implemented\r
+      //\r
+      break;\r
+\r
+    case CLEAR_ENABLE_ACTIVATE:\r
+      CautionKey = TRUE;\r
+      TmpStr2 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_CLEAR_TURN_ON), NULL);\r
+\r
+      TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_HEAD_STR), NULL);\r
+      UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);\r
+      FreePool (TmpStr1);\r
+\r
+      TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_NOTE_ON), NULL);\r
+      StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);\r
+      FreePool (TmpStr1);\r
+\r
+      TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_WARNING_CLEAR), NULL);\r
+      StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);\r
+      FreePool (TmpStr1);\r
+\r
+      TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_WARNING_CLEAR_CONT), NULL);\r
+      StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);\r
+      FreePool (TmpStr1);\r
+\r
+      TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_CAUTION_KEY), NULL);\r
+      StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);\r
+      FreePool (TmpStr1);\r
+      break;\r
+\r
+    case SET_NO_PPI_PROVISION_TRUE:\r
+      TmpStr2 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_NO_PPI_PROVISION), NULL);\r
+\r
+      TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_PPI_HEAD_STR), NULL);\r
+      UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);\r
+      FreePool (TmpStr1);\r
+\r
+      TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_ACCEPT_KEY), NULL);\r
+      StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);\r
+      FreePool (TmpStr1);\r
+\r
+      TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_NO_PPI_INFO), NULL);\r
+      StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);\r
+      FreePool (TmpStr1);\r
+      break;\r
+\r
+    case SET_NO_PPI_CLEAR_TRUE:\r
+      CautionKey = TRUE;\r
+      TmpStr2 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_CLEAR), NULL);\r
+\r
+      TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_PPI_HEAD_STR), NULL);\r
+      UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);\r
+      FreePool (TmpStr1);\r
+\r
+      TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_NOTE_CLEAR), NULL);\r
+      StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);\r
+      FreePool (TmpStr1);\r
+\r
+      TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_WARNING_CLEAR), NULL);\r
+      StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);\r
+      StrnCat (ConfirmText, L" \n\n", (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);\r
+      FreePool (TmpStr1); \r
+\r
+      TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_CAUTION_KEY), NULL);\r
+      StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);\r
+      FreePool (TmpStr1);\r
+\r
+      TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_NO_PPI_INFO), NULL);\r
+      StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);\r
+      FreePool (TmpStr1);\r
+      break;\r
+\r
+    case SET_NO_PPI_MAINTENANCE_TRUE:\r
+      CautionKey = TRUE;\r
+      TmpStr2 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_NO_PPI_MAINTAIN), NULL);\r
+\r
+      TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_PPI_HEAD_STR), NULL);\r
+      UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);\r
+      FreePool (TmpStr1);\r
+\r
+      TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_WARNING_MAINTAIN), NULL);\r
+      StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);\r
+      FreePool (TmpStr1);\r
+\r
+      TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_CAUTION_KEY), NULL);\r
+      StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);\r
+      FreePool (TmpStr1);\r
+\r
+      TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_NO_PPI_INFO), NULL);\r
+      StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);\r
+      FreePool (TmpStr1);\r
+      break;\r
+\r
+    case ENABLE_ACTIVATE_CLEAR:\r
+      CautionKey = TRUE;\r
+      TmpStr2 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_ENABLE_ACTIVATE_CLEAR), NULL);\r
+\r
+      TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_HEAD_STR), NULL);\r
+      UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);\r
+      FreePool (TmpStr1);\r
+\r
+      TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_WARNING_CLEAR), NULL);\r
+      StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);\r
+      StrnCat (ConfirmText, L" \n\n", (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);\r
+      FreePool (TmpStr1);\r
+\r
+      TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_CAUTION_KEY), NULL);\r
+      StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);\r
+      FreePool (TmpStr1);\r
+      break;\r
+\r
+    case ENABLE_ACTIVATE_CLEAR_ENABLE_ACTIVATE:\r
+      CautionKey = TRUE;\r
+      TmpStr2 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_ENABLE_ACTIVATE_CLEAR_ENABLE_ACTIVATE), NULL);\r
+\r
+      TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_HEAD_STR), NULL);\r
+      UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);\r
+      FreePool (TmpStr1);\r
+\r
+      TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_NOTE_ON), NULL);\r
+      StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);\r
+      FreePool (TmpStr1);\r
+\r
+      TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_WARNING_CLEAR), NULL);\r
+      StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);\r
+      FreePool (TmpStr1);\r
+\r
+      TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_WARNING_CLEAR_CONT), NULL);\r
+      StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);\r
+      FreePool (TmpStr1);\r
+\r
+      TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_CAUTION_KEY), NULL);\r
+      StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);\r
+      FreePool (TmpStr1);\r
+      break;\r
+\r
+    default:\r
+      ;\r
+  }\r
+\r
+  if (TmpStr2 == NULL) {\r
+    FreePool (ConfirmText);\r
+    return FALSE;\r
+  }\r
+\r
+  TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_REJECT_KEY), NULL);\r
+  BufSize -= StrSize (ConfirmText);\r
+  UnicodeSPrint (ConfirmText + StrLen (ConfirmText), BufSize, TmpStr1, TmpStr2);\r
+\r
+  DstStr[80] = L'\0';\r
+  for (Index = 0; Index < StrLen (ConfirmText); Index += 80) {\r
+    StrnCpy(DstStr, ConfirmText + Index, 80);    \r
+    Print (DstStr);    \r
+  }\r
+  \r
+  FreePool (TmpStr1);\r
+  FreePool (TmpStr2);\r
+  FreePool (ConfirmText);\r
+\r
+  if (ReadUserKey (CautionKey)) {\r
+    return TRUE;\r
+  }\r
+\r
+  return FALSE;  \r
+}\r
+\r
+/**\r
+  Check and execute the requested physical presence command.\r
+  \r
+  @param[in, out] TcgPpData  Point to the physical presence NV variable.\r
+\r
+**/\r
+VOID\r
+ExecutePendingTpmRequest (\r
+  IN OUT  EFI_PHYSICAL_PRESENCE     *TcgPpData\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  EFI_TCG_PROTOCOL                  *TcgProtocol;\r
+  UINTN                             DataSize;\r
+  UINT8                             Flags;\r
+  BOOLEAN                           RequestConfirmed;\r
+\r
+  Flags            = TcgPpData->Flags;\r
+  RequestConfirmed = FALSE;  \r
+  switch (TcgPpData->PPRequest) {\r
+    case NO_ACTION:\r
+      return;\r
+    case ENABLE:\r
+    case DISABLE:\r
+    case ACTIVATE:\r
+    case DEACTIVATE:\r
+    case ENABLE_ACTIVATE:\r
+    case DEACTIVATE_DISABLE:\r
+    case SET_OWNER_INSTALL_TRUE:\r
+    case SET_OWNER_INSTALL_FALSE:\r
+    case ENABLE_ACTIVATE_OWNER_TRUE:\r
+    case DEACTIVATE_DISABLE_OWNER_FALSE:\r
+    case SET_OPERATOR_AUTH:\r
+      if ((Flags & FLAG_NO_PPI_PROVISION) != 0) {\r
+        RequestConfirmed = TRUE;\r
+      }\r
+      break;\r
+\r
+    case CLEAR:\r
+    case ENABLE_ACTIVATE_CLEAR:\r
+      if ((Flags & FLAG_NO_PPI_CLEAR) != 0) {\r
+        RequestConfirmed = TRUE;\r
+      }\r
+      break;\r
+\r
+    case DEFERRED_PP_UNOWNERED_FIELD_UPGRADE:\r
+      if ((Flags & FLAG_NO_PPI_MAINTENANCE) != 0) {\r
+        RequestConfirmed = TRUE;\r
+      }\r
+      break;\r
+\r
+    case CLEAR_ENABLE_ACTIVATE:\r
+    case ENABLE_ACTIVATE_CLEAR_ENABLE_ACTIVATE:\r
+      if ((Flags & FLAG_NO_PPI_CLEAR) != 0 && (Flags & FLAG_NO_PPI_PROVISION) != 0) {\r
+        RequestConfirmed = TRUE;\r
+      }\r
+      break;  \r
+\r
+    case SET_NO_PPI_PROVISION_FALSE:\r
+    case SET_NO_PPI_CLEAR_FALSE:\r
+    case SET_NO_PPI_MAINTENANCE_FALSE:\r
+      RequestConfirmed = TRUE;\r
+      break;\r
+  }\r
+\r
+  if ((Flags & FLAG_RESET_TRACK) != 0) {\r
+    //\r
+    // It had been confirmed in last boot, it doesn't need confirm again.\r
+    //\r
+    RequestConfirmed = TRUE;\r
+  }\r
+\r
+  if (!RequestConfirmed) {\r
+    //\r
+    // Print confirm text and wait for approval. \r
+    //\r
+    RequestConfirmed = UserConfirm (TcgPpData->PPRequest);\r
+  }\r
+\r
+  //\r
+  // Execute requested physical presence command.\r
+  //\r
+  TcgPpData->PPResponse = TPM_PP_USER_ABORT;\r
+  if (RequestConfirmed) {\r
+    Status = gBS->LocateProtocol (&gEfiTcgProtocolGuid, NULL, (VOID**) &TcgProtocol);\r
+    ASSERT_EFI_ERROR (Status);\r
+    TcgPpData->PPResponse = ExecutePhysicalPresence (TcgProtocol, TcgPpData->PPRequest, &TcgPpData->Flags);\r
+  }\r
+\r
+  //\r
+  // Clear request\r
+  //\r
+  if ((TcgPpData->Flags & FLAG_RESET_TRACK) == 0) {\r
+    TcgPpData->LastPPRequest = TcgPpData->PPRequest;\r
+    TcgPpData->PPRequest = 0;    \r
+  }\r
+\r
+  //\r
+  // Save changes\r
+  //\r
+  DataSize = sizeof (EFI_PHYSICAL_PRESENCE);\r
+  Status = gRT->SetVariable (\r
+                  PHYSICAL_PRESENCE_VARIABLE,\r
+                  &gEfiPhysicalPresenceGuid,\r
+                  EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
+                  DataSize,\r
+                  TcgPpData\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return;\r
+  }\r
+\r
+  if (TcgPpData->PPResponse == TPM_PP_USER_ABORT) {\r
+    return;\r
+  }\r
+\r
+  //\r
+  // Reset system to make new TPM settings in effect\r
+  //\r
+  switch (TcgPpData->LastPPRequest) {\r
+    case ACTIVATE:\r
+    case DEACTIVATE:\r
+    case CLEAR:\r
+    case ENABLE_ACTIVATE:\r
+    case DEACTIVATE_DISABLE:\r
+    case ENABLE_ACTIVATE_OWNER_TRUE:\r
+    case DEACTIVATE_DISABLE_OWNER_FALSE:\r
+    case DEFERRED_PP_UNOWNERED_FIELD_UPGRADE:\r
+    case CLEAR_ENABLE_ACTIVATE:\r
+    case ENABLE_ACTIVATE_CLEAR:\r
+    case ENABLE_ACTIVATE_CLEAR_ENABLE_ACTIVATE:      \r
+      break;\r
+    default:\r
+      if (TcgPpData->PPRequest != 0) {\r
+        break;\r
+      }\r
+      return;\r
+  }\r
+\r
+  Print (L"Rebooting system to make TPM settings in effect\n");\r
+  gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);\r
+  ASSERT (FALSE);  \r
+}\r
+\r
+/**\r
+  Check and execute the physical presence command requested and\r
+  Lock physical presence.\r
+\r
+  @param[in]  Event        Event whose notification function is being invoked\r
+  @param[in]  Context      Pointer to the notification function's context\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+OnReadyToBoot (\r
+  IN EFI_EVENT  Event,\r
+  IN VOID       *Context\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  BOOLEAN                           LifetimeLock;\r
+  BOOLEAN                           CmdEnable;\r
+  UINTN                             DataSize;\r
+  EFI_PHYSICAL_PRESENCE             TcgPpData;\r
+  \r
+  //\r
+  // Check pending request, if not exist, just return.\r
+  //\r
+  DataSize = sizeof (EFI_PHYSICAL_PRESENCE);\r
+  Status = gRT->GetVariable (\r
+                  PHYSICAL_PRESENCE_VARIABLE,\r
+                  &gEfiPhysicalPresenceGuid,\r
+                  NULL,\r
+                  &DataSize,\r
+                  &TcgPpData\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+  DEBUG ((EFI_D_INFO, "[TPM] Flags=%x, PPRequest=%x\n", TcgPpData.Flags, TcgPpData.PPRequest));\r
\r
+  Status = GetTpmCapability (&LifetimeLock, &CmdEnable);\r
+  if (EFI_ERROR (Status)) {\r
+    return ;\r
+  }\r
+\r
+  if (!CmdEnable) {\r
+    if (LifetimeLock) {\r
+      //\r
+      // physicalPresenceCMDEnable is locked, can't execute physical presence command.\r
+      //\r
+      return ;\r
+    }\r
+    Status = TpmPhysicalPresence (TPM_PHYSICAL_PRESENCE_CMD_ENABLE);\r
+    if (EFI_ERROR (Status)) {\r
+      return ;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Set operator physical presence flags\r
+  //\r
+  TpmPhysicalPresence (TPM_PHYSICAL_PRESENCE_PRESENT);\r
+  \r
+  //\r
+  // Execute pending TPM request.\r
+  //  \r
+  ExecutePendingTpmRequest (&TcgPpData);\r
+  DEBUG ((EFI_D_INFO, "[TPM] PPResponse = %x\n", TcgPpData.PPResponse));\r
+\r
+  //\r
+  // Lock physical presence.\r
+  //\r
+  TpmPhysicalPresence (TPM_PHYSICAL_PRESENCE_NOTPRESENT | TPM_PHYSICAL_PRESENCE_LOCK);\r
+}\r
+\r
+/**\r
+  The driver's entry point.\r
+\r
+  @param[in] ImageHandle  The firmware allocated handle for the EFI image.  \r
+  @param[in] SystemTable  A pointer to the EFI System Table.\r
+  \r
+  @retval EFI_SUCCESS     The entry point is executed successfully.\r
+  @retval other           Some error occurs when executing this entry point.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DriverEntry (\r
+  IN      EFI_HANDLE                ImageHandle,\r
+  IN      EFI_SYSTEM_TABLE          *SystemTable\r
+  )\r
+{\r
+  EFI_EVENT                         Event;\r
+  EFI_STATUS                        Status;\r
+  UINTN                             DataSize;\r
+  EFI_PHYSICAL_PRESENCE             TcgPpData;\r
+  \r
+  //\r
+  // Initialize physical presence variable exists.\r
+  //\r
+  DataSize = sizeof (EFI_PHYSICAL_PRESENCE);\r
+  Status = gRT->GetVariable (\r
+                  PHYSICAL_PRESENCE_VARIABLE,\r
+                  &gEfiPhysicalPresenceGuid,\r
+                  NULL,\r
+                  &DataSize,\r
+                  &TcgPpData\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    if (Status == EFI_NOT_FOUND) {\r
+      ZeroMem ((VOID*)&TcgPpData, sizeof (TcgPpData));\r
+      TcgPpData.Flags |= FLAG_NO_PPI_PROVISION;\r
+      DataSize = sizeof (EFI_PHYSICAL_PRESENCE);\r
+      Status   = gRT->SetVariable (\r
+                        PHYSICAL_PRESENCE_VARIABLE,\r
+                        &gEfiPhysicalPresenceGuid,\r
+                        EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
+                        DataSize,\r
+                        &TcgPpData\r
+                        );\r
+    }\r
+    ASSERT_EFI_ERROR (Status);\r
+  }\r
+\r
+  //\r
+  // TPL Level of physical presence should be larger \r
+  // than one of TcgDxe driver (TPL_CALLBACK)\r
+  //\r
+  Status = EfiCreateEventReadyToBootEx (\r
+             TPL_CALLBACK,\r
+             OnReadyToBoot,\r
+             NULL,\r
+             &Event\r
+             );\r
+  return Status;\r
+}\r
+\r
diff --git a/SecurityPkg/Tcg/PhysicalPresenceDxe/PhysicalPresence.h b/SecurityPkg/Tcg/PhysicalPresenceDxe/PhysicalPresence.h
new file mode 100644 (file)
index 0000000..63d6f21
--- /dev/null
@@ -0,0 +1,38 @@
+/** @file\r
+  The header file for TPM physical presence driver.\r
+\r
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef __PHYSICAL_PRESENCE_H__\r
+#define __PHYSICAL_PRESENCE_H__\r
+\r
+#include <PiDxe.h>\r
+\r
+#include <Protocol/TcgService.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/UefiRuntimeServicesTableLib.h>\r
+#include <Library/UefiDriverEntryPoint.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/PrintLib.h>\r
+#include <Library/HiiLib.h>\r
+#include <Guid/EventGroup.h>\r
+#include <Guid/PhysicalPresenceData.h>\r
+\r
+#define TPM_PP_USER_ABORT           ((TPM_RESULT)(-0x10))\r
+#define TPM_PP_BIOS_FAILURE         ((TPM_RESULT)(-0x0f))\r
+\r
+#define CONFIRM_BUFFER_SIZE                    4096\r
+\r
+#endif\r
diff --git a/SecurityPkg/Tcg/PhysicalPresenceDxe/PhysicalPresenceDxe.inf b/SecurityPkg/Tcg/PhysicalPresenceDxe/PhysicalPresenceDxe.inf
new file mode 100644 (file)
index 0000000..9b4aded
--- /dev/null
@@ -0,0 +1,61 @@
+## @file\r
+#  Component file for PhysicalPresenceDxe driver.\r
+#\r
+# Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = PhysicalPresenceDxe\r
+  FILE_GUID                      = D85A4A0C-2E73-4491-92E1-DCEFC3882A68\r
+  MODULE_TYPE                    = DXE_DRIVER\r
+  VERSION_STRING                 = 1.0\r
+\r
+  ENTRY_POINT                    = DriverEntry\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64 IPF\r
+#\r
+\r
+[Sources]\r
+  PhysicalPresence.c\r
+  PhysicalPresence.h\r
+  PhysicalPresenceStrings.uni\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+  SecurityPkg/SecurityPkg.dec\r
+\r
+[LibraryClasses]\r
+  MemoryAllocationLib\r
+  UefiLib\r
+  UefiBootServicesTableLib\r
+  UefiDriverEntryPoint\r
+  UefiRuntimeServicesTableLib\r
+  BaseMemoryLib\r
+  DebugLib\r
+  PrintLib\r
+  HiiLib\r
+\r
+[Protocols]\r
+  gEfiTcgProtocolGuid\r
+\r
+[Guids]\r
+  gEfiPhysicalPresenceGuid\r
+\r
+[Depex]\r
+  gEfiTcgProtocolGuid                  AND\r
+  gEfiVariableArchProtocolGuid         AND\r
+  gEfiVariableWriteArchProtocolGuid    AND\r
+  gEfiResetArchProtocolGuid\r
+\r
diff --git a/SecurityPkg/Tcg/PhysicalPresenceDxe/PhysicalPresenceStrings.uni b/SecurityPkg/Tcg/PhysicalPresenceDxe/PhysicalPresenceStrings.uni
new file mode 100644 (file)
index 0000000..2034af7
Binary files /dev/null and b/SecurityPkg/Tcg/PhysicalPresenceDxe/PhysicalPresenceStrings.uni differ
diff --git a/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePei.c b/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePei.c
new file mode 100644 (file)
index 0000000..e694db8
--- /dev/null
@@ -0,0 +1,134 @@
+/** @file\r
+  This driver produces PEI_LOCK_PHYSICAL_PRESENCE_PPI to indicate \r
+  whether TPM need be locked or not. It can be replaced by a platform \r
+  specific driver.\r
+\r
+Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include <PiPei.h>\r
+#include <Ppi/LockPhysicalPresence.h>\r
+#include <Ppi/ReadOnlyVariable2.h>\r
+#include <Guid/PhysicalPresenceData.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/PeiServicesLib.h>\r
+\r
+/**\r
+  This interface returns whether TPM physical presence needs be locked or not.\r
+\r
+  @param[in]  PeiServices       The pointer to the PEI Services Table.\r
+\r
+  @retval     TRUE              The TPM physical presence should be locked.\r
+  @retval     FALSE             The TPM physical presence cannot be locked.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+LockTpmPhysicalPresence (\r
+  IN CONST  EFI_PEI_SERVICES             **PeiServices\r
+  );\r
+\r
+//\r
+// Gobal defintions for lock physical presence PPI and its descriptor.\r
+//\r
+PEI_LOCK_PHYSICAL_PRESENCE_PPI    mLockPhysicalPresencePpi = {\r
+  LockTpmPhysicalPresence\r
+};\r
+\r
+EFI_PEI_PPI_DESCRIPTOR       mLockPhysicalPresencePpiList = {\r
+  EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,\r
+  &gPeiLockPhysicalPresencePpiGuid,\r
+  &mLockPhysicalPresencePpi\r
+};\r
+\r
+/**\r
+  This interface returns whether TPM physical presence needs be locked or not.\r
+\r
+  @param[in]  PeiServices       The pointer to the PEI Services Table.\r
+\r
+  @retval     TRUE              The TPM physical presence should be locked.\r
+  @retval     FALSE             The TPM physical presence cannot be locked.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+LockTpmPhysicalPresence (\r
+  IN CONST  EFI_PEI_SERVICES             **PeiServices\r
+  )\r
+{\r
+  EFI_STATUS                         Status;\r
+  EFI_PEI_READ_ONLY_VARIABLE2_PPI    *Variable;\r
+  UINTN                              DataSize;\r
+  EFI_PHYSICAL_PRESENCE              TcgPpData;\r
+\r
+  //\r
+  // The CRTM has sensed the physical presence assertion of the user. For example, \r
+  // the user has pressed the startup button or inserted a USB dongle. The details \r
+  // of the implementation are vendor-specific. Here we read a PCD value to indicate\r
+  // whether operator physical presence.\r
+  // \r
+  if (!PcdGetBool (PcdTpmPhysicalPresence)) {\r
+    return TRUE;\r
+  }\r
+\r
+  //\r
+  // Check the pending TPM requests. Lock TPM physical presence if there is no TPM \r
+  // request.  \r
+  //\r
+  Status = PeiServicesLocatePpi (\r
+             &gEfiPeiReadOnlyVariable2PpiGuid,\r
+             0,\r
+             NULL,\r
+             (VOID **)&Variable\r
+             );\r
+  if (!EFI_ERROR (Status)) {\r
+    DataSize = sizeof (EFI_PHYSICAL_PRESENCE);\r
+    Status = Variable->GetVariable ( \r
+                         Variable, \r
+                         PHYSICAL_PRESENCE_VARIABLE,\r
+                         &gEfiPhysicalPresenceGuid,\r
+                         NULL,\r
+                         &DataSize,\r
+                         &TcgPpData\r
+                         );\r
+    if (!EFI_ERROR (Status)) {\r
+      if (TcgPpData.PPRequest != 0) {\r
+        return FALSE;\r
+      }\r
+    }\r
+  }\r
+\r
+  //\r
+  // Lock TPM physical presence by default.\r
+  //\r
+  return TRUE;\r
+}\r
+\r
+/**\r
+  Entry point of this module.\r
+\r
+  It installs lock physical presence PPI. \r
+\r
+  @param[in] FileHandle   Handle of the file being invoked.\r
+  @param[in] PeiServices  Describes the list of possible PEI Services.\r
+\r
+  @return                 Status of install lock physical presence PPI.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PeimEntry (\r
+  IN       EFI_PEI_FILE_HANDLE       FileHandle,\r
+  IN CONST EFI_PEI_SERVICES          **PeiServices\r
+  )\r
+{\r
+  return PeiServicesInstallPpi (&mLockPhysicalPresencePpiList);\r
+}\r
diff --git a/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePei.inf b/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePei.inf
new file mode 100644 (file)
index 0000000..da4e032
--- /dev/null
@@ -0,0 +1,55 @@
+## @file\r
+#  Component description file for physical presence PEI module.\r
+#\r
+# Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved.<BR>\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = PhysicalPresencePei\r
+  FILE_GUID                      = 4FE772E8-FE3E-4086-B638-8C493C490488\r
+  MODULE_TYPE                    = PEIM\r
+  VERSION_STRING                 = 1.0\r
+\r
+  ENTRY_POINT                    = PeimEntry\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64 IPF\r
+#\r
+\r
+[Sources]\r
+  PhysicalPresencePei.c\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+  SecurityPkg/SecurityPkg.dec\r
+\r
+[LibraryClasses]\r
+  PeimEntryPoint\r
+  PeiServicesLib\r
+\r
+[Ppis]\r
+  gPeiLockPhysicalPresencePpiGuid\r
+  gEfiPeiReadOnlyVariable2PpiGuid\r
+\r
+[Guids]\r
+  gEfiPhysicalPresenceGuid\r
+\r
+[Pcd]\r
+  gEfiSecurityPkgTokenSpaceGuid.PcdTpmPhysicalPresence\r
+\r
+[Depex] \r
+  gEfiPeiMemoryDiscoveredPpiGuid AND\r
+  gEfiPeiReadOnlyVariable2PpiGuid AND\r
+  gPeiTpmInitializedPpiGuid\r
diff --git a/SecurityPkg/Tcg/TcgConfigDxe/TcgConfig.vfr b/SecurityPkg/Tcg/TcgConfigDxe/TcgConfig.vfr
new file mode 100644 (file)
index 0000000..360e556
--- /dev/null
@@ -0,0 +1,114 @@
+/** @file\r
+  VFR file used by the TCG configuration component.\r
+\r
+Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "TcgConfigNvData.h"\r
+\r
+formset\r
+  guid      = TCG_CONFIG_PRIVATE_GUID,\r
+  title     = STRING_TOKEN(STR_TPM_TITLE),\r
+  help      = STRING_TOKEN(STR_TPM_HELP),\r
+  classguid = EFI_HII_PLATFORM_SETUP_FORMSET_GUID,\r
+\r
+  varstore TCG_CONFIGURATION,\r
+    varid = TCG_CONFIGURATION_VARSTORE_ID,\r
+    name  = TCG_CONFIGURATION,\r
+    guid  = TCG_CONFIG_PRIVATE_GUID;\r
+\r
+  form formid = TCG_CONFIGURATION_FORM_ID,\r
+    title = STRING_TOKEN(STR_TPM_TITLE);\r
+\r
+    subtitle text = STRING_TOKEN(STR_NULL);\r
+\r
+    suppressif TRUE;\r
+      checkbox varid   = TCG_CONFIGURATION.TpmEnable,\r
+              prompt   = STRING_TOKEN(STR_NULL),\r
+              help     = STRING_TOKEN(STR_NULL),\r
+      endcheckbox;\r
+    endif;\r
+\r
+    suppressif TRUE;\r
+      checkbox varid   = TCG_CONFIGURATION.TpmActivate,\r
+              prompt   = STRING_TOKEN(STR_NULL),\r
+              help     = STRING_TOKEN(STR_NULL),\r
+      endcheckbox;\r
+    endif;\r
+\r
+    suppressif TRUE;\r
+      checkbox varid   = TCG_CONFIGURATION.OriginalHideTpm,\r
+              prompt   = STRING_TOKEN(STR_NULL),\r
+              help     = STRING_TOKEN(STR_NULL),\r
+      endcheckbox;\r
+    endif;\r
+\r
+    text\r
+      help   = STRING_TOKEN(STR_TPM_STATE_HELP),\r
+      text   = STRING_TOKEN(STR_TPM_STATE_PROMPT),\r
+        text   = STRING_TOKEN(STR_TPM_STATE_CONTENT);\r
+\r
+    subtitle text = STRING_TOKEN(STR_NULL);\r
+\r
+    label LABEL_TCG_CONFIGURATION_HIDETPM;\r
+\r
+    checkbox varid = TCG_CONFIGURATION.HideTpm,\r
+          questionid  = KEY_HIDE_TPM,\r
+          prompt      = STRING_TOKEN(STR_HIDE_TPM_PROMPT),\r
+          help        = STRING_TOKEN(STR_HIDE_TPM_HELP),\r
+          flags       = RESET_REQUIRED,\r
+    endcheckbox;\r
+\r
+    label LABEL_END;\r
+\r
+    grayoutif ideqval TCG_CONFIGURATION.OriginalHideTpm == 1;\r
+    oneof varid  = TCG_CONFIGURATION.TpmOperation,\r
+          questionid = KEY_TPM_ACTION,\r
+          prompt = STRING_TOKEN(STR_TPM_OPERATION),\r
+          help   = STRING_TOKEN(STR_TPM_OPERATION_HELP),\r
+          flags  = INTERACTIVE,\r
+          //\r
+          // Disable (TPM_ORD_PhysicalDisable) command is not available when disabled.\r
+          // Activate/deactivate (TPM_ORD_physicalSetDeactivated) command is not available when disabled.\r
+          //\r
+          suppressif ideqval TCG_CONFIGURATION.TpmEnable == 0;\r
+            option text = STRING_TOKEN(STR_DISABLE), value = DISABLE, flags = 0;\r
+            option text = STRING_TOKEN(STR_TPM_ACTIVATE), value = ACTIVATE, flags = 0;\r
+            option text = STRING_TOKEN(STR_TPM_DEACTIVATE), value = DEACTIVATE, flags = 0;\r
+            option text = STRING_TOKEN(STR_TPM_DEACTIVATE_DISABLE), value = DEACTIVATE_DISABLE, flags = 0;\r
+          endif\r
+          //\r
+          // Clear (TPM_ORD_ForceClear) command is not available when disabled or deactivated. \r
+          //\r
+          suppressif ideqval TCG_CONFIGURATION.TpmEnable == 0 OR\r
+                     ideqval TCG_CONFIGURATION.TpmActivate == 0;\r
+            option text = STRING_TOKEN(STR_TPM_CLEAR), value = CLEAR, flags = 0;\r
+            option text = STRING_TOKEN(STR_TPM_CLEAR_ENABLE_ACTIVATE), value = CLEAR_ENABLE_ACTIVATE, flags = 0;\r
+          endif\r
+\r
+          option text = STRING_TOKEN(STR_ENABLE), value = ENABLE, flags = 0;\r
+          option text = STRING_TOKEN(STR_TPM_ENABLE_ACTIVATE), value = ENABLE_ACTIVATE, flags = 0;          \r
+          option text = STRING_TOKEN(STR_TPM_ENABLE_ACTIVATE_CLEAR), value = ENABLE_ACTIVATE_CLEAR, flags = 0;\r
+          option text = STRING_TOKEN(STR_TPM_ENABLE_ACTIVATE_CLEAR_E_A), value = ENABLE_ACTIVATE_CLEAR_ENABLE_ACTIVATE, flags = 0;\r
+    endoneof;\r
+\r
+    subtitle text = STRING_TOKEN(STR_NULL);\r
+\r
+    checkbox varid = TCG_CONFIGURATION.MorState,\r
+          questionid = KEY_TPM_MOR_ENABLE,\r
+          prompt = STRING_TOKEN(STR_MOR_PROMPT),\r
+          help   = STRING_TOKEN(STR_MOR_HELP),\r
+    endcheckbox; \r
+    endif;\r
+\r
+  endform;\r
+\r
+endformset;\r
diff --git a/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDriver.c b/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDriver.c
new file mode 100644 (file)
index 0000000..4b2008f
--- /dev/null
@@ -0,0 +1,147 @@
+/** @file\r
+  The module entry point for Tcg configuration module.\r
+\r
+Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "TcgConfigImpl.h"\r
+\r
+EFI_GUID gTcgConfigPrivateGuid = TCG_CONFIG_PRIVATE_GUID;\r
+\r
+/**\r
+  The entry point for Tcg configuration driver.\r
+\r
+  @param[in]  ImageHandle        The image handle of the driver.\r
+  @param[in]  SystemTable        The system table.\r
+\r
+  @retval EFI_ALREADY_STARTED    The driver already exists in system.\r
+  @retval EFI_OUT_OF_RESOURCES   Fail to execute entry point due to lack of resources.\r
+  @retval EFI_SUCCES             All the related protocols are installed on the driver.\r
+  @retval Others                 Fail to install protocols as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TcgConfigDriverEntryPoint (\r
+  IN EFI_HANDLE          ImageHandle,\r
+  IN EFI_SYSTEM_TABLE    *SystemTable\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  TCG_CONFIG_PRIVATE_DATA   *PrivateData;\r
+  EFI_TCG_PROTOCOL          *TcgProtocol;\r
+\r
+  Status = TisPcRequestUseTpm ((TIS_TPM_HANDLE) (UINTN) TPM_BASE_ADDRESS);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "TPM not detected!\n"));\r
+    return Status;\r
+  }\r
+\r
+  Status = gBS->LocateProtocol (&gEfiTcgProtocolGuid, NULL, (VOID **) &TcgProtocol);\r
+  if (EFI_ERROR (Status)) {\r
+    TcgProtocol = NULL;\r
+  }\r
+  \r
+  Status = gBS->OpenProtocol (\r
+                  ImageHandle,\r
+                  &gTcgConfigPrivateGuid,\r
+                  NULL,\r
+                  ImageHandle,\r
+                  ImageHandle,\r
+                  EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
+                  );\r
+  if (!EFI_ERROR (Status)) {\r
+    return EFI_ALREADY_STARTED;\r
+  }\r
+  \r
+  //\r
+  // Create a private data structure.\r
+  //\r
+  PrivateData = AllocateCopyPool (sizeof (TCG_CONFIG_PRIVATE_DATA), &mTcgConfigPrivateDateTemplate);\r
+  if (PrivateData == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  \r
+  PrivateData->TcgProtocol = TcgProtocol;\r
+  PrivateData->HideTpm     = PcdGetBool (PcdHideTpmSupport) && PcdGetBool (PcdHideTpm);\r
+  \r
+  //\r
+  // Install TCG configuration form\r
+  //\r
+  Status = InstallTcgConfigForm (PrivateData);\r
+  if (EFI_ERROR (Status)) {\r
+    goto ErrorExit;\r
+  }\r
+\r
+  //\r
+  // Install private GUID.\r
+  //    \r
+  Status = gBS->InstallMultipleProtocolInterfaces (\r
+                  &ImageHandle,\r
+                  &gTcgConfigPrivateGuid,\r
+                  PrivateData,\r
+                  NULL\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    goto ErrorExit;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+\r
+ErrorExit:\r
+  if (PrivateData != NULL) {\r
+    UninstallTcgConfigForm (PrivateData);\r
+  }  \r
+  \r
+  return Status;\r
+}\r
+\r
+/**\r
+  Unload the Tcg configuration form.\r
+\r
+  @param[in]  ImageHandle         The driver's image handle.\r
+\r
+  @retval     EFI_SUCCESS         The Tcg configuration form is unloaded.\r
+  @retval     Others              Failed to unload the form.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TcgConfigDriverUnload (\r
+  IN EFI_HANDLE  ImageHandle\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  TCG_CONFIG_PRIVATE_DATA   *PrivateData;\r
+\r
+  Status = gBS->HandleProtocol (\r
+                  ImageHandle,\r
+                  &gTcgConfigPrivateGuid,\r
+                  (VOID **) &PrivateData\r
+                  );  \r
+  if (EFI_ERROR (Status)) {\r
+    return Status;  \r
+  }\r
+  \r
+  ASSERT (PrivateData->Signature == TCG_CONFIG_PRIVATE_DATA_SIGNATURE);\r
+\r
+  gBS->UninstallMultipleProtocolInterfaces (\r
+         &ImageHandle,\r
+         &gTcgConfigPrivateGuid,\r
+         PrivateData,\r
+         NULL\r
+         );\r
+  \r
+  UninstallTcgConfigForm (PrivateData);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
diff --git a/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDxe.inf b/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDxe.inf
new file mode 100644 (file)
index 0000000..d9d3102
--- /dev/null
@@ -0,0 +1,75 @@
+## @file\r
+#  Component name for Tcg configuration module.\r
+#\r
+# Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = TcgConfigDxe\r
+  FILE_GUID                      = 1FA4DAFE-FA5D-4d75-BEA6-5863862C520A\r
+  MODULE_TYPE                    = DXE_DRIVER\r
+  VERSION_STRING                 = 1.0\r
+  ENTRY_POINT                    = TcgConfigDriverEntryPoint\r
+  UNLOAD_IMAGE                   = TcgConfigDriverUnload\r
+\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC\r
+#\r
+\r
+[Sources]\r
+  TcgConfigDriver.c\r
+  TcgConfigImpl.c\r
+  TcgConfigImpl.h\r
+  TcgConfig.vfr\r
+  TcgConfigStrings.uni\r
+  TcgConfigNvData.h\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+  SecurityPkg/SecurityPkg.dec\r
+\r
+[LibraryClasses]\r
+  BaseLib\r
+  BaseMemoryLib\r
+  MemoryAllocationLib\r
+  UefiLib\r
+  UefiBootServicesTableLib\r
+  UefiRuntimeServicesTableLib\r
+  UefiDriverEntryPoint\r
+  UefiHiiServicesLib\r
+  DebugLib\r
+  HiiLib\r
+  PcdLib\r
+  PrintLib\r
+  TpmCommLib\r
+\r
+[Guids]\r
+  gEfiPhysicalPresenceGuid\r
+  gEfiIfrTianoGuid\r
+\r
+[Protocols]\r
+  gEfiHiiConfigAccessProtocolGuid               ## PRODUCES\r
+  gEfiHiiConfigRoutingProtocolGuid              ## CONSUMES\r
+  gEfiTcgProtocolGuid                           ## CONSUMES\r
+\r
+[FixedPcd]\r
+  gEfiSecurityPkgTokenSpaceGuid.PcdHideTpmSupport\r
+\r
+[Pcd]\r
+  gEfiSecurityPkgTokenSpaceGuid.PcdMorEnable\r
+  gEfiSecurityPkgTokenSpaceGuid.PcdHideTpm\r
+\r
+[Depex]\r
+  gEfiHiiConfigRoutingProtocolGuid  AND\r
+  gEfiHiiDatabaseProtocolGuid       AND\r
+  gEfiVariableArchProtocolGuid      AND\r
+  gEfiVariableWriteArchProtocolGuid
\ No newline at end of file
diff --git a/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigImpl.c b/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigImpl.c
new file mode 100644 (file)
index 0000000..535f5e8
--- /dev/null
@@ -0,0 +1,555 @@
+/** @file\r
+  HII Config Access protocol implementation of TCG configuration module.\r
+\r
+Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "TcgConfigImpl.h"\r
+\r
+EFI_GUID                        mTcgFormSetGuid = TCG_CONFIG_PRIVATE_GUID;\r
+CHAR16                          mTcgStorageName[] = L"TCG_CONFIGURATION";\r
+\r
+TCG_CONFIG_PRIVATE_DATA         mTcgConfigPrivateDateTemplate = {\r
+  TCG_CONFIG_PRIVATE_DATA_SIGNATURE,\r
+  {\r
+    TcgExtractConfig,\r
+    TcgRouteConfig,\r
+    TcgCallback\r
+  }\r
+};\r
+\r
+HII_VENDOR_DEVICE_PATH          mTcgHiiVendorDevicePath = {\r
+  {\r
+    {\r
+      HARDWARE_DEVICE_PATH,\r
+      HW_VENDOR_DP,\r
+      {\r
+        (UINT8) (sizeof (VENDOR_DEVICE_PATH)),\r
+        (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)\r
+      }\r
+    },\r
+    TCG_CONFIG_PRIVATE_GUID\r
+  },\r
+  {\r
+    END_DEVICE_PATH_TYPE,\r
+    END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
+    { \r
+      (UINT8) (END_DEVICE_PATH_LENGTH),\r
+      (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)\r
+    }\r
+  }\r
+};\r
+\r
+/**\r
+  Get current state of TPM device.\r
+\r
+  @param[in]   TcgProtocol          Point to EFI_TCG_PROTOCOL instance.\r
+  @param[out]  TpmEnable            Flag to indicate TPM is enabled or not.\r
+  @param[out]  TpmActivate          Flag to indicate TPM is activated or not.\r
+\r
+  @retval EFI_SUCCESS               State is successfully returned.\r
+  @retval EFI_DEVICE_ERROR          Failed to get TPM response.\r
+  @retval Others                    Other errors as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+GetTpmState (\r
+  IN  EFI_TCG_PROTOCOL          *TcgProtocol,\r
+  OUT BOOLEAN                   *TpmEnable,  OPTIONAL\r
+  OUT BOOLEAN                   *TpmActivate OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  TPM_RSP_COMMAND_HDR           *TpmRsp;\r
+  UINT32                        TpmSendSize;\r
+  TPM_PERMANENT_FLAGS           *TpmPermanentFlags;\r
+  UINT8                         CmdBuf[64];\r
+\r
+  ASSERT (TcgProtocol != NULL);\r
+  \r
+  //\r
+  // Get TPM Permanent flags (TpmEnable, TpmActivate)\r
+  //\r
+  if ((TpmEnable != NULL) || (TpmActivate != NULL)) {\r
+    TpmSendSize           = sizeof (TPM_RQU_COMMAND_HDR) + sizeof (UINT32) * 3;\r
+    *(UINT16*)&CmdBuf[0]  = H2NS (TPM_TAG_RQU_COMMAND);\r
+    *(UINT32*)&CmdBuf[2]  = H2NL (TpmSendSize);\r
+    *(UINT32*)&CmdBuf[6]  = H2NL (TPM_ORD_GetCapability);\r
+  \r
+    *(UINT32*)&CmdBuf[10] = H2NL (TPM_CAP_FLAG);\r
+    *(UINT32*)&CmdBuf[14] = H2NL (sizeof (TPM_CAP_FLAG_PERMANENT));\r
+    *(UINT32*)&CmdBuf[18] = H2NL (TPM_CAP_FLAG_PERMANENT);\r
+\r
+    Status = TcgProtocol->PassThroughToTpm (\r
+                            TcgProtocol,\r
+                            TpmSendSize,\r
+                            CmdBuf,\r
+                            sizeof (CmdBuf),\r
+                            CmdBuf\r
+                            ); \r
+    TpmRsp = (TPM_RSP_COMMAND_HDR *) &CmdBuf[0];\r
+    if (EFI_ERROR (Status) || (TpmRsp->tag != H2NS (TPM_TAG_RSP_COMMAND)) || (TpmRsp->returnCode != 0)) {\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+  \r
+    TpmPermanentFlags = (TPM_PERMANENT_FLAGS *) &CmdBuf[sizeof (TPM_RSP_COMMAND_HDR) + sizeof (UINT32)];\r
+\r
+    if (TpmEnable != NULL) {\r
+      *TpmEnable = (BOOLEAN) !TpmPermanentFlags->disable;\r
+    }\r
+\r
+    if (TpmActivate != NULL) {\r
+      *TpmActivate = (BOOLEAN) !TpmPermanentFlags->deactivated;\r
+    }\r
+  }\r
\r
+  return EFI_SUCCESS;  \r
+}\r
+\r
+/**\r
+  This function allows a caller to extract the current configuration for one\r
+  or more named elements from the target driver.\r
+\r
+  @param[in]   This              Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
+  @param[in]   Request           A null-terminated Unicode string in\r
+                                 <ConfigRequest> format.\r
+  @param[out]  Progress          On return, points to a character in the Request\r
+                                 string. Points to the string's null terminator if\r
+                                 request was successful. Points to the most recent\r
+                                 '&' before the first failing name/value pair (or\r
+                                 the beginning of the string if the failure is in\r
+                                 the first name/value pair) if the request was not\r
+                                 successful.\r
+  @param[out]  Results           A null-terminated Unicode string in\r
+                                 <ConfigAltResp> format which has all values filled\r
+                                 in for the names in the Request string. String to\r
+                                 be allocated by the called function.\r
+\r
+  @retval EFI_SUCCESS            The Results is filled with the requested values.\r
+  @retval EFI_OUT_OF_RESOURCES   Not enough memory to store the results.\r
+  @retval EFI_INVALID_PARAMETER  Request is illegal syntax, or unknown name.\r
+  @retval EFI_NOT_FOUND          Routing data doesn't match any storage in this\r
+                                 driver.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TcgExtractConfig (\r
+  IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL        *This,\r
+  IN CONST EFI_STRING                            Request,\r
+       OUT EFI_STRING                            *Progress,\r
+       OUT EFI_STRING                            *Results\r
+  )\r
+{\r
+  EFI_STATUS                 Status;\r
+  UINTN                      BufferSize;\r
+  TCG_CONFIGURATION          Configuration;\r
+  TCG_CONFIG_PRIVATE_DATA    *PrivateData;\r
+  EFI_STRING                 ConfigRequestHdr;\r
+  EFI_STRING                 ConfigRequest;\r
+  BOOLEAN                    AllocatedRequest;\r
+  UINTN                      Size;\r
+  BOOLEAN                    TpmEnable;\r
+  BOOLEAN                    TpmActivate;\r
+  CHAR16                     State[32];\r
+\r
+  if (Progress == NULL || Results == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  *Progress = Request;\r
+  if ((Request != NULL) && !HiiIsConfigHdrMatch (Request, &mTcgFormSetGuid, mTcgStorageName)) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  ConfigRequestHdr = NULL;\r
+  ConfigRequest    = NULL;\r
+  AllocatedRequest = FALSE;\r
+  Size             = 0;\r
+\r
+  PrivateData = TCG_CONFIG_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+  //\r
+  // Convert buffer data to <ConfigResp> by helper function BlockToConfig()\r
+  //  \r
+  ZeroMem (&Configuration, sizeof (TCG_CONFIGURATION));\r
+\r
+  Configuration.MorState        = PcdGetBool (PcdMorEnable);\r
+  Configuration.TpmOperation    = ENABLE;\r
+  Configuration.HideTpm         = PcdGetBool (PcdHideTpmSupport) && PcdGetBool (PcdHideTpm);\r
+  //\r
+  // Read the original value of HideTpm from PrivateData which won't be changed by Setup in this boot.\r
+  //\r
+  Configuration.OriginalHideTpm = PrivateData->HideTpm;\r
+\r
+  //\r
+  // Display current TPM state.\r
+  //\r
+  if (PrivateData->TcgProtocol != NULL) {\r
+    Status = GetTpmState (PrivateData->TcgProtocol, &TpmEnable, &TpmActivate);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    UnicodeSPrint (\r
+      State,\r
+      sizeof (State),\r
+      L"%s, and %s",\r
+      TpmEnable   ? L"Enabled"   : L"Disabled",\r
+      TpmActivate ? L"Activated" : L"Deactivated"\r
+      );\r
+    Configuration.TpmEnable   = TpmEnable;\r
+    Configuration.TpmActivate = TpmActivate;\r
+\r
+    HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_TPM_STATE_CONTENT), State, NULL);\r
+  }\r
+\r
+  BufferSize = sizeof (Configuration);\r
+  ConfigRequest = Request;\r
+  if ((Request == NULL) || (StrStr (Request, L"OFFSET") == NULL)) {\r
+    //\r
+    // Request has no request element, construct full request string.\r
+    // Allocate and fill a buffer large enough to hold the <ConfigHdr> template\r
+    // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator\r
+    //\r
+    ConfigRequestHdr = HiiConstructConfigHdr (&mTcgFormSetGuid, mTcgStorageName, PrivateData->DriverHandle);\r
+    Size = (StrLen (ConfigRequestHdr) + 32 + 1) * sizeof (CHAR16);\r
+    ConfigRequest = AllocateZeroPool (Size);\r
+    ASSERT (ConfigRequest != NULL);\r
+    AllocatedRequest = TRUE;\r
+    UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", ConfigRequestHdr, (UINT64) BufferSize);\r
+    FreePool (ConfigRequestHdr);\r
+  }\r
+\r
+  Status = gHiiConfigRouting->BlockToConfig (\r
+                                gHiiConfigRouting,\r
+                                ConfigRequest,\r
+                                (UINT8 *) &Configuration,\r
+                                BufferSize,\r
+                                Results,\r
+                                Progress\r
+                                );\r
+  //\r
+  // Free the allocated config request string.\r
+  //\r
+  if (AllocatedRequest) {\r
+    FreePool (ConfigRequest);\r
+  }\r
+  //\r
+  // Set Progress string to the original request string.\r
+  //\r
+  if (Request == NULL) {\r
+    *Progress = NULL;\r
+  } else if (StrStr (Request, L"OFFSET") == NULL) {\r
+    *Progress = Request + StrLen (Request);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  This function processes the results of changes in configuration.\r
+\r
+  @param[in]  This               Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
+  @param[in]  Configuration      A null-terminated Unicode string in <ConfigResp>\r
+                                 format.\r
+  @param[out] Progress           A pointer to a string filled in with the offset of\r
+                                 the most recent '&' before the first failing\r
+                                 name/value pair (or the beginning of the string if\r
+                                 the failure is in the first name/value pair) or\r
+                                 the terminating NULL if all was successful.\r
+\r
+  @retval EFI_SUCCESS            The Results is processed successfully.\r
+  @retval EFI_INVALID_PARAMETER  Configuration is NULL.\r
+  @retval EFI_NOT_FOUND          Routing data doesn't match any storage in this\r
+                                 driver.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TcgRouteConfig (\r
+  IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL      *This,\r
+  IN CONST EFI_STRING                          Configuration,\r
+       OUT EFI_STRING                          *Progress\r
+  )\r
+{\r
+  EFI_STATUS                       Status;\r
+  UINTN                            BufferSize;\r
+  TCG_CONFIGURATION                TcgConfiguration;\r
+\r
+  if (Configuration == NULL || Progress == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  *Progress = Configuration;\r
+  if (!HiiIsConfigHdrMatch (Configuration, &mTcgFormSetGuid, mTcgStorageName)) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  //\r
+  // Convert <ConfigResp> to buffer data by helper function ConfigToBlock()\r
+  //\r
+  BufferSize = sizeof (TCG_CONFIGURATION);\r
+  Status = gHiiConfigRouting->ConfigToBlock (\r
+                                gHiiConfigRouting,\r
+                                Configuration,\r
+                                (UINT8 *) &TcgConfiguration,\r
+                                &BufferSize,\r
+                                Progress\r
+                                );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  PcdSetBool (PcdMorEnable,  TcgConfiguration.MorState);\r
+  PcdSetBool (PcdHideTpm,    TcgConfiguration.HideTpm);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Save TPM request to variable space.\r
+\r
+  @param[in] PpRequest             Physical Presence request command.\r
+\r
+  @retval    EFI_SUCCESS           The operation is finished successfully.\r
+  @retval    Others                Other errors as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+SavePpRequest (\r
+  IN UINT8                         PpRequest\r
+  )\r
+{\r
+  EFI_STATUS                       Status;\r
+  UINTN                            DataSize;\r
+  EFI_PHYSICAL_PRESENCE            PpData;\r
+\r
+  //\r
+  // Save TPM command to variable.\r
+  //\r
+  DataSize = sizeof (EFI_PHYSICAL_PRESENCE);\r
+  Status = gRT->GetVariable (\r
+                  PHYSICAL_PRESENCE_VARIABLE,\r
+                  &gEfiPhysicalPresenceGuid,\r
+                  NULL,\r
+                  &DataSize,\r
+                  &PpData\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }                \r
+                  \r
+  PpData.PPRequest = PpRequest;\r
+  Status = gRT->SetVariable (\r
+                  PHYSICAL_PRESENCE_VARIABLE,\r
+                  &gEfiPhysicalPresenceGuid,\r
+                  EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
+                  DataSize,\r
+                  &PpData\r
+                  );\r
+  if (EFI_ERROR(Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Reset system.\r
+  //\r
+  gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  This function processes the results of changes in configuration.\r
+\r
+  @param[in]  This               Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
+  @param[in]  Action             Specifies the type of action taken by the browser.\r
+  @param[in]  QuestionId         A unique value which is sent to the original\r
+                                 exporting driver so that it can identify the type\r
+                                 of data to expect.\r
+  @param[in]  Type               The type of value for the question.\r
+  @param[in]  Value              A pointer to the data being sent to the original\r
+                                 exporting driver.\r
+  @param[out] ActionRequest      On return, points to the action requested by the\r
+                                 callback function.\r
+\r
+  @retval EFI_SUCCESS            The callback successfully handled the action.\r
+  @retval EFI_OUT_OF_RESOURCES   Not enough storage is available to hold the\r
+                                 variable and its data.\r
+  @retval EFI_DEVICE_ERROR       The variable could not be saved.\r
+  @retval EFI_UNSUPPORTED        The specified Action is not supported by the\r
+                                 callback.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TcgCallback (\r
+  IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL      *This,\r
+  IN     EFI_BROWSER_ACTION                    Action,\r
+  IN     EFI_QUESTION_ID                       QuestionId,\r
+  IN     UINT8                                 Type,\r
+  IN     EFI_IFR_TYPE_VALUE                    *Value,\r
+     OUT EFI_BROWSER_ACTION_REQUEST            *ActionRequest\r
+  )\r
+{\r
+  if ((This == NULL) || (Value == NULL) || (ActionRequest == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((Action != EFI_BROWSER_ACTION_CHANGING) || (QuestionId != KEY_TPM_ACTION)) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  SavePpRequest (Value->u8);\r
+  ASSERT (FALSE);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  This function publish the TCG configuration Form for TPM device.\r
+\r
+  @param[in, out]  PrivateData   Points to TCG configuration private data.\r
+\r
+  @retval EFI_SUCCESS            HII Form is installed for this network device.\r
+  @retval EFI_OUT_OF_RESOURCES   Not enough resource for HII Form installation.\r
+  @retval Others                 Other errors as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+InstallTcgConfigForm (\r
+  IN OUT TCG_CONFIG_PRIVATE_DATA  *PrivateData\r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  EFI_HII_HANDLE                  HiiHandle;\r
+  EFI_HANDLE                      DriverHandle;\r
+  VOID                            *StartOpCodeHandle;\r
+  VOID                            *EndOpCodeHandle;\r
+  EFI_IFR_GUID_LABEL              *StartLabel;\r
+  EFI_IFR_GUID_LABEL              *EndLabel;\r
+\r
+  EFI_HII_CONFIG_ACCESS_PROTOCOL  *ConfigAccess;\r
+\r
+  DriverHandle = NULL;\r
+  ConfigAccess = &PrivateData->ConfigAccess;\r
+  Status = gBS->InstallMultipleProtocolInterfaces (\r
+                  &DriverHandle,\r
+                  &gEfiDevicePathProtocolGuid,\r
+                  &mTcgHiiVendorDevicePath,\r
+                  &gEfiHiiConfigAccessProtocolGuid,\r
+                  ConfigAccess,\r
+                  NULL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  PrivateData->DriverHandle = DriverHandle;\r
+\r
+  //\r
+  // Publish the HII package list\r
+  //\r
+  HiiHandle = HiiAddPackages (\r
+                &mTcgFormSetGuid,\r
+                DriverHandle,\r
+                TcgConfigDxeStrings,\r
+                TcgConfigBin,\r
+                NULL\r
+                );\r
+  if (HiiHandle == NULL) {\r
+    gBS->UninstallMultipleProtocolInterfaces (\r
+           DriverHandle,\r
+           &gEfiDevicePathProtocolGuid,\r
+           &mTcgHiiVendorDevicePath,\r
+           &gEfiHiiConfigAccessProtocolGuid,\r
+           ConfigAccess,\r
+           NULL\r
+           );  \r
+\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  \r
+  PrivateData->HiiHandle = HiiHandle;\r
+\r
+  //\r
+  // Remove the Hide TPM question from the IFR\r
+  //\r
+  if (!PcdGetBool (PcdHideTpmSupport)) {\r
+    //\r
+    // Allocate space for creation of UpdateData Buffer\r
+    //\r
+    StartOpCodeHandle = HiiAllocateOpCodeHandle ();\r
+    ASSERT (StartOpCodeHandle != NULL);\r
+\r
+    EndOpCodeHandle = HiiAllocateOpCodeHandle ();\r
+    ASSERT (EndOpCodeHandle != NULL);\r
+\r
+    //\r
+    // Create Hii Extend Label OpCode as the start opcode\r
+    //\r
+    StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));\r
+    StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;\r
+    StartLabel->Number       = LABEL_TCG_CONFIGURATION_HIDETPM;\r
+\r
+    //\r
+    // Create Hii Extend Label OpCode as the end opcode\r
+    //\r
+    EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (EndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));\r
+    EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;\r
+    EndLabel->Number       = LABEL_END;\r
+    \r
+    HiiUpdateForm (HiiHandle, NULL, TCG_CONFIGURATION_FORM_ID, StartOpCodeHandle, EndOpCodeHandle);\r
+\r
+    HiiFreeOpCodeHandle (StartOpCodeHandle);\r
+    HiiFreeOpCodeHandle (EndOpCodeHandle);\r
+  }\r
+\r
+  return EFI_SUCCESS;  \r
+}\r
+\r
+/**\r
+  This function removes TCG configuration Form.\r
+\r
+  @param[in, out]  PrivateData   Points to TCG configuration private data.\r
+\r
+**/\r
+VOID\r
+UninstallTcgConfigForm (\r
+  IN OUT TCG_CONFIG_PRIVATE_DATA    *PrivateData\r
+  )\r
+{\r
+  //\r
+  // Uninstall HII package list\r
+  //\r
+  if (PrivateData->HiiHandle != NULL) {\r
+    HiiRemovePackages (PrivateData->HiiHandle);\r
+    PrivateData->HiiHandle = NULL;\r
+  }\r
+\r
+  //\r
+  // Uninstall HII Config Access Protocol\r
+  //\r
+  if (PrivateData->DriverHandle != NULL) {\r
+    gBS->UninstallMultipleProtocolInterfaces (\r
+           PrivateData->DriverHandle,\r
+           &gEfiDevicePathProtocolGuid,\r
+           &mTcgHiiVendorDevicePath,\r
+           &gEfiHiiConfigAccessProtocolGuid,\r
+           &PrivateData->ConfigAccess,\r
+           NULL\r
+           );\r
+    PrivateData->DriverHandle = NULL;\r
+  }\r
+  \r
+  FreePool (PrivateData);\r
+}\r
diff --git a/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigImpl.h b/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigImpl.h
new file mode 100644 (file)
index 0000000..cbfca74
--- /dev/null
@@ -0,0 +1,195 @@
+/** @file\r
+  The header file of HII Config Access protocol implementation of TCG\r
+  configuration module.\r
+\r
+Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef __TCG_CONFIG_IMPL_H__\r
+#define __TCG_CONFIG_IMPL_H__\r
+\r
+#include <Uefi.h>\r
+\r
+#include <Protocol/HiiConfigAccess.h>\r
+#include <Protocol/HiiConfigRouting.h>\r
+#include <Protocol/TcgService.h>\r
+\r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiRuntimeServicesTableLib.h>\r
+#include <Library/UefiHiiServicesLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/HiiLib.h>\r
+#include <Library/DevicePathLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/PrintLib.h>\r
+#include <Library/TpmCommLib.h>\r
+\r
+#include <Guid/MdeModuleHii.h>\r
+\r
+#include "TcgConfigNvData.h"\r
+\r
+//\r
+// Tool generated IFR binary data and String package data\r
+//\r
+extern UINT8                        TcgConfigBin[];\r
+extern UINT8                        TcgConfigDxeStrings[];\r
+\r
+///\r
+/// HII specific Vendor Device Path definition.\r
+///\r
+typedef struct {\r
+  VENDOR_DEVICE_PATH                VendorDevicePath;\r
+  EFI_DEVICE_PATH_PROTOCOL          End;\r
+} HII_VENDOR_DEVICE_PATH;\r
+\r
+typedef struct {\r
+  UINTN                             Signature;\r
+\r
+  EFI_HII_CONFIG_ACCESS_PROTOCOL    ConfigAccess;\r
+  EFI_HII_HANDLE                    HiiHandle;\r
+  EFI_HANDLE                        DriverHandle;  \r
+\r
+  EFI_TCG_PROTOCOL                  *TcgProtocol;\r
+\r
+  BOOLEAN                           HideTpm;\r
+} TCG_CONFIG_PRIVATE_DATA;\r
+\r
+extern TCG_CONFIG_PRIVATE_DATA      mTcgConfigPrivateDateTemplate;\r
+\r
+#define TCG_CONFIG_PRIVATE_DATA_SIGNATURE     SIGNATURE_32 ('T', 'C', 'G', 'D')\r
+#define TCG_CONFIG_PRIVATE_DATA_FROM_THIS(a)  CR (a, TCG_CONFIG_PRIVATE_DATA, ConfigAccess, TCG_CONFIG_PRIVATE_DATA_SIGNATURE)\r
+\r
+\r
+/**\r
+  This function publish the TCG configuration Form for TPM device.\r
+\r
+  @param[in, out]  PrivateData   Points to TCG configuration private data.\r
+\r
+  @retval EFI_SUCCESS            HII Form is installed for this network device.\r
+  @retval EFI_OUT_OF_RESOURCES   Not enough resource for HII Form installation.\r
+  @retval Others                 Other errors as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+InstallTcgConfigForm (\r
+  IN OUT TCG_CONFIG_PRIVATE_DATA  *PrivateData\r
+  );\r
+\r
+/**\r
+  This function removes TCG configuration Form.\r
+\r
+  @param[in, out]  PrivateData   Points to TCG configuration private data.\r
+\r
+**/\r
+VOID\r
+UninstallTcgConfigForm (\r
+  IN OUT TCG_CONFIG_PRIVATE_DATA    *PrivateData\r
+  );\r
+\r
+/**\r
+  This function allows a caller to extract the current configuration for one\r
+  or more named elements from the target driver.\r
+\r
+  @param[in]   This              Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
+  @param[in]   Request           A null-terminated Unicode string in\r
+                                 <ConfigRequest> format.\r
+  @param[out]  Progress          On return, points to a character in the Request\r
+                                 string. Points to the string's null terminator if\r
+                                 request was successful. Points to the most recent\r
+                                 '&' before the first failing name/value pair (or\r
+                                 the beginning of the string if the failure is in\r
+                                 the first name/value pair) if the request was not\r
+                                 successful.\r
+  @param[out]  Results           A null-terminated Unicode string in\r
+                                 <ConfigAltResp> format which has all values filled\r
+                                 in for the names in the Request string. String to\r
+                                 be allocated by the called function.\r
+\r
+  @retval EFI_SUCCESS            The Results is filled with the requested values.\r
+  @retval EFI_OUT_OF_RESOURCES   Not enough memory to store the results.\r
+  @retval EFI_INVALID_PARAMETER  Request is illegal syntax, or unknown name.\r
+  @retval EFI_NOT_FOUND          Routing data doesn't match any storage in this\r
+                                 driver.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TcgExtractConfig (\r
+  IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL        *This,\r
+  IN CONST EFI_STRING                            Request,\r
+       OUT EFI_STRING                            *Progress,\r
+       OUT EFI_STRING                            *Results\r
+  );\r
+\r
+/**\r
+  This function processes the results of changes in configuration.\r
+\r
+  @param[in]  This               Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
+  @param[in]  Configuration      A null-terminated Unicode string in <ConfigResp>\r
+                                 format.\r
+  @param[out] Progress           A pointer to a string filled in with the offset of\r
+                                 the most recent '&' before the first failing\r
+                                 name/value pair (or the beginning of the string if\r
+                                 the failure is in the first name/value pair) or\r
+                                 the terminating NULL if all was successful.\r
+\r
+  @retval EFI_SUCCESS            The Results is processed successfully.\r
+  @retval EFI_INVALID_PARAMETER  Configuration is NULL.\r
+  @retval EFI_NOT_FOUND          Routing data doesn't match any storage in this\r
+                                 driver.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TcgRouteConfig (\r
+  IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL      *This,\r
+  IN CONST EFI_STRING                          Configuration,\r
+       OUT EFI_STRING                          *Progress\r
+  );\r
+\r
+/**\r
+  This function processes the results of changes in configuration.\r
+\r
+  @param[in]  This               Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
+  @param[in]  Action             Specifies the type of action taken by the browser.\r
+  @param[in]  QuestionId         A unique value which is sent to the original\r
+                                 exporting driver so that it can identify the type\r
+                                 of data to expect.\r
+  @param[in]  Type               The type of value for the question.\r
+  @param[in]  Value              A pointer to the data being sent to the original\r
+                                 exporting driver.\r
+  @param[out] ActionRequest      On return, points to the action requested by the\r
+                                 callback function.\r
+\r
+  @retval EFI_SUCCESS            The callback successfully handled the action.\r
+  @retval EFI_OUT_OF_RESOURCES   Not enough storage is available to hold the\r
+                                 variable and its data.\r
+  @retval EFI_DEVICE_ERROR       The variable could not be saved.\r
+  @retval EFI_UNSUPPORTED        The specified Action is not supported by the\r
+                                 callback.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TcgCallback (\r
+  IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL      *This,\r
+  IN     EFI_BROWSER_ACTION                    Action,\r
+  IN     EFI_QUESTION_ID                       QuestionId,\r
+  IN     UINT8                                 Type,\r
+  IN     EFI_IFR_TYPE_VALUE                    *Value,\r
+     OUT EFI_BROWSER_ACTION_REQUEST            *ActionRequest\r
+  );\r
+\r
+#endif\r
diff --git a/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigNvData.h b/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigNvData.h
new file mode 100644 (file)
index 0000000..982764c
--- /dev/null
@@ -0,0 +1,48 @@
+/** @file\r
+  Header file for NV data structure definition.\r
+\r
+Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef __TCG_CONFIG_NV_DATA_H__\r
+#define __TCG_CONFIG_NV_DATA_H__\r
+\r
+#include <Guid/HiiPlatformSetupFormset.h>\r
+#include <Guid/PhysicalPresenceData.h>\r
+\r
+#define TCG_CONFIG_PRIVATE_GUID \\r
+  { \\r
+    0xb0f901e4, 0xc424, 0x45de, {0x90, 0x81, 0x95, 0xe2, 0xb, 0xde, 0x6f, 0xb5 } \\r
+  }\r
+\r
+#define TCG_CONFIGURATION_VARSTORE_ID  0x0001\r
+#define TCG_CONFIGURATION_FORM_ID      0x0001\r
+\r
+#define KEY_HIDE_TPM                   0x2000\r
+#define KEY_TPM_ACTION                 0x3000\r
+#define KEY_TPM_MOR_ENABLE             0x4000\r
+\r
+#define LABEL_TCG_CONFIGURATION_HIDETPM  0x0001\r
+#define LABEL_END                        0xffff\r
+\r
+//\r
+// Nv Data structure referenced by IFR\r
+//\r
+typedef struct {\r
+  BOOLEAN HideTpm;\r
+  BOOLEAN OriginalHideTpm;\r
+  BOOLEAN MorState;\r
+  UINT8   TpmOperation;\r
+  BOOLEAN TpmEnable;\r
+  BOOLEAN TpmActivate;\r
+} TCG_CONFIGURATION;\r
+\r
+#endif\r
diff --git a/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigStrings.uni b/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigStrings.uni
new file mode 100644 (file)
index 0000000..df39f62
Binary files /dev/null and b/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigStrings.uni differ
diff --git a/SecurityPkg/Tcg/TcgDxe/TcgDxe.c b/SecurityPkg/Tcg/TcgDxe/TcgDxe.c
new file mode 100644 (file)
index 0000000..4cb5d30
--- /dev/null
@@ -0,0 +1,1212 @@
+/** @file  \r
+  This module implements TCG EFI Protocol.\r
+  \r
+Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include <PiDxe.h>\r
+#include <IndustryStandard/Tpm12.h>\r
+#include <IndustryStandard/Acpi.h>\r
+#include <IndustryStandard/PeImage.h>\r
+#include <IndustryStandard/SmBios.h>\r
+\r
+#include <Guid/GlobalVariable.h>\r
+#include <Guid/SmBios.h>\r
+#include <Guid/HobList.h>\r
+#include <Guid/TcgEventHob.h>\r
+#include <Guid/EventGroup.h>\r
+#include <Protocol/DevicePath.h>\r
+#include <Protocol/TcgService.h>\r
+#include <Protocol/AcpiTable.h>\r
+\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/UefiRuntimeServicesTableLib.h>\r
+#include <Library/UefiDriverEntryPoint.h>\r
+#include <Library/HobLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/PrintLib.h>\r
+#include <Library/TpmCommLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/UefiLib.h>\r
+\r
+#include "TpmComm.h"\r
+\r
+#define  EFI_TCG_LOG_AREA_SIZE        0x10000\r
+\r
+#pragma pack (1)\r
+\r
+typedef struct _EFI_TCG_CLIENT_ACPI_TABLE {\r
+  EFI_ACPI_DESCRIPTION_HEADER       Header;\r
+  UINT16                            PlatformClass;\r
+  UINT32                            Laml;\r
+  EFI_PHYSICAL_ADDRESS              Lasa;\r
+} EFI_TCG_CLIENT_ACPI_TABLE;\r
+\r
+typedef struct _EFI_TCG_SERVER_ACPI_TABLE {\r
+  EFI_ACPI_DESCRIPTION_HEADER             Header;\r
+  UINT16                                  PlatformClass;\r
+  UINT16                                  Reserved0;\r
+  UINT64                                  Laml;\r
+  EFI_PHYSICAL_ADDRESS                    Lasa;\r
+  UINT16                                  SpecRev;\r
+  UINT8                                   DeviceFlags;\r
+  UINT8                                   InterruptFlags;\r
+  UINT8                                   Gpe;\r
+  UINT8                                   Reserved1[3];\r
+  UINT32                                  GlobalSysInt;\r
+  EFI_ACPI_3_0_GENERIC_ADDRESS_STRUCTURE  BaseAddress;\r
+  UINT32                                  Reserved2;\r
+  EFI_ACPI_3_0_GENERIC_ADDRESS_STRUCTURE  ConfigAddress;\r
+  UINT8                                   PciSegNum;\r
+  UINT8                                   PciBusNum;\r
+  UINT8                                   PciDevNum;\r
+  UINT8                                   PciFuncNum;\r
+} EFI_TCG_SERVER_ACPI_TABLE;\r
+\r
+#pragma pack ()\r
+\r
+#define TCG_DXE_DATA_FROM_THIS(this)  \\r
+  BASE_CR (this, TCG_DXE_DATA, TcgProtocol)\r
+\r
+typedef struct _TCG_DXE_DATA {\r
+  EFI_TCG_PROTOCOL                  TcgProtocol;\r
+  TCG_EFI_BOOT_SERVICE_CAPABILITY   BsCap;\r
+  EFI_TCG_CLIENT_ACPI_TABLE         *TcgClientAcpiTable;\r
+  EFI_TCG_SERVER_ACPI_TABLE         *TcgServerAcpiTable;\r
+  UINTN                             EventLogSize;\r
+  UINT8                             *LastEvent;\r
+  TIS_TPM_HANDLE                    TpmHandle;\r
+} TCG_DXE_DATA;\r
+\r
+\r
+\r
+EFI_TCG_CLIENT_ACPI_TABLE           mTcgClientAcpiTemplate = {\r
+  {\r
+    EFI_ACPI_3_0_TRUSTED_COMPUTING_PLATFORM_ALLIANCE_CAPABILITIES_TABLE_SIGNATURE,\r
+    sizeof (mTcgClientAcpiTemplate),\r
+    0x02                      //Revision\r
+    //\r
+    // Compiler initializes the remaining bytes to 0\r
+    // These fields should be filled in in production\r
+    //\r
+  },\r
+  0,                          // 0 for PC Client Platform Class\r
+  0,                          // Log Area Max Length\r
+  (EFI_PHYSICAL_ADDRESS) (SIZE_4GB - 1)  // Log Area Start Address\r
+};\r
+\r
+//\r
+// The following EFI_TCG_SERVER_ACPI_TABLE default setting is just one example,\r
+// the TPM device connectes to LPC, and also defined the ACPI _UID as 0xFF,\r
+// this _UID can be changed and should match with the _UID setting of the TPM \r
+// ACPI device object  \r
+//\r
+EFI_TCG_SERVER_ACPI_TABLE           mTcgServerAcpiTemplate = {\r
+  {\r
+    EFI_ACPI_3_0_TRUSTED_COMPUTING_PLATFORM_ALLIANCE_CAPABILITIES_TABLE_SIGNATURE,\r
+    sizeof (mTcgServerAcpiTemplate),\r
+    0x02                      //Revision\r
+    //\r
+    // Compiler initializes the remaining bytes to 0\r
+    // These fields should be filled in in production\r
+    //\r
+  },\r
+  1,                          // 1 for Server Platform Class\r
+  0,                          // Reserved\r
+  0,                          // Log Area Max Length\r
+  (EFI_PHYSICAL_ADDRESS) (SIZE_4GB - 1), // Log Area Start Address\r
+  0x0100,                     // TCG Specification revision 1.0\r
+  2,                          // Device Flags\r
+  0,                          // Interrupt Flags\r
+  0,                          // GPE\r
+  {0},                        // Reserved 3 bytes\r
+  0,                          // Global System Interrupt\r
+  {\r
+    EFI_ACPI_3_0_SYSTEM_MEMORY,\r
+    0,\r
+    0,\r
+    EFI_ACPI_3_0_BYTE,\r
+    TPM_BASE_ADDRESS          // Base Address\r
+  },\r
+  0,                          // Reserved\r
+  {0},                        // Configuration Address\r
+  0xFF,                       // ACPI _UID value of the device, can be changed for different platforms\r
+  0,                          // ACPI _UID value of the device, can be changed for different platforms\r
+  0,                          // ACPI _UID value of the device, can be changed for different platforms\r
+  0                           // ACPI _UID value of the device, can be changed for different platforms\r
+};\r
+\r
+UINTN  mBootAttempts  = 0;\r
+CHAR16 mBootVarName[] = L"BootOrder";\r
+\r
+/**\r
+  This service provides EFI protocol capability information, state information \r
+  about the TPM, and Event Log state information.\r
+\r
+  @param[in]  This               Indicates the calling context\r
+  @param[out] ProtocolCapability The callee allocates memory for a TCG_BOOT_SERVICE_CAPABILITY \r
+                                 structure and fills in the fields with the EFI protocol \r
+                                 capability information and the current TPM state information.\r
+  @param[out] TCGFeatureFlags    This is a pointer to the feature flags. No feature \r
+                                 flags are currently defined so this parameter \r
+                                 MUST be set to 0. However, in the future, \r
+                                 feature flags may be defined that, for example, \r
+                                 enable hash algorithm agility.\r
+  @param[out] EventLogLocation   This is a pointer to the address of the event log in memory.\r
+  @param[out] EventLogLastEntry  If the Event Log contains more than one entry, \r
+                                 this is a pointer to the address of the start of \r
+                                 the last entry in the event log in memory. \r
+\r
+  @retval EFI_SUCCESS            Operation completed successfully.\r
+  @retval EFI_INVALID_PARAMETER  ProtocolCapability does not match TCG capability.\r
+  \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TcgDxeStatusCheck (\r
+  IN      EFI_TCG_PROTOCOL                 *This,\r
+  OUT     TCG_EFI_BOOT_SERVICE_CAPABILITY  *ProtocolCapability,\r
+  OUT     UINT32                           *TCGFeatureFlags,\r
+  OUT     EFI_PHYSICAL_ADDRESS             *EventLogLocation,\r
+  OUT     EFI_PHYSICAL_ADDRESS             *EventLogLastEntry\r
+  )\r
+{\r
+  TCG_DXE_DATA                      *TcgData;\r
+\r
+  TcgData = TCG_DXE_DATA_FROM_THIS (This);\r
+\r
+  if (ProtocolCapability != NULL) {\r
+    *ProtocolCapability = TcgData->BsCap;\r
+  }\r
+\r
+  if (TCGFeatureFlags != NULL) {\r
+    *TCGFeatureFlags = 0;\r
+  }\r
+\r
+  if (EventLogLocation != NULL) {\r
+    if (PcdGet8 (PcdTpmPlatformClass) == TCG_PLATFORM_TYPE_CLIENT) {\r
+      *EventLogLocation = TcgData->TcgClientAcpiTable->Lasa;\r
+    } else {\r
+      *EventLogLocation = TcgData->TcgServerAcpiTable->Lasa;\r
+    }\r
+  }\r
+\r
+  if (EventLogLastEntry != NULL) {\r
+    if (TcgData->BsCap.TPMDeactivatedFlag) {\r
+      *EventLogLastEntry = (EFI_PHYSICAL_ADDRESS)(UINTN)0;\r
+    } else {\r
+      *EventLogLastEntry = (EFI_PHYSICAL_ADDRESS)(UINTN)TcgData->LastEvent;\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  This service abstracts the capability to do a hash operation on a data buffer.\r
+  \r
+  @param[in]      This             Indicates the calling context\r
+  @param[in]      HashData         Pointer to the data buffer to be hashed\r
+  @param[in]      HashDataLen      Length of the data buffer to be hashed\r
+  @param[in]      AlgorithmId      Identification of the Algorithm to use for the hashing operation\r
+  @param[in, out] HashedDataLen    Resultant length of the hashed data\r
+  @param[in, out] HashedDataResult Resultant buffer of the hashed data  \r
+  \r
+  @retval EFI_SUCCESS              Operation completed successfully.\r
+  @retval EFI_INVALID_PARAMETER    HashDataLen is NULL.\r
+  @retval EFI_INVALID_PARAMETER    HashDataLenResult is NULL.\r
+  @retval EFI_OUT_OF_RESOURCES     Cannot allocate buffer of size *HashedDataLen.\r
+  @retval EFI_UNSUPPORTED          AlgorithmId not supported.\r
+  @retval EFI_BUFFER_TOO_SMALL     *HashedDataLen < sizeof (TCG_DIGEST).\r
+  \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TcgDxeHashAll (\r
+  IN      EFI_TCG_PROTOCOL          *This,\r
+  IN      UINT8                     *HashData,\r
+  IN      UINT64                    HashDataLen,\r
+  IN      TCG_ALGORITHM_ID          AlgorithmId,\r
+  IN OUT  UINT64                    *HashedDataLen,\r
+  IN OUT  UINT8                     **HashedDataResult\r
+  )\r
+{\r
+  if (HashedDataLen == NULL || HashedDataResult == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  switch (AlgorithmId) {\r
+    case TPM_ALG_SHA:\r
+      if (*HashedDataLen == 0) {\r
+        *HashedDataLen    = sizeof (TPM_DIGEST);\r
+        *HashedDataResult = AllocatePool ((UINTN) *HashedDataLen);\r
+        if (*HashedDataResult == NULL) {\r
+          return EFI_OUT_OF_RESOURCES;\r
+        }\r
+      }\r
+\r
+      if (*HashedDataLen < sizeof (TPM_DIGEST)) {\r
+        *HashedDataLen = sizeof (TPM_DIGEST);\r
+        return EFI_BUFFER_TOO_SMALL;\r
+      }\r
+      *HashedDataLen = sizeof (TPM_DIGEST);\r
+\r
+      return TpmCommHashAll (\r
+               HashData,\r
+               (UINTN) HashDataLen,\r
+               (TPM_DIGEST*)*HashedDataResult\r
+               );\r
+    default:\r
+      return EFI_UNSUPPORTED;\r
+  }\r
+}\r
+\r
+/**\r
+  Add a new entry to the Event Log.\r
+\r
+  @param[in] TcgData       TCG_DXE_DATA structure.\r
+  @param[in] NewEventHdr   Pointer to a TCG_PCR_EVENT_HDR data structure.  \r
+  @param[in] NewEventData  Pointer to the new event data.  \r
+  \r
+  @retval EFI_SUCCESS           The new event log entry was added.\r
+  @retval EFI_OUT_OF_RESOURCES  No enough memory to log the new event.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TcgDxeLogEventI (\r
+  IN      TCG_DXE_DATA              *TcgData,\r
+  IN      TCG_PCR_EVENT_HDR         *NewEventHdr,\r
+  IN      UINT8                     *NewEventData\r
+  )\r
+{\r
+  if (PcdGet8 (PcdTpmPlatformClass) == TCG_PLATFORM_TYPE_CLIENT) {\r
+    TcgData->LastEvent = (UINT8*)(UINTN)TcgData->TcgClientAcpiTable->Lasa;\r
+    return TpmCommLogEvent (\r
+             &TcgData->LastEvent,\r
+             &TcgData->EventLogSize,\r
+             (UINTN)TcgData->TcgClientAcpiTable->Laml,\r
+             NewEventHdr,\r
+             NewEventData\r
+             );\r
+  } else {\r
+    TcgData->LastEvent = (UINT8*)(UINTN)TcgData->TcgServerAcpiTable->Lasa;\r
+    return TpmCommLogEvent (\r
+             &TcgData->LastEvent,\r
+             &TcgData->EventLogSize,\r
+             (UINTN)TcgData->TcgServerAcpiTable->Laml,\r
+             NewEventHdr,\r
+             NewEventData\r
+             );\r
+  }\r
+}\r
+\r
+/**\r
+  This service abstracts the capability to add an entry to the Event Log.\r
+\r
+  @param[in]      This           Indicates the calling context\r
+  @param[in]      TCGLogData     Pointer to the start of the data buffer containing \r
+                                 the TCG_PCR_EVENT data structure. All fields in \r
+                                 this structure are properly filled by the caller.\r
+  @param[in, out] EventNumber    The event number of the event just logged\r
+  @param[in]      Flags          Indicate additional flags. Only one flag has been \r
+                                 defined at this time, which is 0x01 and means the \r
+                                 extend operation should not be performed. All \r
+                                 other bits are reserved. \r
\r
+  @retval EFI_SUCCESS            Operation completed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES   Insufficient memory in the event log to complete this action.\r
+  \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TcgDxeLogEvent (\r
+  IN      EFI_TCG_PROTOCOL          *This,\r
+  IN      TCG_PCR_EVENT             *TCGLogData,\r
+  IN OUT  UINT32                    *EventNumber,\r
+  IN      UINT32                    Flags\r
+  )\r
+{\r
+  TCG_DXE_DATA  *TcgData;\r
+\r
+  TcgData = TCG_DXE_DATA_FROM_THIS (This);\r
+  \r
+  if (TcgData->BsCap.TPMDeactivatedFlag) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  return TcgDxeLogEventI (\r
+           TcgData,\r
+           (TCG_PCR_EVENT_HDR*)TCGLogData,\r
+           TCGLogData->Event\r
+           );\r
+}\r
+\r
+/**\r
+  This service is a proxy for commands to the TPM.\r
+\r
+  @param[in]  This                        Indicates the calling context\r
+  @param[in]  TpmInputParameterBlockSize  Size of the TPM input parameter block\r
+  @param[in]  TpmInputParameterBlock      Pointer to the TPM input parameter block\r
+  @param[in]  TpmOutputParameterBlockSize Size of the TPM output parameter block\r
+  @param[in]  TpmOutputParameterBlock     Pointer to the TPM output parameter block\r
+\r
+  @retval     EFI_SUCCESS                 Operation completed successfully.\r
+  @retval     EFI_INVALID_PARAMETER       Invalid ordinal.\r
+  @retval     EFI_UNSUPPORTED             Current Task Priority Level  >= EFI_TPL_CALLBACK.\r
+  @retval     EFI_TIMEOUT                 The TIS timed-out.\r
+  \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TcgDxePassThroughToTpm (\r
+  IN      EFI_TCG_PROTOCOL          *This,\r
+  IN      UINT32                    TpmInputParameterBlockSize,\r
+  IN      UINT8                     *TpmInputParameterBlock,\r
+  IN      UINT32                    TpmOutputParameterBlockSize,\r
+  IN      UINT8                     *TpmOutputParameterBlock\r
+  )\r
+{\r
+  TCG_DXE_DATA                      *TcgData;\r
+\r
+  TcgData = TCG_DXE_DATA_FROM_THIS (This);\r
+\r
+  return TisPcExecute (\r
+           TcgData->TpmHandle,\r
+           "%r%/%r",\r
+           TpmInputParameterBlock,\r
+           (UINTN) TpmInputParameterBlockSize,\r
+           TpmOutputParameterBlock,\r
+           (UINTN) TpmOutputParameterBlockSize\r
+           );\r
+}\r
+\r
+/**\r
+  Do a hash operation on a data buffer, extend a specific TPM PCR with the hash result,\r
+  and add an entry to the Event Log.\r
+\r
+  @param[in]      TcgData       TCG_DXE_DATA structure.\r
+  @param[in]      HashData      Physical address of the start of the data buffer \r
+                                to be hashed, extended, and logged.\r
+  @param[in]      HashDataLen   The length, in bytes, of the buffer referenced by HashData\r
+  @param[in, out] NewEventHdr   Pointer to a TCG_PCR_EVENT_HDR data structure.  \r
+  @param[in]      NewEventData  Pointer to the new event data.  \r
+\r
+  @retval EFI_SUCCESS           Operation completed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  No enough memory to log the new event.\r
+  @retval EFI_DEVICE_ERROR      The command was unsuccessful.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TcgDxeHashLogExtendEventI (\r
+  IN      TCG_DXE_DATA              *TcgData,\r
+  IN      UINT8                     *HashData,\r
+  IN      UINT64                    HashDataLen,\r
+  IN OUT  TCG_PCR_EVENT_HDR         *NewEventHdr,\r
+  IN      UINT8                     *NewEventData\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+\r
+  if (HashDataLen > 0) {\r
+    Status = TpmCommHashAll (\r
+               HashData,\r
+               (UINTN) HashDataLen,\r
+               &NewEventHdr->Digest\r
+               );\r
+    ASSERT_EFI_ERROR (Status);\r
+  }\r
+\r
+  Status = TpmCommExtend (\r
+             TcgData->TpmHandle,\r
+             &NewEventHdr->Digest,\r
+             NewEventHdr->PCRIndex,\r
+             NULL\r
+             );\r
+  if (!EFI_ERROR (Status)) {\r
+    Status = TcgDxeLogEventI (TcgData, NewEventHdr, NewEventData);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  This service abstracts the capability to do a hash operation on a data buffer,\r
+  extend a specific TPM PCR with the hash result, and add an entry to the Event Log\r
+\r
+  @param[in]      This               Indicates the calling context\r
+  @param[in]      HashData           Physical address of the start of the data buffer \r
+                                     to be hashed, extended, and logged.\r
+  @param[in]      HashDataLen        The length, in bytes, of the buffer referenced by HashData\r
+  @param[in]      AlgorithmId        Identification of the Algorithm to use for the hashing operation\r
+  @param[in, out] TCGLogData         The physical address of the start of the data \r
+                                     buffer containing the TCG_PCR_EVENT data structure.\r
+  @param[in, out] EventNumber        The event number of the event just logged.\r
+  @param[out]     EventLogLastEntry  Physical address of the first byte of the entry \r
+                                     just placed in the Event Log. If the Event Log was \r
+                                     empty when this function was called then this physical \r
+                                     address will be the same as the physical address of \r
+                                     the start of the Event Log.\r
+\r
+  @retval EFI_SUCCESS                Operation completed successfully.\r
+  @retval EFI_UNSUPPORTED            AlgorithmId != TPM_ALG_SHA.\r
+  @retval EFI_UNSUPPORTED            Current TPL >= EFI_TPL_CALLBACK.\r
+  @retval EFI_DEVICE_ERROR           The command was unsuccessful.\r
+  \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TcgDxeHashLogExtendEvent (\r
+  IN      EFI_TCG_PROTOCOL          *This,\r
+  IN      EFI_PHYSICAL_ADDRESS      HashData,\r
+  IN      UINT64                    HashDataLen,\r
+  IN      TPM_ALGORITHM_ID          AlgorithmId,\r
+  IN OUT  TCG_PCR_EVENT             *TCGLogData,\r
+  IN OUT  UINT32                    *EventNumber,\r
+     OUT  EFI_PHYSICAL_ADDRESS      *EventLogLastEntry\r
+  )\r
+{\r
+  TCG_DXE_DATA  *TcgData;\r
+\r
+  TcgData = TCG_DXE_DATA_FROM_THIS (This);\r
+  \r
+  if (TcgData->BsCap.TPMDeactivatedFlag) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+    \r
+  if (AlgorithmId != TPM_ALG_SHA) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  return TcgDxeHashLogExtendEventI (\r
+           TcgData,\r
+           (UINT8 *) (UINTN) HashData,\r
+           HashDataLen,\r
+           (TCG_PCR_EVENT_HDR*)TCGLogData,\r
+           TCGLogData->Event\r
+           );\r
+}\r
+\r
+TCG_DXE_DATA                 mTcgDxeData = {\r
+  {\r
+    TcgDxeStatusCheck,\r
+    TcgDxeHashAll,\r
+    TcgDxeLogEvent,\r
+    TcgDxePassThroughToTpm,\r
+    TcgDxeHashLogExtendEvent\r
+  },\r
+  {\r
+    sizeof (mTcgDxeData.BsCap),\r
+    { 1, 2, 0, 0 },\r
+    { 1, 2, 0, 0 },\r
+    1,\r
+    TRUE,\r
+    FALSE\r
+  },\r
+  &mTcgClientAcpiTemplate,\r
+  &mTcgServerAcpiTemplate,\r
+  0,\r
+  NULL,\r
+  NULL\r
+};\r
+\r
+/**\r
+  Initialize the Event Log and log events passed from the PEI phase.\r
+\r
+  @retval EFI_SUCCESS           Operation completed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  Out of memory.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SetupEventLog (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  TCG_PCR_EVENT         *TcgEvent;\r
+  EFI_PEI_HOB_POINTERS  GuidHob;\r
+  EFI_PHYSICAL_ADDRESS  Lasa;\r
+  \r
+  if (PcdGet8 (PcdTpmPlatformClass) == TCG_PLATFORM_TYPE_CLIENT) {\r
+    Lasa = mTcgClientAcpiTemplate.Lasa;\r
+  \r
+    Status = gBS->AllocatePages (\r
+                    AllocateMaxAddress,\r
+                    EfiACPIMemoryNVS,\r
+                    EFI_SIZE_TO_PAGES (EFI_TCG_LOG_AREA_SIZE),\r
+                    &Lasa\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    mTcgClientAcpiTemplate.Lasa = Lasa;\r
+    //\r
+    // To initialize them as 0xFF is recommended \r
+    // because the OS can know the last entry for that.\r
+    //\r
+    SetMem ((VOID *)(UINTN)mTcgClientAcpiTemplate.Lasa, EFI_TCG_LOG_AREA_SIZE, 0xFF);\r
+    mTcgClientAcpiTemplate.Laml = EFI_TCG_LOG_AREA_SIZE;\r
+  \r
+  } else {\r
+    Lasa = mTcgServerAcpiTemplate.Lasa;\r
+  \r
+    Status = gBS->AllocatePages (\r
+                    AllocateMaxAddress,\r
+                    EfiACPIMemoryNVS,\r
+                    EFI_SIZE_TO_PAGES (EFI_TCG_LOG_AREA_SIZE),\r
+                    &Lasa\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    mTcgServerAcpiTemplate.Lasa = Lasa;\r
+    //\r
+    // To initialize them as 0xFF is recommended \r
+    // because the OS can know the last entry for that.\r
+    //\r
+    SetMem ((VOID *)(UINTN)mTcgServerAcpiTemplate.Lasa, EFI_TCG_LOG_AREA_SIZE, 0xFF);\r
+    mTcgServerAcpiTemplate.Laml = EFI_TCG_LOG_AREA_SIZE;\r
+  }\r
+\r
+  GuidHob.Raw = GetHobList ();\r
+  while (!EFI_ERROR (Status) && \r
+         (GuidHob.Raw = GetNextGuidHob (&gTcgEventEntryHobGuid, GuidHob.Raw)) != NULL) {\r
+    TcgEvent    = GET_GUID_HOB_DATA (GuidHob.Guid);\r
+    GuidHob.Raw = GET_NEXT_HOB (GuidHob);\r
+    Status = TcgDxeLogEventI (\r
+               &mTcgDxeData,\r
+               (TCG_PCR_EVENT_HDR*)TcgEvent,\r
+               TcgEvent->Event\r
+               );\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Measure and log an action string, and extend the measurement result into PCR[5].\r
+\r
+  @param[in] String           A specific string that indicates an Action event.  \r
+  \r
+  @retval EFI_SUCCESS         Operation completed successfully.\r
+  @retval EFI_DEVICE_ERROR    The operation was unsuccessful.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TcgMeasureAction (\r
+  IN      CHAR8                     *String\r
+  )\r
+{\r
+  TCG_PCR_EVENT_HDR                 TcgEvent;\r
+\r
+  TcgEvent.PCRIndex  = 5;\r
+  TcgEvent.EventType = EV_EFI_ACTION;\r
+  TcgEvent.EventSize = (UINT32)AsciiStrLen (String);\r
+  return TcgDxeHashLogExtendEventI (\r
+           &mTcgDxeData,\r
+           (UINT8*)String,\r
+           TcgEvent.EventSize,\r
+           &TcgEvent,\r
+           (UINT8 *) String\r
+           );\r
+}\r
+\r
+/**\r
+  Measure and log EFI handoff tables, and extend the measurement result into PCR[1].\r
+\r
+  @retval EFI_SUCCESS         Operation completed successfully.\r
+  @retval EFI_DEVICE_ERROR    The operation was unsuccessful.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MeasureHandoffTables (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  SMBIOS_TABLE_ENTRY_POINT          *SmbiosTable;\r
+  TCG_PCR_EVENT_HDR                 TcgEvent;\r
+  EFI_HANDOFF_TABLE_POINTERS        HandoffTables;\r
+\r
+  Status = EfiGetSystemConfigurationTable (\r
+             &gEfiSmbiosTableGuid,\r
+             (VOID **) &SmbiosTable\r
+             );\r
+\r
+  if (!EFI_ERROR (Status)) {\r
+    ASSERT (SmbiosTable != NULL);\r
+\r
+    TcgEvent.PCRIndex  = 1;\r
+    TcgEvent.EventType = EV_EFI_HANDOFF_TABLES;\r
+    TcgEvent.EventSize = sizeof (HandoffTables);\r
+\r
+    HandoffTables.NumberOfTables = 1;\r
+    HandoffTables.TableEntry[0].VendorGuid  = gEfiSmbiosTableGuid;\r
+    HandoffTables.TableEntry[0].VendorTable = SmbiosTable;\r
+\r
+    DEBUG ((DEBUG_INFO, "The Smbios Table starts at: 0x%x\n", SmbiosTable->TableAddress));\r
+    DEBUG ((DEBUG_INFO, "The Smbios Table size: 0x%x\n", SmbiosTable->TableLength));\r
+\r
+    Status = TcgDxeHashLogExtendEventI (\r
+               &mTcgDxeData,\r
+               (UINT8*)(UINTN)SmbiosTable->TableAddress,\r
+               SmbiosTable->TableLength,\r
+               &TcgEvent,\r
+               (UINT8*)&HandoffTables\r
+               );\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Measure and log Separator event, and extend the measurement result into a specific PCR.\r
+\r
+  @param[in] PCRIndex         PCR index.  \r
+\r
+  @retval EFI_SUCCESS         Operation completed successfully.\r
+  @retval EFI_DEVICE_ERROR    The operation was unsuccessful.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MeasureSeparatorEvent (\r
+  IN      TPM_PCRINDEX              PCRIndex\r
+  )\r
+{\r
+  TCG_PCR_EVENT_HDR                 TcgEvent;\r
+  UINT32                            EventData;\r
+\r
+  EventData = 0;\r
+  TcgEvent.PCRIndex  = PCRIndex;\r
+  TcgEvent.EventType = EV_SEPARATOR;\r
+  TcgEvent.EventSize = (UINT32)sizeof (EventData);\r
+  return TcgDxeHashLogExtendEventI (\r
+           &mTcgDxeData,\r
+           (UINT8 *)&EventData,\r
+           sizeof (EventData),\r
+           &TcgEvent,\r
+           (UINT8 *)&EventData\r
+           );\r
+}\r
+\r
+/**\r
+  Read an EFI Variable.\r
+\r
+  This function allocates a buffer to return the contents of the variable. The caller is\r
+  responsible for freeing the buffer.\r
+\r
+  @param[in]  VarName     A Null-terminated string that is the name of the vendor's variable.\r
+  @param[in]  VendorGuid  A unique identifier for the vendor.\r
+  @param[out] VarSize     The size of the variable data.  \r
+\r
+  @return A pointer to the buffer to return the contents of the variable.Otherwise NULL.\r
+\r
+**/\r
+VOID *\r
+EFIAPI\r
+ReadVariable (\r
+  IN      CHAR16                    *VarName,\r
+  IN      EFI_GUID                  *VendorGuid,\r
+  OUT     UINTN                     *VarSize\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  VOID                              *VarData;\r
+\r
+  *VarSize = 0;\r
+  Status = gRT->GetVariable (\r
+                  VarName,\r
+                  VendorGuid,\r
+                  NULL,\r
+                  VarSize,\r
+                  NULL\r
+                  );\r
+  if (Status != EFI_BUFFER_TOO_SMALL) {\r
+    return NULL;\r
+  }\r
+\r
+  VarData = AllocatePool (*VarSize);\r
+  if (VarData != NULL) {\r
+    Status = gRT->GetVariable (\r
+                    VarName,\r
+                    VendorGuid,\r
+                    NULL,\r
+                    VarSize,\r
+                    VarData\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      FreePool (VarData);\r
+      VarData = NULL;\r
+      *VarSize = 0;\r
+    }\r
+  }\r
+  return VarData;\r
+}\r
+\r
+/**\r
+  Measure and log an EFI variable, and extend the measurement result into a specific PCR.\r
+\r
+  @param[in]  PCRIndex          PCR Index.  \r
+  @param[in]  EventType         Event type.  \r
+  @param[in]  VarName           A Null-terminated string that is the name of the vendor's variable.\r
+  @param[in]  VendorGuid        A unique identifier for the vendor.\r
+  @param[in]  VarData           The content of the variable data.  \r
+  @param[in]  VarSize           The size of the variable data.  \r
\r
+  @retval EFI_SUCCESS           Operation completed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  Out of memory.\r
+  @retval EFI_DEVICE_ERROR      The operation was unsuccessful.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MeasureVariable (\r
+  IN      TPM_PCRINDEX              PCRIndex,\r
+  IN      TCG_EVENTTYPE             EventType,\r
+  IN      CHAR16                    *VarName,\r
+  IN      EFI_GUID                  *VendorGuid,\r
+  IN      VOID                      *VarData,\r
+  IN      UINTN                     VarSize\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  TCG_PCR_EVENT_HDR                 TcgEvent;\r
+  UINTN                             VarNameLength;\r
+  EFI_VARIABLE_DATA                 *VarLog;\r
+\r
+  VarNameLength      = StrLen (VarName);\r
+  TcgEvent.PCRIndex  = PCRIndex;\r
+  TcgEvent.EventType = EventType;\r
+  TcgEvent.EventSize = (UINT32)(sizeof (*VarLog) + VarNameLength * sizeof (*VarName) + VarSize\r
+                        - sizeof (VarLog->UnicodeName) - sizeof (VarLog->VariableData));\r
+\r
+  VarLog = (EFI_VARIABLE_DATA*)AllocatePool (TcgEvent.EventSize);\r
+  if (VarLog == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  VarLog->VariableName       = *VendorGuid;\r
+  VarLog->UnicodeNameLength  = VarNameLength;\r
+  VarLog->VariableDataLength = VarSize;\r
+  CopyMem (\r
+     VarLog->UnicodeName,\r
+     VarName,\r
+     VarNameLength * sizeof (*VarName)\r
+     );\r
+  CopyMem (\r
+     (CHAR16 *)VarLog->UnicodeName + VarNameLength,\r
+     VarData,\r
+     VarSize\r
+     );\r
+\r
+  Status = TcgDxeHashLogExtendEventI (\r
+             &mTcgDxeData,\r
+             (UINT8*)VarData,\r
+             VarSize,\r
+             &TcgEvent,\r
+             (UINT8*)VarLog\r
+             );\r
+  FreePool (VarLog);\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Read then Measure and log an EFI boot variable, and extend the measurement result into PCR[5].\r
+\r
+  @param[in]   VarName          A Null-terminated string that is the name of the vendor's variable.\r
+  @param[in]   VendorGuid       A unique identifier for the vendor.\r
+  @param[out]  VarSize          The size of the variable data.  \r
+  @param[out]  VarData          Pointer to the content of the variable.  \r
\r
+  @retval EFI_SUCCESS           Operation completed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  Out of memory.\r
+  @retval EFI_DEVICE_ERROR      The operation was unsuccessful.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ReadAndMeasureBootVariable (\r
+  IN      CHAR16                    *VarName,\r
+  IN      EFI_GUID                  *VendorGuid,\r
+  OUT     UINTN                     *VarSize,\r
+  OUT     VOID                      **VarData\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+\r
+  *VarData = ReadVariable (VarName, VendorGuid, VarSize);\r
+  if (*VarData == NULL) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  Status = MeasureVariable (\r
+             5,\r
+             EV_EFI_VARIABLE_BOOT,\r
+             VarName,\r
+             VendorGuid,\r
+             *VarData,\r
+             *VarSize\r
+             );\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Measure and log all EFI boot variables, and extend the measurement result into a specific PCR.\r
+\r
+  The EFI boot variables are BootOrder and Boot#### variables.\r
+\r
+  @retval EFI_SUCCESS           Operation completed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  Out of memory.\r
+  @retval EFI_DEVICE_ERROR      The operation was unsuccessful.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MeasureAllBootVariables (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  UINT16                            *BootOrder;\r
+  UINTN                             BootCount;\r
+  UINTN                             Index;\r
+  VOID                              *BootVarData;\r
+  UINTN                             Size;\r
+\r
+  Status = ReadAndMeasureBootVariable (\r
+             mBootVarName,\r
+             &gEfiGlobalVariableGuid,\r
+             &BootCount,\r
+             (VOID **) &BootOrder\r
+             );\r
+  if (Status == EFI_NOT_FOUND) {\r
+    return EFI_SUCCESS;\r
+  }\r
+  ASSERT (BootOrder != NULL);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    FreePool (BootOrder);\r
+    return Status;\r
+  }\r
+\r
+  BootCount /= sizeof (*BootOrder);\r
+  for (Index = 0; Index < BootCount; Index++) {\r
+    UnicodeSPrint (mBootVarName, sizeof (mBootVarName), L"Boot%04x", BootOrder[Index]);\r
+    Status = ReadAndMeasureBootVariable (\r
+               mBootVarName,\r
+               &gEfiGlobalVariableGuid,\r
+               &Size,\r
+               &BootVarData\r
+               );\r
+    if (!EFI_ERROR (Status)) {\r
+      FreePool (BootVarData);\r
+    }\r
+  }\r
+\r
+  FreePool (BootOrder);\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Ready to Boot Event notification handler.\r
+\r
+  Sequence of OS boot events is measured in this event notification handler.\r
+\r
+  @param[in]  Event     Event whose notification function is being invoked\r
+  @param[in]  Context   Pointer to the notification function's context\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+OnReadyToBoot (\r
+  IN      EFI_EVENT                 Event,\r
+  IN      VOID                      *Context\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  TPM_PCRINDEX                      PcrIndex;\r
+\r
+  if (mBootAttempts == 0) {\r
+\r
+    //\r
+    // Measure handoff tables.\r
+    //\r
+    Status = MeasureHandoffTables ();\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_ERROR, "HOBs not Measured. Error!\n"));\r
+    }\r
+\r
+    //\r
+    // Measure BootOrder & Boot#### variables.\r
+    //\r
+    Status = MeasureAllBootVariables ();\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_ERROR, "Boot Variables not Measured. Error!\n"));\r
+    }\r
+\r
+    //\r
+    // 1. This is the first boot attempt.\r
+    //\r
+    Status = TcgMeasureAction (\r
+               EFI_CALLING_EFI_APPLICATION\r
+               );\r
+    ASSERT_EFI_ERROR (Status);\r
+\r
+    //\r
+    // 2. Draw a line between pre-boot env and entering post-boot env.\r
+    //\r
+    for (PcrIndex = 0; PcrIndex < 8; PcrIndex++) {\r
+      Status = MeasureSeparatorEvent (PcrIndex);\r
+      ASSERT_EFI_ERROR (Status);\r
+    }\r
+\r
+    //\r
+    // 3. Measure GPT. It would be done in SAP driver.\r
+    //\r
+\r
+    //\r
+    // 4. Measure PE/COFF OS loader. It would be done in SAP driver.\r
+    //\r
+\r
+    //\r
+    // 5. Read & Measure variable. BootOrder already measured.\r
+    //\r
+  } else {\r
+    //\r
+    // 6. Not first attempt, meaning a return from last attempt\r
+    //\r
+    Status = TcgMeasureAction (\r
+               EFI_RETURNING_FROM_EFI_APPLICATOIN\r
+               );\r
+    ASSERT_EFI_ERROR (Status);\r
+  }\r
+\r
+  DEBUG ((EFI_D_INFO, "TPM TcgDxe Measure Data when ReadyToBoot\n"));\r
+  //\r
+  // Increase boot attempt counter.\r
+  //\r
+  mBootAttempts++;\r
+}\r
+\r
+/**\r
+  Install TCG ACPI Table when ACPI Table Protocol is available.\r
+\r
+  A system¡¯s firmware uses an ACPI table to identify the system's TCG capabilities \r
+  to the Post-Boot environment. The information in this ACPI table is not guaranteed \r
+  to be valid until the Host Platform transitions from pre-boot state to post-boot state.  \r
+\r
+  @param[in]  Event     Event whose notification function is being invoked\r
+  @param[in]  Context   Pointer to the notification function's context\r
+**/\r
+VOID\r
+EFIAPI\r
+InstallAcpiTable (\r
+  IN EFI_EVENT                      Event,\r
+  IN VOID*                          Context\r
+  )\r
+{\r
+  UINTN                             TableKey;\r
+  EFI_STATUS                        Status;\r
+  EFI_ACPI_TABLE_PROTOCOL           *AcpiTable;\r
+  UINT8                             Checksum;\r
+\r
+  Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **)&AcpiTable);\r
+  if (EFI_ERROR (Status)) {\r
+    return;\r
+  }\r
+\r
+  if (PcdGet8 (PcdTpmPlatformClass) == TCG_PLATFORM_TYPE_CLIENT) {\r
\r
+    //\r
+    // The ACPI table must be checksumed before calling the InstallAcpiTable() \r
+    // service of the ACPI table protocol to install it.\r
+    //\r
+    Checksum = CalculateCheckSum8 ((UINT8 *)&mTcgClientAcpiTemplate, sizeof (mTcgClientAcpiTemplate));\r
+    mTcgClientAcpiTemplate.Header.Checksum = Checksum;\r
+\r
+    Status = AcpiTable->InstallAcpiTable (\r
+                            AcpiTable,\r
+                            &mTcgClientAcpiTemplate,\r
+                            sizeof (mTcgClientAcpiTemplate),\r
+                            &TableKey\r
+                            );\r
+  } else {\r
+\r
+    //\r
+    // The ACPI table must be checksumed before calling the InstallAcpiTable() \r
+    // service of the ACPI table protocol to install it.\r
+    //\r
+    Checksum = CalculateCheckSum8 ((UINT8 *)&mTcgServerAcpiTemplate, sizeof (mTcgServerAcpiTemplate));\r
+    mTcgServerAcpiTemplate.Header.Checksum = Checksum;\r
+\r
+    Status = AcpiTable->InstallAcpiTable (\r
+                            AcpiTable,\r
+                            &mTcgServerAcpiTemplate,\r
+                            sizeof (mTcgServerAcpiTemplate),\r
+                            &TableKey\r
+                            );\r
+  }\r
+  ASSERT_EFI_ERROR (Status);\r
+}\r
+\r
+/**\r
+  Exit Boot Services Event notification handler.\r
+\r
+  Measure invocation and success of ExitBootServices.\r
+\r
+  @param[in]  Event     Event whose notification function is being invoked\r
+  @param[in]  Context   Pointer to the notification function's context\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+OnExitBootServices (\r
+  IN      EFI_EVENT                 Event,\r
+  IN      VOID                      *Context\r
+  )\r
+{\r
+  EFI_STATUS    Status;\r
+\r
+  //\r
+  // Measure invocation of ExitBootServices,\r
+  //\r
+  Status = TcgMeasureAction (\r
+             EFI_EXIT_BOOT_SERVICES_INVOCATION\r
+             );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // Measure success of ExitBootServices\r
+  //\r
+  Status = TcgMeasureAction (\r
+             EFI_EXIT_BOOT_SERVICES_SUCCEEDED\r
+             );\r
+  ASSERT_EFI_ERROR (Status);\r
+}\r
+\r
+/**\r
+  Get TPM Deactivated state.\r
+\r
+  @param[out] TPMDeactivatedFlag   Returns TPM Deactivated state.  \r
+\r
+  @retval EFI_SUCCESS              Operation completed successfully.\r
+  @retval EFI_DEVICE_ERROR         The operation was unsuccessful.\r
+\r
+**/\r
+EFI_STATUS\r
+GetTpmStatus (\r
+     OUT  BOOLEAN                   *TPMDeactivatedFlag\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  TPM_STCLEAR_FLAGS                 VFlags;\r
+\r
+  Status = TpmCommGetFlags (\r
+             mTcgDxeData.TpmHandle,\r
+             TPM_CAP_FLAG_VOLATILE,\r
+             &VFlags,\r
+             sizeof (VFlags)\r
+             );\r
+  if (!EFI_ERROR (Status)) {\r
+    *TPMDeactivatedFlag = VFlags.deactivated;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  The driver's entry point.\r
+\r
+  It publishes EFI TCG Protocol.\r
+\r
+  @param[in] ImageHandle  The firmware allocated handle for the EFI image.  \r
+  @param[in] SystemTable  A pointer to the EFI System Table.\r
+  \r
+  @retval EFI_SUCCESS     The entry point is executed successfully.\r
+  @retval other           Some error occurs when executing this entry point.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DriverEntry (\r
+  IN    EFI_HANDLE                  ImageHandle,\r
+  IN    EFI_SYSTEM_TABLE            *SystemTable\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  EFI_EVENT                         Event;\r
+  VOID                              *Registration;\r
+\r
+  mTcgDxeData.TpmHandle = (TIS_TPM_HANDLE)(UINTN)TPM_BASE_ADDRESS;\r
+  Status = TisPcRequestUseTpm (mTcgDxeData.TpmHandle);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "TPM not detected!\n"));\r
+    return Status;\r
+  }\r
+\r
+  Status = GetTpmStatus (&mTcgDxeData.BsCap.TPMDeactivatedFlag);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((\r
+      EFI_D_ERROR,\r
+      "Line %d in file " __FILE__ ":\n    "\r
+      "DriverEntry: TPM not working properly\n",\r
+      __LINE__\r
+      ));\r
+    return Status;\r
+  }\r
+\r
+  Status = gBS->InstallProtocolInterface (\r
+                  &ImageHandle,\r
+                  &gEfiTcgProtocolGuid,\r
+                  EFI_NATIVE_INTERFACE,\r
+                  &mTcgDxeData.TcgProtocol\r
+                  );\r
+  //\r
+  // Install ACPI Table\r
+  //\r
+  EfiCreateProtocolNotifyEvent (&gEfiAcpiTableProtocolGuid, TPL_CALLBACK, InstallAcpiTable, NULL, &Registration);\r
+    \r
+  if (!EFI_ERROR (Status) && !mTcgDxeData.BsCap.TPMDeactivatedFlag) {\r
+    //\r
+    // Setup the log area and copy event log from hob list to it\r
+    //\r
+    Status = SetupEventLog ();\r
+    ASSERT_EFI_ERROR (Status);\r
+\r
+    //\r
+    // Measure handoff tables, Boot#### variables etc.\r
+    //\r
+    Status = EfiCreateEventReadyToBootEx (\r
+               TPL_CALLBACK,\r
+               OnReadyToBoot,\r
+               NULL,\r
+               &Event\r
+               );\r
+\r
+    Status = gBS->CreateEventEx (\r
+                    EVT_NOTIFY_SIGNAL,\r
+                    TPL_NOTIFY,\r
+                    OnExitBootServices,\r
+                    NULL,\r
+                    &gEfiEventExitBootServicesGuid,\r
+                    &Event\r
+                    );\r
+  }\r
+\r
+  return Status;\r
+}\r
diff --git a/SecurityPkg/Tcg/TcgDxe/TcgDxe.inf b/SecurityPkg/Tcg/TcgDxe/TcgDxe.inf
new file mode 100644 (file)
index 0000000..95f3773
--- /dev/null
@@ -0,0 +1,70 @@
+## @file\r
+#  Component file for module TcgDxe.\r
+#  This module will produce TCG protocol and measure boot environment.\r
+#\r
+# Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = TcgDxe\r
+  FILE_GUID                      = A5683620-7998-4bb2-A377-1C1E31E1E215\r
+  MODULE_TYPE                    = DXE_DRIVER\r
+  VERSION_STRING                 = 1.0\r
+  ENTRY_POINT                    = DriverEntry\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64 IPF\r
+#\r
+\r
+[Sources]\r
+  TcgDxe.c\r
+  TisDxe.c\r
+  TpmComm.c\r
+  TpmComm.h\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+  SecurityPkg/SecurityPkg.dec\r
+\r
+[LibraryClasses]\r
+  MemoryAllocationLib\r
+  BaseLib\r
+  UefiBootServicesTableLib\r
+  HobLib\r
+  UefiDriverEntryPoint\r
+  UefiRuntimeServicesTableLib\r
+  BaseMemoryLib\r
+  DebugLib\r
+  TpmCommLib\r
+  PrintLib\r
+  UefiLib\r
+\r
+[Guids]\r
+  gEfiSmbiosTableGuid                           # ALWAYS_CONSUMED\r
+  gEfiGlobalVariableGuid                        # ALWAYS_CONSUMED\r
+  gTcgEventEntryHobGuid\r
+  gEfiEventReadyToBootGuid\r
+  gEfiEventExitBootServicesGuid\r
+\r
+[Protocols]\r
+  gEfiTcgProtocolGuid                           ## PRODUCES\r
+  gEfiAcpiTableProtocolGuid                     # PROTOCOL ALWAYS_CONSUMED\r
+  gEfiDevicePathProtocolGuid                    # PROTOCOL ALWAYS_CONSUMED\r
+\r
+[Pcd]\r
+  gEfiSecurityPkgTokenSpaceGuid.PcdTpmPlatformClass\r
+\r
+[Depex]\r
+  TRUE\r
+\r
diff --git a/SecurityPkg/Tcg/TcgDxe/TisDxe.c b/SecurityPkg/Tcg/TcgDxe/TisDxe.c
new file mode 100644 (file)
index 0000000..635ff77
--- /dev/null
@@ -0,0 +1,432 @@
+/** @file  \r
+  TIS (TPM Interface Specification) functions used by TPM Dxe driver.\r
+  \r
+Copyright (c) 2005 - 2010, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include <IndustryStandard/Tpm12.h>\r
+#include <Library/TimerLib.h>\r
+#include <Library/TpmCommLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/IoLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+\r
+STATIC UINT8                        TpmCommandBuf[TPMCMDBUFLENGTH];\r
+\r
+/**\r
+  Send command to TPM for execution.\r
+\r
+  @param[in] TisReg     TPM register space base address.  \r
+  @param[in] TpmBuffer  Buffer for TPM command data.  \r
+  @param[in] DataLength TPM command data length.  \r
\r
+  @retval EFI_SUCCESS   Operation completed successfully.\r
+  @retval EFI_TIMEOUT   The register can't run into the expected status in time.\r
+\r
+**/\r
+EFI_STATUS\r
+TisPcSend (\r
+  IN     TIS_PC_REGISTERS_PTR       TisReg,\r
+  IN     UINT8                      *TpmBuffer,\r
+  IN     UINT32                     DataLength\r
+  )\r
+{\r
+  UINT16                            BurstCount;\r
+  UINT32                            Index;\r
+  EFI_STATUS                        Status;\r
+\r
+  Status = TisPcPrepareCommand (TisReg);\r
+  if (EFI_ERROR (Status)){\r
+    DEBUG ((DEBUG_ERROR, "The Tpm not ready!\n"));\r
+    return Status;\r
+  }\r
+  Index = 0;\r
+  while (Index < DataLength) {\r
+    Status = TisPcReadBurstCount (TisReg, &BurstCount);\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_TIMEOUT;\r
+    }\r
+    for (; BurstCount > 0 && Index < DataLength; BurstCount--) {\r
+      MmioWrite8 ((UINTN) &TisReg->DataFifo, *(TpmBuffer + Index));\r
+      Index++;\r
+    }\r
+  }\r
+  //\r
+  // Ensure the Tpm status STS_EXPECT change from 1 to 0\r
+  //\r
+  Status = TisPcWaitRegisterBits (\r
+             &TisReg->Status,\r
+             (UINT8) TIS_PC_VALID,\r
+             TIS_PC_STS_EXPECT,\r
+             TIS_TIMEOUT_C\r
+             );\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Receive response data of last command from TPM.\r
+\r
+  @param[in]  TisReg            TPM register space base address.  \r
+  @param[out] TpmBuffer         Buffer for response data.  \r
+  @param[out] RespSize          Response data length.  \r
\r
+  @retval EFI_SUCCESS           Operation completed successfully.\r
+  @retval EFI_TIMEOUT           The register can't run into the expected status in time.\r
+  @retval EFI_DEVICE_ERROR      Unexpected device status.\r
+  @retval EFI_BUFFER_TOO_SMALL  Response data is too long.\r
+\r
+**/\r
+EFI_STATUS\r
+TisPcReceive (\r
+  IN      TIS_PC_REGISTERS_PTR      TisReg,\r
+     OUT  UINT8                     *TpmBuffer,\r
+     OUT  UINT32                    *RespSize\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  UINT16                            BurstCount;\r
+  UINT32                            Index;\r
+  UINT32                            ResponseSize;\r
+  UINT32                            Data32;\r
+\r
+  //\r
+  // Wait for the command completion\r
+  //\r
+  Status = TisPcWaitRegisterBits (\r
+             &TisReg->Status,\r
+             (UINT8) (TIS_PC_VALID | TIS_PC_STS_DATA),\r
+             0,\r
+             TIS_TIMEOUT_B\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_TIMEOUT;\r
+  }\r
+  //\r
+  // Read the response data header and check it\r
+  //\r
+  Index = 0;\r
+  BurstCount = 0;\r
+  while (Index < sizeof (TPM_RSP_COMMAND_HDR)) {\r
+    Status = TisPcReadBurstCount (TisReg, &BurstCount);\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_TIMEOUT;\r
+    }\r
+    for (; BurstCount > 0 ; BurstCount--) {\r
+      *(TpmBuffer + Index) = MmioRead8 ((UINTN) &TisReg->DataFifo);\r
+      Index++;\r
+      if (Index == sizeof (TPM_RSP_COMMAND_HDR))\r
+        break;\r
+    }\r
+  }\r
+  //\r
+  // Check the reponse data header (tag,parasize and returncode )\r
+  //\r
+  CopyMem (&Data32, (TpmBuffer + 2), sizeof (UINT32));\r
+  ResponseSize = SwapBytes32 (Data32);\r
+  *RespSize =  ResponseSize;\r
+  if (ResponseSize == sizeof (TPM_RSP_COMMAND_HDR)) {\r
+    return EFI_SUCCESS;\r
+  }\r
+  if (ResponseSize < sizeof (TPM_RSP_COMMAND_HDR)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  if (ResponseSize > TPMCMDBUFLENGTH) {\r
+    return EFI_BUFFER_TOO_SMALL;\r
+  }\r
+  //\r
+  // Continue reading the remaining data\r
+  //\r
+  while (Index < ResponseSize) {\r
+    for (; BurstCount > 0 ; BurstCount--) {\r
+      *(TpmBuffer + Index) = MmioRead8 ((UINTN) &TisReg->DataFifo);\r
+      Index++;\r
+      if (Index == ResponseSize) {\r
+        return EFI_SUCCESS;\r
+      }\r
+    }\r
+    Status = TisPcReadBurstCount (TisReg, &BurstCount);\r
+    if (EFI_ERROR (Status) && (Index < ResponseSize)) {\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+  }\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Format TPM command data according to the format control character.\r
+\r
+  @param[in]      FmtChar       Format control character.  \r
+  @param[in, out] ap            List of arguments.  \r
+  @param[in]      TpmBuffer     Buffer for TPM command data.  \r
+  @param[out]     DataLength    TPM command data length. \r
\r
+  @retval EFI_SUCCESS           Operation completed successfully.\r
+  @retval EFI_INVALID_PARAMETER Invalid format control character.\r
+  @retval EFI_BUFFER_TOO_SMALL  Buffer too small for command data.\r
+\r
+**/\r
+EFI_STATUS\r
+TisPcSendV (\r
+  IN      UINT8                     FmtChar,\r
+  IN OUT  VA_LIST                   *ap,\r
+  UINT8                             *TpmBuffer,\r
+  UINT32                            *DataLength\r
+  )\r
+{\r
+  UINT8                             DataByte;\r
+  UINT16                            DataWord;\r
+  UINT32                            DataDword;\r
+  TPM_RQU_COMMAND_HDR               TpmCmdHdr;\r
+  TPM_RQU_COMMAND_HDR               *TpmCmdPtr;\r
+  UINTN                             Size;\r
+  UINT8                             *Raw;\r
+\r
+  switch (FmtChar) {\r
+\r
+    case 'b':\r
+      DataByte  = VA_ARG (*ap, UINT8);\r
+      Raw = &DataByte;\r
+      Size = sizeof (DataByte);\r
+      break;\r
+\r
+    case 'w':\r
+      DataWord  = VA_ARG (*ap, UINT16);\r
+      DataWord  = SwapBytes16 (DataWord);\r
+      Raw = (UINT8*)&DataWord;\r
+      Size = sizeof (DataWord);\r
+      break;\r
+\r
+    case 'd':\r
+      DataDword  = VA_ARG (*ap, UINT32);\r
+      DataDword  = SwapBytes32 (DataDword);\r
+      Raw = (UINT8*)&DataDword;\r
+      Size = sizeof (DataDword);\r
+      break;\r
+\r
+    case 'h':\r
+      TpmCmdPtr           = VA_ARG (*ap, TPM_RQU_COMMAND_HDR*);\r
+      TpmCmdHdr.tag       = SwapBytes16 (TpmCmdPtr->tag);\r
+      TpmCmdHdr.paramSize = SwapBytes32 (TpmCmdPtr->paramSize);\r
+      TpmCmdHdr.ordinal   = SwapBytes32 (TpmCmdPtr->ordinal);\r
+      Raw                 = (UINT8*) &TpmCmdHdr;\r
+      Size                = sizeof (TpmCmdHdr);\r
+      break;\r
+\r
+    case 'r':\r
+      Raw  = VA_ARG (*ap, UINT8*);\r
+      Size = VA_ARG (*ap, UINTN);\r
+      break;\r
+\r
+    case '\0':\r
+      return EFI_INVALID_PARAMETER;\r
+\r
+    default:\r
+      return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if(*DataLength + (UINT32) Size > TPMCMDBUFLENGTH) {\r
+    return EFI_BUFFER_TOO_SMALL;\r
+  }\r
+  CopyMem (TpmBuffer + *DataLength, Raw, Size);\r
+  *DataLength += (UINT32) Size;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Format reponse data according to the format control character.\r
+\r
+  @param[in]      FmtChar       Format control character.  \r
+  @param[in, out] ap            List of arguments.  \r
+  @param[out]     TpmBuffer     Buffer for reponse data.  \r
+  @param[in, out] DataIndex     Data offset in reponse data buffer. \r
+  @param[in]      RespSize      Response data length.  \r
+  @param[out]     DataFinished  Reach the end of Response data.  \r
\r
+  @retval EFI_SUCCESS           Operation completed successfully.\r
+  @retval EFI_INVALID_PARAMETER Invalid format control character.\r
+  @retval EFI_BUFFER_TOO_SMALL  Buffer too small for command data.\r
+\r
+**/\r
+EFI_STATUS\r
+TisPcReceiveV (\r
+  IN      UINT8                     FmtChar,\r
+  IN OUT  VA_LIST                   *ap,\r
+     OUT  UINT8                     *TpmBuffer,\r
+  IN OUT  UINT32                    *DataIndex,\r
+  IN      UINT32                    RespSize,\r
+     OUT  BOOLEAN                   *DataFinished\r
+  )\r
+{\r
+  UINT8                             *Raw;\r
+  TPM_RSP_COMMAND_HDR               *TpmRspPtr;\r
+  UINTN                             Size;\r
+\r
+  Raw = VA_ARG (*ap, UINT8*);\r
+  switch (FmtChar) {\r
+\r
+    case 'b':\r
+      Size = sizeof (UINT8);\r
+      break;\r
+\r
+    case 'w':\r
+      Size = sizeof (UINT16);\r
+      break;\r
+\r
+    case 'd':\r
+      Size = sizeof (UINT32);\r
+      break;\r
+\r
+    case 'h':\r
+      Size = sizeof (*TpmRspPtr);\r
+      break;\r
+\r
+    case 'r':\r
+      Size = VA_ARG (*ap, UINTN);\r
+      if(*DataIndex + (UINT32) Size <= RespSize) {\r
+        break;\r
+      }\r
+      *DataFinished = TRUE;\r
+      if (*DataIndex >= RespSize) {\r
+        return EFI_SUCCESS;\r
+      }\r
+      CopyMem (Raw, TpmBuffer + *DataIndex, RespSize - *DataIndex);\r
+      *DataIndex += RespSize - *DataIndex;\r
+      return EFI_SUCCESS;\r
+\r
+    case '\0':\r
+      return EFI_INVALID_PARAMETER;\r
+\r
+    default:\r
+      return EFI_WARN_UNKNOWN_GLYPH;\r
+  }\r
+\r
+  if(*DataIndex + (UINT32) Size > RespSize) {\r
+    *DataFinished = TRUE;\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  if( *DataIndex + (UINT32) Size > TPMCMDBUFLENGTH )\r
+    return EFI_BUFFER_TOO_SMALL;\r
+\r
+  CopyMem (Raw, TpmBuffer + *DataIndex, Size);\r
+  *DataIndex += (UINT32) Size;\r
+\r
+  switch (FmtChar) {\r
+\r
+    case 'w':\r
+      *(UINT16*)Raw = SwapBytes16 (*(UINT16*) Raw);\r
+      break;\r
+\r
+    case 'd':\r
+      *(UINT32*)Raw = SwapBytes32 (*(UINT32*) Raw);\r
+      break;\r
+\r
+    case 'h':\r
+      TpmRspPtr = (TPM_RSP_COMMAND_HDR*) Raw;\r
+      TpmRspPtr->tag = SwapBytes16 (TpmRspPtr->tag);\r
+      TpmRspPtr->paramSize = SwapBytes32 (TpmRspPtr->paramSize);\r
+      TpmRspPtr->returnCode = SwapBytes32 (TpmRspPtr->returnCode);\r
+      break;\r
+  }\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Send formatted command to TPM for execution and return formatted data from response.\r
+\r
+  @param[in] TisReg    TPM Handle.  \r
+  @param[in] Fmt       Format control string.  \r
+  @param[in] ...       The variable argument list.\r
\r
+  @retval EFI_SUCCESS  Operation completed successfully.\r
+  @retval EFI_TIMEOUT  The register can't run into the expected status in time.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TisPcExecute (\r
+  IN      TIS_TPM_HANDLE            TisReg,\r
+  IN      CONST CHAR8               *Fmt,\r
+  ...\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  VA_LIST                           Ap;\r
+  UINT32                            BufSize;\r
+  UINT32                            ResponseSize;\r
+  BOOLEAN                           DataFinished;\r
+\r
+  VA_START (Ap, Fmt);\r
+\r
+  //\r
+  // Put the formatted command to the TpmCommandBuf\r
+  //\r
+  BufSize = 0;\r
+  while (*Fmt != '\0') {\r
+    if (*Fmt == '%') Fmt++;\r
+    if (*Fmt == '/') break;\r
+    Status = TisPcSendV (*Fmt, &Ap, TpmCommandBuf, &BufSize);\r
+    if (EFI_ERROR( Status )) {\r
+      return Status;\r
+    }\r
+    Fmt++;\r
+  }\r
+  //\r
+  // Send the command to TPM\r
+  //\r
+  Status = TisPcSend (TisReg, TpmCommandBuf, BufSize);\r
+  if (EFI_ERROR (Status))  {\r
+    //\r
+    // Ensure the TPM state change from "Reception" to "Idle/Ready"\r
+    //\r
+    MmioWrite8 ((UINTN) &(((TIS_PC_REGISTERS_PTR) TisReg)->Status), TIS_PC_STS_READY);\r
+    return Status; \r
+  }\r
+\r
+  MmioWrite8 ((UINTN) &(((TIS_PC_REGISTERS_PTR) TisReg)->Status), TIS_PC_STS_GO);\r
+  Fmt++;\r
+  //\r
+  // Receive the response data from TPM\r
+  //\r
+  ZeroMem (TpmCommandBuf, TPMCMDBUFLENGTH);\r
+  Status = TisPcReceive (TisReg, TpmCommandBuf, &ResponseSize);\r
+  //\r
+  // Ensure the TPM state change from "Execution" or "Completion" to "Idle/Ready"\r
+  //\r
+  MmioWrite8 ((UINTN) &(((TIS_PC_REGISTERS_PTR) TisReg)->Status), TIS_PC_STS_READY);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  \r
+  //\r
+  // Get the formatted data from the TpmCommandBuf.\r
+  //\r
+  BufSize =0;\r
+  DataFinished = FALSE;\r
+  while (*Fmt != '\0') {\r
+    if (*Fmt == '%') {\r
+      Fmt++;\r
+    }\r
+    Status = TisPcReceiveV (*Fmt, &Ap, TpmCommandBuf, &BufSize, ResponseSize, &DataFinished);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    if (DataFinished) {\r
+      return EFI_SUCCESS;\r
+    }\r
+    Fmt++;\r
+  }\r
+\r
+  VA_END (Ap);\r
+  return Status;\r
+}\r
+\r
diff --git a/SecurityPkg/Tcg/TcgDxe/TpmComm.c b/SecurityPkg/Tcg/TcgDxe/TpmComm.c
new file mode 100644 (file)
index 0000000..c47794b
--- /dev/null
@@ -0,0 +1,163 @@
+/** @file  \r
+  Utility functions used by TPM Dxe driver.\r
+\r
+Copyright (c) 2005 - 2010, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include <IndustryStandard/Tpm12.h>\r
+#include <IndustryStandard/UefiTcgPlatform.h>\r
+#include <Library/TpmCommLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+\r
+#include "TpmComm.h"\r
+\r
+/**\r
+  Extend a TPM PCR.\r
+\r
+  @param[in]  TpmHandle       TPM handle.  \r
+  @param[in]  DigestToExtend  The 160 bit value representing the event to be recorded.  \r
+  @param[in]  PcrIndex        The PCR to be updated.\r
+  @param[out] NewPcrValue     New PCR value after extend.  \r
+  \r
+  @retval EFI_SUCCESS         Operation completed successfully.\r
+  @retval EFI_DEVICE_ERROR    The command was unsuccessful.\r
+\r
+**/\r
+EFI_STATUS\r
+TpmCommExtend (\r
+  IN      TIS_TPM_HANDLE            TpmHandle,\r
+  IN      TPM_DIGEST                *DigestToExtend,\r
+  IN      TPM_PCRINDEX              PcrIndex,\r
+     OUT  TPM_DIGEST                *NewPcrValue\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  TPM_DIGEST                        NewValue;\r
+  TPM_RQU_COMMAND_HDR               CmdHdr;\r
+  TPM_RSP_COMMAND_HDR               RspHdr;\r
+\r
+  if (NewPcrValue == NULL) {\r
+    NewPcrValue = &NewValue;\r
+  }\r
+\r
+  CmdHdr.tag = TPM_TAG_RQU_COMMAND;\r
+  CmdHdr.paramSize =\r
+    sizeof (CmdHdr) + sizeof (PcrIndex) + sizeof (*DigestToExtend);\r
+  CmdHdr.ordinal = TPM_ORD_Extend;\r
+  Status = TisPcExecute (\r
+             TpmHandle,\r
+             "%h%d%r%/%h%r",\r
+             &CmdHdr,\r
+             PcrIndex,\r
+             DigestToExtend,\r
+             (UINTN)sizeof (*DigestToExtend),\r
+             &RspHdr,\r
+             NewPcrValue,\r
+             (UINTN)sizeof (*NewPcrValue)\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  if (RspHdr.returnCode != 0) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Get TPM capability flags.\r
+\r
+  @param[in]  TpmHandle    TPM handle.  \r
+  @param[in]  FlagSubcap   Flag subcap.  \r
+  @param[out] FlagBuffer   Pointer to the buffer for returned flag structure.\r
+  @param[in]  FlagSize     Size of the buffer.  \r
+  \r
+  @retval EFI_SUCCESS      Operation completed successfully.\r
+  @retval EFI_DEVICE_ERROR The command was unsuccessful.\r
+\r
+**/\r
+EFI_STATUS\r
+TpmCommGetFlags (\r
+  IN      TIS_TPM_HANDLE            TpmHandle,\r
+  IN      UINT32                    FlagSubcap,\r
+     OUT  VOID                      *FlagBuffer,\r
+  IN      UINTN                     FlagSize\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  TPM_RQU_COMMAND_HDR               CmdHdr;\r
+  TPM_RSP_COMMAND_HDR               RspHdr;\r
+  UINT32                            Size;\r
+\r
+  CmdHdr.tag = TPM_TAG_RQU_COMMAND;\r
+  CmdHdr.paramSize = sizeof (CmdHdr) + sizeof (UINT32) * 3;\r
+  CmdHdr.ordinal = TPM_ORD_GetCapability;\r
+\r
+  Status = TisPcExecute (\r
+             TpmHandle,\r
+             "%h%d%d%d%/%h%d%r",\r
+             &CmdHdr,\r
+             TPM_CAP_FLAG,\r
+             sizeof (FlagSubcap),\r
+             FlagSubcap,\r
+             &RspHdr,\r
+             &Size,\r
+             FlagBuffer,\r
+             FlagSize\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  if (RspHdr.returnCode != 0) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Add a new entry to the Event Log.\r
+\r
+  @param[in, out] EventLogPtr   Pointer to the Event Log data.  \r
+  @param[in, out] LogSize       Size of the Event Log.  \r
+  @param[in]      MaxSize       Maximum size of the Event Log.\r
+  @param[in]      NewEventHdr   Pointer to a TCG_PCR_EVENT_HDR data structure.  \r
+  @param[in]      NewEventData  Pointer to the new event data.  \r
+  \r
+  @retval EFI_SUCCESS           The new event log entry was added.\r
+  @retval EFI_OUT_OF_RESOURCES  No enough memory to log the new event.\r
+\r
+**/\r
+EFI_STATUS\r
+TpmCommLogEvent (\r
+  IN OUT  UINT8                     **EventLogPtr,\r
+  IN OUT  UINTN                     *LogSize,\r
+  IN      UINTN                     MaxSize,\r
+  IN      TCG_PCR_EVENT_HDR         *NewEventHdr,\r
+  IN      UINT8                     *NewEventData\r
+  )\r
+{\r
+  UINT32                            NewLogSize;\r
+\r
+  NewLogSize = sizeof (*NewEventHdr) + NewEventHdr->EventSize;\r
+  if (NewLogSize + *LogSize > MaxSize) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  *EventLogPtr += *LogSize;\r
+  *LogSize += NewLogSize;\r
+  CopyMem (*EventLogPtr, NewEventHdr, sizeof (*NewEventHdr));\r
+  CopyMem (\r
+    *EventLogPtr + sizeof (*NewEventHdr),\r
+    NewEventData,\r
+    NewEventHdr->EventSize\r
+    );\r
+  return EFI_SUCCESS;\r
+}\r
diff --git a/SecurityPkg/Tcg/TcgDxe/TpmComm.h b/SecurityPkg/Tcg/TcgDxe/TpmComm.h
new file mode 100644 (file)
index 0000000..763ad76
--- /dev/null
@@ -0,0 +1,99 @@
+/** @file  \r
+  Definitions and function prototypes used by TPM DXE driver.\r
+\r
+Copyright (c) 2005 - 2010, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _TPM_COMM_H_\r
+#define _TPM_COMM_H_\r
+\r
+/**\r
+  Add a new entry to the Event Log.\r
+\r
+  @param[in, out] EventLogPtr   Pointer to the Event Log data.  \r
+  @param[in, out] LogSize       Size of the Event Log.  \r
+  @param[in]      MaxSize       Maximum size of the Event Log.\r
+  @param[in]      NewEventHdr   Pointer to a TCG_PCR_EVENT_HDR data structure.  \r
+  @param[in]      NewEventData  Pointer to the new event data.  \r
+  \r
+  @retval EFI_SUCCESS           The new event log entry was added.\r
+  @retval EFI_OUT_OF_RESOURCES  No enough memory to log the new event.\r
+\r
+**/\r
+EFI_STATUS\r
+TpmCommLogEvent (\r
+  IN OUT  UINT8                     **EventLogPtr,\r
+  IN OUT  UINTN                     *LogSize,\r
+  IN      UINTN                     MaxSize,\r
+  IN      TCG_PCR_EVENT_HDR         *NewEventHdr,\r
+  IN      UINT8                     *NewEventData\r
+  );\r
+\r
+/**\r
+  Extend a TPM PCR.\r
+\r
+  @param[in]  TpmHandle       TPM handle.  \r
+  @param[in]  DigestToExtend  The 160 bit value representing the event to be recorded.  \r
+  @param[in]  PcrIndex        The PCR to be updated.\r
+  @param[out] NewPcrValue     New PCR value after extend.  \r
+  \r
+  @retval EFI_SUCCESS         Operation completed successfully.\r
+  @retval EFI_DEVICE_ERROR    The command was unsuccessful.\r
+\r
+**/\r
+EFI_STATUS\r
+TpmCommExtend (\r
+  IN      TIS_TPM_HANDLE            TpmHandle,\r
+  IN      TPM_DIGEST                *DigestToExtend,\r
+  IN      TPM_PCRINDEX              PcrIndex,\r
+     OUT  TPM_DIGEST                *NewPcrValue\r
+  );\r
+\r
+/**\r
+  Get TPM capability flags.\r
+\r
+  @param[in]  TpmHandle    TPM handle.  \r
+  @param[in]  FlagSubcap   Flag subcap.  \r
+  @param[out] FlagBuffer   Pointer to the buffer for returned flag structure.\r
+  @param[in]  FlagSize     Size of the buffer.  \r
+  \r
+  @retval EFI_SUCCESS      Operation completed successfully.\r
+  @retval EFI_DEVICE_ERROR The command was unsuccessful.\r
+\r
+**/\r
+EFI_STATUS\r
+TpmCommGetFlags (\r
+  IN      TIS_TPM_HANDLE            TpmHandle,\r
+  IN      UINT32                    FlagSubcap,\r
+     OUT  VOID                      *Buffer,\r
+  IN      UINTN                     Size\r
+  );\r
+\r
+/**\r
+  Send formatted command to TPM for execution and return formatted data from response.\r
+\r
+  @param[in] TisReg    TPM Handle.  \r
+  @param[in] Fmt       Format control string.  \r
+  @param[in] ...       The variable argument list.\r
\r
+  @retval EFI_SUCCESS  Operation completed successfully.\r
+  @retval EFI_TIMEOUT  The register can't run into the expected status in time.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TisPcExecute (\r
+  IN      TIS_TPM_HANDLE            TisReg,\r
+  IN      CONST CHAR8               *Fmt,\r
+  ...\r
+  );\r
+\r
+#endif  // _TPM_COMM_H_\r
diff --git a/SecurityPkg/Tcg/TcgPei/TcgPei.c b/SecurityPkg/Tcg/TcgPei/TcgPei.c
new file mode 100644 (file)
index 0000000..63cadde
--- /dev/null
@@ -0,0 +1,593 @@
+/** @file\r
+  Initialize TPM device and measure FVs before handing off control to DXE.\r
+\r
+Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include <PiPei.h>\r
+\r
+#include <IndustryStandard/Tpm12.h>\r
+#include <IndustryStandard/UefiTcgPlatform.h>\r
+#include <Ppi/FirmwareVolumeInfo.h>\r
+#include <Ppi/LockPhysicalPresence.h>\r
+#include <Ppi/TpmInitialized.h>\r
+#include <Ppi/FirmwareVolume.h>\r
+#include <Guid/TcgEventHob.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/PeiServicesLib.h>\r
+#include <Library/PeimEntryPoint.h>\r
+#include <Library/TpmCommLib.h>\r
+#include <Library/HobLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/PeiServicesTablePointerLib.h>\r
+\r
+#include "TpmComm.h"\r
+\r
+BOOLEAN                 mImageInMemory  = FALSE;\r
+\r
+EFI_PEI_PPI_DESCRIPTOR  mTpmInitializedPpiList = {\r
+  EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,\r
+  &gPeiTpmInitializedPpiGuid,\r
+  NULL\r
+};\r
+\r
+/**\r
+  Lock physical presence if needed.\r
+\r
+  @param[in] PeiServices       An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation\r
+  @param[in] NotifyDescriptor  Address of the notification descriptor data structure.\r
+  @param[in] Ppi               Address of the PPI that was installed.\r
+\r
+  @retval EFI_SUCCESS          Operation completed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PhysicalPresencePpiNotifyCallback (\r
+  IN EFI_PEI_SERVICES              **PeiServices,\r
+  IN EFI_PEI_NOTIFY_DESCRIPTOR     *NotifyDescriptor,\r
+  IN VOID                          *Ppi\r
+  );\r
+\r
+/**\r
+  Measure and record the Firmware Volum Information once FvInfoPPI install.\r
+\r
+  @param[in] PeiServices       An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.\r
+  @param[in] NotifyDescriptor  Address of the notification descriptor data structure.\r
+  @param[in] Ppi               Address of the PPI that was installed.\r
+\r
+  @retval EFI_SUCCESS          The FV Info is measured and recorded to TPM.\r
+  @return Others               Fail to measure FV.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FirmwareVolmeInfoPpiNotifyCallback (\r
+  IN EFI_PEI_SERVICES              **PeiServices,\r
+  IN EFI_PEI_NOTIFY_DESCRIPTOR     *NotifyDescriptor,\r
+  IN VOID                          *Ppi\r
+  );\r
+\r
+EFI_PEI_NOTIFY_DESCRIPTOR           mNotifyList[] = {\r
+  {\r
+    EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,\r
+    &gPeiLockPhysicalPresencePpiGuid,\r
+    PhysicalPresencePpiNotifyCallback\r
+  },\r
+  {\r
+    (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
+    &gEfiPeiFirmwareVolumeInfoPpiGuid,\r
+    FirmwareVolmeInfoPpiNotifyCallback \r
+  }\r
+};\r
+\r
+CHAR8 mSCrtmVersion[] = "{D20BC7C6-A1A5-415c-AE85-38290AB6BE04}";\r
+\r
+EFI_PLATFORM_FIRMWARE_BLOB mMeasuredFvInfo[FixedPcdGet32 (PcdPeiCoreMaxFvSupported)];\r
+UINT32 mMeasuredFvIndex = 0;\r
+\r
+/**\r
+  Do a hash operation on a data buffer, extend a specific TPM PCR with the hash result,\r
+  and build a GUIDed HOB recording the event which will be passed to the DXE phase and\r
+  added into the Event Log.\r
+\r
+  @param[in]      PeiServices   Describes the list of possible PEI Services.\r
+  @param[in]      HashData      Physical address of the start of the data buffer \r
+                                to be hashed, extended, and logged.\r
+  @param[in]      HashDataLen   The length, in bytes, of the buffer referenced by HashData.\r
+  @param[in]      TpmHandle     TPM handle.\r
+  @param[in]      NewEventHdr   Pointer to a TCG_PCR_EVENT_HDR data structure.  \r
+  @param[in]      NewEventData  Pointer to the new event data.  \r
+\r
+  @retval EFI_SUCCESS           Operation completed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  No enough memory to log the new event.\r
+  @retval EFI_DEVICE_ERROR      The command was unsuccessful.\r
+\r
+**/\r
+EFI_STATUS\r
+HashLogExtendEvent (\r
+  IN      EFI_PEI_SERVICES          **PeiServices,\r
+  IN      UINT8                     *HashData,\r
+  IN      UINTN                     HashDataLen,\r
+  IN      TIS_TPM_HANDLE            TpmHandle,\r
+  IN      TCG_PCR_EVENT_HDR         *NewEventHdr,\r
+  IN      UINT8                     *NewEventData\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  VOID                              *HobData;\r
+\r
+  HobData = NULL;\r
+  if (HashDataLen != 0) {\r
+    Status = TpmCommHashAll (\r
+               HashData,\r
+               HashDataLen,\r
+               &NewEventHdr->Digest\r
+               );\r
+    ASSERT_EFI_ERROR (Status);\r
+  }\r
+\r
+  Status = TpmCommExtend (\r
+             PeiServices,\r
+             TpmHandle,\r
+             &NewEventHdr->Digest,\r
+             NewEventHdr->PCRIndex,\r
+             NULL\r
+             );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  HobData = BuildGuidHob (\r
+             &gTcgEventEntryHobGuid,\r
+             sizeof (*NewEventHdr) + NewEventHdr->EventSize\r
+             );\r
+  if (HobData == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  CopyMem (HobData, NewEventHdr, sizeof (*NewEventHdr));\r
+  HobData = (VOID *) ((UINT8*)HobData + sizeof (*NewEventHdr));\r
+  CopyMem (HobData, NewEventData, NewEventHdr->EventSize);\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Measure CRTM version.\r
+\r
+  @param[in]      PeiServices   Describes the list of possible PEI Services.\r
+  @param[in]      TpmHandle     TPM handle.\r
+\r
+  @retval EFI_SUCCESS           Operation completed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  No enough memory to log the new event.\r
+  @retval EFI_DEVICE_ERROR      The command was unsuccessful.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MeasureCRTMVersion (\r
+  IN      EFI_PEI_SERVICES          **PeiServices,\r
+  IN      TIS_TPM_HANDLE            TpmHandle\r
+  )\r
+{\r
+  TCG_PCR_EVENT_HDR                 TcgEventHdr;\r
+\r
+  //\r
+  // Here, only a static GUID is measured instead of real CRTM version.\r
+  // OEMs should get real CRTM version string and measure it.\r
+  //\r
+\r
+  TcgEventHdr.PCRIndex  = 0;\r
+  TcgEventHdr.EventType = EV_S_CRTM_VERSION;\r
+  TcgEventHdr.EventSize = sizeof (mSCrtmVersion);\r
+  return HashLogExtendEvent (\r
+           PeiServices,\r
+           (UINT8*)&mSCrtmVersion,\r
+           TcgEventHdr.EventSize,\r
+           TpmHandle,\r
+           &TcgEventHdr,\r
+           (UINT8*)&mSCrtmVersion\r
+           );\r
+}\r
+\r
+/**\r
+  Measure FV image. \r
+  Add it into the measured FV list after the FV is measured successfully. \r
+\r
+  @param[in]  FvBase            Base address of FV image.\r
+  @param[in]  FvLength          Length of FV image.\r
+\r
+  @retval EFI_SUCCESS           Fv image is measured successfully \r
+                                or it has been already measured.\r
+  @retval EFI_OUT_OF_RESOURCES  No enough memory to log the new event.\r
+  @retval EFI_DEVICE_ERROR      The command was unsuccessful.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MeasureFvImage (\r
+  IN EFI_PHYSICAL_ADDRESS           FvBase,\r
+  IN UINT64                         FvLength\r
+  )\r
+{\r
+  UINT32                            Index;\r
+  EFI_STATUS                        Status;\r
+  EFI_PLATFORM_FIRMWARE_BLOB        FvBlob;\r
+  TCG_PCR_EVENT_HDR                 TcgEventHdr;\r
+  TIS_TPM_HANDLE                    TpmHandle;\r
+\r
+  TpmHandle = (TIS_TPM_HANDLE) (UINTN) TPM_BASE_ADDRESS;\r
+\r
+  //\r
+  // Check whether FV is in the measured FV list.\r
+  //\r
+  for (Index = 0; Index < mMeasuredFvIndex; Index ++) {\r
+    if (mMeasuredFvInfo[Index].BlobBase == FvBase) {\r
+      return EFI_SUCCESS;\r
+    }\r
+  }\r
+  \r
+  //\r
+  // Measure and record the FV to the TPM\r
+  //\r
+  FvBlob.BlobBase   = FvBase;\r
+  FvBlob.BlobLength = FvLength;\r
+\r
+  DEBUG ((DEBUG_INFO, "The FV which is measured by TcgPei starts at: 0x%x\n", FvBlob.BlobBase));\r
+  DEBUG ((DEBUG_INFO, "The FV which is measured by TcgPei has the size: 0x%x\n", FvBlob.BlobLength));\r
+\r
+  TcgEventHdr.PCRIndex = 0;\r
+  TcgEventHdr.EventType = EV_EFI_PLATFORM_FIRMWARE_BLOB;\r
+  TcgEventHdr.EventSize = sizeof (FvBlob);\r
+\r
+  Status = HashLogExtendEvent (\r
+             (EFI_PEI_SERVICES **) GetPeiServicesTablePointer(),\r
+             (UINT8*) (UINTN) FvBlob.BlobBase,\r
+             (UINTN) FvBlob.BlobLength,\r
+             TpmHandle,\r
+             &TcgEventHdr,\r
+             (UINT8*) &FvBlob\r
+             );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // Add new FV into the measured FV list.\r
+  //\r
+  ASSERT (mMeasuredFvIndex < FixedPcdGet32 (PcdPeiCoreMaxFvSupported));\r
+  if (mMeasuredFvIndex < FixedPcdGet32 (PcdPeiCoreMaxFvSupported)) {\r
+    mMeasuredFvInfo[mMeasuredFvIndex].BlobBase   = FvBase;\r
+    mMeasuredFvInfo[mMeasuredFvIndex++].BlobLength = FvLength;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Measure main BIOS.\r
+\r
+  @param[in]      PeiServices   Describes the list of possible PEI Services.\r
+  @param[in]      TpmHandle     TPM handle.\r
+\r
+  @retval EFI_SUCCESS           Operation completed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  No enough memory to log the new event.\r
+  @retval EFI_DEVICE_ERROR      The command was unsuccessful.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MeasureMainBios (\r
+  IN      EFI_PEI_SERVICES          **PeiServices,\r
+  IN      TIS_TPM_HANDLE            TpmHandle\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  UINT32                            FvInstances;\r
+  EFI_PEI_FV_HANDLE                 VolumeHandle;\r
+  EFI_FV_INFO                       VolumeInfo;\r
+  EFI_PEI_FIRMWARE_VOLUME_PPI       *FvPpi;\r
+  \r
+  FvInstances    = 0;\r
+  while (TRUE) {\r
+    //\r
+    // Traverse all firmware volume instances of Static Core Root of Trust for Measurement\r
+    // (S-CRTM), this firmware volume measure policy can be modified/enhanced by special\r
+    // platform for special CRTM TPM measuring.\r
+    //\r
+    Status = PeiServicesFfsFindNextVolume (FvInstances, &VolumeHandle);\r
+    if (EFI_ERROR (Status)) {\r
+      break;\r
+    }\r
+  \r
+    //\r
+    // Measure and record the firmware volume that is dispatched by PeiCore\r
+    //\r
+    Status = PeiServicesFfsGetVolumeInfo (VolumeHandle, &VolumeInfo);\r
+    ASSERT_EFI_ERROR (Status);\r
+    //\r
+    // Locate the corresponding FV_PPI according to founded FV's format guid\r
+    //\r
+    Status = PeiServicesLocatePpi (\r
+               &VolumeInfo.FvFormat, \r
+               0, \r
+               NULL,\r
+               (VOID**)&FvPpi\r
+               );\r
+    if (!EFI_ERROR (Status)) {\r
+      MeasureFvImage ((EFI_PHYSICAL_ADDRESS) (UINTN) VolumeInfo.FvStart, VolumeInfo.FvSize);\r
+    }\r
+\r
+    FvInstances++;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Measure and record the Firmware Volum Information once FvInfoPPI install.\r
+\r
+  @param[in] PeiServices       An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.\r
+  @param[in] NotifyDescriptor  Address of the notification descriptor data structure.\r
+  @param[in] Ppi               Address of the PPI that was installed.\r
+\r
+  @retval EFI_SUCCESS          The FV Info is measured and recorded to TPM.\r
+  @return Others               Fail to measure FV.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FirmwareVolmeInfoPpiNotifyCallback (\r
+  IN EFI_PEI_SERVICES               **PeiServices,\r
+  IN EFI_PEI_NOTIFY_DESCRIPTOR      *NotifyDescriptor,\r
+  IN VOID                           *Ppi\r
+  )\r
+{\r
+  EFI_PEI_FIRMWARE_VOLUME_INFO_PPI  *Fv;\r
+  EFI_STATUS                        Status;\r
+  EFI_PEI_FIRMWARE_VOLUME_PPI       *FvPpi;\r
+\r
+  Fv = (EFI_PEI_FIRMWARE_VOLUME_INFO_PPI *) Ppi;\r
+\r
+  //\r
+  // The PEI Core can not dispatch or load files from memory mapped FVs that do not support FvPpi.\r
+  //\r
+  Status = PeiServicesLocatePpi (\r
+             &Fv->FvFormat, \r
+             0, \r
+             NULL,\r
+             (VOID**)&FvPpi\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_SUCCESS;\r
+  }\r
+  \r
+  //\r
+  // This is an FV from an FFS file, and the parent FV must have already been measured,\r
+  // No need to measure twice, so just returns\r
+  //\r
+  if (Fv->ParentFvName != NULL || Fv->ParentFileName != NULL ) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  return MeasureFvImage ((EFI_PHYSICAL_ADDRESS) (UINTN) Fv->FvInfo, Fv->FvInfoSize);\r
+}\r
+\r
+/**\r
+  Lock physical presence if needed.\r
+\r
+  @param[in] PeiServices        An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation\r
+  @param[in] NotifyDescriptor   Address of the notification descriptor data structure.\r
+  @param[in] Ppi                Address of the PPI that was installed.\r
+\r
+  @retval EFI_SUCCESS           Operation completed successfully.\r
+  @retval EFI_ABORTED           physicalPresenceCMDEnable is locked.\r
+  @retval EFI_DEVICE_ERROR      The command was unsuccessful.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PhysicalPresencePpiNotifyCallback (\r
+  IN EFI_PEI_SERVICES               **PeiServices,\r
+  IN EFI_PEI_NOTIFY_DESCRIPTOR      *NotifyDescriptor,\r
+  IN VOID                           *Ppi\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  PEI_LOCK_PHYSICAL_PRESENCE_PPI    *LockPhysicalPresencePpi;\r
+  BOOLEAN                           LifetimeLock;\r
+  BOOLEAN                           CmdEnable;\r
+  TIS_TPM_HANDLE                    TpmHandle;\r
+\r
+  TpmHandle        = (TIS_TPM_HANDLE) (UINTN) TPM_BASE_ADDRESS;\r
+  LockPhysicalPresencePpi = (PEI_LOCK_PHYSICAL_PRESENCE_PPI *) Ppi;\r
+\r
+  if (!LockPhysicalPresencePpi->LockPhysicalPresence ((CONST EFI_PEI_SERVICES**) PeiServices)) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // Lock TPM physical presence.\r
+  //\r
+\r
+  Status = TpmCommGetCapability (PeiServices, TpmHandle, NULL, &LifetimeLock, &CmdEnable);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  if (!CmdEnable) {\r
+    if (LifetimeLock) {\r
+      //\r
+      // physicalPresenceCMDEnable is locked, can't change.\r
+      //\r
+      return EFI_ABORTED;\r
+    }\r
+\r
+    //\r
+    // Enable physical presence command\r
+    // It is necessary in order to lock physical presence\r
+    //\r
+    Status = TpmCommPhysicalPresence (\r
+               PeiServices,\r
+               TpmHandle,\r
+               TPM_PHYSICAL_PRESENCE_CMD_ENABLE\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Lock physical presence\r
+  // \r
+  Status = TpmCommPhysicalPresence (\r
+              PeiServices,\r
+              TpmHandle,\r
+              TPM_PHYSICAL_PRESENCE_LOCK\r
+              );\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Check if TPM chip is activeated or not.\r
+\r
+  @param[in]      PeiServices   Describes the list of possible PEI Services.\r
+  @param[in]      TpmHandle     TPM handle.\r
+\r
+  @retval TRUE    TPM is activated.\r
+  @retval FALSE   TPM is deactivated.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+IsTpmUsable (\r
+  IN      EFI_PEI_SERVICES          **PeiServices,\r
+  IN      TIS_TPM_HANDLE            TpmHandle\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  BOOLEAN                           Deactivated;\r
+\r
+  Status = TpmCommGetCapability (PeiServices, TpmHandle, &Deactivated, NULL, NULL);\r
+  if (EFI_ERROR (Status)) {\r
+    return FALSE;\r
+  }\r
+  return (BOOLEAN)(!Deactivated); \r
+}\r
+\r
+/**\r
+  Do measurement after memory is ready.\r
+\r
+  @param[in]      PeiServices   Describes the list of possible PEI Services.\r
+\r
+  @retval EFI_SUCCESS           Operation completed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES  No enough memory to log the new event.\r
+  @retval EFI_DEVICE_ERROR      The command was unsuccessful.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PeimEntryMP (\r
+  IN      EFI_PEI_SERVICES          **PeiServices\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  TIS_TPM_HANDLE                    TpmHandle;\r
+\r
+  TpmHandle = (TIS_TPM_HANDLE)(UINTN)TPM_BASE_ADDRESS;\r
+  Status = TisPcRequestUseTpm ((TIS_PC_REGISTERS_PTR)TpmHandle);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  if (IsTpmUsable (PeiServices, TpmHandle)) {\r
+    Status = MeasureCRTMVersion (PeiServices, TpmHandle);\r
+    ASSERT_EFI_ERROR (Status);\r
+\r
+    Status = MeasureMainBios (PeiServices, TpmHandle);\r
+  }  \r
+\r
+  //\r
+  // Post callbacks:\r
+  // 1). for the FvInfoPpi services to measure and record\r
+  // the additional Fvs to TPM\r
+  // 2). for the OperatorPresencePpi service to determine whether to \r
+  // lock the TPM\r
+  //\r
+  Status = PeiServicesNotifyPpi (&mNotifyList[0]);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Entry point of this module.\r
+\r
+  @param[in] FileHandle   Handle of the file being invoked.\r
+  @param[in] PeiServices  Describes the list of possible PEI Services.\r
+\r
+  @return Status.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PeimEntryMA (\r
+  IN       EFI_PEI_FILE_HANDLE      FileHandle,\r
+  IN CONST EFI_PEI_SERVICES         **PeiServices\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  EFI_BOOT_MODE                     BootMode;\r
+  TIS_TPM_HANDLE                    TpmHandle;\r
+\r
+  if (PcdGetBool (PcdHideTpmSupport) && PcdGetBool (PcdHideTpm)) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  Status = (**PeiServices).RegisterForShadow(FileHandle);\r
+  if (Status == EFI_ALREADY_STARTED) {\r
+    mImageInMemory = TRUE;\r
+  } else if (Status == EFI_NOT_FOUND) {\r
+    ASSERT_EFI_ERROR (Status);\r
+  }\r
+\r
+  if (!mImageInMemory) {\r
+    //\r
+    // Initialize TPM device\r
+    //\r
+    Status = PeiServicesGetBootMode (&BootMode);\r
+    ASSERT_EFI_ERROR (Status);\r
+\r
+    TpmHandle = (TIS_TPM_HANDLE)(UINTN)TPM_BASE_ADDRESS;\r
+    Status = TisPcRequestUseTpm ((TIS_PC_REGISTERS_PTR)TpmHandle);\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((DEBUG_ERROR, "TPM not detected!\n"));\r
+      return Status;\r
+    }\r
+\r
+    Status = TpmCommStartup ((EFI_PEI_SERVICES**)PeiServices, TpmHandle, BootMode);\r
+    if (EFI_ERROR (Status) ) {\r
+      return Status;\r
+    }\r
+    Status = TpmCommContinueSelfTest ((EFI_PEI_SERVICES**)PeiServices, TpmHandle);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    Status = PeiServicesInstallPpi (&mTpmInitializedPpiList);\r
+    ASSERT_EFI_ERROR (Status);\r
+  }\r
+\r
+  if (mImageInMemory) {\r
+    Status = PeimEntryMP ((EFI_PEI_SERVICES**)PeiServices);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
diff --git a/SecurityPkg/Tcg/TcgPei/TcgPei.inf b/SecurityPkg/Tcg/TcgPei/TcgPei.inf
new file mode 100644 (file)
index 0000000..60a3bfa
--- /dev/null
@@ -0,0 +1,67 @@
+## @file\r
+#  This module will initialize TPM device and measure FVs in PEI phase.\r
+#\r
+# Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = TcgPei\r
+  FILE_GUID                      = 2BE1E4A6-6505-43b3-9FFC-A3C8330E0432\r
+  MODULE_TYPE                    = PEIM\r
+  VERSION_STRING                 = 1.0\r
+  ENTRY_POINT                    = PeimEntryMA\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC\r
+#\r
+\r
+[Sources]\r
+  TcgPei.c\r
+  TisPei.c\r
+  TpmComm.c\r
+  TpmComm.h\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+  SecurityPkg/SecurityPkg.dec\r
+\r
+[LibraryClasses]\r
+  HobLib\r
+  PeimEntryPoint\r
+  PeiServicesLib\r
+  BaseMemoryLib\r
+  DebugLib\r
+  TpmCommLib\r
+  TimerLib\r
+  IoLib\r
+  PeiServicesTablePointerLib\r
+\r
+[Guids]\r
+  gTcgEventEntryHobGuid\r
+\r
+[Ppis]\r
+  gPeiLockPhysicalPresencePpiGuid\r
+  gEfiPeiFirmwareVolumeInfoPpiGuid\r
+  gPeiTpmInitializedPpiGuid\r
+\r
+[Pcd]\r
+  gEfiSecurityPkgTokenSpaceGuid.PcdHideTpm\r
+\r
+[FixedPcd]\r
+  gEfiSecurityPkgTokenSpaceGuid.PcdHideTpmSupport\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdPeiCoreMaxFvSupported             ## CONSUMES\r
+\r
+[Depex]\r
+  gEfiPeiMasterBootModePpiGuid AND\r
+  gEfiPeiReadOnlyVariable2PpiGuid\r
diff --git a/SecurityPkg/Tcg/TcgPei/TisPei.c b/SecurityPkg/Tcg/TcgPei/TisPei.c
new file mode 100644 (file)
index 0000000..97d9628
--- /dev/null
@@ -0,0 +1,160 @@
+/** @file\r
+  TIS (TPM Interface Specification) functions used by TPM PEI driver.\r
+  \r
+Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include <IndustryStandard/Tpm12.h>\r
+#include <IndustryStandard/UefiTcgPlatform.h>\r
+#include <Library/TpmCommLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/IoLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+\r
+/**\r
+  Send a command to TPM for execution and return response data.\r
+\r
+  @param[in]      PeiServices   Describes the list of possible PEI Services.\r
+  @param[in]      TisReg        TPM register space base address.  \r
+  @param[in]      BufferIn      Buffer for command data.  \r
+  @param[in]      SizeIn        Size of command data.  \r
+  @param[in, out] BufferOut     Buffer for response data.  \r
+  @param[in, out] SizeOut       Size of response data.  \r
\r
+  @retval EFI_SUCCESS           Operation completed successfully.\r
+  @retval EFI_TIMEOUT           The register can't run into the expected status in time.\r
+  @retval EFI_BUFFER_TOO_SMALL  Response data buffer is too small.\r
+  @retval EFI_DEVICE_ERROR      Unexpected device behavior.\r
+\r
+**/\r
+EFI_STATUS\r
+TisTpmCommand (\r
+  IN     EFI_PEI_SERVICES           **PeiServices,\r
+  IN     TIS_PC_REGISTERS_PTR       TisReg,\r
+  IN     UINT8                      *BufferIn,\r
+  IN     UINT32                     SizeIn,\r
+  IN OUT UINT8                      *BufferOut,\r
+  IN OUT UINT32                     *SizeOut\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  UINT16                            BurstCount;\r
+  UINT32                            Index;\r
+  UINT32                            TpmOutSize;\r
+  UINT16                            Data16;\r
+  UINT32                            Data32;\r
+\r
+  Status = TisPcPrepareCommand (TisReg);\r
+  if (EFI_ERROR (Status)){\r
+    DEBUG ((DEBUG_ERROR, "Tpm is not ready for command!\n"));\r
+    return Status;\r
+  }\r
+  //\r
+  // Send the command data to Tpm\r
+  //\r
+  Index = 0;\r
+  while (Index < SizeIn) {\r
+    Status = TisPcReadBurstCount (TisReg, &BurstCount);\r
+    if (EFI_ERROR (Status)) {\r
+      Status = EFI_TIMEOUT;\r
+      goto Exit;\r
+    }\r
+    for (; BurstCount > 0 && Index < SizeIn; BurstCount--) {\r
+      MmioWrite8((UINTN)&TisReg->DataFifo, *(BufferIn + Index));\r
+      Index++;\r
+    }\r
+  }\r
+  //\r
+  // Check the Tpm status STS_EXPECT change from 1 to 0\r
+  //\r
+  Status = TisPcWaitRegisterBits (\r
+             &TisReg->Status,\r
+             (UINT8) TIS_PC_VALID,\r
+             TIS_PC_STS_EXPECT,\r
+             TIS_TIMEOUT_C\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_ERROR, "The send buffer too small!\n"));\r
+    Status = EFI_BUFFER_TOO_SMALL;\r
+    goto Exit;\r
+  }\r
+  //\r
+  // Executed the TPM command and waiting for the response data ready\r
+  //\r
+  MmioWrite8((UINTN)&TisReg->Status, TIS_PC_STS_GO);\r
+  Status = TisPcWaitRegisterBits (\r
+             &TisReg->Status,\r
+             (UINT8) (TIS_PC_VALID | TIS_PC_STS_DATA),\r
+             0,\r
+             TIS_TIMEOUT_B\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_ERROR, "Wait for Tpm response data time out!!\n"));\r
+    Status = EFI_TIMEOUT;\r
+    goto Exit;\r
+  }\r
+  //\r
+  // Get response data header\r
+  //\r
+  Index = 0;\r
+  BurstCount = 0;\r
+  while (Index < sizeof (TPM_RSP_COMMAND_HDR)) {\r
+    Status = TisPcReadBurstCount (TisReg, &BurstCount);\r
+    if (EFI_ERROR (Status)) {\r
+      Status = EFI_TIMEOUT;\r
+      goto Exit;\r
+    }\r
+    for (; BurstCount > 0; BurstCount--) {\r
+      *(BufferOut + Index) = MmioRead8 ((UINTN)&TisReg->DataFifo);\r
+      Index++;\r
+      if (Index == sizeof (TPM_RSP_COMMAND_HDR)) break;\r
+    }\r
+  }\r
+  //\r
+  // Check the reponse data header (tag,parasize and returncode )\r
+  //\r
+  CopyMem (&Data16, BufferOut, sizeof (UINT16));\r
+  if (SwapBytes16 (Data16) != TPM_TAG_RSP_COMMAND ) {\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto Exit;\r
+  }\r
+  \r
+  CopyMem (&Data32, (BufferOut + 2), sizeof (UINT32));\r
+  TpmOutSize  = SwapBytes32 (Data32);\r
+  if (*SizeOut < TpmOutSize) {\r
+    Status = EFI_BUFFER_TOO_SMALL;\r
+    goto Exit;\r
+  }\r
+  *SizeOut = TpmOutSize;\r
+  //\r
+  // Continue reading the remaining data\r
+  //\r
+  while ( Index < TpmOutSize ) {\r
+    for (; BurstCount > 0; BurstCount--) {\r
+      *(BufferOut + Index) = MmioRead8 ((UINTN)&TisReg->DataFifo);\r
+      Index++;\r
+      if (Index == TpmOutSize) {\r
+        Status = EFI_SUCCESS;\r
+        goto Exit;\r
+      }\r
+    }\r
+    Status = TisPcReadBurstCount (TisReg, &BurstCount);\r
+    if (EFI_ERROR (Status)) {\r
+      Status = EFI_TIMEOUT;\r
+      goto Exit;\r
+    }\r
+  }\r
+Exit:\r
+  MmioWrite8((UINTN)&TisReg->Status, TIS_PC_STS_READY);\r
+  return Status;\r
+}\r
+\r
diff --git a/SecurityPkg/Tcg/TcgPei/TpmComm.c b/SecurityPkg/Tcg/TcgPei/TpmComm.c
new file mode 100644 (file)
index 0000000..fb5011e
--- /dev/null
@@ -0,0 +1,272 @@
+/** @file\r
+  Utility functions used by TPM PEI driver.\r
+  \r
+Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "TpmComm.h"\r
+\r
+/**\r
+  Send a command to TPM for execution and return response data.\r
+\r
+  @param[in]      PeiServices   Describes the list of possible PEI Services.\r
+  @param[in]      TisReg        TPM register space base address.  \r
+  @param[in]      BufferIn      Buffer for command data.  \r
+  @param[in]      SizeIn        Size of command data.  \r
+  @param[in, out] BufferOut     Buffer for response data.  \r
+  @param[in, out] SizeOut       size of response data.  \r
\r
+  @retval EFI_SUCCESS           Operation completed successfully.\r
+  @retval EFI_TIMEOUT           The register can't run into the expected status in time.\r
+  @retval EFI_BUFFER_TOO_SMALL  Response data buffer is too small.\r
+  @retval EFI_DEVICE_ERROR      Unexpected device behavior.\r
+\r
+**/\r
+EFI_STATUS\r
+TisTpmCommand (\r
+  IN     EFI_PEI_SERVICES           **PeiServices,\r
+  IN     TIS_PC_REGISTERS_PTR       TisReg,\r
+  IN     UINT8                      *BufferIn,\r
+  IN     UINT32                     SizeIn,\r
+  IN OUT UINT8                      *BufferOut,\r
+  IN OUT UINT32                     *SizeOut\r
+  );\r
+\r
+/**\r
+  Send TPM_Startup command to TPM.\r
+\r
+  @param[in] PeiServices        Describes the list of possible PEI Services.\r
+  @param[in] TpmHandle          TPM handle.  \r
+  @param[in] BootMode           Boot mode.  \r
\r
+  @retval EFI_SUCCESS           Operation completed successfully.\r
+  @retval EFI_TIMEOUT           The register can't run into the expected status in time.\r
+  @retval EFI_BUFFER_TOO_SMALL  Response data buffer is too small.\r
+  @retval EFI_DEVICE_ERROR      Unexpected device behavior.\r
+\r
+**/\r
+EFI_STATUS\r
+TpmCommStartup (\r
+  IN      EFI_PEI_SERVICES          **PeiServices,\r
+  IN      TIS_TPM_HANDLE            TpmHandle,\r
+  IN      EFI_BOOT_MODE             BootMode\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  TPM_STARTUP_TYPE                  TpmSt;\r
+  UINT32                            TpmRecvSize;\r
+  UINT32                            TpmSendSize;\r
+  TPM_CMD_START_UP                  SendBuffer;\r
+  UINT8                             RecvBuffer[20];\r
+\r
+  TpmSt = TPM_ST_CLEAR;\r
+  if (BootMode == BOOT_ON_S3_RESUME) {\r
+    TpmSt = TPM_ST_STATE;\r
+  }\r
+  //\r
+  // send Tpm command TPM_ORD_Startup\r
+  //\r
+  TpmRecvSize               = 20;\r
+  TpmSendSize               = sizeof (TPM_CMD_START_UP);\r
+  SendBuffer.Hdr.tag        = SwapBytes16 (TPM_TAG_RQU_COMMAND);\r
+  SendBuffer.Hdr.paramSize  = SwapBytes32 (TpmSendSize);\r
+  SendBuffer.Hdr.ordinal    = SwapBytes32 (TPM_ORD_Startup);\r
+  SendBuffer.TpmSt          = SwapBytes16 (TpmSt);\r
+  Status = TisTpmCommand (PeiServices, TpmHandle, (UINT8 *)&SendBuffer, TpmSendSize, RecvBuffer, &TpmRecvSize);\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Send TPM_ContinueSelfTest command to TPM.\r
+\r
+  @param[in] PeiServices        Describes the list of possible PEI Services.\r
+  @param[in] TpmHandle          TPM handle.  \r
\r
+  @retval EFI_SUCCESS           Operation completed successfully.\r
+  @retval EFI_TIMEOUT           The register can't run into the expected status in time.\r
+  @retval EFI_BUFFER_TOO_SMALL  Response data buffer is too small.\r
+  @retval EFI_DEVICE_ERROR      Unexpected device behavior.\r
+\r
+**/\r
+EFI_STATUS\r
+TpmCommContinueSelfTest (\r
+  IN      EFI_PEI_SERVICES          **PeiServices,\r
+  IN      TIS_TPM_HANDLE            TpmHandle\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  UINT32                            TpmRecvSize;\r
+  UINT32                            TpmSendSize;\r
+  TPM_CMD_SELF_TEST                 SendBuffer;\r
+  UINT8                             RecvBuffer[20];\r
+\r
+  //\r
+  // send Tpm command TPM_ORD_ContinueSelfTest\r
+  //\r
+  TpmRecvSize               = 20;\r
+  TpmSendSize               = sizeof (TPM_CMD_SELF_TEST);\r
+  SendBuffer.Hdr.tag        = SwapBytes16 (TPM_TAG_RQU_COMMAND);\r
+  SendBuffer.Hdr.paramSize  = SwapBytes32 (TpmSendSize);  \r
+  SendBuffer.Hdr.ordinal    = SwapBytes32 (TPM_ORD_ContinueSelfTest);\r
+  Status = TisTpmCommand (PeiServices, TpmHandle, (UINT8 *)&SendBuffer, TpmSendSize, RecvBuffer, &TpmRecvSize);\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Get TPM capability flags.\r
+\r
+  @param[in]  PeiServices       Describes the list of possible PEI Services.\r
+  @param[in]  TpmHandle         TPM handle.  \r
+  @param[out] Deactivated       Returns deactivated flag.\r
+  @param[out] LifetimeLock      Returns physicalPresenceLifetimeLock permanent flag.  \r
+  @param[out] CmdEnable         Returns physicalPresenceCMDEnable permanent flag.\r
\r
+  @retval EFI_SUCCESS           Operation completed successfully.\r
+  @retval EFI_TIMEOUT           The register can't run into the expected status in time.\r
+  @retval EFI_BUFFER_TOO_SMALL  Response data buffer is too small.\r
+  @retval EFI_DEVICE_ERROR      Unexpected device behavior.\r
+\r
+**/\r
+EFI_STATUS\r
+TpmCommGetCapability (\r
+  IN      EFI_PEI_SERVICES          **PeiServices,\r
+  IN      TIS_TPM_HANDLE            TpmHandle,\r
+     OUT  BOOLEAN                   *Deactivated, OPTIONAL\r
+     OUT  BOOLEAN                   *LifetimeLock, OPTIONAL\r
+     OUT  BOOLEAN                   *CmdEnable OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  UINT32                            TpmRecvSize;\r
+  UINT32                            TpmSendSize;\r
+  TPM_CMD_GET_CAPABILITY            SendBuffer;\r
+  UINT8                             RecvBuffer[40];\r
+  TPM_PERMANENT_FLAGS               *TpmPermanentFlags;\r
+\r
+  //\r
+  // send Tpm command TPM_ORD_GetCapability\r
+  //\r
+  TpmRecvSize                   = 40;\r
+  TpmSendSize                   = sizeof (TPM_CMD_GET_CAPABILITY);\r
+  SendBuffer.Hdr.tag            = SwapBytes16 (TPM_TAG_RQU_COMMAND);\r
+  SendBuffer.Hdr.paramSize      = SwapBytes32 (TpmSendSize);  \r
+  SendBuffer.Hdr.ordinal        = SwapBytes32 (TPM_ORD_GetCapability);\r
+  SendBuffer.Capability         = SwapBytes32 (TPM_CAP_FLAG);\r
+  SendBuffer.CapabilityFlagSize = SwapBytes32 (sizeof (TPM_CAP_FLAG_PERMANENT));\r
+  SendBuffer.CapabilityFlag     = SwapBytes32 (TPM_CAP_FLAG_PERMANENT);\r
+  Status = TisTpmCommand (PeiServices, TpmHandle, (UINT8 *)&SendBuffer, TpmSendSize, RecvBuffer, &TpmRecvSize);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  TpmPermanentFlags = (TPM_PERMANENT_FLAGS *)&RecvBuffer[sizeof (TPM_RSP_COMMAND_HDR) + sizeof (UINT32)];\r
+  if (Deactivated != NULL) {\r
+    *Deactivated      = TpmPermanentFlags->deactivated;\r
+  }\r
+\r
+  if (LifetimeLock != NULL) {\r
+    *LifetimeLock = TpmPermanentFlags->physicalPresenceLifetimeLock;\r
+  }\r
+\r
+  if (CmdEnable != NULL) {\r
+    *CmdEnable = TpmPermanentFlags->physicalPresenceCMDEnable;\r
+  }\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Extend a TPM PCR.\r
+\r
+  @param[in]  PeiServices       Describes the list of possible PEI Services.\r
+  @param[in]  TpmHandle         TPM handle.  \r
+  @param[in]  DigestToExtend    The 160 bit value representing the event to be recorded.  \r
+  @param[in]  PcrIndex          The PCR to be updated.\r
+  @param[out] NewPcrValue       New PCR value after extend.  \r
\r
+  @retval EFI_SUCCESS           Operation completed successfully.\r
+  @retval EFI_TIMEOUT           The register can't run into the expected status in time.\r
+  @retval EFI_BUFFER_TOO_SMALL  Response data buffer is too small.\r
+  @retval EFI_DEVICE_ERROR      Unexpected device behavior.\r
+\r
+**/\r
+EFI_STATUS\r
+TpmCommExtend (\r
+  IN      EFI_PEI_SERVICES          **PeiServices,\r
+  IN      TIS_TPM_HANDLE            TpmHandle,\r
+  IN      TPM_DIGEST                *DigestToExtend,\r
+  IN      TPM_PCRINDEX              PcrIndex,\r
+     OUT  TPM_DIGEST                *NewPcrValue\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  UINT32                            TpmSendSize;\r
+  UINT32                            TpmRecvSize;\r
+  TPM_CMD_EXTEND                    SendBuffer;\r
+  UINT8                             RecvBuffer[10 + sizeof(TPM_DIGEST)];\r
+\r
+  //\r
+  // send Tpm command TPM_ORD_Extend\r
+  //\r
+  TpmRecvSize               = sizeof (TPM_RSP_COMMAND_HDR) + sizeof (TPM_DIGEST);\r
+  TpmSendSize               = sizeof (TPM_CMD_EXTEND);\r
+  SendBuffer.Hdr.tag        = SwapBytes16 (TPM_TAG_RQU_COMMAND);\r
+  SendBuffer.Hdr.paramSize  = SwapBytes32 (TpmSendSize);\r
+  SendBuffer.Hdr.ordinal    = SwapBytes32 (TPM_ORD_Extend);\r
+  SendBuffer.PcrIndex       = SwapBytes32 (PcrIndex);\r
+  CopyMem (&SendBuffer.TpmDigest, (UINT8 *)DigestToExtend, sizeof (TPM_DIGEST));\r
+  Status = TisTpmCommand (PeiServices, TpmHandle, (UINT8 *)&SendBuffer, TpmSendSize, RecvBuffer, &TpmRecvSize);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  if(NewPcrValue != NULL) {\r
+    CopyMem ((UINT8*)NewPcrValue, &RecvBuffer[10], sizeof (TPM_DIGEST));\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Send TSC_PhysicalPresence command to TPM.\r
+\r
+  @param[in] PeiServices        Describes the list of possible PEI Services.\r
+  @param[in] TpmHandle          TPM handle.  \r
+  @param[in] PhysicalPresence   The state to set the TPMs Physical Presence flags.  \r
\r
+  @retval EFI_SUCCESS           Operation completed successfully.\r
+  @retval EFI_TIMEOUT           The register can't run into the expected status in time.\r
+  @retval EFI_BUFFER_TOO_SMALL  Response data buffer is too small.\r
+  @retval EFI_DEVICE_ERROR      Unexpected device behavior.\r
+\r
+**/\r
+EFI_STATUS\r
+TpmCommPhysicalPresence (\r
+  IN      EFI_PEI_SERVICES          **PeiServices,\r
+  IN      TIS_TPM_HANDLE            TpmHandle,\r
+  IN      TPM_PHYSICAL_PRESENCE     PhysicalPresence\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  UINT32                            TpmSendSize;\r
+  UINT32                            TpmRecvSize;\r
+  TPM_CMD_PHYSICAL_PRESENCE         SendBuffer;\r
+  UINT8                             RecvBuffer[10];\r
+\r
+  //\r
+  // send Tpm command TSC_ORD_PhysicalPresence\r
+  //\r
+  TpmRecvSize                 = 10;\r
+  TpmSendSize                 = sizeof (TPM_CMD_PHYSICAL_PRESENCE);\r
+  SendBuffer.Hdr.tag          = SwapBytes16 (TPM_TAG_RQU_COMMAND);\r
+  SendBuffer.Hdr.paramSize    = SwapBytes32 (TpmSendSize);\r
+  SendBuffer.Hdr.ordinal      = SwapBytes32 (TSC_ORD_PhysicalPresence);\r
+  SendBuffer.PhysicalPresence = SwapBytes16 (PhysicalPresence);\r
+  Status = TisTpmCommand (PeiServices, TpmHandle, (UINT8 *)&SendBuffer, TpmSendSize, RecvBuffer, &TpmRecvSize);\r
+  return Status;\r
+}\r
diff --git a/SecurityPkg/Tcg/TcgPei/TpmComm.h b/SecurityPkg/Tcg/TcgPei/TpmComm.h
new file mode 100644 (file)
index 0000000..52d7f2e
--- /dev/null
@@ -0,0 +1,163 @@
+/** @file\r
+  The header file for TPM PEI driver.\r
+  \r
+Copyright (c) 2005 - 2010, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _TPM_COMM_H_\r
+#define _TPM_COMM_H_\r
+\r
+#include <IndustryStandard/Tpm12.h>\r
+#include <IndustryStandard/UefiTcgPlatform.h>\r
+#include <Library/TpmCommLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+\r
+#pragma pack(1)\r
+\r
+typedef struct {\r
+  TPM_RQU_COMMAND_HDR   Hdr;\r
+  TPM_STARTUP_TYPE      TpmSt;\r
+} TPM_CMD_START_UP;\r
+\r
+typedef struct {\r
+  TPM_RQU_COMMAND_HDR   Hdr;\r
+} TPM_CMD_SELF_TEST;\r
+\r
+typedef struct {\r
+  TPM_RQU_COMMAND_HDR   Hdr;\r
+  UINT32                Capability;\r
+  UINT32                CapabilityFlagSize;\r
+  UINT32                CapabilityFlag;\r
+} TPM_CMD_GET_CAPABILITY;\r
+\r
+typedef struct {\r
+  TPM_RQU_COMMAND_HDR   Hdr;\r
+  TPM_PCRINDEX          PcrIndex;\r
+  TPM_DIGEST            TpmDigest;\r
+} TPM_CMD_EXTEND;\r
+\r
+typedef struct {\r
+  TPM_RQU_COMMAND_HDR   Hdr;\r
+  TPM_PHYSICAL_PRESENCE PhysicalPresence;\r
+} TPM_CMD_PHYSICAL_PRESENCE;\r
+\r
+#pragma pack()\r
+\r
+/**\r
+  Send TPM_Startup command to TPM.\r
+\r
+  @param[in] PeiServices        Describes the list of possible PEI Services.\r
+  @param[in] TpmHandle          TPM handle.  \r
+  @param[in] BootMode           Boot mode.  \r
\r
+  @retval EFI_SUCCESS           Operation completed successfully.\r
+  @retval EFI_TIMEOUT           The register can't run into the expected status in time.\r
+  @retval EFI_BUFFER_TOO_SMALL  Response data buffer is too small.\r
+  @retval EFI_DEVICE_ERROR      Unexpected device behavior.\r
+\r
+**/\r
+EFI_STATUS\r
+TpmCommStartup (\r
+  IN      EFI_PEI_SERVICES          **PeiServices,\r
+  IN      TIS_TPM_HANDLE            TpmHandle,\r
+  IN      EFI_BOOT_MODE             BootMode\r
+  );\r
+\r
+/**\r
+  Send TPM_ContinueSelfTest command to TPM.\r
+\r
+  @param[in] PeiServices        Describes the list of possible PEI Services.\r
+  @param[in] TpmHandle          TPM handle.  \r
\r
+  @retval EFI_SUCCESS           Operation completed successfully.\r
+  @retval EFI_TIMEOUT           The register can't run into the expected status in time.\r
+  @retval EFI_BUFFER_TOO_SMALL  Response data buffer is too small.\r
+  @retval EFI_DEVICE_ERROR      Unexpected device behavior.\r
+\r
+**/\r
+EFI_STATUS\r
+TpmCommContinueSelfTest (\r
+  IN      EFI_PEI_SERVICES          **PeiServices,\r
+  IN      TIS_TPM_HANDLE            TpmHandle\r
+  );\r
+\r
+/**\r
+  Get TPM capability flags.\r
+\r
+  @param[in]  PeiServices       Describes the list of possible PEI Services.\r
+  @param[in]  TpmHandle         TPM handle.  \r
+  @param[out] Deactivated       Returns deactivated flag.\r
+  @param[out] LifetimeLock      Returns physicalPresenceLifetimeLock permanent flag.  \r
+  @param[out] CmdEnable         Returns physicalPresenceCMDEnable permanent flag.\r
\r
+  @retval EFI_SUCCESS           Operation completed successfully.\r
+  @retval EFI_TIMEOUT           The register can't run into the expected status in time.\r
+  @retval EFI_BUFFER_TOO_SMALL  Response data buffer is too small.\r
+  @retval EFI_DEVICE_ERROR      Unexpected device behavior.\r
+\r
+**/\r
+EFI_STATUS\r
+TpmCommGetCapability (\r
+  IN      EFI_PEI_SERVICES          **PeiServices,\r
+  IN      TIS_TPM_HANDLE            TpmHandle,\r
+     OUT  BOOLEAN                   *Deactivated, OPTIONAL\r
+     OUT  BOOLEAN                   *LifetimeLock, OPTIONAL\r
+     OUT  BOOLEAN                   *CmdEnable OPTIONAL\r
+  );\r
+\r
+/**\r
+  Extend a TPM PCR.\r
+\r
+  @param[in]  PeiServices       Describes the list of possible PEI Services.\r
+  @param[in]  TpmHandle         TPM handle.  \r
+  @param[in]  DigestToExtend    The 160 bit value representing the event to be recorded.  \r
+  @param[in]  PcrIndex          The PCR to be updated.\r
+  @param[out] NewPcrValue       New PCR value after extend.  \r
\r
+  @retval EFI_SUCCESS           Operation completed successfully.\r
+  @retval EFI_TIMEOUT           The register can't run into the expected status in time.\r
+  @retval EFI_BUFFER_TOO_SMALL  Response data buffer is too small.\r
+  @retval EFI_DEVICE_ERROR      Unexpected device behavior.\r
+\r
+**/\r
+EFI_STATUS\r
+TpmCommExtend (\r
+  IN      EFI_PEI_SERVICES          **PeiServices,\r
+  IN      TIS_TPM_HANDLE            TpmHandle,\r
+  IN      TPM_DIGEST                *DigestToExtend,\r
+  IN      TPM_PCRINDEX              PcrIndex,\r
+     OUT  TPM_DIGEST                *NewPcrValue\r
+  );\r
+\r
+\r
+/**\r
+  Send TSC_PhysicalPresence command to TPM.\r
+\r
+  @param[in] PeiServices        Describes the list of possible PEI Services.\r
+  @param[in] TpmHandle          TPM handle.  \r
+  @param[in] PhysicalPresence   The state to set the TPMs Physical Presence flags.  \r
\r
+  @retval EFI_SUCCESS           Operation completed successfully.\r
+  @retval EFI_TIMEOUT           The register can't run into the expected status in time.\r
+  @retval EFI_BUFFER_TOO_SMALL  Response data buffer is too small.\r
+  @retval EFI_DEVICE_ERROR      Unexpected device behavior.\r
+\r
+**/\r
+EFI_STATUS\r
+TpmCommPhysicalPresence (\r
+  IN      EFI_PEI_SERVICES          **PeiServices,\r
+  IN      TIS_TPM_HANDLE            TpmHandle,\r
+  IN      TPM_PHYSICAL_PRESENCE     PhysicalPresence\r
+  );\r
+\r
+#endif  // _TPM_COMM_H_\r
diff --git a/SecurityPkg/Tcg/TcgSmm/TcgSmm.c b/SecurityPkg/Tcg/TcgSmm/TcgSmm.c
new file mode 100644 (file)
index 0000000..9116944
--- /dev/null
@@ -0,0 +1,455 @@
+/** @file\r
+  It updates TPM items in ACPI table and registers SMI callback\r
+  functions for physical presence and ClearMemory.\r
+\r
+Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+\r
+#include <PiDxe.h>\r
+#include <IndustryStandard/Acpi.h>\r
+#include <Guid/PhysicalPresenceData.h>\r
+#include <Guid/MemoryOverwriteControl.h>\r
+#include <Protocol/SmmSwDispatch2.h>\r
+#include <Protocol/AcpiTable.h>\r
+#include <Protocol/SmmVariable.h>\r
+\r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/SmmServicesTableLib.h>\r
+#include <Library/UefiDriverEntryPoint.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/DxeServicesLib.h>\r
+\r
+//\r
+// AML parsing definitions\r
+//\r
+#define AML_OPREGION_OP     0x80\r
+#define AML_BYTE_PREFIX     0x0A\r
+#define AML_DWORD_PREFIX    0x0C\r
+\r
+#pragma pack(1)\r
+typedef struct {\r
+  UINT8                  SoftwareSmi;\r
+  UINT32                 Parameter;\r
+  UINT32                 Response;\r
+  UINT32                 Request;\r
+  UINT32                 LastRequest;\r
+  UINT32                 ReturnCode;\r
+} PHYSICAL_PRESENCE_NVS;\r
+\r
+typedef struct {\r
+  UINT8                  SoftwareSmi;\r
+  UINT32                 Parameter;\r
+  UINT32                 Request;\r
+} MEMORY_CLEAR_NVS;\r
+\r
+typedef struct {\r
+  PHYSICAL_PRESENCE_NVS  PhysicalPresence;\r
+  MEMORY_CLEAR_NVS       MemoryClear;\r
+} TCG_NVS;\r
+\r
+typedef struct {\r
+  UINT8                  OpRegionOp;\r
+  UINT32                 NameString;\r
+  UINT8                  RegionSpace;\r
+  UINT8                  DWordPrefix;\r
+  UINT32                 RegionOffset;\r
+  UINT8                  BytePrefix;\r
+  UINT8                  RegionLen;\r
+} AML_OP_REGION_32_8;\r
+#pragma pack()\r
+\r
+EFI_SMM_VARIABLE_PROTOCOL  *mSmmVariable;\r
+TCG_NVS                    *mTcgNvs;\r
+\r
+/**\r
+  Software SMI callback for TPM physical presence which is called from ACPI method.\r
+\r
+  @param[in]      DispatchHandle  The unique handle assigned to this handler by SmiHandlerRegister().\r
+  @param[in]      Context         Points to an optional handler context which was specified when the\r
+                                  handler was registered.\r
+  @param[in, out] CommBuffer      A pointer to a collection of data in memory that will\r
+                                  be conveyed from a non-SMM environment into an SMM environment.\r
+  @param[in, out] CommBufferSize  The size of the CommBuffer.\r
+\r
+  @retval EFI_SUCCESS             The interrupt was handled successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PhysicalPresenceCallback (\r
+  IN EFI_HANDLE                  DispatchHandle,\r
+  IN CONST VOID                  *Context,\r
+  IN OUT VOID                    *CommBuffer,\r
+  IN OUT UINTN                   *CommBufferSize\r
+  )\r
+{\r
+  EFI_STATUS                     Status;\r
+  UINTN                          DataSize;\r
+  EFI_PHYSICAL_PRESENCE          PpData;\r
+  UINT8                          Flags;\r
+  BOOLEAN                        RequestConfirmed;\r
+\r
+  //\r
+  // Get the Physical Presence variable\r
+  //\r
+  DataSize = sizeof (EFI_PHYSICAL_PRESENCE);\r
+  Status = mSmmVariable->SmmGetVariable (\r
+                           PHYSICAL_PRESENCE_VARIABLE,\r
+                           &gEfiPhysicalPresenceGuid,\r
+                           NULL,\r
+                           &DataSize,\r
+                           &PpData\r
+                           );\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  DEBUG ((EFI_D_INFO, "[TPM] PP callback, Parameter = %x\n", mTcgNvs->PhysicalPresence.Parameter));\r
+  if (mTcgNvs->PhysicalPresence.Parameter == 5) {\r
+    //\r
+    // Return TPM Operation Response to OS Environment\r
+    //\r
+    mTcgNvs->PhysicalPresence.LastRequest = PpData.LastPPRequest;\r
+    mTcgNvs->PhysicalPresence.Response    = PpData.PPResponse;\r
+\r
+  } else if ((mTcgNvs->PhysicalPresence.Parameter == 2) || (mTcgNvs->PhysicalPresence.Parameter == 7)) {\r
+    //\r
+    // Submit TPM Operation Request to Pre-OS Environment\r
+    //\r
+\r
+    if (mTcgNvs->PhysicalPresence.Request == SET_OPERATOR_AUTH) {\r
+      //\r
+      // This command requires UI to prompt user for Auth data, NOT implemented.\r
+      //\r
+      mTcgNvs->PhysicalPresence.ReturnCode = 1;\r
+      return EFI_SUCCESS;\r
+    }\r
+\r
+    if (PpData.PPRequest != mTcgNvs->PhysicalPresence.Request) {\r
+      PpData.PPRequest = (UINT8) mTcgNvs->PhysicalPresence.Request;\r
+      DataSize = sizeof (EFI_PHYSICAL_PRESENCE);\r
+      Status = mSmmVariable->SmmSetVariable (\r
+                               PHYSICAL_PRESENCE_VARIABLE,\r
+                               &gEfiPhysicalPresenceGuid,\r
+                               EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
+                               DataSize,\r
+                               &PpData\r
+                               );\r
+    }\r
+\r
+    if (EFI_ERROR (Status)) { \r
+      //\r
+      // General failure.\r
+      //\r
+      mTcgNvs->PhysicalPresence.ReturnCode = 2;\r
+      return EFI_SUCCESS;\r
+    }\r
+    mTcgNvs->PhysicalPresence.ReturnCode = 0;\r
+  } else if (mTcgNvs->PhysicalPresence.Parameter == 8) {\r
+    // \r
+    // Get User Confirmation Status for Operation\r
+    //\r
+    Flags = PpData.Flags;  \r
+    RequestConfirmed = FALSE;\r
+\r
+    switch (mTcgNvs->PhysicalPresence.Request) {\r
+      case ENABLE:\r
+      case DISABLE:\r
+      case ACTIVATE:\r
+      case DEACTIVATE:\r
+      case ENABLE_ACTIVATE:\r
+      case DEACTIVATE_DISABLE:\r
+      case SET_OWNER_INSTALL_TRUE:\r
+      case SET_OWNER_INSTALL_FALSE:\r
+      case ENABLE_ACTIVATE_OWNER_TRUE:\r
+      case DEACTIVATE_DISABLE_OWNER_FALSE:\r
+        if ((Flags & FLAG_NO_PPI_PROVISION) != 0) {\r
+          RequestConfirmed = TRUE;\r
+        }\r
+        break;\r
+\r
+      case CLEAR:\r
+      case ENABLE_ACTIVATE_CLEAR:\r
+        if ((Flags & FLAG_NO_PPI_CLEAR) != 0) {\r
+          RequestConfirmed = TRUE;\r
+        }\r
+        break;\r
+\r
+      case DEFERRED_PP_UNOWNERED_FIELD_UPGRADE:\r
+        if ((Flags & FLAG_NO_PPI_MAINTENANCE) != 0) {\r
+          RequestConfirmed = TRUE;\r
+        }\r
+        break;\r
+\r
+      case ENABLE_ACTIVATE_CLEAR_ENABLE_ACTIVATE:\r
+      case CLEAR_ENABLE_ACTIVATE:\r
+        if ((Flags & FLAG_NO_PPI_CLEAR) != 0 && (Flags & FLAG_NO_PPI_PROVISION) != 0) {\r
+          RequestConfirmed = TRUE;\r
+        }\r
+        break;  \r
+\r
+      case SET_NO_PPI_PROVISION_FALSE:\r
+      case SET_NO_PPI_CLEAR_FALSE:\r
+      case SET_NO_PPI_MAINTENANCE_FALSE:\r
+      case NO_ACTION:\r
+        RequestConfirmed = TRUE;\r
+        break;\r
+\r
+      case SET_OPERATOR_AUTH:\r
+        //\r
+        // This command requires UI to prompt user for Auth data\r
+        // Here it is NOT implemented\r
+        //\r
+        mTcgNvs->PhysicalPresence.ReturnCode = 0; \r
+        return EFI_SUCCESS;\r
+    }\r
+\r
+    if (RequestConfirmed) {\r
+      //\r
+      // Allowed and physically present user not required \r
+      //\r
+      mTcgNvs->PhysicalPresence.ReturnCode = 4;\r
+    } else {\r
+      //\r
+      // Allowed and physically present user required \r
+      //\r
+      mTcgNvs->PhysicalPresence.ReturnCode = 3;\r
+    }    \r
+  } \r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Software SMI callback for MemoryClear which is called from ACPI method.\r
+\r
+  @param[in]      DispatchHandle  The unique handle assigned to this handler by SmiHandlerRegister().\r
+  @param[in]      Context         Points to an optional handler context which was specified when the\r
+                                  handler was registered.\r
+  @param[in, out] CommBuffer      A pointer to a collection of data in memory that will\r
+                                  be conveyed from a non-SMM environment into an SMM environment.\r
+  @param[in, out] CommBufferSize  The size of the CommBuffer.\r
+\r
+  @retval EFI_SUCCESS             The interrupt was handled successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+MemoryClearCallback (\r
+  IN EFI_HANDLE                  DispatchHandle,\r
+  IN CONST VOID                  *Context,\r
+  IN OUT VOID                    *CommBuffer,\r
+  IN OUT UINTN                   *CommBufferSize\r
+  )\r
+{\r
+  EFI_STATUS                     Status;\r
+  UINTN                          DataSize;\r
+  UINT8                          MorControl;\r
+\r
+  if (mTcgNvs->MemoryClear.Parameter == 1) {\r
+    //\r
+    // Called from ACPI _DSM method, save the MOR data to variable.\r
+    //\r
+    MorControl = (UINT8) mTcgNvs->MemoryClear.Request;\r
+  } else if (mTcgNvs->MemoryClear.Parameter == 2) {\r
+    //\r
+    // Called from ACPI _PTS method, setup ClearMemory flags if needed.\r
+    //\r
+    DataSize = sizeof (UINT8);\r
+    Status = mSmmVariable->SmmGetVariable (\r
+                             MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,\r
+                             &gEfiMemoryOverwriteControlDataGuid,\r
+                             NULL,\r
+                             &DataSize,\r
+                             &MorControl\r
+                             );\r
+    if (EFI_ERROR (Status)) {\r
+      ASSERT (Status == EFI_NOT_FOUND);\r
+      return EFI_SUCCESS;\r
+    }\r
+\r
+    if (MOR_CLEAR_MEMORY_VALUE (MorControl) == 0x0) {\r
+      return EFI_SUCCESS;\r
+    }\r
+    MorControl &= ~MOR_CLEAR_MEMORY_BIT_MASK;\r
+  }\r
+\r
+  DataSize = sizeof (UINT8);\r
+  Status = mSmmVariable->SmmSetVariable (\r
+                           MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,\r
+                           &gEfiMemoryOverwriteControlDataGuid,\r
+                           EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
+                           DataSize,\r
+                           &MorControl\r
+                           );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Find the operation region in TCG ACPI table by given Name and Size,\r
+  and initialize it if the region is found.\r
+\r
+  @param[in, out] Table          The TPM item in ACPI table.\r
+  @param[in]      Name           The name string to find in TPM table.\r
+  @param[in]      Size           The size of the region to find.\r
+\r
+  @return                        The allocated address for the found region.\r
+\r
+**/\r
+VOID *\r
+AssignOpRegion (\r
+  EFI_ACPI_DESCRIPTION_HEADER    *Table,\r
+  UINT32                         Name,\r
+  UINT16                         Size\r
+  )\r
+{\r
+  EFI_STATUS                     Status;\r
+  AML_OP_REGION_32_8             *OpRegion;\r
+  EFI_PHYSICAL_ADDRESS           MemoryAddress;\r
+\r
+  MemoryAddress = SIZE_4GB - 1;\r
+\r
+  //\r
+  // Patch some pointers for the ASL code before loading the SSDT.\r
+  //\r
+  for (OpRegion  = (AML_OP_REGION_32_8 *) (Table + 1);\r
+       OpRegion <= (AML_OP_REGION_32_8 *) ((UINT8 *) Table + Table->Length);\r
+       OpRegion  = (AML_OP_REGION_32_8 *) ((UINT8 *) OpRegion + 1)) {\r
+    if ((OpRegion->OpRegionOp  == AML_OPREGION_OP) && \r
+        (OpRegion->NameString  == Name) &&\r
+        (OpRegion->RegionLen   == Size) &&\r
+        (OpRegion->DWordPrefix == AML_DWORD_PREFIX) &&\r
+        (OpRegion->BytePrefix  == AML_BYTE_PREFIX)) {\r
+\r
+      Status = gBS->AllocatePages(AllocateMaxAddress, EfiACPIMemoryNVS, EFI_SIZE_TO_PAGES (Size), &MemoryAddress);\r
+      ASSERT_EFI_ERROR (Status);\r
+      ZeroMem ((VOID *)(UINTN)MemoryAddress, Size);\r
+      OpRegion->RegionOffset = (UINT32) (UINTN) MemoryAddress;\r
+      break;\r
+    }\r
+  }\r
+\r
+  return (VOID *) (UINTN) MemoryAddress;\r
+}\r
+\r
+/**\r
+  Initialize and publish TPM items in ACPI table.\r
+\r
+  @retval   EFI_SUCCESS     The TCG ACPI table is published successfully.\r
+  @retval   Others          The TCG ACPI table is not published.\r
+\r
+**/\r
+EFI_STATUS\r
+PublishAcpiTable (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS                     Status;\r
+  EFI_ACPI_TABLE_PROTOCOL        *AcpiTable;\r
+  UINTN                          TableKey;\r
+  EFI_ACPI_DESCRIPTION_HEADER    *Table;\r
+  UINTN                          TableSize;\r
+\r
+  Status = GetSectionFromFv (\r
+             &gEfiCallerIdGuid,\r
+             EFI_SECTION_RAW,\r
+             0,\r
+             (VOID **) &Table,\r
+             &TableSize\r
+             );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  ASSERT (Table->OemTableId == SIGNATURE_64 ('T', 'c', 'g', 'T', 'a', 'b', 'l', 'e'));\r
+  mTcgNvs = AssignOpRegion (Table, SIGNATURE_32 ('T', 'N', 'V', 'S'), sizeof (TCG_NVS));\r
+  ASSERT (mTcgNvs != NULL);\r
+\r
+  //\r
+  // Publish the TPM ACPI table\r
+  //\r
+  Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTable);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  TableKey = 0;\r
+  Status = AcpiTable->InstallAcpiTable (\r
+                        AcpiTable,\r
+                        Table,\r
+                        TableSize,\r
+                        &TableKey\r
+                        );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  The driver's entry point.\r
+\r
+  It install callbacks for TPM physical presence and MemoryClear, and locate \r
+  SMM variable to be used in the callback function.\r
+\r
+  @param[in] ImageHandle  The firmware allocated handle for the EFI image.  \r
+  @param[in] SystemTable  A pointer to the EFI System Table.\r
+  \r
+  @retval EFI_SUCCESS     The entry point is executed successfully.\r
+  @retval Others          Some error occurs when executing this entry point.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+InitializeTcgSmm (\r
+  IN EFI_HANDLE                  ImageHandle,\r
+  IN EFI_SYSTEM_TABLE            *SystemTable\r
+  )\r
+{\r
+  EFI_STATUS                     Status;\r
+  EFI_SMM_SW_DISPATCH2_PROTOCOL  *SwDispatch;\r
+  EFI_SMM_SW_REGISTER_CONTEXT    SwContext;\r
+  EFI_HANDLE                     SwHandle;\r
+\r
+  Status = PublishAcpiTable ();\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // Get the Sw dispatch protocol and register SMI callback functions.\r
+  //\r
+  Status = gSmst->SmmLocateProtocol (&gEfiSmmSwDispatch2ProtocolGuid, NULL, (VOID**)&SwDispatch);\r
+  ASSERT_EFI_ERROR (Status);\r
+  SwContext.SwSmiInputValue = (UINTN) -1;\r
+  Status = SwDispatch->Register (SwDispatch, PhysicalPresenceCallback, &SwContext, &SwHandle);\r
+  ASSERT_EFI_ERROR (Status);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  mTcgNvs->PhysicalPresence.SoftwareSmi = (UINT8) SwContext.SwSmiInputValue;\r
+\r
+  SwContext.SwSmiInputValue = (UINTN) -1;\r
+  Status = SwDispatch->Register (SwDispatch, MemoryClearCallback, &SwContext, &SwHandle);\r
+  ASSERT_EFI_ERROR (Status);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  mTcgNvs->MemoryClear.SoftwareSmi = (UINT8) SwContext.SwSmiInputValue;\r
+  \r
+  //\r
+  // Locate SmmVariableProtocol.\r
+  //\r
+  Status = gSmst->SmmLocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID**)&mSmmVariable);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
diff --git a/SecurityPkg/Tcg/TcgSmm/TcgSmm.inf b/SecurityPkg/Tcg/TcgSmm/TcgSmm.inf
new file mode 100644 (file)
index 0000000..c8e7092
--- /dev/null
@@ -0,0 +1,56 @@
+## @file\r
+#  This driver implements TPM definition block in ACPI table and \r
+#  registers SMI callback functions for physical presence and \r
+#  MemoryClear to handle the requests from ACPI method.\r
+#\r
+# Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = TcgSmm\r
+  FILE_GUID                      = 42293093-76B9-4482-8C02-3BEFDEA9B35D\r
+  MODULE_TYPE                    = DXE_SMM_DRIVER\r
+  PI_SPECIFICATION_VERSION       = 0x0001000A\r
+  VERSION_STRING                 = 1.0\r
+  ENTRY_POINT                    = InitializeTcgSmm\r
+\r
+[Sources]\r
+  TcgSmm.c\r
+  Tpm.asl\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+  SecurityPkg/SecurityPkg.dec\r
+\r
+[LibraryClasses]\r
+  BaseLib\r
+  BaseMemoryLib\r
+  UefiDriverEntryPoint\r
+  SmmServicesTableLib\r
+  UefiBootServicesTableLib\r
+  DebugLib\r
+  DxeServicesLib\r
+\r
+[Guids]\r
+  gEfiPhysicalPresenceGuid\r
+  gEfiMemoryOverwriteControlDataGuid\r
+\r
+[Protocols]\r
+  gEfiSmmSwDispatch2ProtocolGuid                # PROTOCOL ALWAYS_CONSUMED\r
+  gEfiSmmVariableProtocolGuid                   # PROTOCOL ALWAYS_CONSUMED\r
+  gEfiAcpiTableProtocolGuid                     # PROTOCOL ALWAYS_CONSUMED\r
+\r
+[Depex]\r
+  gEfiAcpiTableProtocolGuid AND\r
+  gEfiSmmSwDispatch2ProtocolGuid AND\r
+  gEfiSmmVariableProtocolGuid AND\r
+  gEfiTcgProtocolGuid
\ No newline at end of file
diff --git a/SecurityPkg/Tcg/TcgSmm/Tpm.asl b/SecurityPkg/Tcg/TcgSmm/Tpm.asl
new file mode 100644 (file)
index 0000000..000fc66
--- /dev/null
@@ -0,0 +1,354 @@
+/** @file\r
+  The TPM definition block in ACPI table for physical presence  \r
+  and MemoryClear.\r
+\r
+Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+DefinitionBlock (\r
+  "Tpm.aml",\r
+  "SSDT",\r
+  1,\r
+  "Intel_",\r
+  "TcgTable",\r
+  0x1000\r
+  )\r
+{\r
+  Scope (\_SB)\r
+  {\r
+    Device (TPM)\r
+    {\r
+      //\r
+      // Define _HID, "PNP0C31" is defined in\r
+      // "Secure Startup-FVE and TPM Admin BIOS and Platform Requirements"\r
+      //\r
+      Name (_HID, EISAID ("PNP0C31"))\r
+\r
+      //\r
+      // Readable name of this device, don't know if this way is correct yet\r
+      //\r
+      Name (_STR, Unicode ("TPM 1.2 Device"))\r
+\r
+      //\r
+      // Return the resource consumed by TPM device\r
+      //\r
+      Name (_CRS, ResourceTemplate () {\r
+        Memory32Fixed (ReadOnly, 0xfed40000, 0x5000)\r
+      })\r
+\r
+      //\r
+      // Operational region for Smi port access\r
+      //\r
+      OperationRegion (SMIP, SystemIO, 0xB2, 1)\r
+      Field (SMIP, ByteAcc, NoLock, Preserve)\r
+      { \r
+          IOB2, 8\r
+      }\r
+\r
+      //\r
+      // Operational region for TPM access\r
+      //\r
+      OperationRegion (TPMR, SystemMemory, 0xfed40000, 0x5000)\r
+      Field (TPMR, AnyAcc, NoLock, Preserve)\r
+      {\r
+        ACC0, 8,\r
+      }\r
+\r
+      //\r
+      // Operational region for TPM support, TPM Physical Presence and TPM Memory Clear\r
+      // Region Offset to be fixed at runtime\r
+      //\r
+      OperationRegion (TNVS, SystemMemory, 0xFFFF0000, 0x1E)\r
+      Field (TNVS, AnyAcc, NoLock, Preserve)\r
+      {\r
+        PPIN,   8,  //   Software SMI for Physical Presence Interface\r
+        PPIP,   32, //   Used for save physical presence paramter\r
+        PPRP,   32, //   Physical Presence request operation response\r
+        PPRQ,   32, //   Physical Presence request operation\r
+        LPPR,   32, //   Last Physical Presence request operation\r
+        FRET,   32, //   Physical Presence function return code\r
+        MCIN,   8,  //   Software SMI for Memory Clear Interface\r
+        MCIP,   32, //   Used for save the Mor paramter\r
+        MORD,   32  //   Memory Overwrite Request Data\r
+      }\r
+\r
+      Method (PTS, 1, Serialized)\r
+      {  \r
+        //\r
+        // Detect Sx state for MOR, only S4, S5 need to handle\r
+        //\r
+        If (LAnd (LLess (Arg0, 6), LGreater (Arg0, 3)))\r
+        {   \r
+          //\r
+          // Bit4 -- DisableAutoDetect. 0 -- Firmware MAY autodetect.\r
+          //\r
+          If (LNot (And (MORD, 0x10)))\r
+          {\r
+            //\r
+            // Triggle the SMI through ACPI _PTS method.\r
+            //\r
+            Store (0x02, MCIP)\r
+              \r
+            //\r
+            // Triggle the SMI interrupt\r
+            //\r
+            Store (MCIN, IOB2)\r
+          }\r
+        }\r
+        Return (0)\r
+      }   \r
+\r
+      Method (_STA, 0)\r
+      {\r
+        if (LEqual (ACC0, 0xff))\r
+        {\r
+            Return (0)\r
+        }\r
+        Return (0x0f)\r
+      }\r
+\r
+      //\r
+      // TCG Hardware Information\r
+      //\r
+      Method (HINF, 3, Serialized, 0, {BuffObj, PkgObj}, {IntObj, IntObj, PkgObj})\r
+      {\r
+        //\r
+        // Switch by function index\r
+        //\r
+        Switch (ToInteger(Arg1))\r
+        {\r
+          Case (0)\r
+          {\r
+            //\r
+            // Standard query\r
+            //\r
+            Return (Buffer () {0x03})\r
+          }\r
+          Case (1)\r
+          {\r
+            //\r
+            // Return failure if no TPM present\r
+            //\r
+            Name(TPMV, Package () {0x01, Package () {ToBCD (1), ToBCD (20)}})\r
+            if (LEqual (_STA (), 0x00))\r
+            {\r
+              Return (Package () {0x00})\r
+            }\r
+\r
+            //\r
+            // Return TPM version\r
+            //\r
+            Return (TPMV)\r
+          }\r
+          Default {BreakPoint}\r
+        }\r
+        Return (Buffer () {0})\r
+      }\r
+\r
+      Name(TPM2, Package (0x02){\r
+        Zero, \r
+        Zero\r
+      })\r
+\r
+      Name(TPM3, Package (0x03){\r
+        Zero, \r
+        Zero,\r
+        Zero\r
+      })\r
+\r
+      //\r
+      // TCG Physical Presence Interface\r
+      //\r
+      Method (TPPI, 3, Serialized, 0, {BuffObj, PkgObj, IntObj, StrObj}, {IntObj, IntObj, PkgObj})\r
+      {        \r
+        //\r
+        // Switch by function index\r
+        //\r
+        Switch (ToInteger(Arg1))\r
+        {\r
+          Case (0)\r
+          {\r
+            //\r
+            // Standard query, supports function 1-8\r
+            //\r
+            Return (Buffer () {0xFF, 0x01})\r
+          }\r
+          Case (1)\r
+          {\r
+            //\r
+            // a) Get Physical Presence Interface Version\r
+            //\r
+            Return ("1.2")\r
+          }\r
+          Case (2)\r
+          {\r
+            //\r
+            // b) Submit TPM Operation Request to Pre-OS Environment\r
+            //\r
+                  \r
+            Store (DerefOf (Index (Arg2, 0x00)), PPRQ)\r
+            Store (0x02, PPIP)\r
+              \r
+            //\r
+            // Triggle the SMI interrupt\r
+            //\r
+            Store (PPIN, IOB2)\r
+            Return (FRET)\r
+\r
+\r
+          }\r
+          Case (3)\r
+          {\r
+            //\r
+            // c) Get Pending TPM Operation Requested By the OS\r
+            //\r
+                  \r
+            Store (PPRQ, Index (TPM2, 0x01))\r
+            Return (TPM2)\r
+          }\r
+          Case (4)\r
+          {\r
+            //\r
+            // d) Get Platform-Specific Action to Transition to Pre-OS Environment\r
+            //\r
+            Return (2)\r
+          }\r
+          Case (5)\r
+          {\r
+            //\r
+            // e) Return TPM Operation Response to OS Environment\r
+            //\r
+            Store (0x05, PPIP)\r
+                  \r
+            //\r
+            // Triggle the SMI interrupt\r
+            //\r
+            Store (PPIN, IOB2)\r
+                  \r
+            Store (LPPR, Index (TPM3, 0x01))\r
+            Store (PPRP, Index (TPM3, 0x02))\r
+\r
+            Return (TPM3)\r
+          }\r
+          Case (6)\r
+          {\r
+\r
+            //\r
+            // f) Submit preferred user language (Not implemented)\r
+            //\r
+\r
+            Return (3)\r
+\r
+          }\r
+          Case (7)\r
+          {\r
+            //\r
+            // g) Submit TPM Operation Request to Pre-OS Environment 2\r
+            //\r
+            Store (7, PPIP)\r
+            Store (DerefOf (Index (Arg2, 0x00)), PPRQ)\r
+                \r
+            //\r
+            // Triggle the SMI interrupt \r
+            //\r
+            Store (PPIN, IOB2)  \r
+            Return (FRET)\r
+          }\r
+          Case (8)\r
+          {\r
+            //\r
+            // e) Get User Confirmation Status for Operation\r
+            //\r
+            Store (8, PPIP)\r
+            Store (DerefOf (Index (Arg2, 0x00)), PPRQ)\r
+                  \r
+            //\r
+            // Triggle the SMI interrupt\r
+            //\r
+            Store (PPIN, IOB2)\r
+                  \r
+            Return (FRET)\r
+          }\r
+\r
+          Default {BreakPoint}\r
+        }\r
+        Return (1)\r
+      }\r
+\r
+      Method (TMCI, 3, Serialized, 0, IntObj, {IntObj, IntObj, PkgObj})\r
+      {\r
+        //\r
+        // Switch by function index\r
+        //\r
+        Switch (ToInteger (Arg1))\r
+        {\r
+          Case (0)\r
+          {\r
+            //\r
+            // Standard query, supports function 1-1\r
+            //\r
+            Return (Buffer () {0x03})\r
+          }\r
+          Case (1)\r
+          {\r
+            //\r
+            // Save the Operation Value of the Request to MORD (reserved memory)\r
+            //\r
+            Store (DerefOf (Index (Arg2, 0x00)), MORD)\r
+                  \r
+            //\r
+            // Triggle the SMI through ACPI _DSM method.\r
+            //\r
+            Store (0x01, MCIP)\r
+                  \r
+            //\r
+            // Triggle the SMI interrupt\r
+            //\r
+            Store (MCIN, IOB2)\r
+            Return (0)\r
+          }\r
+          Default {BreakPoint}\r
+        }\r
+        Return (1)        \r
+      }\r
+\r
+      Method (_DSM, 4, Serialized, 0, UnknownObj, {BuffObj, IntObj, IntObj, PkgObj})\r
+      {\r
+\r
+        //\r
+        // TCG Hardware Information\r
+        //\r
+        If(LEqual(Arg0, ToUUID ("cf8e16a5-c1e8-4e25-b712-4f54a96702c8")))\r
+        {\r
+          Return (HINF (Arg1, Arg2, Arg3))\r
+        }\r
+\r
+        //\r
+        // TCG Physical Presence Interface\r
+        //\r
+        If(LEqual(Arg0, ToUUID ("3dddfaa6-361b-4eb4-a424-8d10089d1653")))\r
+        {\r
+          Return (TPPI (Arg1, Arg2, Arg3))\r
+        }\r
+\r
+        //\r
+        // TCG Memory Clear Interface\r
+        //\r
+        If(LEqual(Arg0, ToUUID ("376054ed-cc13-4675-901c-4756d7f2d45d")))\r
+        {\r
+          Return (TMCI (Arg1, Arg2, Arg3))\r
+        }\r
+\r
+        Return (Buffer () {0})\r
+      }\r
+    }\r
+  }\r
+}\r
diff --git a/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProvider.c b/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProvider.c
new file mode 100644 (file)
index 0000000..ad15210
--- /dev/null
@@ -0,0 +1,1422 @@
+/** @file\r
+  Password Credential Provider driver implementation.\r
+    \r
+Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "PwdCredentialProvider.h"\r
+\r
+CREDENTIAL_TABLE            *mPwdTable      = NULL;\r
+PWD_PROVIDER_CALLBACK_INFO  *mCallbackInfo  = NULL;\r
+PASSWORD_CREDENTIAL_INFO    *mPwdInfoHandle = NULL;\r
+\r
+//\r
+// Used for save password credential and form browser.\r
+// Also used as provider identifier.\r
+//\r
+EFI_GUID  mPwdCredentialGuid = PWD_CREDENTIAL_PROVIDER_GUID;\r
+\r
+HII_VENDOR_DEVICE_PATH      mHiiVendorDevicePath = {\r
+  {\r
+    {\r
+      HARDWARE_DEVICE_PATH,\r
+      HW_VENDOR_DP,\r
+      {\r
+        (UINT8) (sizeof (VENDOR_DEVICE_PATH)),\r
+        (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)\r
+      }\r
+    },\r
+    { 0xeba7fc2b, 0xa465, 0x4d96, { 0x85, 0xa9, 0xd2, 0xf6, 0x64, 0xdf, 0x9b, 0x45 } }   \r
+  },\r
+  {\r
+    END_DEVICE_PATH_TYPE,\r
+    END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
+    {\r
+      (UINT8) (END_DEVICE_PATH_LENGTH),\r
+      (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)\r
+    }\r
+  }\r
+};\r
+\r
+EFI_USER_CREDENTIAL_PROTOCOL  gPwdCredentialProviderDriver = {\r
+  PWD_CREDENTIAL_PROVIDER_GUID,\r
+  EFI_USER_CREDENTIAL_CLASS_PASSWORD,\r
+  CredentialEnroll,\r
+  CredentialForm,\r
+  CredentialTile,\r
+  CredentialTitle,\r
+  CredentialUser,\r
+  CredentialSelect,\r
+  CredentialDeselect,\r
+  CredentialDefault,\r
+  CredentialGetInfo,\r
+  CredentialGetNextInfo\r
+};\r
+\r
+\r
+/**\r
+  Get string by string id from HII Interface.\r
+\r
+\r
+  @param[in] Id      String ID to get the string from.\r
+\r
+  @retval  CHAR16 *  String from ID.\r
+  @retval  NULL      If error occurs.\r
+\r
+**/\r
+CHAR16 *\r
+GetStringById (\r
+  IN EFI_STRING_ID             Id\r
+  )\r
+{\r
+  //\r
+  // Get the current string for the current Language.\r
+  //\r
+  return HiiGetString (mCallbackInfo->HiiHandle, Id, NULL);\r
+}\r
+\r
+\r
+/**\r
+  Expand password table size.\r
+\r
+**/\r
+VOID\r
+ExpandTableSize (\r
+  VOID\r
+  )\r
+{\r
+  CREDENTIAL_TABLE  *NewTable;\r
+  UINTN             Count;\r
+\r
+  Count = mPwdTable->MaxCount + PASSWORD_TABLE_INC;\r
+  //\r
+  // Create new credential table.\r
+  //\r
+  NewTable = (CREDENTIAL_TABLE *) AllocateZeroPool (\r
+                                    sizeof (CREDENTIAL_TABLE) + \r
+                                    (Count - 1) * sizeof (PASSWORD_INFO)\r
+                                    );\r
+  ASSERT (NewTable != NULL); \r
+\r
+  NewTable->MaxCount    = Count;\r
+  NewTable->Count       = mPwdTable->Count;\r
+  NewTable->ValidIndex  = mPwdTable->ValidIndex;\r
+  //\r
+  // Copy old entries\r
+  //\r
+  CopyMem (\r
+    &NewTable->UserInfo, \r
+    &mPwdTable->UserInfo, \r
+    mPwdTable->Count * sizeof (PASSWORD_INFO)\r
+    );\r
+  FreePool (mPwdTable);\r
+  mPwdTable = NewTable;\r
+}\r
+\r
+\r
+/**\r
+  Add or delete info in table, and sync with NV variable.\r
+\r
+  @param[in]  Index     The index of the password in table. The index begin from 1.\r
+                        If index is found in table, delete the info, else add the \r
+                        into to table. \r
+  @param[in]  Info      The new password info to add into table.\r
+\r
+  @retval EFI_INVALID_PARAMETER  Info is NULL when save the info.\r
+  @retval EFI_SUCCESS            Modify the table successfully.\r
+  @retval Others                 Failed to modify the table.\r
+\r
+**/\r
+EFI_STATUS\r
+ModifyTable (\r
+  IN  UINTN                                     Index,\r
+  IN  PASSWORD_INFO                             * Info OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  \r
+  if (Index < mPwdTable->Count) {\r
+    //\r
+    // Delete the specified entry.\r
+    //\r
+    mPwdTable->Count--;\r
+    if (Index != mPwdTable->Count) {\r
+      CopyMem (\r
+        &mPwdTable->UserInfo[Index],\r
+        &mPwdTable->UserInfo[mPwdTable->Count],\r
+        sizeof (PASSWORD_INFO)\r
+        );\r
+    }\r
+  } else {\r
+    //\r
+    // Add a new entry.\r
+    //\r
+    if (Info == NULL) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    if (mPwdTable->Count >= mPwdTable->MaxCount) {\r
+      ExpandTableSize ();\r
+    }\r
+\r
+    CopyMem (\r
+      &mPwdTable->UserInfo[mPwdTable->Count], \r
+      Info, \r
+      sizeof (PASSWORD_INFO)\r
+      );\r
+    mPwdTable->Count++;\r
+  }\r
+\r
+  //\r
+  // Save the credential table.\r
+  //\r
+  Status = gRT->SetVariable (\r
+                  L"PwdCredential",\r
+                  &mPwdCredentialGuid,\r
+                  EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
+                  mPwdTable->Count * sizeof (PASSWORD_INFO),\r
+                  &mPwdTable->UserInfo\r
+                  );\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Create a password table.\r
+\r
+  @retval EFI_SUCCESS      Create a password table successfully.\r
+  @retval Others           Failed to create a password.\r
+\r
+**/\r
+EFI_STATUS\r
+InitCredentialTable (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  UINT8       *Var;\r
+  UINTN       VarSize;\r
+\r
+  //\r
+  // Get Password credential data from NV variable.\r
+  //\r
+  VarSize = 0;\r
+  Var     = NULL;\r
+  Status  = gRT->GetVariable (\r
+                   L"PwdCredential", \r
+                   &mPwdCredentialGuid, \r
+                   NULL, \r
+                   &VarSize,\r
+                   Var\r
+                   );\r
+  if (Status == EFI_BUFFER_TOO_SMALL) {\r
+    Var = AllocateZeroPool (VarSize);\r
+    if (Var == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+    Status = gRT->GetVariable (\r
+                    L"PwdCredential", \r
+                    &mPwdCredentialGuid, \r
+                    NULL, \r
+                    &VarSize,\r
+                    Var\r
+                    );\r
+  }\r
+  if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {\r
+    return Status;\r
+  }\r
+  \r
+  //\r
+  // Create the password credential table.\r
+  //\r
+  mPwdTable = AllocateZeroPool (\r
+                sizeof (CREDENTIAL_TABLE) - sizeof (PASSWORD_INFO) +\r
+                PASSWORD_TABLE_INC * sizeof (PASSWORD_INFO) + \r
+                VarSize\r
+                );\r
+  if (mPwdTable == NULL) {\r
+    FreePool (Var);\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  mPwdTable->Count      = VarSize / sizeof (PASSWORD_INFO);\r
+  mPwdTable->MaxCount   = mPwdTable->Count + PASSWORD_TABLE_INC;\r
+  mPwdTable->ValidIndex = 0;\r
+  if (Var != NULL) {\r
+    CopyMem (mPwdTable->UserInfo, Var, VarSize);\r
+    FreePool (Var);\r
+  }\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Hash the password to get credential.\r
+\r
+  @param[in]   Password       Points to the input password.\r
+  @param[in]   PasswordSize   The size of password, in bytes.\r
+  @param[out]  Credential     Points to the hashed result.\r
+\r
+  @retval      TRUE           Hash the password successfully.\r
+  @retval      FALSE          Failed to hash the password.\r
+                 \r
+**/\r
+BOOLEAN\r
+GenerateCredential (\r
+  IN      CHAR16                              *Password,\r
+  IN      UINTN                               PasswordSize,\r
+     OUT  UINT8                               *Credential\r
+  )\r
+{\r
+  BOOLEAN           Status;\r
+  UINTN             HashSize;\r
+  VOID              *Hash;\r
+  \r
+  HashSize = Sha1GetContextSize ();\r
+  Hash     = AllocatePool (HashSize);\r
+  ASSERT (Hash != NULL);\r
+  \r
+  Status = Sha1Init (Hash);\r
+  if (!Status) {\r
+    goto Done;\r
+  }\r
+  \r
+  Status = Sha1Update (Hash, Password, PasswordSize);\r
+  if (!Status) {\r
+    goto Done;\r
+  }\r
+  \r
+  Status = Sha1Final (Hash, Credential);\r
+  \r
+Done:\r
+  FreePool (Hash);\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Get password from user input.\r
+\r
+  @param[in]   FirstPwd       If True, prompt to input the first password.\r
+                              If False, prompt to input password again.\r
+  @param[out]  Credential     Points to the input password.\r
+\r
+**/\r
+VOID\r
+GetPassword (\r
+  IN  BOOLEAN                               FirstPwd,\r
+  OUT CHAR8                                 *Credential\r
+  )\r
+{\r
+  EFI_INPUT_KEY Key;\r
+  CHAR16        PasswordMask[CREDENTIAL_LEN + 1];\r
+  CHAR16        Password[CREDENTIAL_LEN];\r
+  UINTN         PasswordLen;\r
+  CHAR16        *QuestionStr;\r
+  CHAR16        *LineStr;\r
+  \r
+  PasswordLen = 0;\r
+  while (TRUE) {\r
+    PasswordMask[PasswordLen]     = L'_';\r
+    PasswordMask[PasswordLen + 1] = L'\0';\r
+    LineStr = GetStringById (STRING_TOKEN (STR_DRAW_A_LINE));\r
+    if (FirstPwd) {\r
+      QuestionStr = GetStringById (STRING_TOKEN (STR_INPUT_PASSWORD));\r
+    } else {\r
+      QuestionStr = GetStringById (STRING_TOKEN (STR_INPUT_PASSWORD_AGAIN));\r
+    }\r
+    CreatePopUp (\r
+      EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+      &Key,\r
+      QuestionStr,\r
+      LineStr,\r
+      PasswordMask,\r
+      NULL\r
+      );\r
+    FreePool (QuestionStr);\r
+    FreePool (LineStr);\r
+    \r
+    //\r
+    // Check key stroke\r
+    //\r
+    if (Key.ScanCode == SCAN_NULL) {\r
+      if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {\r
+        break;\r
+      } else if (Key.UnicodeChar == CHAR_BACKSPACE) {\r
+        if (PasswordLen > 0) {\r
+          PasswordLen--;\r
+        }\r
+      } else if ((Key.UnicodeChar == CHAR_NULL) || \r
+                 (Key.UnicodeChar == CHAR_TAB) || \r
+                 (Key.UnicodeChar == CHAR_LINEFEED)) {\r
+        continue;\r
+      } else {\r
+        Password[PasswordLen] = Key.UnicodeChar;\r
+        PasswordMask[PasswordLen] = L'*';\r
+        PasswordLen++;\r
+        if (PasswordLen == CREDENTIAL_LEN) {\r
+          break;\r
+        }\r
+      }\r
+    }\r
+  }\r
+  \r
+  PasswordLen = PasswordLen * sizeof (CHAR16);\r
+  GenerateCredential (Password, PasswordLen, (UINT8 *)Credential);\r
+}\r
+\r
+/**\r
+  Check whether the password can be found on this provider.\r
+\r
+  @param[in]  Password           The password to be found.\r
+\r
+  @retval EFI_SUCCESS            Found password sucessfully.\r
+  @retval EFI_NOT_FOUND          Fail to find the password.\r
+\r
+**/\r
+EFI_STATUS\r
+CheckPassword (\r
+  IN CHAR8                                      *Password\r
+  )\r
+{\r
+  UINTN      Index;\r
+  CHAR8      *Pwd;\r
+  \r
+  //\r
+  // Check password credential.\r
+  //\r
+  mPwdTable->ValidIndex = 0;\r
+  for (Index = 0; Index < mPwdTable->Count; Index++) {\r
+    Pwd = mPwdTable->UserInfo[Index].Password;\r
+    if (CompareMem (Pwd, Password, CREDENTIAL_LEN) == 0) {\r
+      mPwdTable->ValidIndex = Index + 1;\r
+      return EFI_SUCCESS;\r
+    }\r
+  }\r
+\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+\r
+/**\r
+  Find a user infomation record by the information record type.\r
+\r
+  This function searches all user information records of User from beginning \r
+  until either the information is found, or there are no more user infomation\r
+  records. A match occurs when a Info.InfoType field matches the user information\r
+  record type.\r
+\r
+  @param[in]     User      Points to the user profile record to search.                          \r
+  @param[in]     InfoType  The infomation type to be searched.\r
+  @param[out]    Info      Points to the user info found, the caller is responsible\r
+                           to free.\r
+  \r
+  @retval EFI_SUCCESS      Find the user information successfully.\r
+  @retval Others           Fail to find the user information.\r
+\r
+**/\r
+EFI_STATUS\r
+FindUserInfoByType (\r
+  IN      EFI_USER_PROFILE_HANDLE               User,\r
+  IN      UINT8                                 InfoType,\r
+  OUT     EFI_USER_INFO                         **Info\r
+  )\r
+{\r
+  EFI_STATUS                 Status;\r
+  EFI_USER_INFO              *UserInfo;\r
+  UINTN                      UserInfoSize;\r
+  EFI_USER_INFO_HANDLE       UserInfoHandle;\r
+  EFI_USER_MANAGER_PROTOCOL  *UserManager;\r
+  \r
+  //\r
+  // Find user information by information type.\r
+  //\r
+  if (Info == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Status = gBS->LocateProtocol (\r
+                  &gEfiUserManagerProtocolGuid,\r
+                  NULL,\r
+                  (VOID **) &UserManager\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  //\r
+  // Get each user information.\r
+  //\r
+\r
+  UserInfoHandle = NULL;\r
+  UserInfo       = NULL;\r
+  UserInfoSize   = 0;\r
+  while (TRUE) {\r
+    Status = UserManager->GetNextInfo (UserManager, User, &UserInfoHandle);\r
+    if (EFI_ERROR (Status)) {\r
+      break;\r
+    }\r
+    //\r
+    // Get information.\r
+    //\r
+    Status = UserManager->GetInfo (\r
+                            UserManager,\r
+                            User,\r
+                            UserInfoHandle,\r
+                            UserInfo,\r
+                            &UserInfoSize\r
+                            );\r
+    if (Status == EFI_BUFFER_TOO_SMALL) {\r
+      if (UserInfo != NULL) {\r
+        FreePool (UserInfo);\r
+      }\r
+      UserInfo = AllocateZeroPool (UserInfoSize);\r
+      if (UserInfo == NULL) {\r
+        return EFI_OUT_OF_RESOURCES;\r
+      }\r
+      Status = UserManager->GetInfo (\r
+                              UserManager,\r
+                              User,\r
+                              UserInfoHandle,\r
+                              UserInfo,\r
+                              &UserInfoSize\r
+                              );\r
+    }\r
+    if (EFI_ERROR (Status)) {\r
+      break;\r
+    }\r
+\r
+    ASSERT (UserInfo != NULL);\r
+    if (UserInfo->InfoType == InfoType) {\r
+      *Info = UserInfo;\r
+      return EFI_SUCCESS;\r
+    }    \r
+  }\r
+\r
+  if (UserInfo != NULL) {\r
+    FreePool (UserInfo);\r
+  }\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  This function processes the results of changes in configuration.\r
+\r
+  @param  This                   Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
+  @param  Action                 Specifies the type of action taken by the browser.\r
+  @param  QuestionId             A unique value which is sent to the original\r
+                                 exporting driver so that it can identify the type\r
+                                 of data to expect.\r
+  @param  Type                   The type of value for the question.\r
+  @param  Value                  A pointer to the data being sent to the original\r
+                                 exporting driver.\r
+  @param  ActionRequest          On return, points to the action requested by the\r
+                                 callback function.\r
+\r
+  @retval EFI_SUCCESS            The callback successfully handled the action.\r
+  @retval EFI_OUT_OF_RESOURCES   Not enough storage is available to hold the\r
+                                 variable and its data.\r
+  @retval EFI_DEVICE_ERROR       The variable could not be saved.\r
+  @retval EFI_UNSUPPORTED        The specified Action is not supported by the\r
+                                 callback.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CredentialDriverCallback (\r
+  IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,\r
+  IN  EFI_BROWSER_ACTION                     Action,\r
+  IN  EFI_QUESTION_ID                        QuestionId,\r
+  IN  UINT8                                  Type,\r
+  IN  EFI_IFR_TYPE_VALUE                     *Value,\r
+  OUT EFI_BROWSER_ACTION_REQUEST             *ActionRequest\r
+  )\r
+{\r
+  EFI_STATUS    Status;\r
+  EFI_INPUT_KEY Key;\r
+  CHAR8         Password[CREDENTIAL_LEN];\r
+  CHAR16        *PromptStr;\r
+\r
+  if (Action == EFI_BROWSER_ACTION_CHANGING) {\r
+    if (QuestionId == KEY_GET_PASSWORD) {\r
+      //\r
+      // Get and check password.\r
+      //\r
+      GetPassword (TRUE, Password);\r
+      Status = CheckPassword (Password);\r
+      if (EFI_ERROR (Status)) {\r
+        PromptStr = GetStringById (STRING_TOKEN (STR_PASSWORD_INCORRECT));\r
+        CreatePopUp (\r
+          EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+          &Key,\r
+          L"",\r
+          PromptStr,\r
+          L"",\r
+          NULL\r
+          );\r
+        FreePool (PromptStr);\r
+        return Status;\r
+      }\r
+      *ActionRequest  = EFI_BROWSER_ACTION_REQUEST_EXIT;\r
+    }    \r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // All other action return unsupported.\r
+  //\r
+  return EFI_UNSUPPORTED;\r
+}\r
+\r
+\r
+/**\r
+  This function allows a caller to extract the current configuration for one\r
+  or more named elements from the target driver.\r
+\r
+\r
+  @param This            Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
+  @param Request         A null-terminated Unicode string in <ConfigRequest> format.\r
+  @param Progress        On return, points to a character in the Request string.\r
+                         Points to the string's null terminator if request was successful.\r
+                         Points to the most recent '&' before the first failing name/value\r
+                         pair (or the beginning of the string if the failure is in the\r
+                         first name/value pair) if the request was not successful.\r
+  @param Results         A null-terminated Unicode string in <ConfigAltResp> format which\r
+                         has all values filled in for the names in the Request string.\r
+                         String to be allocated by the called function.\r
+\r
+  @retval  EFI_SUCCESS            The Results is filled with the requested values.\r
+  @retval  EFI_OUT_OF_RESOURCES   Not enough memory to store the results.\r
+  @retval  EFI_INVALID_PARAMETER  Request is illegal syntax, or unknown name.\r
+  @retval  EFI_NOT_FOUND          Routing data doesn't match any storage in this driver.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FakeExtractConfig (\r
+  IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,\r
+  IN  CONST EFI_STRING                       Request,\r
+  OUT EFI_STRING                             *Progress,\r
+  OUT EFI_STRING                             *Results\r
+  )\r
+{\r
+  if (Progress == NULL || Results == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  *Progress = Request;\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+/**\r
+  This function processes the results of changes in configuration.\r
+\r
+\r
+  @param This            Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
+  @param Configuration   A null-terminated Unicode string in <ConfigResp> format.\r
+  @param Progress        A pointer to a string filled in with the offset of the most\r
+                         recent '&' before the first failing name/value pair (or the\r
+                         beginning of the string if the failure is in the first\r
+                         name/value pair) or the terminating NULL if all was successful.\r
+\r
+  @retval  EFI_SUCCESS            The Results is processed successfully.\r
+  @retval  EFI_INVALID_PARAMETER  Configuration is NULL.\r
+  @retval  EFI_NOT_FOUND          Routing data doesn't match any storage in this driver.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FakeRouteConfig (\r
+  IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,\r
+  IN  CONST EFI_STRING                       Configuration,\r
+  OUT EFI_STRING                             *Progress\r
+  )\r
+{\r
+  if (Configuration == NULL || Progress == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+/**\r
+  This function initialize the data mainly used in form browser.\r
+\r
+  @retval EFI_SUCCESS          Initialize form data successfully.\r
+  @retval Others               Fail to Initialize form data.\r
+\r
+**/\r
+EFI_STATUS\r
+InitFormBrowser (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  PWD_PROVIDER_CALLBACK_INFO  *CallbackInfo;\r
+\r
+  //\r
+  // Initialize driver private data.\r
+  //\r
+  CallbackInfo = AllocateZeroPool (sizeof (PWD_PROVIDER_CALLBACK_INFO));\r
+  if (CallbackInfo == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  CallbackInfo->Signature                   = PWD_PROVIDER_SIGNATURE;\r
+  CallbackInfo->ConfigAccess.ExtractConfig  = FakeExtractConfig;\r
+  CallbackInfo->ConfigAccess.RouteConfig    = FakeRouteConfig;\r
+  CallbackInfo->ConfigAccess.Callback       = CredentialDriverCallback;\r
+  CallbackInfo->DriverHandle  = NULL;\r
+\r
+  //\r
+  // Install Device Path Protocol and Config Access protocol to driver handle.\r
+  //\r
+  Status = gBS->InstallMultipleProtocolInterfaces (\r
+                  &CallbackInfo->DriverHandle,\r
+                  &gEfiDevicePathProtocolGuid,\r
+                  &mHiiVendorDevicePath,\r
+                  &gEfiHiiConfigAccessProtocolGuid,\r
+                  &CallbackInfo->ConfigAccess,\r
+                  NULL\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // Publish HII data.\r
+  //\r
+  CallbackInfo->HiiHandle = HiiAddPackages (\r
+                              &mPwdCredentialGuid,\r
+                              CallbackInfo->DriverHandle,\r
+                              PwdCredentialProviderStrings,\r
+                              PwdCredentialProviderVfrBin,\r
+                              NULL\r
+                              );\r
+  if (CallbackInfo->HiiHandle == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  mCallbackInfo = CallbackInfo;\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Enroll a user on a credential provider.\r
+\r
+  This function enrolls and deletes a user profile using this credential provider. \r
+  If a user profile is successfully enrolled, it calls the User Manager Protocol \r
+  function Notify() to notify the user manager driver that credential information \r
+  has changed. If an enrolled user does exist, delete the user on the credential \r
+  provider.\r
+  \r
+  @param[in] This                Points to this instance of EFI_USER_CREDENTIAL_PROTOCOL.\r
+  @param[in] User                The user profile to enroll.\r
\r
+  @retval EFI_SUCCESS            User profile was successfully enrolled.\r
+  @retval EFI_ACCESS_DENIED      Current user profile does not permit enrollment on the\r
+                                 user profile handle. Either the user profile cannot enroll\r
+                                 on any user profile or cannot enroll on a user profile \r
+                                 other than the current user profile.\r
+  @retval EFI_UNSUPPORTED        This credential provider does not support enrollment in\r
+                                 the pre-OS.\r
+  @retval EFI_DEVICE_ERROR       The new credential could not be created because of a device\r
+                                 error.\r
+  @retval EFI_INVALID_PARAMETER  User does not refer to a valid user profile handle.\r
+  \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CredentialEnroll (\r
+  IN CONST  EFI_USER_CREDENTIAL_PROTOCOL        *This,\r
+  IN        EFI_USER_PROFILE_HANDLE             User\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  UINTN                     Index;\r
+  PASSWORD_INFO             PwdInfo;\r
+  EFI_USER_INFO             *UserInfo;\r
+  CHAR8                     Password[CREDENTIAL_LEN];\r
+  EFI_INPUT_KEY             Key;\r
+  EFI_USER_MANAGER_PROTOCOL *UserManager;\r
+  UINT8                     *UserId;\r
+  UINT8                     *NewUserId;\r
+  CHAR16                    *QuestionStr;\r
+  CHAR16                    *PromptStr;\r
+\r
+  if ((This == NULL) || (User == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Status = gBS->LocateProtocol (\r
+                  &gEfiUserManagerProtocolGuid,\r
+                  NULL,\r
+                  (VOID **) &UserManager\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  //\r
+  // Get User Identifier.\r
+  //\r
+  UserInfo = NULL;\r
+  Status = FindUserInfoByType (\r
+             User,\r
+             EFI_USER_INFO_IDENTIFIER_RECORD,\r
+             &UserInfo\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // If User exists in mPwdTable, delete User.\r
+  // \r
+  for (Index = 0; Index < mPwdTable->Count; Index++) {\r
+    UserId    = (UINT8 *) &mPwdTable->UserInfo[Index].UserId;\r
+    NewUserId = (UINT8 *) (UserInfo + 1);\r
+    if (CompareMem (UserId, NewUserId, sizeof (EFI_USER_INFO_IDENTIFIER)) == 0) {\r
+      //\r
+      // Delete the existing password.\r
+      //\r
+      FreePool (UserInfo);\r
+      return ModifyTable (Index, NULL);\r
+    }\r
+  }\r
+\r
+  //\r
+  // The User doesn't exist in mPwdTable; Enroll the new User.\r
+  //  \r
+  while (TRUE) {\r
+    //\r
+    // Input password.\r
+    //\r
+    GetPassword (TRUE, PwdInfo.Password);\r
+\r
+    //\r
+    // Input password again.\r
+    //\r
+    GetPassword (FALSE, Password);\r
+\r
+    //\r
+    // Compare the two password consistency.\r
+    //\r
+    if (CompareMem (PwdInfo.Password, Password, CREDENTIAL_LEN) == 0) {\r
+      break;\r
+    } \r
+\r
+    QuestionStr = GetStringById (STRING_TOKEN (STR_PASSWORD_MISMATCH));\r
+    PromptStr   = GetStringById (STRING_TOKEN (STR_INPUT_PASSWORD_AGAIN));    \r
+    CreatePopUp (\r
+      EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+      &Key,\r
+      QuestionStr,\r
+      L"",\r
+      PromptStr,\r
+      NULL\r
+      );\r
+    FreePool (QuestionStr);\r
+    FreePool (PromptStr);\r
+  }\r
+\r
+  CopyMem (\r
+    PwdInfo.UserId, \r
+    (UINT8 *) (UserInfo + 1), \r
+    sizeof (EFI_USER_INFO_IDENTIFIER)\r
+    );  \r
+  FreePool (UserInfo);\r
+  \r
+  //\r
+  // Save the new added entry.\r
+  //\r
+  Status = ModifyTable (mPwdTable->Count, &PwdInfo);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Notify the user manager driver that credential information has changed.\r
+  //\r
+  UserManager->Notify (UserManager, mCallbackInfo->DriverHandle);  \r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Returns the user interface information used during user identification.\r
+\r
+  This function returns information about the form used when interacting with the\r
+  user during user identification. The form is the first enabled form in the form-set\r
+  class EFI_HII_USER_CREDENTIAL_FORMSET_GUID installed on the HII handle HiiHandle. If \r
+  the user credential provider does not require a form to identify the user, then this\r
+  function should return EFI_NOT_FOUND.\r
+\r
+  @param[in]  This       Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.\r
+  @param[out] Hii        On return, holds the HII database handle.\r
+  @param[out] FormSetId  On return, holds the identifier of the form set which contains\r
+                         the form used during user identification.\r
+  @param[out] FormId     On return, holds the identifier of the form used during user \r
+                         identification.\r
+                         \r
+  @retval EFI_SUCCESS            Form returned successfully.\r
+  @retval EFI_NOT_FOUND          Form not returned.\r
+  @retval EFI_INVALID_PARAMETER  Hii is NULL or FormSetId is NULL or FormId is NULL.\r
+  \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CredentialForm (\r
+  IN CONST  EFI_USER_CREDENTIAL_PROTOCOL        *This,\r
+  OUT       EFI_HII_HANDLE                      *Hii,\r
+  OUT       EFI_GUID                            *FormSetId,\r
+  OUT       EFI_FORM_ID                         *FormId\r
+  )\r
+{\r
+  if ((This == NULL) || (Hii == NULL) || \r
+      (FormSetId == NULL) || (FormId == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  *Hii       = mCallbackInfo->HiiHandle;\r
+  *FormId    = FORMID_GET_PASSWORD_FORM;\r
+  CopyGuid (FormSetId, &mPwdCredentialGuid);\r
+  \r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Returns bitmap used to describe the credential provider type.\r
+\r
+  This optional function returns a bitmap that is less than or equal to the number\r
+  of pixels specified by Width and Height. If no such bitmap exists, then EFI_NOT_FOUND\r
+  is returned. \r
+\r
+  @param[in]      This    Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.\r
+  @param[in, out] Width   On entry, points to the desired bitmap width. If NULL then no \r
+                          bitmap information will be returned. On exit, points to the \r
+                          width of the bitmap returned.\r
+  @param[in, out] Height  On entry, points to the desired bitmap height. If NULL then no\r
+                          bitmap information will be returned. On exit, points to the \r
+                          height of the bitmap returned\r
+  @param[out]     Hii     On return, holds the HII database handle. \r
+  @param[out]     Image   On return, holds the HII image identifier. \r
\r
+  @retval EFI_SUCCESS            Image identifier returned successfully.\r
+  @retval EFI_NOT_FOUND          Image identifier not returned.\r
+  @retval EFI_INVALID_PARAMETER  Hii is NULL or Image is NULL.\r
+  \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CredentialTile (\r
+  IN  CONST  EFI_USER_CREDENTIAL_PROTOCOL        *This,\r
+  IN  OUT    UINTN                               *Width,\r
+  IN  OUT    UINTN                               *Height,\r
+      OUT    EFI_HII_HANDLE                      *Hii,\r
+      OUT    EFI_IMAGE_ID                        *Image\r
+  )\r
+{  \r
+  if ((This == NULL) || (Hii == NULL) || (Image == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+\r
+/**\r
+  Returns string used to describe the credential provider type.\r
+\r
+  This function returns a string which describes the credential provider. If no\r
+  such string exists, then EFI_NOT_FOUND is returned. \r
+\r
+  @param[in]  This       Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.\r
+  @param[out] Hii        On return, holds the HII database handle.\r
+  @param[out] String     On return, holds the HII string identifier.\r
\r
+  @retval EFI_SUCCESS            String identifier returned successfully.\r
+  @retval EFI_NOT_FOUND          String identifier not returned.\r
+  @retval EFI_INVALID_PARAMETER  Hii is NULL or String is NULL.\r
+  \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CredentialTitle (\r
+  IN CONST  EFI_USER_CREDENTIAL_PROTOCOL        *This,\r
+  OUT       EFI_HII_HANDLE                      *Hii,\r
+  OUT       EFI_STRING_ID                       *String\r
+  )\r
+{\r
+  if ((This == NULL) || (Hii == NULL) || (String == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  \r
+  //\r
+  // Set Hii handle and String ID.\r
+  //\r
+  *Hii    = mCallbackInfo->HiiHandle;\r
+  *String = STRING_TOKEN (STR_CREDENTIAL_TITLE);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Return the user identifier associated with the currently authenticated user.\r
+\r
+  This function returns the user identifier of the user authenticated by this credential\r
+  provider. This function is called after the credential-related information has been \r
+  submitted on a form, OR after a call to Default() has returned that this credential is\r
+  ready to log on.\r
+\r
+  @param[in]  This           Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.\r
+  @param[in]  User           The user profile handle of the user profile currently being \r
+                             considered by the user identity manager. If NULL, then no user\r
+                             profile is currently under consideration.\r
+  @param[out] Identifier     On return, points to the user identifier. \r
\r
+  @retval EFI_SUCCESS            User identifier returned successfully.\r
+  @retval EFI_NOT_READY          No user identifier can be returned.\r
+  @retval EFI_ACCESS_DENIED      The user has been locked out of this user credential.\r
+  @retval EFI_INVALID_PARAMETER  This is NULL, or Identifier is NULL.\r
+  @retval EFI_NOT_FOUND          User is not NULL, and the specified user handle can't be\r
+                                 found in user profile database\r
+  \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CredentialUser (\r
+  IN CONST  EFI_USER_CREDENTIAL_PROTOCOL        *This,\r
+  IN        EFI_USER_PROFILE_HANDLE             User,\r
+  OUT       EFI_USER_INFO_IDENTIFIER            *Identifier\r
+  )\r
+{\r
+  EFI_STATUS    Status;\r
+  UINTN         Index;\r
+  EFI_USER_INFO *UserInfo;\r
+  UINT8         *UserId;\r
+  UINT8         *NewUserId;\r
+  CHAR8         *Pwd;\r
+  CHAR8         *NewPwd;\r
+\r
+  if ((This == NULL) || (Identifier == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (mPwdTable->ValidIndex == 0) {\r
+    //\r
+    // No password input, or the input password doesn't match\r
+    // anyone in PwdTable.\r
+    //\r
+    return EFI_NOT_READY;\r
+  }\r
+  \r
+  if (User == NULL) {\r
+    //\r
+    // Return the user ID whose password matches the input password.\r
+    // \r
+    CopyMem (\r
+      Identifier, \r
+      &mPwdTable->UserInfo[mPwdTable->ValidIndex - 1].UserId, \r
+      sizeof (EFI_USER_INFO_IDENTIFIER)\r
+      );    \r
+    return EFI_SUCCESS;\r
+  }\r
+  \r
+  //\r
+  // Get the User's ID.\r
+  //\r
+  Status = FindUserInfoByType (\r
+             User,\r
+             EFI_USER_INFO_IDENTIFIER_RECORD,\r
+             &UserInfo\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+  \r
+  //\r
+  // Check whether the input password matches one in PwdTable.\r
+  //\r
+  for (Index = 0; Index < mPwdTable->Count; Index++) {\r
+    UserId    = (UINT8 *) &mPwdTable->UserInfo[Index].UserId;\r
+    NewUserId = (UINT8 *) (UserInfo + 1);\r
+    if (CompareMem (UserId, NewUserId, sizeof (EFI_USER_INFO_IDENTIFIER)) == 0) {\r
+      Pwd    = mPwdTable->UserInfo[Index].Password;\r
+      NewPwd = mPwdTable->UserInfo[mPwdTable->ValidIndex - 1].Password;\r
+      if (CompareMem (Pwd, NewPwd, CREDENTIAL_LEN) == 0) {\r
+        CopyMem (Identifier, UserId, sizeof (EFI_USER_INFO_IDENTIFIER));\r
+        FreePool (UserInfo);\r
+        return EFI_SUCCESS;\r
+      } \r
+    }\r
+  }\r
+\r
+  //\r
+  // The User's password doesn't match the input password.\r
+  // Return the user ID whose password matches the input password.\r
+  //\r
+  CopyMem (\r
+    Identifier,\r
+    &mPwdTable->UserInfo[mPwdTable->ValidIndex - 1].UserId,\r
+    sizeof (EFI_USER_INFO_IDENTIFIER)\r
+    );\r
+  FreePool (UserInfo);  \r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Indicate that user interface interaction has begun for the specified credential.\r
+\r
+  This function is called when a credential provider is selected by the user. If \r
+  AutoLogon returns FALSE, then the user interface will be constructed by the User\r
+  Identity Manager. \r
+\r
+  @param[in]  This       Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.\r
+  @param[out] AutoLogon  On return, points to the credential provider's capabilities \r
+                         after the credential provider has been selected by the user. \r
\r
+  @retval EFI_SUCCESS            Credential provider successfully selected.\r
+  @retval EFI_INVALID_PARAMETER  AutoLogon is NULL.\r
+  \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CredentialSelect (\r
+  IN  CONST  EFI_USER_CREDENTIAL_PROTOCOL    *This,\r
+  OUT        EFI_CREDENTIAL_LOGON_FLAGS      *AutoLogon\r
+  )\r
+{\r
+  if ((This == NULL) || (AutoLogon == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  *AutoLogon = 0;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Indicate that user interface interaction has ended for the specified credential.\r
+\r
+  This function is called when a credential provider is deselected by the user.\r
+\r
+  @param[in] This        Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.\r
\r
+  @retval EFI_SUCCESS    Credential provider successfully deselected.\r
+  \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CredentialDeselect (\r
+  IN CONST  EFI_USER_CREDENTIAL_PROTOCOL        *This\r
+  )\r
+{\r
+  if (This == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Return the default logon behavior for this user credential.\r
+\r
+  This function reports the default login behavior regarding this credential provider.  \r
+\r
+  @param[in]  This       Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.\r
+  @param[out] AutoLogon  On return, holds whether the credential provider should be used\r
+                         by default to automatically log on the user.  \r
\r
+  @retval EFI_SUCCESS            Default information successfully returned.\r
+  @retval EFI_INVALID_PARAMETER  AutoLogon is NULL.\r
+  \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CredentialDefault (\r
+  IN CONST  EFI_USER_CREDENTIAL_PROTOCOL        *This,\r
+  OUT       EFI_CREDENTIAL_LOGON_FLAGS          *AutoLogon\r
+  )\r
+{\r
+  if ((This == NULL) || (AutoLogon == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  *AutoLogon = 0;\r
+  \r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Return information attached to the credential provider.\r
+\r
+  This function returns user information. \r
+\r
+  @param[in]      This          Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.\r
+  @param[in]      UserInfo      Handle of the user information data record. \r
+  @param[out]     Info          On entry, points to a buffer of at least *InfoSize bytes. On\r
+                                exit, holds the user information. If the buffer is too small\r
+                                to hold the information, then EFI_BUFFER_TOO_SMALL is returned\r
+                                and InfoSize is updated to contain the number of bytes actually\r
+                                required.\r
+  @param[in, out] InfoSize      On entry, points to the size of Info. On return, points to the \r
+                                size of the user information. \r
\r
+  @retval EFI_SUCCESS           Information returned successfully.\r
+  @retval EFI_BUFFER_TOO_SMALL  The size specified by InfoSize is too small to hold all of the\r
+                                user information. The size required is returned in *InfoSize.\r
+  @retval EFI_INVALID_PARAMETER Info is NULL or InfoSize is NULL.\r
+  @retval EFI_NOT_FOUND         The specified UserInfo does not refer to a valid user info handle. \r
+                                \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CredentialGetInfo (\r
+  IN CONST  EFI_USER_CREDENTIAL_PROTOCOL        *This,\r
+  IN        EFI_USER_INFO_HANDLE                UserInfo,\r
+  OUT       EFI_USER_INFO                       *Info,\r
+  IN OUT    UINTN                               *InfoSize\r
+  )\r
+{\r
+  EFI_USER_INFO            *CredentialInfo;\r
+  UINTN                    Index;\r
+  \r
+  if ((This == NULL) || (InfoSize == NULL) || (Info == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((UserInfo == NULL) || (mPwdInfoHandle == NULL)) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+  \r
+  //\r
+  // Find information handle in credential info table.\r
+  //\r
+  for (Index = 0; Index < mPwdInfoHandle->Count; Index++) {\r
+    CredentialInfo = mPwdInfoHandle->Info[Index];\r
+    if (UserInfo == (EFI_USER_INFO_HANDLE)CredentialInfo) {\r
+      //\r
+      // The handle is found, copy the user info.\r
+      //\r
+      if (CredentialInfo->InfoSize > *InfoSize) {\r
+        *InfoSize = CredentialInfo->InfoSize;\r
+        return EFI_BUFFER_TOO_SMALL;\r
+      }\r
+      CopyMem (Info, CredentialInfo, CredentialInfo->InfoSize);      \r
+      return EFI_SUCCESS; \r
+    }\r
+  }\r
+  \r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+\r
+/**\r
+  Enumerate all of the user informations on the credential provider.\r
+\r
+  This function returns the next user information record. To retrieve the first user\r
+  information record handle, point UserInfo at a NULL. Each subsequent call will retrieve\r
+  another user information record handle until there are no more, at which point UserInfo\r
+  will point to NULL. \r
+\r
+  @param[in]      This     Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.\r
+  @param[in, out] UserInfo On entry, points to the previous user information handle or NULL\r
+                           to start enumeration. On exit, points to the next user information\r
+                           handle or NULL if there is no more user information.\r
\r
+  @retval EFI_SUCCESS            User information returned.\r
+  @retval EFI_NOT_FOUND          No more user information found.\r
+  @retval EFI_INVALID_PARAMETER  UserInfo is NULL.\r
+  \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CredentialGetNextInfo (\r
+  IN CONST  EFI_USER_CREDENTIAL_PROTOCOL        *This,\r
+  IN OUT    EFI_USER_INFO_HANDLE                *UserInfo\r
+  )\r
+{\r
+  EFI_USER_INFO            *Info;\r
+  CHAR16                   *ProvNameStr;\r
+  UINTN                    InfoLen;\r
+  UINTN                    Index;\r
+  UINTN                    ProvStrLen;\r
+    \r
+  if ((This == NULL) || (UserInfo == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (mPwdInfoHandle == NULL) {\r
+    //\r
+    // Initilized user info table. There are 4 user info records in the table.\r
+    //\r
+    InfoLen  = sizeof (PASSWORD_CREDENTIAL_INFO) + (4 - 1) * sizeof (EFI_USER_INFO *);\r
+    mPwdInfoHandle = AllocateZeroPool (InfoLen);\r
+    if (mPwdInfoHandle == NULL) {\r
+      *UserInfo = NULL;\r
+      return EFI_NOT_FOUND;\r
+    }\r
+\r
+    //\r
+    // The first information, Credential Provider info.\r
+    //\r
+    InfoLen = sizeof (EFI_USER_INFO) + sizeof (EFI_GUID);\r
+    Info    = AllocateZeroPool (InfoLen);\r
+    ASSERT (Info != NULL);\r
+    \r
+    Info->InfoType    = EFI_USER_INFO_CREDENTIAL_PROVIDER_RECORD;\r
+    Info->InfoSize    = (UINT32) InfoLen;\r
+    Info->InfoAttribs = EFI_USER_INFO_PROTECTED;\r
+    CopyGuid (&Info->Credential, &mPwdCredentialGuid);\r
+    CopyGuid ((EFI_GUID *)(Info + 1), &mPwdCredentialGuid);\r
+    \r
+    mPwdInfoHandle->Info[0] = Info;\r
+    mPwdInfoHandle->Count++;\r
+\r
+    //\r
+    // The second information, Credential Provider name info.\r
+    //\r
+    ProvNameStr = GetStringById (STRING_TOKEN (STR_PROVIDER_NAME));\r
+    ProvStrLen  = StrSize (ProvNameStr);\r
+    InfoLen     = sizeof (EFI_USER_INFO) + ProvStrLen;\r
+    Info        = AllocateZeroPool (InfoLen);\r
+    ASSERT (Info != NULL);\r
+    \r
+    Info->InfoType    = EFI_USER_INFO_CREDENTIAL_PROVIDER_NAME_RECORD;\r
+    Info->InfoSize    = (UINT32) InfoLen;\r
+    Info->InfoAttribs = EFI_USER_INFO_PROTECTED;\r
+    CopyGuid (&Info->Credential, &mPwdCredentialGuid);\r
+    CopyMem ((UINT8*)(Info + 1), ProvNameStr, ProvStrLen);\r
+    FreePool (ProvNameStr);\r
+\r
+    mPwdInfoHandle->Info[1] = Info;\r
+    mPwdInfoHandle->Count++;\r
+\r
+    //\r
+    // The third information, Credential Provider type info.\r
+    //\r
+    InfoLen = sizeof (EFI_USER_INFO) + sizeof (EFI_GUID);\r
+    Info    = AllocateZeroPool (InfoLen);\r
+    ASSERT (Info != NULL);\r
+      \r
+    Info->InfoType    = EFI_USER_INFO_CREDENTIAL_TYPE_RECORD;\r
+    Info->InfoSize    = (UINT32) InfoLen;\r
+    Info->InfoAttribs = EFI_USER_INFO_PROTECTED;\r
+    CopyGuid (&Info->Credential, &mPwdCredentialGuid);\r
+    CopyGuid ((EFI_GUID *)(Info + 1), &gEfiUserCredentialClassPasswordGuid);\r
+    \r
+    mPwdInfoHandle->Info[2] = Info;\r
+    mPwdInfoHandle->Count++;\r
\r
+    //\r
+    // The fourth information, Credential Provider type name info.\r
+    //\r
+    ProvNameStr = GetStringById (STRING_TOKEN (STR_PROVIDER_TYPE_NAME));\r
+    ProvStrLen  = StrSize (ProvNameStr);\r
+    InfoLen     = sizeof (EFI_USER_INFO) + ProvStrLen;\r
+    Info        = AllocateZeroPool (InfoLen);\r
+    ASSERT (Info != NULL);\r
+    \r
+    Info->InfoType    = EFI_USER_INFO_CREDENTIAL_PROVIDER_NAME_RECORD;\r
+    Info->InfoSize    = (UINT32) InfoLen;\r
+    Info->InfoAttribs = EFI_USER_INFO_PROTECTED;\r
+    CopyGuid (&Info->Credential, &mPwdCredentialGuid);\r
+    CopyMem ((UINT8*)(Info + 1), ProvNameStr, ProvStrLen);\r
+    FreePool (ProvNameStr);\r
+    \r
+    mPwdInfoHandle->Info[3] = Info;\r
+    mPwdInfoHandle->Count++;\r
+  }\r
+  \r
+  if (*UserInfo == NULL) {\r
+    //\r
+    // Return the first info handle.\r
+    //\r
+    *UserInfo = (EFI_USER_INFO_HANDLE) mPwdInfoHandle->Info[0];\r
+    return EFI_SUCCESS;\r
+  }\r
+  \r
+  //\r
+  // Find information handle in credential info table.\r
+  //\r
+  for (Index = 0; Index < mPwdInfoHandle->Count; Index++) {\r
+    Info = mPwdInfoHandle->Info[Index];\r
+    if (*UserInfo == (EFI_USER_INFO_HANDLE)Info) {\r
+      //\r
+      // The handle is found, get the next one.\r
+      //\r
+      if (Index == mPwdInfoHandle->Count - 1) {\r
+        //\r
+        // Already last one.\r
+        //\r
+        *UserInfo = NULL;\r
+        return EFI_NOT_FOUND;\r
+      }\r
+    \r
+      Index++;\r
+      *UserInfo = (EFI_USER_INFO_HANDLE)mPwdInfoHandle->Info[Index];\r
+      return EFI_SUCCESS;            \r
+    }\r
+  }\r
+\r
+  *UserInfo = NULL;\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+\r
+/**\r
+  Main entry for this driver.\r
+\r
+  @param ImageHandle     Image handle this driver.\r
+  @param SystemTable     Pointer to SystemTable.\r
+\r
+  @retval EFI_SUCESS     This function always complete successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PasswordProviderInit (\r
+  IN EFI_HANDLE        ImageHandle,\r
+  IN EFI_SYSTEM_TABLE  *SystemTable\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  //\r
+  // Init credential table.\r
+  //\r
+  Status = InitCredentialTable ();\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  \r
+  //\r
+  // Init Form Browser.\r
+  //\r
+  Status = InitFormBrowser ();\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  \r
+  //\r
+  // Install protocol interfaces for the password credential provider.\r
+  //\r
+  Status = gBS->InstallProtocolInterface (\r
+                  &mCallbackInfo->DriverHandle,\r
+                  &gEfiUserCredentialProtocolGuid,\r
+                  EFI_NATIVE_INTERFACE,\r
+                  &gPwdCredentialProviderDriver\r
+                  );\r
+  return Status;\r
+}\r
diff --git a/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProvider.h b/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProvider.h
new file mode 100644 (file)
index 0000000..9b5e776
--- /dev/null
@@ -0,0 +1,354 @@
+/** @file\r
+  Password Credential Provider driver header file.\r
+    \r
+Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _PASSWORD_CREDENTIAL_PROVIDER_H_\r
+#define _PASSWORD_CREDENTIAL_PROVIDER_H_\r
+\r
+#include <Uefi.h>\r
+\r
+#include <Guid/GlobalVariable.h>\r
+#include <Guid/MdeModuleHii.h>\r
+\r
+#include <Protocol/HiiConfigAccess.h>\r
+#include <Protocol/UserCredential.h>\r
+#include <Protocol/UserManager.h>\r
+\r
+#include <Library/UefiRuntimeServicesTableLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/DevicePathLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/PrintLib.h>\r
+#include <Library/HiiLib.h>\r
+#include <Library/BaseCryptLib.h>\r
+\r
+#include "PwdCredentialProviderData.h"\r
+\r
+extern UINT8      PwdCredentialProviderStrings[];\r
+extern UINT8      PwdCredentialProviderVfrBin[];\r
+\r
+#define PASSWORD_TABLE_INC  16\r
+#define CREDENTIAL_LEN      20\r
+\r
+//\r
+// Password credential information.\r
+//\r
+typedef struct {\r
+  EFI_USER_INFO_IDENTIFIER  UserId;\r
+  CHAR8                     Password[CREDENTIAL_LEN];\r
+} PASSWORD_INFO;\r
+\r
+//\r
+// Password credential table.\r
+//\r
+typedef struct {\r
+  UINTN         Count;\r
+  UINTN         MaxCount;\r
+  UINTN         ValidIndex;\r
+  PASSWORD_INFO UserInfo[1];\r
+} CREDENTIAL_TABLE;\r
+\r
+//\r
+// The user information on the password provider.\r
+//\r
+typedef struct {\r
+  UINTN                         Count;\r
+  EFI_USER_INFO                 *Info[1];\r
+} PASSWORD_CREDENTIAL_INFO;\r
+\r
+///\r
+/// HII specific Vendor Device Path definition.\r
+///\r
+typedef struct {\r
+  VENDOR_DEVICE_PATH        VendorDevicePath;\r
+  EFI_DEVICE_PATH_PROTOCOL  End;\r
+} HII_VENDOR_DEVICE_PATH;\r
+\r
+#define PWD_PROVIDER_SIGNATURE  SIGNATURE_32 ('P', 'W', 'D', 'P')\r
+\r
+typedef struct {\r
+  UINTN                           Signature;\r
+  EFI_HANDLE                      DriverHandle;\r
+  EFI_HII_HANDLE                  HiiHandle;\r
+  //\r
+  // Produced protocol.\r
+  //\r
+  EFI_HII_CONFIG_ACCESS_PROTOCOL  ConfigAccess;\r
+} PWD_PROVIDER_CALLBACK_INFO;\r
+\r
+\r
+/**\r
+  Enroll a user on a credential provider.\r
+\r
+  This function enrolls and deletes a user profile using this credential provider. \r
+  If a user profile is successfully enrolled, it calls the User Manager Protocol \r
+  function Notify() to notify the user manager driver that credential information \r
+  has changed. If an enrolled user does exist, delete the user on the credential \r
+  provider.\r
+\r
+  @param[in] This                Points to this instance of EFI_USER_CREDENTIAL_PROTOCOL.\r
+  @param[in] User                The user profile to enroll.\r
\r
+  @retval EFI_SUCCESS            User profile was successfully enrolled.\r
+  @retval EFI_ACCESS_DENIED      Current user profile does not permit enrollment on the\r
+                                 user profile handle. Either the user profile cannot enroll\r
+                                 on any user profile or cannot enroll on a user profile \r
+                                 other than the current user profile.\r
+  @retval EFI_UNSUPPORTED        This credential provider does not support enrollment in\r
+                                 the pre-OS.\r
+  @retval EFI_DEVICE_ERROR       The new credential could not be created because of a device\r
+                                 error.\r
+  @retval EFI_INVALID_PARAMETER  User does not refer to a valid user profile handle.\r
+  \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CredentialEnroll (\r
+  IN CONST  EFI_USER_CREDENTIAL_PROTOCOL        *This,\r
+  IN        EFI_USER_PROFILE_HANDLE             User\r
+  );\r
+\r
+/**\r
+  Returns the user interface information used during user identification.\r
+\r
+  This function returns information about the form used when interacting with the\r
+  user during user identification. The form is the first enabled form in the form-set\r
+  class EFI_HII_USER_CREDENTIAL_FORMSET_GUID installed on the HII handle HiiHandle. If \r
+  the user credential provider does not require a form to identify the user, then this\r
+  function should return EFI_NOT_FOUND.\r
+\r
+  @param[in]  This       Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.\r
+  @param[out] Hii        On return, holds the HII database handle.\r
+  @param[out] FormSetId  On return, holds the identifier of the form set which contains\r
+                         the form used during user identification.\r
+  @param[out] FormId     On return, holds the identifier of the form used during user \r
+                         identification.\r
+                         \r
+  @retval EFI_SUCCESS            Form returned successfully.\r
+  @retval EFI_NOT_FOUND          Form not returned.\r
+  @retval EFI_INVALID_PARAMETER  Hii is NULL or FormSetId is NULL or FormId is NULL.\r
+  \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CredentialForm (\r
+  IN CONST  EFI_USER_CREDENTIAL_PROTOCOL        *This,\r
+  OUT       EFI_HII_HANDLE                      *Hii,\r
+  OUT       EFI_GUID                            *FormSetId,\r
+  OUT       EFI_FORM_ID                         *FormId\r
+  );\r
+\r
+/**\r
+  Returns bitmap used to describe the credential provider type.\r
+\r
+  This optional function returns a bitmap which is less than or equal to the number\r
+  of pixels specified by Width and Height. If no such bitmap exists, then EFI_NOT_FOUND\r
+  is returned. \r
+\r
+  @param[in]      This    Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.\r
+  @param[in, out] Width   On entry, points to the desired bitmap width. If NULL then no \r
+                          bitmap information will be returned. On exit, points to the \r
+                          width of the bitmap returned.\r
+  @param[in, out] Height  On entry, points to the desired bitmap height. If NULL then no\r
+                          bitmap information will be returned. On exit, points to the \r
+                          height of the bitmap returned\r
+  @param[out]     Hii     On return, holds the HII database handle. \r
+  @param[out]     Image   On return, holds the HII image identifier. \r
\r
+  @retval EFI_SUCCESS            Image identifier returned successfully.\r
+  @retval EFI_NOT_FOUND          Image identifier not returned.\r
+  @retval EFI_INVALID_PARAMETER  Hii is NULL or Image is NULL.\r
+  \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CredentialTile (\r
+  IN  CONST  EFI_USER_CREDENTIAL_PROTOCOL        *This,\r
+  IN  OUT    UINTN                               *Width,\r
+  IN  OUT    UINTN                               *Height,\r
+      OUT    EFI_HII_HANDLE                      *Hii,\r
+      OUT    EFI_IMAGE_ID                        *Image\r
+  );\r
+\r
+/**\r
+  Returns string used to describe the credential provider type.\r
+\r
+  This function returns a string which describes the credential provider. If no\r
+  such string exists, then EFI_NOT_FOUND is returned. \r
+\r
+  @param[in]  This       Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.\r
+  @param[out] Hii        On return, holds the HII database handle.\r
+  @param[out] String     On return, holds the HII string identifier.\r
\r
+  @retval EFI_SUCCESS            String identifier returned successfully.\r
+  @retval EFI_NOT_FOUND          String identifier not returned.\r
+  @retval EFI_INVALID_PARAMETER  Hii is NULL or String is NULL.\r
+  \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CredentialTitle (\r
+  IN CONST  EFI_USER_CREDENTIAL_PROTOCOL        *This,\r
+  OUT       EFI_HII_HANDLE                      *Hii,\r
+  OUT       EFI_STRING_ID                       *String\r
+  );\r
+\r
+/**\r
+  Return the user identifier associated with the currently authenticated user.\r
+\r
+  This function returns the user identifier of the user authenticated by this credential\r
+  provider. This function is called after the credential-related information has been \r
+  submitted on a form OR after a call to Default() has returned that this credential is\r
+  ready to log on.\r
+\r
+  @param[in]  This           Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.\r
+  @param[in]  User           The user profile handle of the user profile currently being \r
+                             considered by the user identity manager. If NULL, then no user\r
+                             profile is currently under consideration.\r
+  @param[out] Identifier     On return, points to the user identifier. \r
\r
+  @retval EFI_SUCCESS            User identifier returned successfully.\r
+  @retval EFI_NOT_READY          No user identifier can be returned.\r
+  @retval EFI_ACCESS_DENIED      The user has been locked out of this user credential.\r
+  @retval EFI_INVALID_PARAMETER  This is NULL, or Identifier is NULL.\r
+  @retval EFI_NOT_FOUND          User is not NULL, and the specified user handle can't be\r
+                                 found in user profile database\r
+  \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CredentialUser (\r
+  IN CONST  EFI_USER_CREDENTIAL_PROTOCOL        *This,\r
+  IN        EFI_USER_PROFILE_HANDLE             User,\r
+  OUT       EFI_USER_INFO_IDENTIFIER            *Identifier\r
+  );\r
+\r
+/**\r
+  Indicate that user interface interaction has begun for the specified credential.\r
+\r
+  This function is called when a credential provider is selected by the user. If \r
+  AutoLogon returns FALSE, then the user interface will be constructed by the User\r
+  Identity Manager. \r
+\r
+  @param[in]  This       Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.\r
+  @param[out] AutoLogon  On return, points to the credential provider's capabilities \r
+                         after the credential provider has been selected by the user. \r
\r
+  @retval EFI_SUCCESS            Credential provider successfully selected.\r
+  @retval EFI_INVALID_PARAMETER  AutoLogon is NULL.\r
+  \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CredentialSelect (\r
+  IN  CONST  EFI_USER_CREDENTIAL_PROTOCOL    *This,\r
+  OUT        EFI_CREDENTIAL_LOGON_FLAGS      *AutoLogon\r
+  );\r
+\r
+/**\r
+  Indicate that user interface interaction has ended for the specified credential.\r
+\r
+  This function is called when a credential provider is deselected by the user.\r
+\r
+  @param[in] This        Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.\r
\r
+  @retval EFI_SUCCESS    Credential provider successfully deselected.\r
+  \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CredentialDeselect (\r
+  IN CONST  EFI_USER_CREDENTIAL_PROTOCOL        *This\r
+  );\r
+\r
+/**\r
+  Return the default logon behavior for this user credential.\r
+\r
+  This function reports the default login behavior regarding this credential provider.  \r
+\r
+  @param[in]  This       Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.\r
+  @param[out] AutoLogon  On return, holds whether the credential provider should be used\r
+                         by default to automatically log on the user.  \r
\r
+  @retval EFI_SUCCESS            Default information successfully returned.\r
+  @retval EFI_INVALID_PARAMETER  AutoLogon is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CredentialDefault (\r
+  IN CONST  EFI_USER_CREDENTIAL_PROTOCOL        *This,\r
+  OUT       EFI_CREDENTIAL_LOGON_FLAGS          *AutoLogon\r
+  );\r
+\r
+/**\r
+  Return information attached to the credential provider.\r
+\r
+  This function returns user information. \r
+\r
+  @param[in]      This          Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.\r
+  @param[in]      UserInfo      Handle of the user information data record. \r
+  @param[out]     Info          On entry, points to a buffer of at least *InfoSize bytes. On\r
+                                exit, holds the user information. If the buffer is too small\r
+                                to hold the information, then EFI_BUFFER_TOO_SMALL is returned\r
+                                and InfoSize is updated to contain the number of bytes actually\r
+                                required.\r
+  @param[in, out] InfoSize      On entry, points to the size of Info. On return, points to the \r
+                                size of the user information. \r
\r
+  @retval EFI_SUCCESS           Information returned successfully.\r
+  @retval EFI_BUFFER_TOO_SMALL  The size specified by InfoSize is too small to hold all of the\r
+                                user information. The size required is returned in *InfoSize.\r
+  @retval EFI_INVALID_PARAMETER Info is NULL or InfoSize is NULL.\r
+  @retval EFI_NOT_FOUND         The specified UserInfo does not refer to a valid user info handle. \r
+                                \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CredentialGetInfo (\r
+  IN CONST  EFI_USER_CREDENTIAL_PROTOCOL        *This,\r
+  IN        EFI_USER_INFO_HANDLE                UserInfo,\r
+  OUT       EFI_USER_INFO                       *Info,\r
+  IN OUT    UINTN                               *InfoSize\r
+  );\r
+\r
+\r
+/**\r
+  Enumerate all of the user informations on the credential provider.\r
+\r
+  This function returns the next user information record. To retrieve the first user\r
+  information record handle, point UserInfo at a NULL. Each subsequent call will retrieve\r
+  another user information record handle until there are no more, at which point UserInfo\r
+  will point to NULL. \r
+\r
+  @param[in]      This     Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.\r
+  @param[in, out] UserInfo On entry, points to the previous user information handle or NULL\r
+                           to start enumeration. On exit, points to the next user information\r
+                           handle or NULL if there is no more user information.\r
\r
+  @retval EFI_SUCCESS            User information returned.\r
+  @retval EFI_NOT_FOUND          No more user information found.\r
+  @retval EFI_INVALID_PARAMETER  UserInfo is NULL.\r
+  \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CredentialGetNextInfo (\r
+  IN CONST  EFI_USER_CREDENTIAL_PROTOCOL        *This,\r
+  IN OUT    EFI_USER_INFO_HANDLE                *UserInfo\r
+  );\r
+\r
+#endif\r
diff --git a/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderData.h b/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderData.h
new file mode 100644 (file)
index 0000000..ffe0ade
--- /dev/null
@@ -0,0 +1,33 @@
+/** @file\r
+  Data structure used by the Password Credential Provider driver.\r
+    \r
+Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _PWD_CREDENTIAL_PROVIDER_DATA_H_\r
+#define _PWD_CREDENTIAL_PROVIDER_DATA_H_\r
+\r
+#define PWD_CREDENTIAL_PROVIDER_GUID \\r
+  { \\r
+    0x78b9ec8b, 0xc000, 0x46c5, { 0xac, 0x93, 0x24, 0xa0, 0xc1, 0xbb, 0x0, 0xce } \\r
+  }\r
+\r
+//\r
+// Forms definition\r
+//\r
+#define FORMID_GET_PASSWORD_FORM      1\r
+\r
+//\r
+// Key defination\r
+// \r
+#define KEY_GET_PASSWORD              0x1000\r
+\r
+#endif\r
diff --git a/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderDxe.inf b/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderDxe.inf
new file mode 100644 (file)
index 0000000..0ffc24e
--- /dev/null
@@ -0,0 +1,53 @@
+## @file\r
+#  Component description file for Password Credential Provider.\r
+#\r
+# Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = PwdCredentialProvider\r
+  FILE_GUID                      = D6C589EA-DD29-49ef-97F6-1A9FE19A04E0\r
+  MODULE_TYPE                    = UEFI_DRIVER\r
+  VERSION_STRING                 = 1.0\r
+  ENTRY_POINT                    = PasswordProviderInit\r
+\r
+[Sources]\r
+  PwdCredentialProvider.c\r
+  PwdCredentialProvider.h\r
+  PwdCredentialProviderData.h\r
+  PwdCredentialProviderVfr.Vfr\r
+  PwdCredentialProviderStrings.uni\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+  CryptoPkg/CryptoPkg.dec\r
+\r
+[LibraryClasses]\r
+  UefiRuntimeServicesTableLib\r
+  UefiBootServicesTableLib\r
+  UefiDriverEntryPoint\r
+  MemoryAllocationLib\r
+  BaseMemoryLib\r
+  DebugLib\r
+  HiiLib\r
+  UefiLib\r
+  BaseCryptLib\r
+  \r
+[Guids]\r
+  gEfiIfrTianoGuid                              ## CONSUMES ## Guid\r
+  gEfiUserCredentialClassPasswordGuid           ## CONSUMES ## Guid\r
+\r
+[Protocols]\r
+  gEfiDevicePathProtocolGuid                    # PROTOCOL ALWAYS_CONSUMED\r
+  gEfiHiiConfigAccessProtocolGuid\r
+  gEfiUserCredentialProtocolGuid\r
+  gEfiUserManagerProtocolGuid
\ No newline at end of file
diff --git a/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderStrings.uni b/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderStrings.uni
new file mode 100644 (file)
index 0000000..48573b6
Binary files /dev/null and b/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderStrings.uni differ
diff --git a/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderVfr.Vfr b/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderVfr.Vfr
new file mode 100644 (file)
index 0000000..69f4be8
--- /dev/null
@@ -0,0 +1,35 @@
+/** @file\r
+  Password Credential Provider formset.\r
+\r
+Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "PwdCredentialProviderData.h"\r
+\r
+formset \r
+  guid      = PWD_CREDENTIAL_PROVIDER_GUID,\r
+  title     = STRING_TOKEN(STR_CREDENTIAL_TITLE),  \r
+  help      = STRING_TOKEN(STR_NULL_STRING), \r
+  classguid = PWD_CREDENTIAL_PROVIDER_GUID,\r
+  \r
+  form formid = FORMID_GET_PASSWORD_FORM,            \r
+    title = STRING_TOKEN(STR_FORM_TITLE);\r
+    \r
+    text \r
+       help   = STRING_TOKEN(STR_NULL_STRING),  \r
+      text   = STRING_TOKEN(STR_INPUT_PASSWORD),\r
+      text   = STRING_TOKEN(STR_NULL_STRING),\r
+      flags  = INTERACTIVE,\r
+      key    = KEY_GET_PASSWORD;\r
+\r
+  endform;\r
+  \r
+endformset;
\ No newline at end of file
diff --git a/SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProvider.c b/SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProvider.c
new file mode 100644 (file)
index 0000000..6c22bfb
--- /dev/null
@@ -0,0 +1,1407 @@
+/** @file\r
+  Usb Credential Provider driver implemenetation.\r
+    \r
+Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "UsbCredentialProvider.h"\r
+\r
+CREDENTIAL_TABLE            *mUsbTable       = NULL;\r
+USB_PROVIDER_CALLBACK_INFO  *mCallbackInfo   = NULL;\r
+USB_CREDENTIAL_INFO         *mUsbInfoHandle  = NULL;\r
+\r
+//\r
+// Used for save password credential and form browser\r
+// And used as provider identifier\r
+//\r
+EFI_GUID     mUsbCredentialGuid = USB_CREDENTIAL_PROVIDER_GUID;\r
+\r
+HII_VENDOR_DEVICE_PATH      mHiiVendorDevicePath = {\r
+  {\r
+    {\r
+      HARDWARE_DEVICE_PATH,\r
+      HW_VENDOR_DP,\r
+      {\r
+        (UINT8) (sizeof (VENDOR_DEVICE_PATH)),\r
+        (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)\r
+      }\r
+    },\r
+    { 0x9463f883, 0x48f6, 0x4a7a, { 0x97, 0x2d, 0x9f, 0x8f, 0x38, 0xf2, 0xdd, 0x91 } }\r
+  },\r
+  {\r
+    END_DEVICE_PATH_TYPE,\r
+    END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
+    {\r
+      (UINT8) (END_DEVICE_PATH_LENGTH),\r
+      (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)\r
+    }\r
+  }\r
+};\r
+\r
+EFI_USER_CREDENTIAL_PROTOCOL  gUsbCredentialProviderDriver = {\r
+  USB_CREDENTIAL_PROVIDER_GUID,\r
+  EFI_USER_CREDENTIAL_CLASS_SECURE_CARD,\r
+  CredentialEnroll,\r
+  CredentialForm,\r
+  CredentialTile,\r
+  CredentialTitle,\r
+  CredentialUser,\r
+  CredentialSelect,\r
+  CredentialDeselect,\r
+  CredentialDefault,\r
+  CredentialGetInfo,\r
+  CredentialGetNextInfo\r
+};\r
+\r
+\r
+/**\r
+  Get string by string id from HII Interface.\r
+\r
+\r
+  @param[in] Id      String ID to get the string from.\r
+\r
+  @retval  CHAR16 *  String from ID.\r
+  @retval  NULL      If error occurs.\r
+\r
+**/\r
+CHAR16 *\r
+GetStringById (\r
+  IN EFI_STRING_ID             Id\r
+  )\r
+{\r
+  //\r
+  // Get the current string for the current Language\r
+  //\r
+  return HiiGetString (mCallbackInfo->HiiHandle, Id, NULL);\r
+}\r
+\r
+\r
+/**\r
+  Expand password table size.\r
+\r
+**/\r
+VOID\r
+ExpandTableSize (\r
+  VOID\r
+  )\r
+{\r
+  CREDENTIAL_TABLE  *NewTable;\r
+  UINTN             Count;\r
+\r
+  Count = mUsbTable->MaxCount + USB_TABLE_INC;\r
+  //\r
+  // Create new credential table.\r
+  //\r
+  NewTable = AllocateZeroPool (\r
+               sizeof (CREDENTIAL_TABLE) - sizeof (USB_INFO) +\r
+               Count * sizeof (USB_INFO)\r
+               );\r
+  ASSERT (NewTable != NULL); \r
+\r
+  NewTable->MaxCount = Count;\r
+  NewTable->Count    = mUsbTable->Count;\r
+\r
+  //\r
+  // Copy old entries.\r
+  //\r
+  CopyMem (\r
+    &NewTable->UserInfo, \r
+    &mUsbTable->UserInfo, \r
+    mUsbTable->Count * sizeof (USB_INFO)\r
+    );\r
+  FreePool (mUsbTable);\r
+  mUsbTable = NewTable;\r
+}\r
+\r
+\r
+/**\r
+  Add or delete info in table, and sync with NV variable.\r
+\r
+  @param[in]  Index     The index of the password in table. The index begin from 1.\r
+                        If index is found in table, delete the info, else add the \r
+                        into to table. \r
+  @param[in]  Info      The new password info to add into table.\r
+\r
+  @retval EFI_INVALID_PARAMETER  Info is NULL when save the info.\r
+  @retval EFI_SUCCESS            Modify the table successfully.\r
+  @retval Others                 Failed to modify the table.\r
+\r
+**/\r
+EFI_STATUS\r
+ModifyTable (\r
+  IN  UINTN                                Index,\r
+  IN  USB_INFO                             * Info OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  \r
+  if (Index < mUsbTable->Count) {\r
+    //\r
+    // Delete the specified entry\r
+    //\r
+    mUsbTable->Count--;\r
+    if (Index != mUsbTable->Count) {\r
+      CopyMem (\r
+        &mUsbTable->UserInfo[Index],\r
+        &mUsbTable->UserInfo[mUsbTable->Count],\r
+        sizeof (USB_INFO)\r
+        );\r
+    }\r
+  } else {\r
+    //\r
+    // Add a new entry\r
+    //\r
+    if (Info == NULL) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    if (mUsbTable->Count >= mUsbTable->MaxCount) {\r
+      ExpandTableSize ();\r
+    }\r
+\r
+    CopyMem (\r
+      &mUsbTable->UserInfo[mUsbTable->Count], \r
+      Info, \r
+      sizeof (USB_INFO)\r
+      );\r
+    mUsbTable->Count++;\r
+  }\r
+\r
+  //\r
+  // Save the credential table.\r
+  //\r
+  Status = gRT->SetVariable (\r
+                  L"UsbCredential",\r
+                  &mUsbCredentialGuid,\r
+                  EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
+                  mUsbTable->Count * sizeof (USB_INFO),\r
+                  &mUsbTable->UserInfo\r
+                  );\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Create a credential table\r
+\r
+  @retval EFI_SUCCESS      Create a credential table successfully.\r
+  @retval Others           Failed to create a password.\r
+\r
+**/\r
+EFI_STATUS\r
+InitCredentialTable (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  UINT8       *Var;\r
+  UINTN       VarSize;\r
+\r
+  //\r
+  // Get Usb credential data from NV variable.\r
+  //\r
+  VarSize = 0;\r
+  Var     = NULL;\r
+  Status  = gRT->GetVariable (\r
+                   L"UsbCredential", \r
+                   &mUsbCredentialGuid, \r
+                   NULL, \r
+                   &VarSize,\r
+                   Var\r
+                   );\r
+  if (Status == EFI_BUFFER_TOO_SMALL) {\r
+    Var = AllocateZeroPool (VarSize);\r
+    if (Var == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+    Status = gRT->GetVariable (\r
+                    L"UsbCredential", \r
+                    &mUsbCredentialGuid, \r
+                    NULL, \r
+                    &VarSize,\r
+                    Var\r
+                    );\r
+  }\r
+  if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {\r
+    return Status;\r
+  }\r
+  \r
+  //\r
+  // Init Usb credential table.\r
+  //\r
+  mUsbTable = AllocateZeroPool (\r
+                sizeof (CREDENTIAL_TABLE) - sizeof (USB_INFO) +\r
+                USB_TABLE_INC * sizeof (USB_INFO) + \r
+                VarSize\r
+                );\r
+  if (mUsbTable == NULL) {\r
+    FreePool (Var);\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  mUsbTable->Count      = VarSize / sizeof (USB_INFO);\r
+  mUsbTable->MaxCount   = mUsbTable->Count + USB_TABLE_INC;\r
+  if (Var != NULL) {\r
+    CopyMem (mUsbTable->UserInfo, Var, VarSize);\r
+    FreePool (Var);\r
+  }\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Read the specified file by FileName in the Usb key and return the file size in BufferSize\r
+  and file content in Buffer.\r
+  Note: the caller is responsible to free the buffer memory.\r
+\r
+  @param  FileName               File to read.\r
+  @param  Buffer                 Returned with data read from the file.\r
+  @param  BufferSize             Size of the data buffer.\r
+\r
+  @retval EFI_SUCCESS            The command completed successfully.\r
+  @retval EFI_OUT_OF_RESOURCES   Resource allocation failed.\r
+  @retval EFI_NOT_FOUND          File not found.\r
+  @retval EFI_DEVICE_ERROR       Device I/O error.\r
+\r
+**/\r
+EFI_STATUS\r
+GetFileData (\r
+  IN     CHAR16                                 *FileName,\r
+  OUT VOID                                      **Buffer,\r
+  OUT UINTN                                     *BufferSize\r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  UINTN                           Index;\r
+  UINTN                           HandleCount;\r
+  UINTN                           ScratchBufferSize;\r
+  EFI_HANDLE                      *HandleBuffer;\r
+  EFI_FILE                        *RootFs;\r
+  EFI_FILE                        *FileHandle;\r
+  EFI_FILE_INFO                   *FileInfo;\r
+  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFileSystem;\r
+  EFI_BLOCK_IO_PROTOCOL           *BlkIo;\r
+\r
+  FileInfo      = NULL;\r
+  FileHandle    = NULL;\r
+\r
+  Status = gBS->LocateHandleBuffer (\r
+                  ByProtocol,\r
+                  &gEfiSimpleFileSystemProtocolGuid,\r
+                  NULL,\r
+                  &HandleCount,\r
+                  &HandleBuffer\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_ERROR, "Can not Locate SimpleFileSystemProtocol\n"));\r
+    goto Done;\r
+  }\r
+\r
+  //\r
+  // Find and open the file in removable media disk.\r
+  //\r
+  for (Index = 0; Index < HandleCount; Index++) {\r
+    Status = gBS->HandleProtocol (\r
+                    HandleBuffer[Index],\r
+                    &gEfiBlockIoProtocolGuid,\r
+                    (VOID **) &BlkIo\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      continue;\r
+    }\r
+\r
+    if (BlkIo->Media->RemovableMedia) {\r
+      Status = gBS->HandleProtocol (\r
+                      HandleBuffer[Index],\r
+                      &gEfiSimpleFileSystemProtocolGuid,\r
+                      (VOID **) &SimpleFileSystem\r
+                      );\r
+      if (EFI_ERROR (Status)) {\r
+        continue;\r
+      }\r
+    \r
+      Status = SimpleFileSystem->OpenVolume (\r
+                                   SimpleFileSystem,\r
+                                   &RootFs\r
+                                   );\r
+      if (EFI_ERROR (Status)) {\r
+        continue;\r
+      }\r
+                                   \r
+      Status = RootFs->Open (\r
+                         RootFs,\r
+                         &FileHandle,\r
+                         FileName,\r
+                         EFI_FILE_MODE_READ,\r
+                         0\r
+                         );\r
+      if (!EFI_ERROR (Status)) {\r
+        break;\r
+      }      \r
+    }\r
+  }\r
+\r
+  FreePool (HandleBuffer);\r
+\r
+  if (Index >= HandleCount) {\r
+    DEBUG ((DEBUG_ERROR, "Can not found the token file!\n"));\r
+    Status = EFI_NOT_FOUND;\r
+    goto Done;\r
+  }\r
+  \r
+  //\r
+  // Figure out how big the file is.\r
+  //\r
+  ScratchBufferSize = 0;\r
+  Status = FileHandle->GetInfo (\r
+                        FileHandle,\r
+                        &gEfiFileInfoGuid,\r
+                        &ScratchBufferSize,\r
+                        NULL\r
+                        );\r
+  if (EFI_ERROR (Status) && (Status != EFI_BUFFER_TOO_SMALL)) {\r
+    DEBUG ((DEBUG_ERROR, "Can not obtain file size info!\n"));\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto Done;\r
+  }\r
+\r
+  FileInfo = AllocateZeroPool (ScratchBufferSize);                                    \r
+  if (FileInfo == NULL) {\r
+    DEBUG ((DEBUG_ERROR, "Can not allocate enough memory for the token file!\n"));\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto Done;\r
+  }\r
+\r
+  Status = FileHandle->GetInfo (\r
+                        FileHandle,\r
+                        &gEfiFileInfoGuid,\r
+                        &ScratchBufferSize,\r
+                        FileInfo\r
+                        );\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_ERROR, "Can not obtain file info from the token file!\n"));\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto Done;\r
+  }\r
+  \r
+  //\r
+  // Allocate a buffer for the file.\r
+  //\r
+  *BufferSize = (UINT32) FileInfo->FileSize;\r
+  *Buffer     = AllocateZeroPool (*BufferSize); \r
+  if (*Buffer == NULL) {\r
+    DEBUG ((DEBUG_ERROR, "Can not allocate a buffer for the file!\n"));\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto Done;\r
+  }\r
+  \r
+  //\r
+  // Load file into the allocated memory.\r
+  //\r
+  Status = FileHandle->Read (FileHandle, BufferSize, *Buffer);\r
+  if (EFI_ERROR (Status)) {\r
+    FreePool (*Buffer);\r
+    DEBUG ((DEBUG_ERROR, "Can not read the token file!\n"));\r
+    Status = EFI_DEVICE_ERROR;\r
+    goto Done;\r
+  }\r
+  \r
+  //\r
+  // Close file.\r
+  //\r
+  Status = FileHandle->Close (FileHandle);\r
+  if (EFI_ERROR (Status)) {\r
+    FreePool (*Buffer);\r
+    DEBUG ((DEBUG_ERROR, "Can not close the token file !\n"));\r
+    Status = EFI_DEVICE_ERROR;\r
+  }\r
+\r
+Done:\r
+\r
+  if (FileInfo != NULL) {\r
+    FreePool (FileInfo);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Hash the data to get credential.\r
+\r
+  @param[in]   Buffer         Points to the data buffer \r
+  @param[in]   BufferSize     The size of data in buffer, in bytes.\r
+  @param[out]  Credential     Points to the hashed result\r
+\r
+  @retval      TRUE           Hash the data successfully.\r
+  @retval      FALSE          Failed to hash the data.\r
+                 \r
+**/\r
+BOOLEAN\r
+GenerateCredential (\r
+  IN      UINT8                               *Buffer,\r
+  IN      UINTN                               BufferSize,\r
+     OUT  UINT8                               *Credential\r
+  )\r
+{\r
+  BOOLEAN           Status;\r
+  UINTN             HashSize;\r
+  VOID              *Hash;\r
+  \r
+  HashSize = Sha1GetContextSize ();\r
+  Hash     = AllocatePool (HashSize);\r
+  ASSERT (Hash != NULL);\r
+  \r
+  Status = Sha1Init (Hash);\r
+  if (!Status) {\r
+    goto Done;\r
+  }\r
+  \r
+  Status = Sha1Update (Hash, Buffer, BufferSize);\r
+  if (!Status) {\r
+    goto Done;\r
+  }\r
+  \r
+  Status = Sha1Final (Hash, Credential);\r
+  \r
+Done:\r
+  FreePool (Hash);\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Read the token file, and default the Token is saved at the begining of the file.\r
+\r
+  @param[out]  Token            Token read from a Token file.\r
+\r
+  @retval EFI_SUCCESS           Read a Token successfully.\r
+  @retval Others                Fails to read a Token.\r
+  \r
+**/\r
+EFI_STATUS\r
+GetToken (\r
+  OUT UINT8                                 *Token\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  UINT8       *Buffer;\r
+  UINTN       BufSize;\r
+  CHAR16      *TokenFile;\r
+\r
+  BufSize = 0;\r
+  Buffer  = NULL;\r
+  TokenFile = FixedPcdGetPtr (PcdFixedUsbCredentialProviderTokenFileName);\r
+  Status = GetFileData (TokenFile, (VOID *)&Buffer, &BufSize);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_ERROR, "Read file %s from USB error! Status=(%r)\n", TokenFile, Status));\r
+    return Status;\r
+  }\r
+  \r
+  if (!GenerateCredential (Buffer, BufSize, Token)) {\r
+    DEBUG ((DEBUG_ERROR, "Generate credential from read data failed!\n"));\r
+    FreePool (Buffer);\r
+    return EFI_SECURITY_VIOLATION;\r
+  }\r
+  \r
+  FreePool (Buffer);  \r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Find a user infomation record by the information record type.\r
+\r
+  This function searches all user information records of User from beginning \r
+  until either the information is found or there are no more user infomation\r
+  record. A match occurs when a Info.InfoType field matches the user information\r
+  record type.\r
+\r
+  @param[in]     User      Points to the user profile record to search.                          \r
+  @param[in]     InfoType  The infomation type to be searched.\r
+  @param[out]    Info      Points to the user info found, the caller is responsible\r
+                           to free.\r
+  \r
+  @retval EFI_SUCCESS      Find the user information successfully.\r
+  @retval Others           Fail to find the user information.\r
+\r
+**/\r
+EFI_STATUS\r
+FindUserInfoByType (\r
+  IN      EFI_USER_PROFILE_HANDLE               User,\r
+  IN      UINT8                                 InfoType,\r
+  OUT     EFI_USER_INFO                         **Info\r
+  )\r
+{\r
+  EFI_STATUS                 Status;\r
+  EFI_USER_INFO              *UserInfo;\r
+  UINTN                      UserInfoSize;\r
+  EFI_USER_INFO_HANDLE       UserInfoHandle;\r
+  EFI_USER_MANAGER_PROTOCOL  *UserManager;\r
+  \r
+  //\r
+  // Find user information by information type.\r
+  //\r
+  if (Info == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Status = gBS->LocateProtocol (\r
+                  &gEfiUserManagerProtocolGuid,\r
+                  NULL,\r
+                  (VOID **) &UserManager\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  //\r
+  // Get each user information.\r
+  //\r
+\r
+  UserInfoHandle = NULL;\r
+  UserInfo       = NULL;\r
+  UserInfoSize   = 0;\r
+  while (TRUE) {\r
+    Status = UserManager->GetNextInfo (UserManager, User, &UserInfoHandle);\r
+    if (EFI_ERROR (Status)) {\r
+      break;\r
+    }\r
+    //\r
+    // Get information.\r
+    //\r
+    Status = UserManager->GetInfo (\r
+                            UserManager,\r
+                            User,\r
+                            UserInfoHandle,\r
+                            UserInfo,\r
+                            &UserInfoSize\r
+                            );\r
+    if (Status == EFI_BUFFER_TOO_SMALL) {\r
+      if (UserInfo != NULL) {\r
+        FreePool (UserInfo);\r
+      }\r
+      UserInfo = AllocateZeroPool (UserInfoSize);\r
+      if (UserInfo == NULL) {\r
+        return EFI_OUT_OF_RESOURCES;\r
+      }\r
+      Status = UserManager->GetInfo (\r
+                              UserManager,\r
+                              User,\r
+                              UserInfoHandle,\r
+                              UserInfo,\r
+                              &UserInfoSize\r
+                              );\r
+    }\r
+    if (EFI_ERROR (Status)) {\r
+      break;\r
+    }\r
+\r
+    ASSERT (UserInfo != NULL);\r
+    if (UserInfo->InfoType == InfoType) {\r
+      *Info = UserInfo;\r
+      return EFI_SUCCESS;\r
+    }    \r
+  }\r
+\r
+  if (UserInfo != NULL) {\r
+    FreePool (UserInfo);\r
+  }\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  This function initialize the data mainly used in form browser.\r
+\r
+  @retval EFI_SUCCESS          Initialize form data successfully.\r
+  @retval Others               Fail to Initialize form data.\r
+\r
+**/\r
+EFI_STATUS\r
+InitFormBrowser (\r
+  VOID\r
+  )\r
+{\r
+  USB_PROVIDER_CALLBACK_INFO  *CallbackInfo;\r
+    \r
+  //\r
+  // Initialize driver private data.\r
+  //\r
+  CallbackInfo = AllocateZeroPool (sizeof (USB_PROVIDER_CALLBACK_INFO));\r
+  if (CallbackInfo == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
\r
+  CallbackInfo->DriverHandle  = NULL;\r
+\r
+  //\r
+  // Publish HII data.\r
+  //\r
+  CallbackInfo->HiiHandle = HiiAddPackages (\r
+                              &mUsbCredentialGuid,\r
+                              CallbackInfo->DriverHandle,\r
+                              UsbCredentialProviderStrings,\r
+                              NULL\r
+                              );\r
+  if (CallbackInfo->HiiHandle == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  mCallbackInfo = CallbackInfo;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Enroll a user on a credential provider.\r
+\r
+  This function enrolls and deletes a user profile using this credential provider. \r
+  If a user profile is successfully enrolled, it calls the User Manager Protocol \r
+  function Notify() to notify the user manager driver that credential information \r
+  has changed. If an enrolled user does exist, delete the user on the credential \r
+  provider.\r
+  \r
+  @param[in] This                Points to this instance of EFI_USER_CREDENTIAL_PROTOCOL.\r
+  @param[in] User                The user profile to enroll.\r
\r
+  @retval EFI_SUCCESS            User profile was successfully enrolled.\r
+  @retval EFI_ACCESS_DENIED      Current user profile does not permit enrollment on the\r
+                                 user profile handle. Either the user profile cannot enroll\r
+                                 on any user profile or cannot enroll on a user profile \r
+                                 other than the current user profile.\r
+  @retval EFI_UNSUPPORTED        This credential provider does not support enrollment in\r
+                                 the pre-OS.\r
+  @retval EFI_DEVICE_ERROR       The new credential could not be created because of a device\r
+                                 error.\r
+  @retval EFI_INVALID_PARAMETER  User does not refer to a valid user profile handle.\r
+  \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CredentialEnroll (\r
+  IN CONST  EFI_USER_CREDENTIAL_PROTOCOL        *This,\r
+  IN        EFI_USER_PROFILE_HANDLE             User\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  UINTN                     Index;\r
+  USB_INFO                  UsbInfo;\r
+  EFI_USER_INFO             *UserInfo;\r
+  EFI_INPUT_KEY             Key;\r
+  EFI_USER_MANAGER_PROTOCOL *UserManager;\r
+  UINT8                     *UserId;\r
+  UINT8                     *NewUserId;\r
+  EFI_TPL                   OldTpl;\r
+  CHAR16                    *QuestionStr;\r
+  CHAR16                    *PromptStr;\r
+\r
+  if ((This == NULL) || (User == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
\r
+  Status = gBS->LocateProtocol (\r
+                  &gEfiUserManagerProtocolGuid,\r
+                  NULL,\r
+                  (VOID **) &UserManager\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  //\r
+  // Get User Identifier\r
+  //\r
+  UserInfo = NULL;\r
+  Status = FindUserInfoByType (\r
+             User,\r
+             EFI_USER_INFO_IDENTIFIER_RECORD,\r
+             &UserInfo\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  \r
+  //\r
+  // If User exists in mUsbTable, delete User.\r
+  // \r
+  for (Index = 0; Index < mUsbTable->Count; Index++) {\r
+    UserId    = (UINT8 *) &mUsbTable->UserInfo[Index].UserId;\r
+    NewUserId = (UINT8 *) (UserInfo + 1);\r
+    if (CompareMem (UserId, NewUserId, sizeof (EFI_USER_INFO_IDENTIFIER)) == 0) {\r
+      //\r
+      // Delete the exist Token.\r
+      //\r
+      FreePool (UserInfo);\r
+      return ModifyTable (Index, NULL);\r
+    }\r
+  }\r
+\r
+  //\r
+  // Get Token and User ID to UsbInfo.\r
+  //\r
+  Status = GetToken (UsbInfo.Token);\r
+  if (EFI_ERROR (Status)) {\r
+    QuestionStr = GetStringById (STRING_TOKEN (STR_READ_USB_TOKEN_ERROR));\r
+    PromptStr   = GetStringById (STRING_TOKEN (STR_INSERT_USB_TOKEN)); \r
+    OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);\r
+    gBS->RestoreTPL (TPL_APPLICATION);    \r
+    CreatePopUp (\r
+      EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+      &Key,\r
+      QuestionStr,\r
+      L"",\r
+      PromptStr,\r
+      NULL\r
+      );\r
+    gBS->RaiseTPL (OldTpl);\r
+    FreePool (QuestionStr);\r
+    FreePool (PromptStr);\r
+    FreePool (UserInfo);\r
+    return Status;\r
+  } \r
+  CopyMem (\r
+    UsbInfo.UserId,\r
+    (UINT8 *) (UserInfo + 1),\r
+    sizeof (EFI_USER_INFO_IDENTIFIER)\r
+    );\r
+  FreePool (UserInfo);\r
+\r
+  //\r
+  // Save the new added entry.\r
+  //\r
+  Status = ModifyTable (mUsbTable->Count, &UsbInfo);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Notify the user manager driver that credential information has changed.\r
+  //\r
+  UserManager->Notify (UserManager, mCallbackInfo->DriverHandle);  \r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Returns the user interface information used during user identification.\r
+\r
+  This function returns information about the form used when interacting with the\r
+  user during user identification. The form is the first enabled form in the form-set\r
+  class EFI_HII_USER_CREDENTIAL_FORMSET_GUID installed on the HII handle HiiHandle. If \r
+  the user credential provider does not require a form to identify the user, then this\r
+  function should return EFI_NOT_FOUND.\r
+\r
+  @param[in]  This       Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.\r
+  @param[out] Hii        On return, holds the HII database handle.\r
+  @param[out] FormSetId  On return, holds the identifier of the form set which contains\r
+                         the form used during user identification.\r
+  @param[out] FormId     On return, holds the identifier of the form used during user \r
+                         identification.\r
+                         \r
+  @retval EFI_SUCCESS            Form returned successfully.\r
+  @retval EFI_NOT_FOUND          Form not returned.\r
+  @retval EFI_INVALID_PARAMETER  Hii is NULL or FormSetId is NULL or FormId is NULL.\r
+  \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CredentialForm (\r
+  IN CONST  EFI_USER_CREDENTIAL_PROTOCOL        *This,\r
+  OUT       EFI_HII_HANDLE                      *Hii,\r
+  OUT       EFI_GUID                            *FormSetId,\r
+  OUT       EFI_FORM_ID                         *FormId\r
+  )\r
+{\r
+  if ((This == NULL) || (Hii == NULL) || \r
+      (FormSetId == NULL) || (FormId == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+\r
+/**\r
+  Returns bitmap used to describe the credential provider type.\r
+\r
+  This optional function returns a bitmap which is less than or equal to the number\r
+  of pixels specified by Width and Height. If no such bitmap exists, then EFI_NOT_FOUND\r
+  is returned. \r
+\r
+  @param[in]     This    Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.\r
+  @param[in, out] Width  On entry, points to the desired bitmap width. If NULL then no \r
+                         bitmap information will be returned. On exit, points to the \r
+                         width of the bitmap returned.\r
+  @param[in, out] Height On entry, points to the desired bitmap height. If NULL then no\r
+                         bitmap information will be returned. On exit, points to the \r
+                         height of the bitmap returned.\r
+  @param[out]    Hii     On return, holds the HII database handle. \r
+  @param[out]    Image   On return, holds the HII image identifier. \r
\r
+  @retval EFI_SUCCESS            Image identifier returned successfully.\r
+  @retval EFI_NOT_FOUND          Image identifier not returned.\r
+  @retval EFI_INVALID_PARAMETER  Hii is NULL or Image is NULL.\r
+  \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CredentialTile (\r
+  IN CONST  EFI_USER_CREDENTIAL_PROTOCOL        *This,\r
+  IN OUT    UINTN                               *Width,\r
+  IN OUT    UINTN                               *Height,\r
+  OUT       EFI_HII_HANDLE                      *Hii,\r
+  OUT       EFI_IMAGE_ID                        *Image\r
+  )\r
+{\r
+  if ((This == NULL) || (Hii == NULL) || (Image == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+\r
+/**\r
+  Returns string used to describe the credential provider type.\r
+\r
+  This function returns a string which describes the credential provider. If no\r
+  such string exists, then EFI_NOT_FOUND is returned. \r
+\r
+  @param[in]  This       Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.\r
+  @param[out] Hii        On return, holds the HII database handle.\r
+  @param[out] String     On return, holds the HII string identifier.\r
\r
+  @retval EFI_SUCCESS            String identifier returned successfully.\r
+  @retval EFI_NOT_FOUND          String identifier not returned.\r
+  @retval EFI_INVALID_PARAMETER  Hii is NULL or String is NULL.\r
+  \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CredentialTitle (\r
+  IN CONST  EFI_USER_CREDENTIAL_PROTOCOL        *This,\r
+  OUT       EFI_HII_HANDLE                      *Hii,\r
+  OUT       EFI_STRING_ID                       *String\r
+  )\r
+{\r
+  if ((This == NULL) || (Hii == NULL) || (String == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  //\r
+  // Set Hii handle and String ID.\r
+  //\r
+  *Hii    = mCallbackInfo->HiiHandle;\r
+  *String = STRING_TOKEN (STR_CREDENTIAL_TITLE);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Return the user identifier associated with the currently authenticated user.\r
+\r
+  This function returns the user identifier of the user authenticated by this credential\r
+  provider. This function is called after the credential-related information has been \r
+  submitted on a form OR after a call to Default() has returned that this credential is\r
+  ready to log on.\r
+\r
+  @param[in]  This           Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.\r
+  @param[in]  User           The user profile handle of the user profile currently being \r
+                             considered by the user identity manager. If NULL, then no user\r
+                             profile is currently under consideration.\r
+  @param[out] Identifier     On return, points to the user identifier. \r
\r
+  @retval EFI_SUCCESS            User identifier returned successfully.\r
+  @retval EFI_NOT_READY          No user identifier can be returned.\r
+  @retval EFI_ACCESS_DENIED      The user has been locked out of this user credential.\r
+  @retval EFI_INVALID_PARAMETER  This is NULL, or Identifier is NULL.\r
+  @retval EFI_NOT_FOUND          User is not NULL, and the specified user handle can't be\r
+                                 found in user profile database.\r
+  \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CredentialUser (\r
+  IN CONST  EFI_USER_CREDENTIAL_PROTOCOL        *This,\r
+  IN        EFI_USER_PROFILE_HANDLE             User,\r
+  OUT       EFI_USER_INFO_IDENTIFIER            *Identifier\r
+  )\r
+{\r
+  EFI_STATUS    Status;\r
+  UINTN         Index;\r
+  EFI_USER_INFO *UserInfo;\r
+  UINT8         *UserId;\r
+  UINT8         *NewUserId;\r
+  UINT8         *UserToken; \r
+  UINT8         ReadToken[HASHED_CREDENTIAL_LEN];\r
+  EFI_INPUT_KEY Key;\r
+  EFI_TPL       OldTpl;\r
+  CHAR16        *QuestionStr;\r
+  CHAR16        *PromptStr;\r
+  \r
+  if ((This == NULL) || (Identifier == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
\r
+  if (User == NULL) {\r
+    //\r
+    // Verify the auto logon user, get user id by matched token.\r
+    //\r
+    if (mUsbTable->Count == 0) {\r
+      return EFI_NOT_READY;\r
+    }\r
+    \r
+    //\r
+    // No user selected, get token first and verify the user existed in user database.\r
+    //\r
+    Status = GetToken (ReadToken);\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_NOT_READY;\r
+    }\r
+    \r
+    for (Index = 0; Index < mUsbTable->Count; Index++) {\r
+      //\r
+      // find the specified credential in the Usb credential database.\r
+      //\r
+      UserToken = mUsbTable->UserInfo[Index].Token;\r
+      if (CompareMem (UserToken, ReadToken, HASHED_CREDENTIAL_LEN) == 0) {\r
+        UserId  = (UINT8 *) &mUsbTable->UserInfo[Index].UserId;\r
+        CopyMem (Identifier, UserId, sizeof (EFI_USER_INFO_IDENTIFIER));\r
+        return EFI_SUCCESS;\r
+      }\r
+    }\r
+\r
+    return EFI_NOT_READY;  \r
+  }\r
+   \r
+  //  \r
+  // User is not NULL here. Read a token, and check whether the token matches with \r
+  // the selected user's Token. If not, try to find a token in token DB to matches \r
+  // with read token.\r
+  // \r
+  \r
+  Status = GetToken (ReadToken);\r
+  if (EFI_ERROR (Status)) {\r
+    QuestionStr = GetStringById (STRING_TOKEN (STR_READ_USB_TOKEN_ERROR));\r
+    PromptStr   = GetStringById (STRING_TOKEN (STR_INSERT_USB_TOKEN));\r
+    OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);\r
+    gBS->RestoreTPL (TPL_APPLICATION);\r
+    CreatePopUp (\r
+      EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+      &Key,\r
+      QuestionStr,\r
+      L"",\r
+      PromptStr,\r
+      NULL\r
+      );\r
+    gBS->RaiseTPL (OldTpl);\r
+    FreePool (QuestionStr);\r
+    FreePool (PromptStr);\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  //\r
+  // Get the selected user's identifier.\r
+  //\r
+  Status = FindUserInfoByType (User, EFI_USER_INFO_IDENTIFIER_RECORD, &UserInfo);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_NOT_FOUND;\r
+  } \r
+  \r
+  //\r
+  // Check the selected user's Token with the read token.\r
+  //\r
+  for (Index = 0; Index < mUsbTable->Count; Index++) {\r
+    UserId    = (UINT8 *) &mUsbTable->UserInfo[Index].UserId;\r
+    NewUserId = (UINT8 *) (UserInfo + 1);\r
+    if (CompareMem (UserId, NewUserId, sizeof (EFI_USER_INFO_IDENTIFIER)) == 0) {\r
+      //\r
+      // The user's ID is found in the UsbTable.\r
+      //\r
+      UserToken = mUsbTable->UserInfo[Index].Token;\r
+      if (CompareMem (UserToken, ReadToken, HASHED_CREDENTIAL_LEN) == 0) {\r
+        //\r
+        // The read token matches with the one in UsbTable.\r
+        //\r
+        CopyMem (Identifier, UserId, sizeof (EFI_USER_INFO_IDENTIFIER));\r
+        FreePool (UserInfo);\r
+        return EFI_SUCCESS;\r
+      } \r
+    }\r
+  }\r
+  FreePool (UserInfo);\r
+  \r
+  //\r
+  // The read token mismatch with the User's Token.\r
+  // Only check token.\r
+  //\r
+  for (Index = 0; Index < mUsbTable->Count; Index++) {\r
+    UserToken = mUsbTable->UserInfo[Index].Token;\r
+    if (CompareMem (UserToken, ReadToken, HASHED_CREDENTIAL_LEN) == 0) {\r
+      //\r
+      // The read token matches with the one in UsbTable.\r
+      //\r
+      UserId = (UINT8 *) &mUsbTable->UserInfo[Index].UserId;\r
+      CopyMem (Identifier, UserId, sizeof (EFI_USER_INFO_IDENTIFIER));\r
+      return EFI_SUCCESS;\r
+    } \r
+  }\r
+  \r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+\r
+/**\r
+  Indicate that user interface interaction has begun for the specified credential.\r
+\r
+  This function is called when a credential provider is selected by the user. If \r
+  AutoLogon returns FALSE, then the user interface will be constructed by the User\r
+  Identity Manager. \r
+\r
+  @param[in]  This       Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.\r
+  @param[out] AutoLogon  On return, points to the credential provider's capabilities \r
+                         after the credential provider has been selected by the user. \r
\r
+  @retval EFI_SUCCESS            Credential provider successfully selected.\r
+  @retval EFI_INVALID_PARAMETER  AutoLogon is NULL.\r
+  \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CredentialSelect (\r
+  IN  CONST  EFI_USER_CREDENTIAL_PROTOCOL    *This,\r
+  OUT        EFI_CREDENTIAL_LOGON_FLAGS      *AutoLogon\r
+  )\r
+{\r
+  if ((This == NULL) || (AutoLogon == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  *AutoLogon = EFI_CREDENTIAL_LOGON_FLAG_DEFAULT | EFI_CREDENTIAL_LOGON_FLAG_AUTO;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Indicate that user interface interaction has ended for the specified credential.\r
+\r
+  This function is called when a credential provider is deselected by the user.\r
+\r
+  @param[in] This        Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.\r
\r
+  @retval EFI_SUCCESS    Credential provider successfully deselected.\r
+  \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CredentialDeselect (\r
+  IN CONST  EFI_USER_CREDENTIAL_PROTOCOL        *This\r
+  )\r
+{\r
+  if (This == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Return the default logon behavior for this user credential.\r
+\r
+  This function reports the default login behavior regarding this credential provider.  \r
+\r
+  @param[in]  This       Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.\r
+  @param[out] AutoLogon  On return, holds whether the credential provider should be used\r
+                         by default to automatically log on the user.  \r
\r
+  @retval EFI_SUCCESS            Default information successfully returned.\r
+  @retval EFI_INVALID_PARAMETER  AutoLogon is NULL.\r
+  \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CredentialDefault (\r
+  IN CONST  EFI_USER_CREDENTIAL_PROTOCOL        *This,\r
+  OUT       EFI_CREDENTIAL_LOGON_FLAGS          *AutoLogon\r
+  )\r
+{\r
+  if ((This == NULL) || (AutoLogon == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  *AutoLogon = EFI_CREDENTIAL_LOGON_FLAG_DEFAULT | EFI_CREDENTIAL_LOGON_FLAG_AUTO;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Return information attached to the credential provider.\r
+\r
+  This function returns user information. \r
+\r
+  @param[in]      This          Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.\r
+  @param[in]      UserInfo      Handle of the user information data record. \r
+  @param[out]     Info          On entry, points to a buffer of at least *InfoSize bytes. On\r
+                                exit, holds the user information. If the buffer is too small\r
+                                to hold the information, then EFI_BUFFER_TOO_SMALL is returned\r
+                                and InfoSize is updated to contain the number of bytes actually\r
+                                required.\r
+  @param[in, out] InfoSize      On entry, points to the size of Info. On return, points to the \r
+                                size of the user information. \r
\r
+  @retval EFI_SUCCESS           Information returned successfully.\r
+  @retval EFI_BUFFER_TOO_SMALL  The size specified by InfoSize is too small to hold all of the\r
+                                user information. The size required is returned in *InfoSize.\r
+  @retval EFI_INVALID_PARAMETER Info is NULL or InfoSize is NULL.\r
+  @retval EFI_NOT_FOUND         The specified UserInfo does not refer to a valid user info handle. \r
+                                \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CredentialGetInfo (\r
+  IN CONST  EFI_USER_CREDENTIAL_PROTOCOL        *This,\r
+  IN        EFI_USER_INFO_HANDLE                UserInfo,\r
+  OUT       EFI_USER_INFO                       *Info,\r
+  IN OUT    UINTN                               *InfoSize\r
+  )\r
+{\r
+  EFI_USER_INFO            *CredentialInfo;\r
+  UINTN                    Index;\r
+  \r
+  if ((This == NULL) || (InfoSize == NULL) || (Info == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((UserInfo == NULL) || (mUsbInfoHandle == NULL)) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+  \r
+  //\r
+  // Find information handle in credential info table.\r
+  //\r
+  for (Index = 0; Index < mUsbInfoHandle->Count; Index++) {\r
+    CredentialInfo = mUsbInfoHandle->Info[Index];\r
+    if (UserInfo == (EFI_USER_INFO_HANDLE)CredentialInfo) {\r
+      //\r
+      // The handle is found, copy the user info.\r
+      //\r
+      if (CredentialInfo->InfoSize > *InfoSize) {\r
+        *InfoSize = CredentialInfo->InfoSize;\r
+        return EFI_BUFFER_TOO_SMALL;\r
+      }\r
+      \r
+      CopyMem (Info, CredentialInfo, CredentialInfo->InfoSize);      \r
+      return EFI_SUCCESS;            \r
+    }\r
+  }\r
+  \r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+\r
+/**\r
+  Enumerate all of the user informations on the credential provider.\r
+\r
+  This function returns the next user information record. To retrieve the first user\r
+  information record handle, point UserInfo at a NULL. Each subsequent call will retrieve\r
+  another user information record handle until there are no more, at which point UserInfo\r
+  will point to NULL. \r
+\r
+  @param[in]      This     Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.\r
+  @param[in, out] UserInfo On entry, points to the previous user information handle or NULL\r
+                           to start enumeration. On exit, points to the next user information\r
+                           handle or NULL if there is no more user information.\r
\r
+  @retval EFI_SUCCESS            User information returned.\r
+  @retval EFI_NOT_FOUND          No more user information found.\r
+  @retval EFI_INVALID_PARAMETER  UserInfo is NULL.\r
+  \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CredentialGetNextInfo (\r
+  IN CONST  EFI_USER_CREDENTIAL_PROTOCOL        *This,\r
+  IN OUT    EFI_USER_INFO_HANDLE                *UserInfo\r
+  )\r
+{\r
+  EFI_USER_INFO            *Info;\r
+  CHAR16                   *ProvNameStr;\r
+  UINTN                    InfoLen;\r
+  UINTN                    Index;\r
+  UINTN                    ProvStrLen;\r
+    \r
+  if ((This == NULL) || (UserInfo == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (mUsbInfoHandle == NULL) {\r
+    //\r
+    // Initilized user info table. There are 4 user info records in the table.\r
+    //\r
+    InfoLen  = sizeof (USB_CREDENTIAL_INFO) + (4 - 1) * sizeof (EFI_USER_INFO *);\r
+    mUsbInfoHandle = AllocateZeroPool (InfoLen);\r
+    if (mUsbInfoHandle == NULL) {\r
+      *UserInfo = NULL;\r
+      return EFI_NOT_FOUND;\r
+    }\r
+\r
+    //\r
+    // The first information, Credential Provider info.\r
+    //\r
+    InfoLen = sizeof (EFI_USER_INFO) + sizeof (EFI_GUID);\r
+    Info    = AllocateZeroPool (InfoLen);\r
+    ASSERT (Info != NULL);\r
+    \r
+    Info->InfoType    = EFI_USER_INFO_CREDENTIAL_PROVIDER_RECORD;\r
+    Info->InfoSize    = (UINT32) InfoLen;\r
+    Info->InfoAttribs = EFI_USER_INFO_PROTECTED;\r
+    CopyGuid (&Info->Credential, &mUsbCredentialGuid);\r
+    CopyGuid ((EFI_GUID *)(Info + 1), &mUsbCredentialGuid);\r
+    \r
+    mUsbInfoHandle->Info[0] = Info;\r
+    mUsbInfoHandle->Count++;\r
+\r
+    //\r
+    // The second information, Credential Provider name info.\r
+    //\r
+    ProvNameStr = GetStringById (STRING_TOKEN (STR_PROVIDER_NAME));\r
+    ProvStrLen  = StrSize (ProvNameStr);\r
+    InfoLen     = sizeof (EFI_USER_INFO) + ProvStrLen;\r
+    Info        = AllocateZeroPool (InfoLen);\r
+    ASSERT (Info != NULL);\r
+    \r
+    Info->InfoType    = EFI_USER_INFO_CREDENTIAL_PROVIDER_NAME_RECORD;\r
+    Info->InfoSize    = (UINT32) InfoLen;\r
+    Info->InfoAttribs = EFI_USER_INFO_PROTECTED;\r
+    CopyGuid (&Info->Credential, &mUsbCredentialGuid);\r
+    CopyMem ((UINT8*)(Info + 1), ProvNameStr, ProvStrLen);\r
+    FreePool (ProvNameStr);\r
+    \r
+    mUsbInfoHandle->Info[1] = Info;\r
+    mUsbInfoHandle->Count++;\r
+\r
+    //\r
+    // The third information, Credential Provider type info.\r
+    //\r
+    InfoLen = sizeof (EFI_USER_INFO) + sizeof (EFI_GUID);\r
+    Info    = AllocateZeroPool (InfoLen);\r
+    ASSERT (Info != NULL);\r
+      \r
+    Info->InfoType    = EFI_USER_INFO_CREDENTIAL_TYPE_RECORD;\r
+    Info->InfoSize    = (UINT32) InfoLen;\r
+    Info->InfoAttribs = EFI_USER_INFO_PROTECTED;\r
+    CopyGuid (&Info->Credential, &mUsbCredentialGuid);\r
+    CopyGuid ((EFI_GUID *)(Info + 1), &gEfiUserCredentialClassSecureCardGuid);\r
+    \r
+    mUsbInfoHandle->Info[2] = Info;\r
+    mUsbInfoHandle->Count++;\r
\r
+    //\r
+    // The fourth information, Credential Provider type name info.\r
+    //\r
+    ProvNameStr = GetStringById (STRING_TOKEN (STR_PROVIDER_TYPE_NAME));\r
+    ProvStrLen  = StrSize (ProvNameStr);\r
+    InfoLen     = sizeof (EFI_USER_INFO) + ProvStrLen;\r
+    Info        = AllocateZeroPool (InfoLen);\r
+    ASSERT (Info != NULL);\r
+    \r
+    Info->InfoType    = EFI_USER_INFO_CREDENTIAL_PROVIDER_NAME_RECORD;\r
+    Info->InfoSize    = (UINT32) InfoLen;\r
+    Info->InfoAttribs = EFI_USER_INFO_PROTECTED;\r
+    CopyGuid (&Info->Credential, &mUsbCredentialGuid);\r
+    CopyMem ((UINT8*)(Info + 1), ProvNameStr, ProvStrLen);\r
+    FreePool (ProvNameStr);\r
+    \r
+    mUsbInfoHandle->Info[3] = Info;\r
+    mUsbInfoHandle->Count++;\r
+  }\r
+  \r
+  if (*UserInfo == NULL) {\r
+    //\r
+    // Return the first info handle.\r
+    //\r
+    *UserInfo = (EFI_USER_INFO_HANDLE) mUsbInfoHandle->Info[0];\r
+    return EFI_SUCCESS;\r
+  }\r
+  \r
+  //\r
+  // Find information handle in credential info table.\r
+  //\r
+  for (Index = 0; Index < mUsbInfoHandle->Count; Index++) {\r
+    Info = mUsbInfoHandle->Info[Index];\r
+    if (*UserInfo == (EFI_USER_INFO_HANDLE)Info) {\r
+      //\r
+      // The handle is found, get the next one.\r
+      //\r
+      if (Index == mUsbInfoHandle->Count - 1) {\r
+        //\r
+        // Already last one.\r
+        //\r
+        *UserInfo = NULL;\r
+        return EFI_NOT_FOUND;\r
+      }\r
+      Index++;\r
+      *UserInfo = (EFI_USER_INFO_HANDLE)mUsbInfoHandle->Info[Index];\r
+      return EFI_SUCCESS; \r
+    }\r
+  }\r
+\r
+  *UserInfo = NULL;\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+\r
+/**\r
+  Main entry for this driver.\r
+\r
+  @param ImageHandle     Image handle this driver.\r
+  @param SystemTable     Pointer to SystemTable.\r
+\r
+  @retval EFI_SUCESS     This function always complete successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UsbProviderInit (\r
+  IN EFI_HANDLE        ImageHandle,\r
+  IN EFI_SYSTEM_TABLE  *SystemTable\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  //\r
+  // Init credential table.\r
+  //\r
+  Status = InitCredentialTable ();\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  \r
+  //\r
+  // Init Form Browser\r
+  //\r
+  Status = InitFormBrowser ();\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  \r
+  //\r
+  // Install protocol interfaces for the Usb Credential Provider.\r
+  //\r
+  Status = gBS->InstallProtocolInterface (\r
+                  &mCallbackInfo->DriverHandle,\r
+                  &gEfiUserCredentialProtocolGuid,\r
+                  EFI_NATIVE_INTERFACE,\r
+                  &gUsbCredentialProviderDriver\r
+                  );\r
+  return Status;\r
+}\r
diff --git a/SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProvider.h b/SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProvider.h
new file mode 100644 (file)
index 0000000..1d43e9a
--- /dev/null
@@ -0,0 +1,354 @@
+/** @file\r
+  Usb Credential Provider driver header file.\r
+    \r
+Copyright (c) 2009, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _USB_CREDENTIAL_PROVIDER_H_\r
+#define _USB_CREDENTIAL_PROVIDER_H_\r
+\r
+#include <Uefi.h>\r
+\r
+#include <Guid/GlobalVariable.h>\r
+#include <Guid/MdeModuleHii.h>\r
+#include <Guid/FileInfo.h>\r
+#include <Guid/SecurityPkgTokenSpace.h>\r
+\r
+#include <Protocol/SimpleFileSystem.h>\r
+#include <Protocol/BlockIo.h>\r
+#include <Protocol/UserCredential.h>\r
+#include <Protocol/UserManager.h>\r
+\r
+#include <Library/UefiRuntimeServicesTableLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/DevicePathLib.h>\r
+#include <Library/BaseCryptLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/PrintLib.h>\r
+#include <Library/HiiLib.h>\r
+#include <Library/PcdLib.h>\r
+\r
+extern UINT8      UsbCredentialProviderStrings[];\r
+extern UINT8      UsbCredentialProviderVfrBin[];\r
+\r
+#define USB_TABLE_INC          16\r
+#define HASHED_CREDENTIAL_LEN  20\r
+\r
+#define USB_CREDENTIAL_PROVIDER_GUID \\r
+  { \\r
+    0xd0849ed1, 0xa88c, 0x4ba6, { 0xb1, 0xd6, 0xab, 0x50, 0xe2, 0x80, 0xb7, 0xa9 }\\r
+  }\r
+\r
+//\r
+// Save the enroll user credential Information.\r
+//\r
+typedef struct {\r
+  EFI_USER_INFO_IDENTIFIER  UserId;\r
+  UINT8                     Token[HASHED_CREDENTIAL_LEN];\r
+} USB_INFO;\r
+\r
+//\r
+// USB Credential Table.\r
+//\r
+typedef struct {\r
+  UINTN     Count;\r
+  UINTN     MaxCount;\r
+  USB_INFO  UserInfo[1];\r
+} CREDENTIAL_TABLE;\r
+\r
+//\r
+// The user information on the USB provider.\r
+//\r
+typedef struct {\r
+  UINTN                         Count;\r
+  EFI_USER_INFO                 *Info[1];\r
+} USB_CREDENTIAL_INFO;\r
+\r
+///\r
+/// HII specific Vendor Device Path definition.\r
+///\r
+typedef struct {\r
+  VENDOR_DEVICE_PATH        VendorDevicePath;\r
+  EFI_DEVICE_PATH_PROTOCOL  End;\r
+} HII_VENDOR_DEVICE_PATH;\r
+\r
+#define USB_PROVIDER_SIGNATURE  SIGNATURE_32 ('U', 'S', 'B', 'P')\r
+\r
+typedef struct {\r
+  UINTN                           Signature;\r
+  EFI_HANDLE                      DriverHandle;\r
+  EFI_HII_HANDLE                  HiiHandle;\r
+} USB_PROVIDER_CALLBACK_INFO;\r
+\r
+/**\r
+  Enroll a user on a credential provider.\r
+\r
+  This function enrolls and deletes a user profile using this credential provider. \r
+  If a user profile is successfully enrolled, it calls the User Manager Protocol \r
+  function Notify() to notify the user manager driver that credential information \r
+  has changed. If an enrolled user does exist, delete the user on the credential \r
+  provider.\r
+\r
+  @param[in] This                Points to this instance of EFI_USER_CREDENTIAL_PROTOCOL.\r
+  @param[in] User                The user profile to enroll.\r
\r
+  @retval EFI_SUCCESS            User profile was successfully enrolled.\r
+  @retval EFI_ACCESS_DENIED      Current user profile does not permit enrollment on the\r
+                                 user profile handle. Either the user profile cannot enroll\r
+                                 on any user profile or cannot enroll on a user profile \r
+                                 other than the current user profile.\r
+  @retval EFI_UNSUPPORTED        This credential provider does not support enrollment in\r
+                                 the pre-OS.\r
+  @retval EFI_DEVICE_ERROR       The new credential could not be created because of a device\r
+                                 error.\r
+  @retval EFI_INVALID_PARAMETER  User does not refer to a valid user profile handle.\r
+  \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CredentialEnroll (\r
+  IN CONST  EFI_USER_CREDENTIAL_PROTOCOL        *This,\r
+  IN        EFI_USER_PROFILE_HANDLE             User\r
+  );\r
+\r
+/**\r
+  Returns the user interface information used during user identification.\r
+\r
+  This function returns information about the form used when interacting with the\r
+  user during user identification. The form is the first enabled form in the form-set\r
+  class EFI_HII_USER_CREDENTIAL_FORMSET_GUID installed on the HII handle HiiHandle. If \r
+  the user credential provider does not require a form to identify the user, then this\r
+  function should return EFI_NOT_FOUND.\r
+\r
+  @param[in]  This       Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.\r
+  @param[out] Hii        On return, holds the HII database handle.\r
+  @param[out] FormSetId  On return, holds the identifier of the form set which contains\r
+                         the form used during user identification.\r
+  @param[out] FormId     On return, holds the identifier of the form used during user \r
+                         identification.\r
+                         \r
+  @retval EFI_SUCCESS            Form returned successfully.\r
+  @retval EFI_NOT_FOUND          Form not returned.\r
+  @retval EFI_INVALID_PARAMETER  Hii is NULL or FormSetId is NULL or FormId is NULL.\r
+  \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CredentialForm (\r
+  IN CONST  EFI_USER_CREDENTIAL_PROTOCOL        *This,\r
+  OUT       EFI_HII_HANDLE                      *Hii,\r
+  OUT       EFI_GUID                            *FormSetId,\r
+  OUT       EFI_FORM_ID                         *FormId\r
+  );\r
+\r
+/**\r
+  Returns bitmap used to describe the credential provider type.\r
+\r
+  This optional function returns a bitmap which is less than or equal to the number\r
+  of pixels specified by Width and Height. If no such bitmap exists, then EFI_NOT_FOUND\r
+  is returned. \r
+\r
+  @param[in]     This    Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.\r
+  @param[in, out] Width  On entry, points to the desired bitmap width. If NULL then no \r
+                         bitmap information will be returned. On exit, points to the \r
+                         width of the bitmap returned.\r
+  @param[in, out] Height On entry, points to the desired bitmap height. If NULL then no\r
+                         bitmap information will be returned. On exit, points to the \r
+                         height of the bitmap returned.\r
+  @param[out]    Hii     On return, holds the HII database handle. \r
+  @param[out]    Image   On return, holds the HII image identifier. \r
\r
+  @retval EFI_SUCCESS            Image identifier returned successfully.\r
+  @retval EFI_NOT_FOUND          Image identifier not returned.\r
+  @retval EFI_INVALID_PARAMETER  Hii is NULL or Image is NULL.\r
+  \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CredentialTile (\r
+  IN CONST  EFI_USER_CREDENTIAL_PROTOCOL        *This,\r
+  IN OUT    UINTN                               *Width,\r
+  IN OUT    UINTN                               *Height,\r
+  OUT       EFI_HII_HANDLE                      *Hii,\r
+  OUT       EFI_IMAGE_ID                        *Image\r
+  );\r
+\r
+/**\r
+  Returns string used to describe the credential provider type.\r
+\r
+  This function returns a string which describes the credential provider. If no\r
+  such string exists, then EFI_NOT_FOUND is returned. \r
+\r
+  @param[in]  This       Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.\r
+  @param[out] Hii        On return, holds the HII database handle.\r
+  @param[out] String     On return, holds the HII string identifier.\r
\r
+  @retval EFI_SUCCESS            String identifier returned successfully.\r
+  @retval EFI_NOT_FOUND          String identifier not returned.\r
+  @retval EFI_INVALID_PARAMETER  Hii is NULL or String is NULL.\r
+  \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CredentialTitle (\r
+  IN CONST  EFI_USER_CREDENTIAL_PROTOCOL        *This,\r
+  OUT       EFI_HII_HANDLE                      *Hii,\r
+  OUT       EFI_STRING_ID                       *String\r
+  );\r
+\r
+/**\r
+  Return the user identifier associated with the currently authenticated user.\r
+\r
+  This function returns the user identifier of the user authenticated by this credential\r
+  provider. This function is called after the credential-related information has been \r
+  submitted on a form OR after a call to Default() has returned that this credential is\r
+  ready to log on.\r
+\r
+  @param[in]  This           Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.\r
+  @param[in]  User           The user profile handle of the user profile currently being \r
+                             considered by the user identity manager. If NULL, then no user\r
+                             profile is currently under consideration.\r
+  @param[out] Identifier     On return, points to the user identifier. \r
\r
+  @retval EFI_SUCCESS        User identifier returned successfully.\r
+  @retval EFI_NOT_READY      No user identifier can be returned.\r
+  @retval EFI_ACCESS_DENIED  The user has been locked out of this user credential.\r
+  @retval EFI_INVALID_PARAMETER  This is NULL, or Identifier is NULL.\r
+  @retval EFI_NOT_FOUND          User is not NULL, and the specified user handle can't be\r
+                                 found in user profile database.\r
+  \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CredentialUser (\r
+  IN CONST  EFI_USER_CREDENTIAL_PROTOCOL        *This,\r
+  IN        EFI_USER_PROFILE_HANDLE             User,\r
+  OUT       EFI_USER_INFO_IDENTIFIER            *Identifier\r
+  );\r
+\r
+/**\r
+  Indicate that user interface interaction has begun for the specified credential.\r
+\r
+  This function is called when a credential provider is selected by the user. If \r
+  AutoLogon returns FALSE, then the user interface will be constructed by the User\r
+  Identity Manager. \r
+\r
+  @param[in]  This       Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.\r
+  @param[out] AutoLogon  On return, points to the credential provider's capabilities \r
+                         after the credential provider has been selected by the user. \r
\r
+  @retval EFI_SUCCESS            Credential provider successfully selected.\r
+  @retval EFI_INVALID_PARAMETER  AutoLogon is NULL.\r
+  \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CredentialSelect (\r
+  IN  CONST  EFI_USER_CREDENTIAL_PROTOCOL    *This,\r
+  OUT        EFI_CREDENTIAL_LOGON_FLAGS      *AutoLogon\r
+  );\r
+\r
+/**\r
+  Indicate that user interface interaction has ended for the specified credential.\r
+\r
+  This function is called when a credential provider is deselected by the user.\r
+\r
+  @param[in] This        Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.\r
\r
+  @retval EFI_SUCCESS    Credential provider successfully deselected.\r
+  \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CredentialDeselect (\r
+  IN CONST  EFI_USER_CREDENTIAL_PROTOCOL        *This\r
+  );\r
+\r
+/**\r
+  Return the default logon behavior for this user credential.\r
+\r
+  This function reports the default login behavior regarding this credential provider.  \r
+\r
+  @param[in]  This       Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.\r
+  @param[out] AutoLogon  On return, holds whether the credential provider should be used\r
+                         by default to automatically log on the user.  \r
\r
+  @retval EFI_SUCCESS            Default information successfully returned.\r
+  @retval EFI_INVALID_PARAMETER  AutoLogon is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CredentialDefault (\r
+  IN CONST  EFI_USER_CREDENTIAL_PROTOCOL        *This,\r
+  OUT       EFI_CREDENTIAL_LOGON_FLAGS          *AutoLogon\r
+  );\r
+\r
+/**\r
+  Return information attached to the credential provider.\r
+\r
+  This function returns user information. \r
+\r
+  @param[in]      This          Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.\r
+  @param[in]      UserInfo      Handle of the user information data record. \r
+  @param[out]     Info          On entry, points to a buffer of at least *InfoSize bytes. On\r
+                                exit, holds the user information. If the buffer is too small\r
+                                to hold the information, then EFI_BUFFER_TOO_SMALL is returned\r
+                                and InfoSize is updated to contain the number of bytes actually\r
+                                required.\r
+  @param[in, out] InfoSize      On entry, points to the size of Info. On return, points to the \r
+                                size of the user information. \r
\r
+  @retval EFI_SUCCESS           Information returned successfully.\r
+  @retval EFI_BUFFER_TOO_SMALL  The size specified by InfoSize is too small to hold all of the\r
+                                user information. The size required is returned in *InfoSize.\r
+  @retval EFI_INVALID_PARAMETER Info is NULL or InfoSize is NULL.\r
+  @retval EFI_NOT_FOUND         The specified UserInfo does not refer to a valid user info handle. \r
+                                \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CredentialGetInfo (\r
+  IN CONST  EFI_USER_CREDENTIAL_PROTOCOL        *This,\r
+  IN        EFI_USER_INFO_HANDLE                UserInfo,\r
+  OUT       EFI_USER_INFO                       *Info,\r
+  IN OUT    UINTN                               *InfoSize\r
+  );\r
+\r
+/**\r
+  Enumerate all of the user informations on the credential provider.\r
+\r
+  This function returns the next user information record. To retrieve the first user\r
+  information record handle, point UserInfo at a NULL. Each subsequent call will retrieve\r
+  another user information record handle until there are no more, at which point UserInfo\r
+  will point to NULL. \r
+\r
+  @param[in]      This     Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.\r
+  @param[in, out] UserInfo On entry, points to the previous user information handle or NULL\r
+                           to start enumeration. On exit, points to the next user information\r
+                           handle or NULL if there is no more user information.\r
\r
+  @retval EFI_SUCCESS            User information returned.\r
+  @retval EFI_NOT_FOUND          No more user information found.\r
+  @retval EFI_INVALID_PARAMETER  UserInfo is NULL.\r
+  \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CredentialGetNextInfo (\r
+  IN CONST  EFI_USER_CREDENTIAL_PROTOCOL        *This,\r
+  IN OUT    EFI_USER_INFO_HANDLE                *UserInfo\r
+  );\r
+\r
+#endif\r
diff --git a/SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProviderDxe.inf b/SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProviderDxe.inf
new file mode 100644 (file)
index 0000000..2a45763
--- /dev/null
@@ -0,0 +1,58 @@
+## @file\r
+#  Component description file for USB Credential Provider.\r
+#\r
+# Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = UsbCredentialProvider\r
+  FILE_GUID                      = 672A0C68-2BF0-46f9-93C3-C4E7DC0FA555\r
+  MODULE_TYPE                    = UEFI_DRIVER\r
+  VERSION_STRING                 = 1.0\r
+  ENTRY_POINT                    = UsbProviderInit\r
+\r
+[Sources]\r
+  UsbCredentialProvider.c\r
+  UsbCredentialProvider.h\r
+  UsbCredentialProviderStrings.uni\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+  CryptoPkg/CryptoPkg.dec\r
+  SecurityPkg/SecurityPkg.dec\r
+\r
+[LibraryClasses]\r
+  UefiRuntimeServicesTableLib\r
+  UefiBootServicesTableLib\r
+  UefiDriverEntryPoint\r
+  MemoryAllocationLib\r
+  BaseMemoryLib\r
+  DebugLib\r
+  HiiLib\r
+  UefiLib\r
+  BaseCryptLib\r
+  \r
+[Guids]\r
+  gEfiIfrTianoGuid                              ## CONSUMES ## Guid\r
+  gEfiFileInfoGuid                              ## CONSUMES ## Guid\r
+  gEfiUserCredentialClassSecureCardGuid         ## CONSUMES ## Guid\r
+\r
+[Pcd]\r
+  gEfiSecurityPkgTokenSpaceGuid.PcdFixedUsbCredentialProviderTokenFileName\r
+\r
+[Protocols]\r
+  gEfiDevicePathProtocolGuid                    # PROTOCOL ALWAYS_CONSUMED\r
+  gEfiUserCredentialProtocolGuid\r
+  gEfiUserManagerProtocolGuid\r
+  gEfiBlockIoProtocolGuid\r
+  gEfiSimpleFileSystemProtocolGuid\r
+  
\ No newline at end of file
diff --git a/SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProviderStrings.uni b/SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProviderStrings.uni
new file mode 100644 (file)
index 0000000..7c531f4
Binary files /dev/null and b/SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProviderStrings.uni differ
diff --git a/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/LoadDeferredImage.c b/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/LoadDeferredImage.c
new file mode 100644 (file)
index 0000000..da1201a
--- /dev/null
@@ -0,0 +1,148 @@
+/** @file\r
+  Load the deferred images after user is identified.\r
+    \r
+Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "UserIdentifyManager.h"\r
+\r
+EFI_HANDLE        mDeferredImageHandle;\r
+\r
+/**\r
+  The function will load all the deferred images again. If the deferred image is loaded\r
+  successfully, try to start it.\r
+\r
+  @param  Event         Event whose notification function is being invoked.\r
+  @param  Context       Pointer to the notification function's context\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+LoadDeferredImage (\r
+  IN EFI_EVENT                       Event,\r
+  IN VOID                            *Context\r
+  )\r
+{\r
+  EFI_STATUS                         Status;\r
+  EFI_DEFERRED_IMAGE_LOAD_PROTOCOL   *DeferredImage;\r
+  UINTN                              HandleCount;\r
+  EFI_HANDLE                         *HandleBuf;\r
+  UINTN                              Index;\r
+  UINTN                              DriverIndex;\r
+  EFI_DEVICE_PATH_PROTOCOL           *ImageDevicePath;\r
+  VOID                               *DriverImage;\r
+  UINTN                              ImageSize; \r
+  BOOLEAN                            BootOption;\r
+  EFI_HANDLE                         ImageHandle;\r
+  UINTN                              ExitDataSize;\r
+  CHAR16                             *ExitData;\r
+\r
+  //\r
+  // Find all the deferred image load protocols.\r
+  //\r
+  HandleCount = 0;\r
+  HandleBuf   = NULL;\r
+  Status = gBS->LocateHandleBuffer (\r
+                  ByProtocol,\r
+                  &gEfiDeferredImageLoadProtocolGuid,\r
+                  NULL,\r
+                  &HandleCount,\r
+                  &HandleBuf\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return ;\r
+  }\r
+\r
+  for (Index = 0; Index < HandleCount; Index++) {\r
+    Status = gBS->HandleProtocol (\r
+                    HandleBuf[Index],\r
+                    &gEfiDeferredImageLoadProtocolGuid,\r
+                    (VOID **) &DeferredImage\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      continue ;\r
+    }\r
+\r
+    DriverIndex = 0;\r
+    do {\r
+      //\r
+      // Load all the deferred images in this protocol instance.\r
+      //\r
+      Status = DeferredImage->GetImageInfo(\r
+                                DeferredImage, \r
+                                DriverIndex, \r
+                                &ImageDevicePath, \r
+                                (VOID **) &DriverImage,\r
+                                &ImageSize, \r
+                                &BootOption\r
+                                );\r
+      if (EFI_ERROR (Status)) {\r
+        break;\r
+      } \r
+\r
+      //\r
+      // Load and start the image.\r
+      //\r
+      Status = gBS->LoadImage (\r
+                      BootOption,\r
+                      mDeferredImageHandle,\r
+                      ImageDevicePath,\r
+                      NULL,\r
+                      0,\r
+                      &ImageHandle\r
+                      );\r
+      if (!EFI_ERROR (Status)) {\r
+        //\r
+        // Before calling the image, enable the Watchdog Timer for\r
+        // a 5 Minute period\r
+        //\r
+        gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);\r
+        Status = gBS->StartImage (ImageHandle, &ExitDataSize, &ExitData);\r
+    \r
+        //\r
+        // Clear the Watchdog Timer after the image returns.\r
+        //\r
+        gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);\r
+      }\r
+      DriverIndex++;\r
+    } while (TRUE);\r
+  }\r
+  FreePool (HandleBuf); \r
+}\r
+\r
+\r
+/**\r
+  Register an event notification function for user profile changed.\r
+\r
+  @param[in]  ImageHandle     Image handle this driver.\r
+\r
+**/\r
+VOID\r
+LoadDeferredImageInit (\r
+  IN EFI_HANDLE        ImageHandle\r
+  )\r
+{\r
+  EFI_STATUS    Status;\r
+  EFI_EVENT     Event;\r
+\r
+  mDeferredImageHandle = ImageHandle;\r
+  \r
+  Status = gBS->CreateEventEx (\r
+                  EVT_NOTIFY_SIGNAL,\r
+                  TPL_CALLBACK,\r
+                  LoadDeferredImage,\r
+                  NULL,\r
+                  &gEfiEventUserProfileChangedGuid,\r
+                  &Event\r
+                  );\r
+\r
+  ASSERT (Status == EFI_SUCCESS);\r
+}\r
diff --git a/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManager.c b/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManager.c
new file mode 100644 (file)
index 0000000..e105579
--- /dev/null
@@ -0,0 +1,4381 @@
+/** @file\r
+  This driver manages user information and produces user manager protocol.\r
+  \r
+Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "UserIdentifyManager.h"\r
+\r
+//\r
+// Guid used in user profile saving and in form browser.\r
+//\r
+EFI_GUID                    mUserManagerGuid  = USER_IDENTIFY_MANAGER_GUID;\r
+\r
+//\r
+// Default user name.\r
+//\r
+CHAR16                      mUserName[]       = L"Administrator";\r
+\r
+//\r
+// Points to the user profile database.\r
+//\r
+USER_PROFILE_DB             *mUserProfileDb   = NULL;\r
+\r
+//\r
+// Points to the credential providers found in system.\r
+//\r
+CREDENTIAL_PROVIDER_INFO    *mProviderDb      = NULL;\r
+\r
+//\r
+// Current user shared in multi function.\r
+//\r
+EFI_USER_PROFILE_HANDLE     mCurrentUser      = NULL;\r
+\r
+//\r
+// Flag indicates a user is identified.\r
+//\r
+BOOLEAN                     mIdentified       = FALSE;\r
+USER_MANAGER_CALLBACK_INFO  *mCallbackInfo    = NULL;\r
+HII_VENDOR_DEVICE_PATH      mHiiVendorDevicePath = {\r
+  {\r
+    {\r
+      HARDWARE_DEVICE_PATH,\r
+      HW_VENDOR_DP,\r
+      {\r
+        (UINT8) (sizeof (VENDOR_DEVICE_PATH)),\r
+        (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)\r
+      }\r
+    },\r
+    //\r
+    // {ACA7C06F-743C-454f-9C6D-692138482498}\r
+    //\r
+    { 0xaca7c06f, 0x743c, 0x454f, { 0x9c, 0x6d, 0x69, 0x21, 0x38, 0x48, 0x24, 0x98 } }\r
+  },\r
+  {\r
+    END_DEVICE_PATH_TYPE,\r
+    END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
+    {\r
+      (UINT8) (END_DEVICE_PATH_LENGTH),\r
+      (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)\r
+    }\r
+  }\r
+};\r
+\r
+\r
+EFI_USER_MANAGER_PROTOCOL gUserIdentifyManager = {\r
+  UserProfileCreate,\r
+  UserProfileDelete,\r
+  UserProfileGetNext,\r
+  UserProfileCurrent,\r
+  UserProfileIdentify,\r
+  UserProfileFind,\r
+  UserProfileNotify,\r
+  UserProfileGetInfo,\r
+  UserProfileSetInfo,\r
+  UserProfileDeleteInfo,\r
+  UserProfileGetNextInfo,\r
+};\r
+\r
+\r
+/**\r
+  Find the specified user in the user database.\r
+\r
+  This function searches the specified user from the beginning of the user database. \r
+  And if NextUser is TRUE, return the next User in the user database.  \r
+  \r
+  @param[in, out] User         On entry, points to the user profile entry to search. \r
+                               On return, points to the user profile entry or NULL if not found.\r
+  @param[in]      NextUser     If FALSE, find the user in user profile database specifyed by User\r
+                               If TRUE, find the next user in user profile database specifyed \r
+                               by User. \r
+  @param[out]     ProfileIndex A pointer to the index of user profile database that matches the \r
+                               user specifyed by User.\r
+\r
+  @retval EFI_NOT_FOUND        User was NULL, or User was not found, or the next user was not found.\r
+  @retval EFI_SUCCESS          User or the next user are found in user profile database\r
+  \r
+**/\r
+EFI_STATUS\r
+FindUserProfile (\r
+  IN OUT  USER_PROFILE_ENTRY                    **User,\r
+  IN      BOOLEAN                               NextUser,\r
+     OUT  UINTN                                 *ProfileIndex OPTIONAL\r
+  )\r
+{\r
+  UINTN               Index;\r
+\r
+  //\r
+  // Check parameters\r
+  //\r
+  if ((mUserProfileDb == NULL) || (User == NULL)) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+  \r
+  //\r
+  // Check whether the user profile is in the user profile database.\r
+  //\r
+  for (Index = 0; Index < mUserProfileDb->UserProfileNum; Index++) {\r
+    if (mUserProfileDb->UserProfile[Index] == *User) {\r
+      if (ProfileIndex != NULL) {\r
+        *ProfileIndex = Index;\r
+      }\r
+      break;\r
+    }\r
+  }\r
+\r
+  if (NextUser) {\r
+    //\r
+    // Find the next user profile.\r
+    //\r
+    Index++;\r
+    if (Index < mUserProfileDb->UserProfileNum) {\r
+      *User = mUserProfileDb->UserProfile[Index];\r
+    } else if (Index == mUserProfileDb->UserProfileNum) {\r
+      *User = NULL;\r
+      return EFI_NOT_FOUND;\r
+    } else {\r
+      if ((mUserProfileDb->UserProfileNum > 0) && (*User == NULL)) {\r
+        *User = mUserProfileDb->UserProfile[0];\r
+      } else {\r
+        *User = NULL;\r
+        return EFI_NOT_FOUND;\r
+      }\r
+    }\r
+  } else if (Index == mUserProfileDb->UserProfileNum) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Find the specified user information record in the specified User profile.\r
+\r
+  This function searches the specified user information record from the beginning of the user \r
+  profile. And if NextInfo is TRUE, return the next info in the user profile.  \r
+  \r
+  @param[in]      User     Points to the user profile entry.                             \r
+  @param[in, out] Info     On entry, points to the user information record or NULL to start\r
+                           searching with the first user information record.\r
+                           On return, points to the user information record or NULL if not found.                           \r
+  @param[in]      NextInfo If FALSE, find the user information record in profile specifyed by User.\r
+                           If TRUE, find the next user information record in profile specifyed \r
+                           by User. \r
+  @param[out]     Offset   A pointer to the offset of the information record in the user profile.\r
+\r
+  @retval EFI_INVALID_PARAMETER Info is NULL\r
+  @retval EFI_NOT_FOUND         Info was not found, or the next Info was not found.\r
+  @retval EFI_SUCCESS           Info or the next info are found in user profile.\r
+  \r
+**/\r
+EFI_STATUS\r
+FindUserInfo (\r
+  IN     USER_PROFILE_ENTRY                    * User,\r
+  IN OUT EFI_USER_INFO                         **Info,\r
+  IN     BOOLEAN                               NextInfo,\r
+     OUT UINTN                                 *Offset OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS    Status;\r
+  EFI_USER_INFO *UserInfo;\r
+  UINTN         InfoLen;\r
+\r
+  if (Info == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  \r
+  //\r
+  // Check user profile entry\r
+  //\r
+  Status = FindUserProfile (&User, FALSE, NULL);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Find user information in the specified user record.\r
+  //\r
+  InfoLen = 0;\r
+  while (InfoLen < User->UserProfileSize) {\r
+    UserInfo = (EFI_USER_INFO *) (User->ProfileInfo + InfoLen);\r
+    if (UserInfo == *Info) {\r
+      if (Offset != NULL) {\r
+        *Offset = InfoLen;\r
+      }\r
+      break;\r
+    }\r
+    InfoLen += ALIGN_VARIABLE (UserInfo->InfoSize);\r
+  }\r
+  \r
+  //\r
+  // Check whether to find the next user information.\r
+  //\r
+  if (NextInfo) {\r
+    if (InfoLen < User->UserProfileSize) {\r
+      UserInfo = (EFI_USER_INFO *) (User->ProfileInfo + InfoLen);\r
+      InfoLen += ALIGN_VARIABLE (UserInfo->InfoSize);\r
+      if (InfoLen < User->UserProfileSize) {\r
+        *Info = (EFI_USER_INFO *) (User->ProfileInfo + InfoLen);\r
+        if (Offset != NULL) {\r
+          *Offset = InfoLen;\r
+        }\r
+      } else if (InfoLen == User->UserProfileSize) {\r
+        *Info = NULL;\r
+        return EFI_NOT_FOUND;\r
+      }\r
+    } else {\r
+      if (*Info == NULL) {\r
+        *Info = (EFI_USER_INFO *) User->ProfileInfo;\r
+        if (Offset != NULL) {\r
+          *Offset = 0;\r
+        }\r
+      } else {\r
+        *Info = NULL;\r
+        return EFI_NOT_FOUND;\r
+      }\r
+    }\r
+  } else if (InfoLen == User->UserProfileSize) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Find a user infomation record by the information record type.\r
+\r
+  This function searches all user information records of User. The search starts with the \r
+  user information record following Info and continues until either the information is found \r
+  or there are no more user infomation record.\r
+  A match occurs when a Info.InfoType field matches the user information record type.\r
+\r
+  @param[in]      User     Points to the user profile record to search.                          \r
+  @param[in, out] Info     On entry, points to the user information record or NULL to start\r
+                           searching with the first user information record.\r
+                           On return, points to the user information record or NULL if not found.\r
+  @param[in]      InfoType The infomation type to be searched.\r
+\r
+  @retval EFI_SUCCESS           User information was found. Info points to the user information record.\r
+  @retval EFI_NOT_FOUND         User information was not found.                           \r
+  @retval EFI_INVALID_PARAMETER User is NULL or Info is NULL.\r
+  \r
+**/\r
+EFI_STATUS\r
+FindUserInfoByType (\r
+  IN      USER_PROFILE_ENTRY                    *User,\r
+  IN OUT  EFI_USER_INFO                         **Info,\r
+  IN      UINT8                                 InfoType\r
+  )\r
+{\r
+  EFI_STATUS    Status;\r
+  EFI_USER_INFO *UserInfo;\r
+  UINTN         InfoLen;\r
+\r
+  if (Info == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  \r
+  //\r
+  // Check whether the user has the specified user information.\r
+  //\r
+  InfoLen = 0;\r
+  if (*Info == NULL) {\r
+    Status = FindUserProfile (&User, FALSE, NULL);\r
+  } else {\r
+    Status = FindUserInfo (User, Info, TRUE, &InfoLen);\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+  \r
+  while (InfoLen < User->UserProfileSize) {\r
+    UserInfo = (EFI_USER_INFO *) (User->ProfileInfo + InfoLen);\r
+    if (UserInfo->InfoType == InfoType) {\r
+      if (UserInfo != *Info) {\r
+        *Info = UserInfo;\r
+        return EFI_SUCCESS;\r
+      }\r
+    }\r
+\r
+    InfoLen += ALIGN_VARIABLE (UserInfo->InfoSize);\r
+  }\r
+\r
+  *Info = NULL;\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+/**\r
+  Find a user using a user information record.\r
+\r
+  This function searches all user profiles for the specified user information record. The \r
+  search starts with the user information record handle following UserInfo and continues \r
+  until either the information is found or there are no more user profiles.\r
+  A match occurs when the Info.InfoType field matches the user information record type and the \r
+  user information record data matches the portion of Info passed the EFI_USER_INFO header.\r
+\r
+  @param[in, out] User     On entry, points to the previously returned user profile record, \r
+                           or NULL to start searching with the first user profile. \r
+                           On return, points to the user profile entry, or NULL if not found.\r
+  @param[in, out] UserInfo On entry, points to the previously returned user information record, \r
+                           or NULL to start searching with the first. \r
+                           On return, points to the user information record, or NULL if not found.\r
+  @param[in]      Info     Points to the buffer containing the user information to be compared \r
+                           to the user information record.\r
+  @param[in]      InfoSize The size of Info, in bytes. Same as Info->InfoSize.\r
+\r
+  @retval EFI_SUCCESS           User information was found. User points to the user profile record, \r
+                                and UserInfo points to the user information record.\r
+  @retval EFI_NOT_FOUND         User information was not found.                           \r
+  @retval EFI_INVALID_PARAMETER User is NULL; Info is NULL; or, InfoSize is too small.\r
+  \r
+**/\r
+EFI_STATUS\r
+FindUserProfileByInfo (\r
+  IN OUT  USER_PROFILE_ENTRY                    **User,\r
+  IN OUT  EFI_USER_INFO                         **UserInfo, OPTIONAL\r
+  IN      EFI_USER_INFO                         *Info,\r
+  IN      UINTN                                 InfoSize\r
+  )\r
+{\r
+  EFI_STATUS    Status;\r
+  EFI_USER_INFO *InfoEntry;\r
+\r
+\r
+  if ((User == NULL) || (Info == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (InfoSize < sizeof (EFI_USER_INFO)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (UserInfo != NULL) {\r
+    InfoEntry = *UserInfo;\r
+  } else {\r
+    InfoEntry = NULL;\r
+  }\r
+  //\r
+  // Find user profile according to information.\r
+  //\r
+  if (*User == NULL) {\r
+    *User = mUserProfileDb->UserProfile[0];\r
+  }\r
+  \r
+  //\r
+  // Check user profile handle.\r
+  //\r
+  Status = FindUserProfile (User, FALSE, NULL);\r
+\r
+  while (!EFI_ERROR (Status)) {\r
+    //\r
+    // Find the user information in a user profile.\r
+    //\r
+    while (TRUE) {\r
+      Status = FindUserInfoByType (*User, &InfoEntry, Info->InfoType);\r
+      if (EFI_ERROR (Status)) {\r
+        break;\r
+      }\r
+      \r
+      if (InfoSize == Info->InfoSize) {\r
+        if (CompareMem ((UINT8 *) (InfoEntry + 1), (UINT8 *) (Info + 1), InfoSize - sizeof (EFI_USER_INFO)) == 0) {\r
+          //\r
+          // Found the infomation record.\r
+          //\r
+          if (UserInfo != NULL) {\r
+            *UserInfo = InfoEntry;\r
+          }\r
+          return EFI_SUCCESS;\r
+        }\r
+      }      \r
+    }\r
+    \r
+    //\r
+    // Get next user profile.\r
+    //\r
+    InfoEntry = NULL;\r
+    Status    = FindUserProfile (User, TRUE, NULL);\r
+  }\r
+\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+/**\r
+  Find the credential provider in the specified identity policy.\r
+\r
+  @param[in]  FindIdentity        Point to the user identity policy.\r
+  @param[in]  IdentifyInfo        Point to the user information to be searched.\r
+\r
+  @retval TRUE     The credential provider was found in the identity policy.\r
+  @retval FALSE    The credential provider was not found.\r
+**/\r
+BOOLEAN\r
+FindProvider (\r
+  IN       EFI_USER_INFO_IDENTITY_POLICY        *FindIdentity,\r
+  IN CONST EFI_USER_INFO                        *IdentifyInfo\r
+  )\r
+{\r
+  UINTN                         TotalLen;\r
+  EFI_USER_INFO_IDENTITY_POLICY *Identity;\r
+\r
+  //\r
+  // Found the credential provider.\r
+  //\r
+  TotalLen = 0;\r
+  while (TotalLen < IdentifyInfo->InfoSize - sizeof (EFI_USER_INFO)) {\r
+    Identity = (EFI_USER_INFO_IDENTITY_POLICY *) ((UINT8 *) (IdentifyInfo + 1) + TotalLen);\r
+    if ((Identity->Type == FindIdentity->Type) &&\r
+        (Identity->Length == FindIdentity->Length) &&\r
+        CompareGuid ((EFI_GUID *) (Identity + 1), (EFI_GUID *) (FindIdentity + 1))\r
+        ) {\r
+      return TRUE;\r
+    }\r
+\r
+    TotalLen += Identity->Length;\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+\r
+/**\r
+  Check whether the access policy is valid.\r
+\r
+  @param[in]  PolicyInfo          Point to the access policy.\r
+  @param[in]  InfoLen             The policy length.\r
+\r
+  @retval TRUE     The policy is a valid access policy.\r
+  @retval FALSE    The access policy is not a valid access policy.\r
+  \r
+**/\r
+BOOLEAN\r
+CheckAccessPolicy (\r
+  IN  UINT8                                     *PolicyInfo,\r
+  IN  UINTN                                     InfoLen\r
+  )\r
+{\r
+  UINTN                         TotalLen;\r
+  UINTN                         ValueLen;\r
+  UINTN                         OffSet;\r
+  EFI_USER_INFO_ACCESS_CONTROL  Access;\r
+  EFI_DEVICE_PATH_PROTOCOL      *Path;\r
+  UINTN                         PathSize;\r
+\r
+  TotalLen = 0;\r
+  while (TotalLen < InfoLen) {\r
+    //\r
+    // Check access policy according to type.\r
+    //\r
+    CopyMem (&Access, PolicyInfo + TotalLen, sizeof (Access));    \r
+    ValueLen = Access.Size - sizeof (EFI_USER_INFO_ACCESS_CONTROL);\r
+    switch (Access.Type) {\r
+    case EFI_USER_INFO_ACCESS_FORBID_LOAD:\r
+    case EFI_USER_INFO_ACCESS_PERMIT_LOAD:\r
+    case EFI_USER_INFO_ACCESS_FORBID_CONNECT:\r
+    case EFI_USER_INFO_ACCESS_PERMIT_CONNECT:\r
+      OffSet = 0;\r
+      while (OffSet < ValueLen) {\r
+        Path      = (EFI_DEVICE_PATH_PROTOCOL *) (PolicyInfo + TotalLen + sizeof (Access) + OffSet);\r
+        PathSize  = GetDevicePathSize (Path);\r
+        OffSet += PathSize;\r
+      }\r
+      if (OffSet != ValueLen) {\r
+        return FALSE;\r
+      }\r
+      break;\r
+\r
+    case EFI_USER_INFO_ACCESS_SETUP:\r
+      if (ValueLen % sizeof (EFI_GUID) != 0) {\r
+        return FALSE;\r
+      }\r
+      break;\r
+\r
+    case EFI_USER_INFO_ACCESS_BOOT_ORDER:\r
+      if (ValueLen % sizeof (EFI_USER_INFO_ACCESS_BOOT_ORDER_HDR) != 0) {\r
+        return FALSE;\r
+      }\r
+      break;\r
+\r
+    case EFI_USER_INFO_ACCESS_ENROLL_SELF:\r
+    case EFI_USER_INFO_ACCESS_ENROLL_OTHERS:\r
+    case EFI_USER_INFO_ACCESS_MANAGE:\r
+      if (ValueLen != 0) {\r
+        return FALSE;\r
+      }\r
+      break;\r
+\r
+    default:\r
+      return FALSE;\r
+      break;\r
+    }\r
+\r
+    TotalLen += Access.Size;\r
+  }\r
+\r
+  if (TotalLen != InfoLen) {\r
+    return FALSE;\r
+  }\r
+\r
+  return TRUE;\r
+}\r
+\r
+\r
+/**\r
+  Check whether the identity policy is valid.\r
+\r
+  @param[in]  PolicyInfo          Point to the identity policy.\r
+  @param[in]  InfoLen             The policy length.\r
+\r
+  @retval TRUE     The policy is a valid identity policy.\r
+  @retval FALSE    The access policy is not a valid identity policy.\r
+  \r
+**/\r
+BOOLEAN\r
+CheckIdentityPolicy (\r
+  IN  UINT8                                     *PolicyInfo,\r
+  IN  UINTN                                     InfoLen\r
+  )\r
+{\r
+  UINTN                         TotalLen;\r
+  UINTN                         ValueLen;\r
+  EFI_USER_INFO_IDENTITY_POLICY *Identity;\r
+\r
+  TotalLen  = 0;\r
+\r
+  //\r
+  // Check each part of policy expression.\r
+  //\r
+  while (TotalLen < InfoLen) {\r
+    //\r
+    // Check access polisy according to type.\r
+    //\r
+    Identity  = (EFI_USER_INFO_IDENTITY_POLICY *) (PolicyInfo + TotalLen);\r
+    ValueLen  = Identity->Length - sizeof (EFI_USER_INFO_IDENTITY_POLICY);\r
+    switch (Identity->Type) {\r
+    //\r
+    // Check False option.\r
+    //\r
+    case EFI_USER_INFO_IDENTITY_FALSE:\r
+      if (ValueLen != 0) {\r
+        return FALSE;\r
+      }\r
+      break;\r
+\r
+    //\r
+    // Check True option.\r
+    //\r
+    case EFI_USER_INFO_IDENTITY_TRUE:\r
+      if (ValueLen != 0) {\r
+        return FALSE;\r
+      }\r
+      break;\r
+\r
+    //\r
+    // Check negative operation.\r
+    //\r
+    case EFI_USER_INFO_IDENTITY_NOT:\r
+      if (ValueLen != 0) {\r
+        return FALSE;\r
+      }\r
+      break;\r
+\r
+    //\r
+    // Check and operation.\r
+    //\r
+    case EFI_USER_INFO_IDENTITY_AND:\r
+      if (ValueLen != 0) {\r
+        return FALSE;\r
+      }\r
+      break;\r
+\r
+    //\r
+    // Check or operation.\r
+    //\r
+    case EFI_USER_INFO_IDENTITY_OR:\r
+      if (ValueLen != 0) {\r
+        return FALSE;\r
+      }\r
+      break;\r
+\r
+    //\r
+    // Check credential provider by type.\r
+    //\r
+    case EFI_USER_INFO_IDENTITY_CREDENTIAL_TYPE:\r
+      if (ValueLen != sizeof (EFI_GUID)) {\r
+        return FALSE;\r
+      }\r
+      break;\r
+\r
+    //\r
+    // Check credential provider by ID.\r
+    //\r
+    case EFI_USER_INFO_IDENTITY_CREDENTIAL_PROVIDER:\r
+      if (ValueLen != sizeof (EFI_GUID)) {\r
+        return FALSE;\r
+      }\r
+      break;\r
+\r
+    default:\r
+      return FALSE;\r
+      break;\r
+    }\r
+\r
+    TotalLen += Identity->Length;\r
+  }\r
+\r
+  if (TotalLen != InfoLen) {\r
+    return FALSE;\r
+  }\r
+\r
+  return TRUE;\r
+}\r
+\r
+\r
+/**\r
+  Check whether the user information is a valid user information record.\r
+\r
+  @param[in]  Info points to the user information.\r
+\r
+  @retval TRUE     The info is a valid user information record.\r
+  @retval FALSE    The info is not a valid user information record.\r
+  \r
+**/\r
+BOOLEAN\r
+CheckUserInfo (\r
+  IN CONST  EFI_USER_INFO                       *Info\r
+  )\r
+{\r
+  UINTN       InfoLen;\r
+\r
+  if (Info == NULL) {\r
+    return FALSE;\r
+  }\r
+  //\r
+  // Check user information according to information type.\r
+  //\r
+  InfoLen = Info->InfoSize - sizeof (EFI_USER_INFO);\r
+  switch (Info->InfoType) {\r
+  case EFI_USER_INFO_EMPTY_RECORD:\r
+    if (InfoLen != 0) {\r
+      return FALSE;\r
+    }\r
+    break;\r
+\r
+  case EFI_USER_INFO_NAME_RECORD:\r
+  case EFI_USER_INFO_CREDENTIAL_TYPE_NAME_RECORD:\r
+  case EFI_USER_INFO_CREDENTIAL_PROVIDER_NAME_RECORD:\r
+    break;\r
+\r
+  case EFI_USER_INFO_CREATE_DATE_RECORD:\r
+  case EFI_USER_INFO_USAGE_DATE_RECORD:\r
+    if (InfoLen != sizeof (EFI_TIME)) {\r
+      return FALSE;\r
+    }\r
+    break;\r
+\r
+  case EFI_USER_INFO_USAGE_COUNT_RECORD:\r
+    if (InfoLen != sizeof (UINT64)) {\r
+      return FALSE;\r
+    }\r
+    break;\r
+\r
+  case EFI_USER_INFO_IDENTIFIER_RECORD:\r
+    if (InfoLen != 16) {\r
+      return FALSE;\r
+    }\r
+    break;\r
+\r
+  case EFI_USER_INFO_CREDENTIAL_TYPE_RECORD:\r
+  case EFI_USER_INFO_CREDENTIAL_PROVIDER_RECORD:\r
+  case EFI_USER_INFO_GUID_RECORD:\r
+    if (InfoLen != sizeof (EFI_GUID)) {\r
+      return FALSE;\r
+    }\r
+    break;\r
+\r
+  case EFI_USER_INFO_PKCS11_RECORD:\r
+  case EFI_USER_INFO_CBEFF_RECORD:\r
+    break;\r
+\r
+  case EFI_USER_INFO_FAR_RECORD:\r
+  case EFI_USER_INFO_RETRY_RECORD:\r
+    if (InfoLen != 1) {\r
+      return FALSE;\r
+    }\r
+    break;\r
+\r
+  case EFI_USER_INFO_ACCESS_POLICY_RECORD:\r
+    if(!CheckAccessPolicy ((UINT8 *) (Info + 1), InfoLen)) {\r
+      return FALSE;\r
+    }\r
+    break;\r
+\r
+  case EFI_USER_INFO_IDENTITY_POLICY_RECORD:\r
+    if (!CheckIdentityPolicy ((UINT8 *) (Info + 1), InfoLen)) {\r
+      return FALSE;\r
+    }\r
+    break;\r
+\r
+  default:\r
+    return FALSE;\r
+    break;\r
+  }\r
+\r
+  return TRUE;\r
+}\r
+\r
+\r
+/**\r
+  Check the user profile data format to be added.\r
+\r
+  @param[in]  UserProfileInfo     Points to the user profile data.\r
+  @param[in]  UserProfileSize     The length of user profile data.\r
+\r
+  @retval TRUE     It is a valid user profile.\r
+  @retval FALSE    It is not a valid user profile.\r
+  \r
+**/\r
+BOOLEAN\r
+CheckProfileInfo (\r
+  IN  UINT8                                     *UserProfileInfo,\r
+  IN  UINTN                                     UserProfileSize\r
+  )\r
+{\r
+  UINTN         ChkLen;\r
+  EFI_USER_INFO *Info;\r
+\r
+  if (UserProfileInfo == NULL) {\r
+    return FALSE;\r
+  }\r
+  \r
+  //\r
+  // Check user profile information length.\r
+  //\r
+  ChkLen = 0;\r
+  while (ChkLen < UserProfileSize) {\r
+    Info = (EFI_USER_INFO *) (UserProfileInfo + ChkLen);\r
+    //\r
+    // Check user information format.\r
+    //\r
+    if (!CheckUserInfo (Info)) {\r
+      return FALSE;\r
+    }\r
+\r
+    ChkLen += ALIGN_VARIABLE (Info->InfoSize);\r
+  }\r
+\r
+  if (ChkLen != UserProfileSize) {\r
+    return FALSE;\r
+  }\r
+\r
+  return TRUE;\r
+}\r
+\r
+\r
+/**\r
+  Find the specified RightType in current user profile.\r
+\r
+  @param[in]  RightType      Could be EFI_USER_INFO_ACCESS_MANAGE,\r
+                             EFI_USER_INFO_ACCESS_ENROLL_OTHERS or\r
+                             EFI_USER_INFO_ACCESS_ENROLL_SELF.\r
+  \r
+  @retval TRUE     Find the specified RightType in current user profile.\r
+  @retval FALSE    Can't find the right in the profile.\r
+  \r
+**/\r
+BOOLEAN\r
+CheckCurrentUserAccessRight (\r
+  IN        UINT32                              RightType\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  EFI_USER_INFO                 *Info;\r
+  UINTN                         TotalLen;\r
+  UINTN                         CheckLen;\r
+  EFI_USER_INFO_ACCESS_CONTROL  Access;\r
+\r
+  //\r
+  // Get user access right information.\r
+  //\r
+  Info = NULL;\r
+  Status = FindUserInfoByType (\r
+            (USER_PROFILE_ENTRY *) mCurrentUser,\r
+            &Info,\r
+            EFI_USER_INFO_ACCESS_POLICY_RECORD\r
+            );\r
+  if (EFI_ERROR (Status)) {\r
+    return FALSE;\r
+  }\r
+\r
+  ASSERT (Info != NULL);\r
+  TotalLen  = Info->InfoSize - sizeof (EFI_USER_INFO);\r
+  CheckLen  = 0;\r
+  while (CheckLen < TotalLen) {\r
+    //\r
+    // Check right according to access type.\r
+    //\r
+    CopyMem (&Access, (UINT8 *) (Info + 1) + CheckLen, sizeof (Access));\r
+    if (Access.Type == RightType) {\r
+      return TRUE;;\r
+    }\r
+\r
+    CheckLen += Access.Size;\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+\r
+/**\r
+  Create a unique user identifier.\r
+\r
+  @param[out]  Identifier     This points to the identifier.\r
+\r
+**/\r
+VOID\r
+GenerateIdentifier (\r
+   OUT    UINT8                               *Identifier\r
+  )\r
+{\r
+  EFI_TIME  Time;\r
+  UINT64    MonotonicCount;\r
+  UINT32    *MonotonicPointer;\r
+  UINTN     Index;\r
+\r
+  //\r
+  // Create a unique user identifier.\r
+  //\r
+  gRT->GetTime (&Time, NULL);\r
+  CopyMem (Identifier, &Time, sizeof (EFI_TIME));\r
+  //\r
+  // Remove zeros.\r
+  //\r
+  for (Index = 0; Index < sizeof (EFI_TIME); Index++) {\r
+    if (Identifier[Index] == 0) {\r
+      Identifier[Index] = 0x5a;\r
+    }\r
+  }\r
+\r
+  MonotonicPointer = (UINT32 *) Identifier;\r
+  gBS->GetNextMonotonicCount (&MonotonicCount);\r
+  MonotonicPointer[0] += (UINT32) MonotonicCount;\r
+  MonotonicPointer[1] += (UINT32) MonotonicCount;\r
+  MonotonicPointer[2] += (UINT32) MonotonicCount;\r
+  MonotonicPointer[3] += (UINT32) MonotonicCount;\r
+}\r
+\r
+\r
+/**\r
+  Generate unique user ID.\r
+\r
+  @param[out]  UserId                 Points to the user identifer.\r
+\r
+**/\r
+VOID\r
+GenerateUserId (\r
+  OUT    UINT8                               *UserId\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  USER_PROFILE_ENTRY      *UserProfile;\r
+  EFI_USER_INFO           *UserInfo;\r
+  UINTN                   Index;\r
+\r
+  //\r
+  // Generate unique user ID\r
+  //\r
+  while (TRUE) {\r
+    GenerateIdentifier (UserId);\r
+    //\r
+    // Check whether it's unique in user profile database.\r
+    //\r
+    if (mUserProfileDb == NULL) {\r
+      return ;\r
+    }\r
+\r
+    for (Index = 0; Index < mUserProfileDb->UserProfileNum; Index++) {\r
+      UserProfile = (USER_PROFILE_ENTRY *) (mUserProfileDb->UserProfile[Index]);\r
+      UserInfo    = NULL;\r
+      Status      = FindUserInfoByType (UserProfile, &UserInfo, EFI_USER_INFO_IDENTIFIER_RECORD);\r
+      if (EFI_ERROR (Status)) {\r
+        continue;\r
+      }\r
+\r
+      if (CompareMem ((UINT8 *) (UserInfo + 1), UserId, sizeof (EFI_USER_INFO_IDENTIFIER)) == 0) {\r
+        break;\r
+      }\r
+    }\r
+\r
+    if (Index == mUserProfileDb->UserProfileNum) {\r
+      return ;\r
+    }\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Expand user profile database.\r
+\r
+  @retval TRUE     Success to expand user profile database.\r
+  @retval FALSE    Fail to expand user profile database.\r
+  \r
+**/\r
+BOOLEAN\r
+ExpandUsermUserProfileDb (\r
+  VOID\r
+  )\r
+{\r
+  UINTN               MaxNum;\r
+  USER_PROFILE_DB     *NewDataBase;\r
+\r
+  //\r
+  // Create new user profile database.\r
+  //\r
+  if (mUserProfileDb == NULL) {\r
+    MaxNum = USER_NUMBER_INC;\r
+  } else {\r
+    MaxNum = mUserProfileDb->MaxProfileNum + USER_NUMBER_INC;\r
+  }\r
+\r
+  NewDataBase = AllocateZeroPool (\r
+                  sizeof (USER_PROFILE_DB) - sizeof (EFI_USER_PROFILE_HANDLE) +\r
+                  MaxNum * sizeof (EFI_USER_PROFILE_HANDLE)\r
+                  );\r
+  if (NewDataBase == NULL) {\r
+    return FALSE;\r
+  }\r
+\r
+  NewDataBase->MaxProfileNum = MaxNum;\r
+\r
+  //\r
+  // Copy old user profile database value\r
+  //\r
+  if (mUserProfileDb == NULL) {\r
+    NewDataBase->UserProfileNum = 0;\r
+  } else {\r
+    NewDataBase->UserProfileNum = mUserProfileDb->UserProfileNum;\r
+    CopyMem (\r
+      NewDataBase->UserProfile,\r
+      mUserProfileDb->UserProfile,\r
+      NewDataBase->UserProfileNum * sizeof (EFI_USER_PROFILE_HANDLE)\r
+      );\r
+    FreePool (mUserProfileDb);\r
+  }\r
+\r
+  mUserProfileDb = NewDataBase;\r
+  return TRUE;\r
+}\r
+\r
+\r
+/**\r
+  Expand user profile\r
+\r
+  @param[in]  User                    Points to user profile.\r
+  @param[in]  ExpandSize              The size of user profile. \r
+\r
+  @retval TRUE     Success to expand user profile size.\r
+  @retval FALSE    Fail to expand user profile size.\r
+  \r
+**/\r
+BOOLEAN\r
+ExpandUserProfile (\r
+  IN USER_PROFILE_ENTRY                         *User,\r
+  IN UINTN                                      ExpandSize\r
+  )\r
+{\r
+  UINT8 *Info;\r
+  UINTN InfoSizeInc;\r
+\r
+  //\r
+  // Allocate new memory.\r
+  //\r
+  InfoSizeInc = 128;\r
+  User->MaxProfileSize += ((ExpandSize + InfoSizeInc - 1) / InfoSizeInc) * InfoSizeInc;\r
+  Info = AllocateZeroPool (User->MaxProfileSize);\r
+  if (Info == NULL) {\r
+    return FALSE;\r
+  }\r
+  \r
+  //\r
+  // Copy exist information.\r
+  //\r
+  if (User->UserProfileSize > 0) {\r
+    CopyMem (Info, User->ProfileInfo, User->UserProfileSize);\r
+    FreePool (User->ProfileInfo);\r
+  }\r
+\r
+  User->ProfileInfo = Info;\r
+  return TRUE;\r
+}\r
+\r
+\r
+/**\r
+  Add or delete the user's credential record in the provider.\r
+\r
+  @param[in]  ProviderGuid        Point to credential provider guid or class guid.\r
+  @param[in]  ByType              If TRUE, Provider is credential class guid.\r
+                                  If FALSE, Provider is provider guid.\r
+  @param[in]  User                Points to user profile.\r
+\r
+  @retval EFI_SUCCESS      Add or delete record successfully.\r
+  @retval Others           Fail to add or delete record.\r
+\r
+**/\r
+EFI_STATUS\r
+ModifyProviderCredential (\r
+  IN  EFI_GUID                                  *Provider,\r
+  IN  BOOLEAN                                   ByType,\r
+  IN  USER_PROFILE_ENTRY                        *User\r
+  )\r
+{\r
+  UINTN                         Index;\r
+  EFI_USER_CREDENTIAL_PROTOCOL  *UserCredential;\r
+  \r
+  if (Provider == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  \r
+  //\r
+  // Find the specified credential provider.\r
+  //\r
+  for (Index = 0; Index < mProviderDb->Count; Index++) {\r
+    //\r
+    // Check credential provider ID.\r
+    //\r
+    UserCredential = mProviderDb->Provider[Index];\r
+    if (CompareGuid (&UserCredential->Identifier, Provider)) {\r
+      return UserCredential->Enroll (UserCredential, User);\r
+    }\r
+  }\r
+\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+\r
+/**\r
+  Modify user's credential record in the providers.\r
+\r
+  Found the providers information in PolicyInfo, and then add or delete the user's credential\r
+  record in the providers.\r
+\r
+  @param  User                    Points to user profile.\r
+  @param  PolicyInfo              Point to identification policy to be modified.\r
+  @param  InfoLen                 The length of PolicyInfo.\r
+\r
+  @retval EFI_SUCCESS      Modify PolicyInfo successfully.\r
+  @retval Others           Fail to modify PolicyInfo.\r
+\r
+**/\r
+EFI_STATUS\r
+ModifyCredentialInfo (\r
+  IN  USER_PROFILE_ENTRY                        *User,\r
+  IN  UINT8                                     *PolicyInfo,\r
+  IN  UINTN                                     InfoLen\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  UINTN                         TotalLen;\r
+  EFI_USER_INFO_IDENTITY_POLICY *Identity;\r
+\r
+  //\r
+  // Modify user's credential.\r
+  //\r
+  TotalLen = 0;\r
+  while (TotalLen < InfoLen) {\r
+    //\r
+    // Check identification policy according to type.\r
+    //\r
+    Identity = (EFI_USER_INFO_IDENTITY_POLICY *) (PolicyInfo + TotalLen);\r
+    switch (Identity->Type) {\r
+    case EFI_USER_INFO_IDENTITY_CREDENTIAL_TYPE:\r
+      Status = ModifyProviderCredential ((EFI_GUID *) (Identity + 1), TRUE, User);\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+      break;\r
+\r
+    case EFI_USER_INFO_IDENTITY_CREDENTIAL_PROVIDER:\r
+      Status = ModifyProviderCredential ((EFI_GUID *) (Identity + 1), FALSE, User);\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+      break;\r
+\r
+    default:\r
+      break;\r
+    }\r
+\r
+    TotalLen += Identity->Length;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Save the user profile to non-volatile memory, or delete it from non-volatile memory.\r
+\r
+  @param[in]  User         Point to the user profile\r
+  @param[in]  Delete       If TRUE, delete the found user profile.\r
+                           If FALSE, save the user profile.\r
+  @retval EFI_SUCCESS      Save or delete user profile successfully.\r
+  @retval Others           Fail to change the profile.\r
+  \r
+**/\r
+EFI_STATUS\r
+SaveNvUserProfile (\r
+  IN  USER_PROFILE_ENTRY                        *User,\r
+  IN  BOOLEAN                                   Delete\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  //\r
+  // Check user profile entry.\r
+  //\r
+  Status = FindUserProfile (&User, FALSE, NULL);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  \r
+  //\r
+  // Save the user profile to non-volatile memory.\r
+  //\r
+  Status = gRT->SetVariable (\r
+                  User->UserVarName,\r
+                  &mUserManagerGuid,\r
+                  EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
+                  Delete ? 0 : User->UserProfileSize,\r
+                  User->ProfileInfo\r
+                  );\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Replace the old identity info with NewInfo in NV Flash.\r
+\r
+  This function only replace the identity record in the user profile. Don't update\r
+  the the information on the credential provider.\r
+  \r
+  @param[in]   User               Point to the user profile.\r
+  @param[in]   NewInfo            Point to the new identity policy info.\r
+  @param[out]  UserInfo           Point to the new added identity info.\r
+\r
+  @retval EFI_SUCCESS      Replace user identity successfully.\r
+  @retval Others           Fail to Replace user identity.\r
+\r
+**/\r
+EFI_STATUS\r
+SaveUserIpInfo (\r
+  IN       USER_PROFILE_ENTRY                   * User,\r
+  IN CONST EFI_USER_INFO                        * NewInfo,\r
+  OUT   EFI_USER_INFO                           **UserInfo OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS    Status;\r
+  EFI_USER_INFO *OldIpInfo;\r
+  UINTN         Offset;\r
+  UINTN         NextOffset;\r
+\r
+  if ((NewInfo == NULL) || (User == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  \r
+  //\r
+  // Get user old identify policy information.\r
+  //\r
+  OldIpInfo = NULL;\r
+  Status    = FindUserInfoByType (User, &OldIpInfo, EFI_USER_INFO_IDENTITY_POLICY_RECORD);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  \r
+  //\r
+  // Get the old identity policy offset.\r
+  //\r
+  Status = FindUserInfo (User, &OldIpInfo, FALSE, &Offset);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  \r
+  //\r
+  // Delete the old identity policy information.\r
+  //\r
+  NextOffset = ALIGN_VARIABLE (OldIpInfo->InfoSize) + Offset;\r
+  User->UserProfileSize -= ALIGN_VARIABLE (OldIpInfo->InfoSize);\r
+  if (Offset < User->UserProfileSize) {\r
+    CopyMem (User->ProfileInfo + Offset, User->ProfileInfo + NextOffset, User->UserProfileSize - Offset);\r
+  }\r
+  \r
+  //\r
+  // Add new user information.\r
+  //\r
+  if (User->MaxProfileSize - User->UserProfileSize < ALIGN_VARIABLE (NewInfo->InfoSize)) {\r
+    if (!ExpandUserProfile (User, ALIGN_VARIABLE (NewInfo->InfoSize))) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+  }\r
+\r
+  CopyMem (User->ProfileInfo + User->UserProfileSize, (VOID *) NewInfo, NewInfo->InfoSize);\r
+  if (UserInfo != NULL) {\r
+    *UserInfo = (EFI_USER_INFO *) (User->ProfileInfo + User->UserProfileSize);\r
+  }\r
+\r
+  User->UserProfileSize += ALIGN_VARIABLE (NewInfo->InfoSize);\r
+\r
+  //\r
+  // Save user profile information.\r
+  //\r
+  Status = SaveNvUserProfile (User, FALSE);\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Remove the provider in FindIdentity from the user identification information record.\r
+  \r
+  @param[in, out] NewInfo       On entry, points to the user information to remove provider. \r
+                                On return, points to the user information the provider is removed.\r
+  @param[in]      FindIdentity  Point to the user identity policy.\r
+\r
+  @retval TRUE                  The provider is removed successfully.\r
+  @retval FALSE                 Fail to remove the provider.\r
+\r
+**/\r
+BOOLEAN\r
+RemoveProvider (\r
+  IN OUT EFI_USER_INFO                         **NewInfo,\r
+  IN     EFI_USER_INFO_IDENTITY_POLICY         *FindIdentity\r
+  )\r
+{\r
+  UINTN                         TotalLen;\r
+  EFI_USER_INFO_IDENTITY_POLICY *Identity;\r
+  EFI_USER_INFO                 *IdentifyInfo;\r
+  UINT8                         *Buffer;\r
+\r
+  IdentifyInfo = *NewInfo;\r
+  TotalLen = IdentifyInfo->InfoSize - sizeof (EFI_USER_INFO);\r
+  if (TotalLen == FindIdentity->Length) {\r
+    //\r
+    // Only one credential provider in the identification policy.\r
+    // Set the new policy to be TRUE after removed the provider.\r
+    //\r
+    Identity = (EFI_USER_INFO_IDENTITY_POLICY *) (IdentifyInfo + 1);\r
+    Identity->Type         = EFI_USER_INFO_IDENTITY_TRUE;\r
+    Identity->Length       = sizeof (EFI_USER_INFO_IDENTITY_POLICY);  \r
+    IdentifyInfo->InfoSize = sizeof (EFI_USER_INFO) + Identity->Length;\r
+    return TRUE;\r
+  }\r
+\r
+  //\r
+  // Found the credential provider.\r
+  //\r
+  TotalLen = 0;\r
+  while (TotalLen < IdentifyInfo->InfoSize - sizeof (EFI_USER_INFO)) {\r
+    Identity = (EFI_USER_INFO_IDENTITY_POLICY *) ((UINT8 *) (IdentifyInfo + 1) + TotalLen);\r
+    if ((Identity->Type == FindIdentity->Type) &&\r
+        (Identity->Length == FindIdentity->Length) &&\r
+        CompareGuid ((EFI_GUID *) (Identity + 1), (EFI_GUID *) (FindIdentity + 1))\r
+        ) {\r
+      //\r
+      // Found the credential provider to delete\r
+      //\r
+      if (Identity == (EFI_USER_INFO_IDENTITY_POLICY *)(IdentifyInfo + 1)) {\r
+        //\r
+        // It is the first item in the identification policy, delete it and the connector after it.\r
+        //\r
+        Buffer = (UINT8 *) Identity + Identity->Length + sizeof(EFI_USER_INFO_IDENTITY_POLICY);\r
+        IdentifyInfo->InfoSize -= Identity->Length + sizeof(EFI_USER_INFO_IDENTITY_POLICY);\r
+        TotalLen = IdentifyInfo->InfoSize - sizeof (EFI_USER_INFO);\r
+        CopyMem (Identity, Buffer, TotalLen);\r
+       } else {\r
+        //\r
+        // It is not the first item in the identification policy, delete it and the connector before it.\r
+        //\r
+        Buffer    = (UINT8 *) Identity + Identity->Length;\r
+        TotalLen  = IdentifyInfo->InfoSize - sizeof (EFI_USER_INFO);\r
+        TotalLen -= (Buffer - (UINT8 *)(IdentifyInfo + 1));\r
+        IdentifyInfo->InfoSize -= Identity->Length + sizeof(EFI_USER_INFO_IDENTITY_POLICY);\r
+        CopyMem ((UINT8 *) (Identity - 1), Buffer, TotalLen);\r
+      }      \r
+      return TRUE;\r
+    }\r
+\r
+    TotalLen += Identity->Length;\r
+  }  \r
+  return FALSE;\r
+}\r
+\r
+\r
+/**\r
+  This function replaces the old identity policy with a new identity policy.\r
+\r
+  This function changes user identity policy information.\r
+  If enroll new credential failed, recover the old identity policy.\r
+\r
+  For new policy:\r
+  a. For each credential, if it is newly added, try to enroll it.\r
+     If enroll failed, try to delete the newly added ones.\r
+  \r
+  b. For each credential, if it exists in the old policy, delete old one, \r
+     and enroll new one. If failed to enroll the new one, removed it from new \r
+     identification policy.\r
+\r
+  For old policy:  \r
+  a. For each credential, if it does not exist in new one, delete it.\r
+\r
+  @param[in]  User         Point to the user profile.\r
+  @param[in]  Info         Points to the user identity information.\r
+  @param[in]  InfoSize     The size of Info (Not used in this function).\r
+  @param[out] IpInfo       The new identification info after modify.\r
+\r
+  @retval EFI_SUCCESS      Modify user identity policy successfully.\r
+  @retval Others           Fail to modify user identity policy.\r
+\r
+**/\r
+EFI_STATUS\r
+ModifyUserIpInfo (\r
+  IN        USER_PROFILE_ENTRY                  *User,\r
+  IN CONST  EFI_USER_INFO                       *Info,\r
+  IN        UINTN                               InfoSize,\r
+     OUT    EFI_USER_INFO                       **IpInfo\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  EFI_USER_INFO                 *OldIpInfo;\r
+  UINTN                         TotalLen;\r
+  EFI_USER_INFO_IDENTITY_POLICY *Identity;\r
+  UINT32                        CredentialCount;\r
+  EFI_USER_INFO                 *NewIpInfo;\r
+\r
+  //\r
+  // Get user old identify policy information.\r
+  //\r
+  OldIpInfo = NULL;\r
+  Status    = FindUserInfoByType (User, &OldIpInfo, EFI_USER_INFO_IDENTITY_POLICY_RECORD);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  ASSERT (OldIpInfo != NULL);\r
+  \r
+  //\r
+  // Enroll new added credential provider.\r
+  //\r
+  CredentialCount = 0;\r
+  TotalLen        = 0;\r
+  while (TotalLen < Info->InfoSize - sizeof (EFI_USER_INFO)) {\r
+    Identity = (EFI_USER_INFO_IDENTITY_POLICY *) ((UINT8 *) (Info + 1) + TotalLen);\r
+    if (Identity->Type == EFI_USER_INFO_IDENTITY_CREDENTIAL_PROVIDER) {\r
+      if (!FindProvider (Identity, OldIpInfo)) {\r
+        //\r
+        // The credential is NOT found in the old identity policy; add it.\r
+        //\r
+        Status = ModifyCredentialInfo (User, (UINT8 *) Identity, Identity->Length);\r
+        if (EFI_ERROR (Status)) {\r
+          break;\r
+        }\r
+        CredentialCount++;\r
+      }\r
+    }\r
+\r
+    TotalLen += Identity->Length;\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    //\r
+    // Enroll new credential failed. Delete the newly enrolled credential, and return.\r
+    //\r
+    TotalLen = 0;\r
+    while (TotalLen < Info->InfoSize - sizeof (EFI_USER_INFO)) {\r
+      Identity = (EFI_USER_INFO_IDENTITY_POLICY *) ((UINT8 *) (Info + 1) + TotalLen);\r
+      if (Identity->Type == EFI_USER_INFO_IDENTITY_CREDENTIAL_PROVIDER) {\r
+        if (!FindProvider (Identity, OldIpInfo)) {\r
+          //\r
+          // The credential is NOT found in the old identity policy. Delete it.\r
+          //\r
+          if (CredentialCount == 0) {\r
+            break;\r
+          }\r
+\r
+          ModifyCredentialInfo (User, (UINT8 *) Identity, Identity->Length);\r
+          CredentialCount--;\r
+        }\r
+      }\r
+      TotalLen += Identity->Length;\r
+    }\r
+\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  \r
+  //\r
+  // Backup new identification policy\r
+  //\r
+  NewIpInfo = AllocateCopyPool (Info->InfoSize, Info);    \r
+  ASSERT (NewIpInfo != NULL);\r
+\r
+  //\r
+  // Enroll the credential that existed in the old identity policy.\r
+  //\r
+  TotalLen = 0;\r
+  while (TotalLen < Info->InfoSize - sizeof (EFI_USER_INFO)) {\r
+    Identity = (EFI_USER_INFO_IDENTITY_POLICY *) ((UINT8 *) (Info + 1) + TotalLen);\r
+    if (Identity->Type == EFI_USER_INFO_IDENTITY_CREDENTIAL_PROVIDER) {\r
+      if (FindProvider (Identity, OldIpInfo)) {\r
+        //\r
+        // The credential is found in the old identity policy, so delete the old credential first.\r
+        //\r
+        Status = ModifyCredentialInfo (User, (UINT8 *) Identity, Identity->Length);\r
+        if (EFI_ERROR (Status)) {\r
+          //\r
+          // Failed to delete old credential.\r
+          //\r
+          FreePool (NewIpInfo);\r
+          return EFI_DEVICE_ERROR;\r
+        }\r
+\r
+        //\r
+        // Add the new credential.\r
+        //\r
+        Status = ModifyCredentialInfo (User, (UINT8 *) Identity, Identity->Length);\r
+        if (EFI_ERROR (Status)) {\r
+          //\r
+          // Failed to enroll the user by new identification policy.\r
+          // So removed the credential provider from the identification policy          \r
+          //\r
+          RemoveProvider (&NewIpInfo, Identity);\r
+        }        \r
+      }\r
+    }\r
+    TotalLen += Identity->Length;\r
+  }\r
+  \r
+  //\r
+  // Delete old credential that didn't exist in the new identity policy.\r
+  //\r
+  TotalLen = 0;\r
+  while (TotalLen < OldIpInfo->InfoSize - sizeof (EFI_USER_INFO)) {\r
+    Identity = (EFI_USER_INFO_IDENTITY_POLICY *) ((UINT8 *) (OldIpInfo + 1) + TotalLen);\r
+    if (Identity->Type == EFI_USER_INFO_IDENTITY_CREDENTIAL_PROVIDER) {\r
+      if (!FindProvider (Identity, Info)) {\r
+        //\r
+        // The credential is NOT found in the new identity policy. Delete the old credential.\r
+        //\r
+        ModifyCredentialInfo (User, (UINT8 *) Identity, Identity->Length);\r
+      }\r
+    }\r
+    TotalLen += Identity->Length;\r
+  }\r
+\r
+  *IpInfo = NewIpInfo;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Add one new user info into the user's profile.\r
+\r
+  @param[in]   User        point to the user profile\r
+  @param[in]   Info        Points to the user information payload.\r
+  @param[in]   InfoSize    The size of the user information payload, in bytes.\r
+  @param[out]  UserInfo    Point to the new info in user profile\r
+  @param[in]   Save        If TRUE, save the profile to NV flash.\r
+                           If FALSE, don't need to save the profile to NV flash.\r
+\r
+  @retval EFI_SUCCESS      Add user info to user profile successfully.\r
+  @retval Others           Fail to add user info to user profile.\r
+\r
+**/\r
+EFI_STATUS\r
+AddUserInfo (\r
+  IN  USER_PROFILE_ENTRY                        *User,\r
+  IN  UINT8                                     *Info,\r
+  IN  UINTN                                     InfoSize,\r
+  OUT EFI_USER_INFO                             **UserInfo, OPTIONAL\r
+  IN  BOOLEAN                                   Save\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  if ((Info == NULL) || (User == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  \r
+  //\r
+  // Check user profile handle.\r
+  //\r
+  Status = FindUserProfile (&User, FALSE, NULL);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  \r
+  //\r
+  // Check user information memory size.\r
+  //\r
+  if (User->MaxProfileSize - User->UserProfileSize < ALIGN_VARIABLE (InfoSize)) {\r
+    if (!ExpandUserProfile (User, ALIGN_VARIABLE (InfoSize))) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+  }\r
+  \r
+  //\r
+  // Add credential.\r
+  //\r
+  if (((EFI_USER_INFO *) Info)->InfoType == EFI_USER_INFO_IDENTITY_POLICY_RECORD) {\r
+    Status = ModifyCredentialInfo (\r
+              User,\r
+              (UINT8 *) ((EFI_USER_INFO *) Info + 1),\r
+              InfoSize - sizeof (EFI_USER_INFO)\r
+              );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+  \r
+  //\r
+  // Add new user information.\r
+  //\r
+  CopyMem (User->ProfileInfo + User->UserProfileSize, Info, InfoSize);\r
+  if (UserInfo != NULL) {\r
+    *UserInfo = (EFI_USER_INFO *) (User->ProfileInfo + User->UserProfileSize);\r
+  }\r
+  User->UserProfileSize += ALIGN_VARIABLE (InfoSize);\r
+\r
+  //\r
+  // Save user profile information.\r
+  //\r
+  if (Save) {\r
+    Status = SaveNvUserProfile (User, FALSE);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Get the user info from the specified user info handle.\r
+\r
+  @param[in]      User            Point to the user profile.\r
+  @param[in]      UserInfo        Point to the user information record to get.\r
+  @param[out]     Info            On entry, points to a buffer of at least *InfoSize bytes. \r
+                                  On exit, holds the user information.\r
+  @param[in, out] InfoSize        On entry, points to the size of Info. \r
+                                  On return, points to the size of the user information.\r
+  @param[in]      ChkRight        If TRUE, check the user info attribute.\r
+                                  If FALSE, don't check the user info attribute.\r
+\r
+\r
+  @retval EFI_ACCESS_DENIED       The information cannot be accessed by the current user.\r
+  @retval EFI_INVALID_PARAMETER   InfoSize is NULL or UserInfo is NULL.\r
+  @retval EFI_BUFFER_TOO_SMALL    The number of bytes specified by *InfoSize is too small to hold the \r
+                                  returned data. The actual size required is returned in *InfoSize.\r
+  @retval EFI_SUCCESS             Information returned successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+GetUserInfo (\r
+  IN        USER_PROFILE_ENTRY                  *User,\r
+  IN        EFI_USER_INFO                       *UserInfo,\r
+  OUT       EFI_USER_INFO                       *Info,\r
+  IN OUT    UINTN                               *InfoSize,\r
+  IN        BOOLEAN                             ChkRight\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  if ((InfoSize == NULL) || (UserInfo == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((*InfoSize != 0) && (Info == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  \r
+  //\r
+  // Find the user information to get.\r
+  //\r
+  Status = FindUserInfo (User, &UserInfo, FALSE, NULL);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  \r
+  //\r
+  // Check information attributes.\r
+  //\r
+  if (ChkRight) {\r
+    switch (UserInfo->InfoAttribs & EFI_USER_INFO_ACCESS) {\r
+    case EFI_USER_INFO_PRIVATE:\r
+    case EFI_USER_INFO_PROTECTED:\r
+      if (User != mCurrentUser) {\r
+        return EFI_ACCESS_DENIED;\r
+      }\r
+      break;\r
+\r
+    case EFI_USER_INFO_PUBLIC:\r
+      break;\r
+\r
+    default:\r
+      return EFI_INVALID_PARAMETER;\r
+      break;\r
+    }\r
+  }\r
+  \r
+  //\r
+  // Get user information.\r
+  //\r
+  if (UserInfo->InfoSize > *InfoSize) {\r
+    *InfoSize = UserInfo->InfoSize;\r
+    return EFI_BUFFER_TOO_SMALL;\r
+  }\r
+\r
+  *InfoSize = UserInfo->InfoSize;\r
+  if (Info != NULL) {\r
+    CopyMem (Info, UserInfo, *InfoSize);\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Delete the specified user information from user profile.\r
+\r
+  @param[in]  User        Point to the user profile.\r
+  @param[in]  Info        Point to the user information record to delete.\r
+  @param[in]  Save        If TRUE, save the profile to NV flash.\r
+                          If FALSE, don't need to save the profile to NV flash.\r
+\r
+  @retval EFI_SUCCESS     Delete user info from user profile successfully.\r
+  @retval Others          Fail to delete user info from user profile.\r
+\r
+**/\r
+EFI_STATUS\r
+DelUserInfo (\r
+  IN  USER_PROFILE_ENTRY                        *User,\r
+  IN  EFI_USER_INFO                             *Info,\r
+  IN  BOOLEAN                                   Save\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  UINTN       Offset;\r
+  UINTN       NextOffset;\r
+\r
+  //\r
+  // Check user information handle.\r
+  //\r
+  Status = FindUserInfo (User, &Info, FALSE, &Offset);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  if (Info->InfoType == EFI_USER_INFO_IDENTIFIER_RECORD) {\r
+    return EFI_ACCESS_DENIED;\r
+  } else if (Info->InfoType == EFI_USER_INFO_IDENTITY_POLICY_RECORD) {\r
+    Status = ModifyCredentialInfo (User, (UINT8 *) (Info + 1), Info->InfoSize - sizeof (EFI_USER_INFO));\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+  \r
+  //\r
+  // Delete the specified user information.\r
+  //\r
+  NextOffset = Offset + ALIGN_VARIABLE (Info->InfoSize);\r
+  User->UserProfileSize -= ALIGN_VARIABLE (Info->InfoSize);\r
+  if (Offset < User->UserProfileSize) {\r
+    CopyMem (User->ProfileInfo + Offset, User->ProfileInfo + NextOffset, User->UserProfileSize - Offset);\r
+  }\r
+\r
+  if (Save) {\r
+    Status = SaveNvUserProfile (User, FALSE);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Add or update user information.\r
+\r
+  @param[in]      User           Point to the user profile.\r
+  @param[in, out] UserInfo       On entry, points to the user information to modify,\r
+                                 or NULL to add a new UserInfo. \r
+                                 On return, points to the modified user information.\r
+  @param[in]      Info           Points to the new user information.\r
+  @param[in]      InfoSize       The size of Info,in bytes.\r
+\r
+  @retval EFI_INVALID_PARAMETER  UserInfo is NULL or Info is NULL.\r
+  @retval EFI_ACCESS_DENIED      The record is exclusive.\r
+  @retval EFI_SUCCESS            User information was successfully changed/added.\r
+\r
+**/\r
+EFI_STATUS\r
+ModifyUserInfo (\r
+  IN        USER_PROFILE_ENTRY                  *User,\r
+  IN OUT    EFI_USER_INFO                       **UserInfo,\r
+  IN CONST  EFI_USER_INFO                       *Info,\r
+  IN        UINTN                               InfoSize\r
+  )\r
+{\r
+  EFI_STATUS    Status;\r
+  UINTN         PayloadLen;\r
+  EFI_USER_INFO *OldInfo;\r
+  EFI_USER_INFO *IpInfo;\r
+\r
+  if ((UserInfo == NULL) || (Info == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (InfoSize < sizeof (EFI_USER_INFO) || InfoSize != Info->InfoSize) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  \r
+  //\r
+  // Check user information.\r
+  //\r
+  if (Info->InfoType == EFI_USER_INFO_IDENTIFIER_RECORD) {\r
+    return EFI_ACCESS_DENIED;\r
+  }\r
+  \r
+  if (!CheckUserInfo (Info)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+\r
+  if (*UserInfo == NULL) {\r
+    //\r
+    // Add new user information.\r
+    //\r
+    OldInfo = NULL;\r
+    do {\r
+      Status = FindUserInfoByType (User, &OldInfo, Info->InfoType);\r
+      if (EFI_ERROR (Status)) {\r
+        break;\r
+      }\r
+      ASSERT (OldInfo != NULL);\r
+\r
+      if (((OldInfo->InfoAttribs & EFI_USER_INFO_EXCLUSIVE) != 0) || \r
+           ((Info->InfoAttribs & EFI_USER_INFO_EXCLUSIVE) != 0)) {\r
+        //\r
+        //  Same type can not co-exist for exclusive information.\r
+        //\r
+        return EFI_ACCESS_DENIED;\r
+      }\r
+\r
+      //\r
+      // Check whether it exists in DB.\r
+      //\r
+      if (Info->InfoSize != OldInfo->InfoSize) {\r
+        continue;\r
+      }\r
+\r
+      if (!CompareGuid (&OldInfo->Credential, &Info->Credential)) {\r
+        continue;\r
+      }\r
+  \r
+      PayloadLen = Info->InfoSize - sizeof (EFI_USER_INFO);\r
+      if (PayloadLen == 0) {\r
+        continue;\r
+      }\r
+\r
+      if (CompareMem ((UINT8 *)(OldInfo + 1), (UINT8 *)(Info + 1), PayloadLen) != 0) {\r
+        continue;\r
+      }\r
+\r
+      //\r
+      // Yes. The new info is as same as the one in profile.\r
+      //\r
+      return EFI_SUCCESS;\r
+    } while (!EFI_ERROR (Status));\r
+\r
+    Status = AddUserInfo (User, (UINT8 *) Info, InfoSize, UserInfo, TRUE);\r
+    return Status;\r
+  }\r
+  \r
+  //\r
+  // Modify existing user information.\r
+  //\r
+  OldInfo = *UserInfo;\r
+  if (OldInfo->InfoType != Info->InfoType) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  \r
+  if (((Info->InfoAttribs & EFI_USER_INFO_EXCLUSIVE) != 0) && \r
+       (OldInfo->InfoAttribs & EFI_USER_INFO_EXCLUSIVE) == 0) {\r
+    //\r
+    // Try to add exclusive attrib in new info. \r
+    // Check whether there is another information with the same type in profile.\r
+    //\r
+    OldInfo = NULL;\r
+    do {\r
+      Status = FindUserInfoByType (User, &OldInfo, Info->InfoType);\r
+      if (EFI_ERROR (Status)) {\r
+        break;\r
+      }\r
+      if (OldInfo != *UserInfo) {\r
+        //\r
+        // There is another information with the same type in profile.\r
+        // Therefore, can't modify existing user information to add exclusive attribute.\r
+        //\r
+        return EFI_ACCESS_DENIED;\r
+      }\r
+    } while (TRUE);    \r
+  }\r
+\r
+  if (Info->InfoType == EFI_USER_INFO_IDENTITY_POLICY_RECORD) {\r
+    //\r
+    // For user identification policy, need to update the info in credential provider.\r
+    //\r
+    IpInfo = NULL;\r
+    Status = ModifyUserIpInfo (User, Info, InfoSize, &IpInfo);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    ASSERT (IpInfo != NULL);\r
+    Status = SaveUserIpInfo (User, IpInfo, UserInfo);\r
+    if (IpInfo->InfoSize != Info->InfoSize) {\r
+      Status = EFI_DEVICE_ERROR;\r
+    }\r
+    FreePool (IpInfo);    \r
+    return Status;\r
+  }\r
+\r
+  Status = DelUserInfo (User, *UserInfo, FALSE);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  return AddUserInfo (User, (UINT8 *) Info, InfoSize, UserInfo, TRUE);\r
+}\r
+\r
+\r
+/**\r
+  Delete the user profile from non-volatile memory and database.\r
+\r
+  @param[in]  User              Points to the user profile.\r
+\r
+  @retval EFI_SUCCESS      Delete user from the user profile successfully.\r
+  @retval Others           Fail to delete user from user profile\r
+  \r
+**/\r
+EFI_STATUS\r
+DelUserProfile (\r
+  IN  USER_PROFILE_ENTRY                        *User\r
+  )\r
+{\r
+  EFI_STATUS          Status;\r
+  UINTN               Index;\r
+  EFI_USER_INFO       *UserInfo;\r
+\r
+  //\r
+  // Check whether it is in the user profile database.\r
+  //\r
+  Status = FindUserProfile (&User, FALSE, &Index);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  \r
+  //\r
+  // Check whether it is the current user.\r
+  //\r
+  if (User == mCurrentUser) {\r
+    return EFI_ACCESS_DENIED;\r
+  }\r
+  \r
+  //\r
+  // Delete user credential information.\r
+  //\r
+  UserInfo  = NULL;\r
+  Status    = FindUserInfoByType (User, &UserInfo, EFI_USER_INFO_IDENTITY_POLICY_RECORD);\r
+  if (Status == EFI_SUCCESS) {\r
+    Status = DelUserInfo (User, UserInfo, FALSE);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+  \r
+  //\r
+  // Delete user profile from the non-volatile memory.\r
+  //\r
+  Status    = SaveNvUserProfile (mUserProfileDb->UserProfile[mUserProfileDb->UserProfileNum - 1], TRUE);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  mUserProfileDb->UserProfileNum--;\r
+\r
+  //\r
+  // Modify user profile database.\r
+  //\r
+  if (Index != mUserProfileDb->UserProfileNum) {\r
+    mUserProfileDb->UserProfile[Index] = mUserProfileDb->UserProfile[mUserProfileDb->UserProfileNum];\r
+    CopyMem (\r
+      ((USER_PROFILE_ENTRY *) mUserProfileDb->UserProfile[Index])->UserVarName,\r
+      User->UserVarName,\r
+      sizeof (User->UserVarName)\r
+      );\r
+    Status = SaveNvUserProfile (mUserProfileDb->UserProfile[Index], FALSE);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+  //\r
+  // Delete user profile information.\r
+  //\r
+  if (User->ProfileInfo != NULL) {\r
+    FreePool (User->ProfileInfo);\r
+  }\r
+\r
+  FreePool (User);\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Add user profile to user profile database.\r
+\r
+  @param[out]   UserProfile   Point to the newly added user profile.\r
+  @param[in]    ProfileSize   The size of the user profile.\r
+  @param[in]    ProfileInfo   Point to the user profie data.\r
+  @param[in]    Save          If TRUE, save the new added profile to NV flash.\r
+                              If FALSE, don't save the profile to NV flash.\r
+\r
+  @retval EFI_SUCCESS         Add user profile to user profile database successfully.\r
+  @retval Others              Fail to add user profile to user profile database.\r
+\r
+**/\r
+EFI_STATUS\r
+AddUserProfile (\r
+     OUT  USER_PROFILE_ENTRY                    **UserProfile, OPTIONAL\r
+  IN      UINTN                                 ProfileSize,\r
+  IN      UINT8                                 *ProfileInfo,\r
+  IN      BOOLEAN                               Save\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  USER_PROFILE_ENTRY      *User;\r
+\r
+  //\r
+  // Check the data format to be added.\r
+  //\r
+  if (!CheckProfileInfo (ProfileInfo, ProfileSize)) {\r
+    return EFI_SECURITY_VIOLATION;\r
+  }\r
+  \r
+  //\r
+  // Create user profile entry.\r
+  //\r
+  User = AllocateZeroPool (sizeof (USER_PROFILE_ENTRY));\r
+  if (User == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  //\r
+  // Add the entry to the user profile database.\r
+  //\r
+  if (mUserProfileDb->UserProfileNum == mUserProfileDb->MaxProfileNum) {\r
+    if (!ExpandUsermUserProfileDb ()) {\r
+      FreePool (User);\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+  }\r
+\r
+  UnicodeSPrint (\r
+    User->UserVarName, \r
+    sizeof (User->UserVarName),\r
+    L"User%04x", \r
+    mUserProfileDb->UserProfileNum\r
+    );\r
+  User->UserProfileSize = 0;\r
+  User->MaxProfileSize  = 0;\r
+  User->ProfileInfo     = NULL;\r
+  mUserProfileDb->UserProfile[mUserProfileDb->UserProfileNum] = (EFI_USER_PROFILE_HANDLE) User;\r
+  mUserProfileDb->UserProfileNum++;\r
+\r
+  //\r
+  // Add user profile information.\r
+  //\r
+  Status = AddUserInfo (User, ProfileInfo, ProfileSize, NULL, Save);\r
+  if (EFI_ERROR (Status)) {\r
+    DelUserProfile (User);\r
+    return Status;\r
+  }\r
+  //\r
+  // Set new user profile handle.\r
+  //\r
+  if (UserProfile != NULL) {\r
+    *UserProfile = User;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  This function creates a new user profile with only a new user identifier\r
+  attached and returns its handle. The user profile is non-volatile, but the\r
+  handle User can change across reboots.\r
+\r
+  @param[out]  User               Handle of a new user profile.\r
+\r
+  @retval EFI_SUCCESS             User profile was successfully created.\r
+  @retval Others                  Fail to create user profile\r
+\r
+**/\r
+EFI_STATUS\r
+CreateUserProfile (\r
+  OUT USER_PROFILE_ENTRY                        **User\r
+  )\r
+{\r
+  EFI_STATUS    Status;\r
+  EFI_USER_INFO *UserInfo;\r
+\r
+  if (User == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  //\r
+  // Generate user id information.\r
+  //\r
+  UserInfo = AllocateZeroPool (sizeof (EFI_USER_INFO) + sizeof (EFI_USER_INFO_IDENTIFIER));\r
+  if (UserInfo == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  UserInfo->InfoType    = EFI_USER_INFO_IDENTIFIER_RECORD;\r
+  UserInfo->InfoSize    = sizeof (EFI_USER_INFO) + sizeof (EFI_USER_INFO_IDENTIFIER);\r
+  UserInfo->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV | EFI_USER_INFO_PUBLIC | EFI_USER_INFO_EXCLUSIVE;\r
+  GenerateUserId ((UINT8 *) (UserInfo + 1));\r
+  \r
+  //\r
+  // Add user profile to the user profile database.\r
+  //\r
+  Status = AddUserProfile (User, UserInfo->InfoSize, (UINT8 *) UserInfo, TRUE);\r
+  FreePool (UserInfo);\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Add a default user profile to user profile database.\r
+\r
+  @retval EFI_SUCCESS             A default user profile is added successfully.\r
+  @retval Others                  Fail to add a default user profile\r
+  \r
+**/\r
+EFI_STATUS\r
+AddDefaultUserProfile (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  USER_PROFILE_ENTRY            *User;\r
+  EFI_USER_INFO                 *Info;\r
+  EFI_USER_INFO                 *NewInfo;\r
+  EFI_USER_INFO_CREATE_DATE     CreateDate;\r
+  EFI_USER_INFO_USAGE_COUNT     UsageCount;\r
+  EFI_USER_INFO_ACCESS_CONTROL  *Access;\r
+  EFI_USER_INFO_IDENTITY_POLICY *Policy;\r
+  \r
+  //\r
+  // Create a user profile.\r
+  //\r
+  Status = CreateUserProfile (&User);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
\r
+  //\r
+  // Allocate a buffer to add all default user information.\r
+  //\r
+  Info = AllocateZeroPool (sizeof (EFI_USER_INFO) + INFO_PAYLOAD_SIZE);\r
+  if (Info == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  //\r
+  // Add user name.\r
+  //\r
+  Info->InfoType    = EFI_USER_INFO_NAME_RECORD;\r
+  Info->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV | EFI_USER_INFO_PUBLIC | EFI_USER_INFO_EXCLUSIVE;\r
+  Info->InfoSize    = sizeof (EFI_USER_INFO) + sizeof (mUserName);\r
+  CopyMem ((UINT8 *) (Info + 1), mUserName, sizeof (mUserName));\r
+  NewInfo = NULL;\r
+  Status  = ModifyUserInfo (User, &NewInfo, Info, Info->InfoSize);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+  \r
+  //\r
+  // Add user profile create date record.\r
+  //\r
+  Info->InfoType    = EFI_USER_INFO_CREATE_DATE_RECORD;\r
+  Info->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV | EFI_USER_INFO_PUBLIC | EFI_USER_INFO_EXCLUSIVE;\r
+  Info->InfoSize    = sizeof (EFI_USER_INFO) + sizeof (EFI_USER_INFO_CREATE_DATE);\r
+  Status            = gRT->GetTime (&CreateDate, NULL);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+\r
+  CopyMem ((UINT8 *) (Info + 1), &CreateDate, sizeof (EFI_USER_INFO_CREATE_DATE));\r
+  NewInfo = NULL;\r
+  Status  = ModifyUserInfo (User, &NewInfo, Info, Info->InfoSize);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+  \r
+  //\r
+  // Add user profile usage count record.\r
+  //\r
+  Info->InfoType    = EFI_USER_INFO_USAGE_COUNT_RECORD;\r
+  Info->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV | EFI_USER_INFO_PUBLIC | EFI_USER_INFO_EXCLUSIVE;\r
+  Info->InfoSize    = sizeof (EFI_USER_INFO) + sizeof (EFI_USER_INFO_USAGE_COUNT);\r
+  UsageCount        = 0;\r
+  CopyMem ((UINT8 *) (Info + 1), &UsageCount, sizeof (EFI_USER_INFO_USAGE_COUNT));\r
+  NewInfo = NULL;\r
+  Status  = ModifyUserInfo (User, &NewInfo, Info, Info->InfoSize);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
\r
+  //\r
+  // Add user access right.\r
+  //\r
+  Info->InfoType    = EFI_USER_INFO_ACCESS_POLICY_RECORD;\r
+  Info->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV | EFI_USER_INFO_PUBLIC | EFI_USER_INFO_EXCLUSIVE;\r
+  Access            = (EFI_USER_INFO_ACCESS_CONTROL *) (Info + 1);\r
+  Access->Type      = EFI_USER_INFO_ACCESS_MANAGE;\r
+  Access->Size      = sizeof (EFI_USER_INFO_ACCESS_CONTROL);\r
+  Info->InfoSize    = sizeof (EFI_USER_INFO) + Access->Size;\r
+  NewInfo = NULL;\r
+  Status  = ModifyUserInfo (User, &NewInfo, Info, Info->InfoSize);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+  \r
+  //\r
+  // Add user identity policy.\r
+  //\r
+  Info->InfoType    = EFI_USER_INFO_IDENTITY_POLICY_RECORD;\r
+  Info->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV | EFI_USER_INFO_PRIVATE | EFI_USER_INFO_EXCLUSIVE;\r
+  Policy            = (EFI_USER_INFO_IDENTITY_POLICY *) (Info + 1);\r
+  Policy->Type      = EFI_USER_INFO_IDENTITY_TRUE;\r
+  Policy->Length    = sizeof (EFI_USER_INFO_IDENTITY_POLICY);  \r
+  Info->InfoSize    = sizeof (EFI_USER_INFO) + Policy->Length;\r
+  NewInfo = NULL;\r
+  Status  = ModifyUserInfo (User, &NewInfo, Info, Info->InfoSize);\r
+\r
+Done:\r
+  FreePool (Info);\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Publish current user information into EFI System Configuration Table.\r
+\r
+  By UEFI spec, the User Identity Manager will publish the current user profile \r
+  into the EFI System Configuration Table. Currently, only the user identifier and user\r
+  name are published.\r
+\r
+  @retval EFI_SUCCESS      Current user information is published successfully.\r
+  @retval Others           Fail to publish current user information\r
+\r
+**/\r
+EFI_STATUS\r
+PublishUserTable (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  EFI_CONFIGURATION_TABLE *EfiConfigurationTable;\r
+  EFI_USER_INFO_TABLE     *UserInfoTable;\r
+  EFI_USER_INFO           *IdInfo;\r
+  EFI_USER_INFO           *NameInfo;\r
+\r
+  Status = EfiGetSystemConfigurationTable (\r
+             &gEfiUserManagerProtocolGuid,\r
+             (VOID **) &EfiConfigurationTable\r
+             );\r
+  if (!EFI_ERROR (Status)) {\r
+    //\r
+    // The table existed! \r
+    //\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // Get user ID information.\r
+  //\r
+  IdInfo  = NULL;\r
+  Status  = FindUserInfoByType (mCurrentUser, &IdInfo, EFI_USER_INFO_IDENTIFIER_RECORD);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+\r
+  }\r
+  //\r
+  // Get user name information.\r
+  //\r
+  NameInfo  = NULL;\r
+  Status    = FindUserInfoByType (mCurrentUser, &NameInfo, EFI_USER_INFO_NAME_RECORD);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  \r
+  //\r
+  // Allocate a buffer for user information table.\r
+  //\r
+  UserInfoTable = (EFI_USER_INFO_TABLE *) AllocateRuntimePool (\r
+                                            sizeof (EFI_USER_INFO_TABLE) + \r
+                                            IdInfo->InfoSize + \r
+                                            NameInfo->InfoSize\r
+                                            );\r
+  if (UserInfoTable == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    return Status;\r
+  }\r
+\r
+  UserInfoTable->Size = sizeof (EFI_USER_INFO_TABLE);  \r
+  \r
+  //\r
+  // Append the user information to the user info table\r
+  //\r
+  CopyMem ((UINT8 *) UserInfoTable + UserInfoTable->Size, (UINT8 *) IdInfo, IdInfo->InfoSize);\r
+  UserInfoTable->Size += IdInfo->InfoSize;\r
+\r
+  CopyMem ((UINT8 *) UserInfoTable + UserInfoTable->Size, (UINT8 *) NameInfo, NameInfo->InfoSize);\r
+  UserInfoTable->Size += NameInfo->InfoSize;\r
+\r
+  Status = gBS->InstallConfigurationTable (&gEfiUserManagerProtocolGuid, (VOID *) UserInfoTable);\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Get the user's identity type.\r
+\r
+  The identify manager only supports the identity policy in which the credential \r
+  provider handles are connected by the operator 'AND' or 'OR'.\r
+\r
+\r
+  @param[in]   User              Handle of a user profile.\r
+  @param[out]  PolicyType        Point to the identity type.\r
+\r
+  @retval EFI_SUCCESS            Get user's identity type successfully.\r
+  @retval Others                 Fail to get user's identity type.\r
+\r
+**/\r
+EFI_STATUS\r
+GetIdentifyType (\r
+  IN      EFI_USER_PROFILE_HANDLE               User,\r
+     OUT  UINT8                                 *PolicyType\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  EFI_USER_INFO                 *IdentifyInfo;\r
+  UINTN                         TotalLen;\r
+  EFI_USER_INFO_IDENTITY_POLICY *Identity;\r
+\r
+  //\r
+  // Get user identify policy information.\r
+  //\r
+  IdentifyInfo  = NULL;\r
+  Status        = FindUserInfoByType (User, &IdentifyInfo, EFI_USER_INFO_IDENTITY_POLICY_RECORD);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  ASSERT (IdentifyInfo != NULL);\r
+  \r
+  //\r
+  // Search the user identify policy according to type.\r
+  //\r
+  TotalLen    = 0;\r
+  *PolicyType = EFI_USER_INFO_IDENTITY_FALSE;\r
+  while (TotalLen < IdentifyInfo->InfoSize - sizeof (EFI_USER_INFO)) {\r
+    Identity = (EFI_USER_INFO_IDENTITY_POLICY *) ((UINT8 *) (IdentifyInfo + 1) + TotalLen);\r
+    if (Identity->Type == EFI_USER_INFO_IDENTITY_AND) {\r
+      *PolicyType = EFI_USER_INFO_IDENTITY_AND;\r
+      break;\r
+    }\r
+\r
+    if (Identity->Type == EFI_USER_INFO_IDENTITY_OR) {\r
+      *PolicyType = EFI_USER_INFO_IDENTITY_OR;\r
+      break;\r
+    }\r
+    TotalLen += Identity->Length;\r
+  }\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Identify the User by the specfied provider.\r
+\r
+  @param[in]  User                Handle of a user profile.\r
+  @param[in]  Provider            Points to the identifir of credential provider.\r
+\r
+  @retval EFI_INVALID_PARAMETER   Provider is NULL.\r
+  @retval EFI_NOT_FOUND           Fail to identify the specified user.\r
+  @retval EFI_SUCCESS             User is identified successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+IdentifyByProviderId (\r
+  IN  EFI_USER_PROFILE_HANDLE                   User,\r
+  IN  EFI_GUID                                  *Provider\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  EFI_USER_INFO_IDENTIFIER      UserId;\r
+  UINTN                         Index;\r
+  EFI_CREDENTIAL_LOGON_FLAGS    AutoLogon;\r
+  EFI_HII_HANDLE                HiiHandle;\r
+  EFI_GUID                      FormSetId;\r
+  EFI_FORM_ID                   FormId;\r
+  EFI_USER_CREDENTIAL_PROTOCOL  *UserCredential;\r
+  EFI_USER_INFO                 *IdInfo;\r
+\r
+  if (Provider == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  \r
+  //\r
+  // Check the user ID identified by the specified credential provider.\r
+  //\r
+  for (Index = 0; Index < mProviderDb->Count; Index++) {\r
+    //\r
+    // Check credential provider class.\r
+    //\r
+    UserCredential = mProviderDb->Provider[Index];\r
+    if (CompareGuid (&UserCredential->Identifier, Provider)) {\r
+      Status = UserCredential->Select (UserCredential, &AutoLogon);\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+\r
+      if ((AutoLogon & EFI_CREDENTIAL_LOGON_FLAG_AUTO) == 0) {\r
+        //\r
+        // Get credential provider form.\r
+        //\r
+        Status = UserCredential->Form (\r
+                                   UserCredential, \r
+                                   &HiiHandle, \r
+                                   &FormSetId, \r
+                                   &FormId\r
+                                   );\r
+        if (!EFI_ERROR (Status)) {        \r
+          //\r
+          // Send form to get user input.\r
+          //\r
+          Status = mCallbackInfo->FormBrowser2->SendForm (\r
+                                                  mCallbackInfo->FormBrowser2,\r
+                                                  &HiiHandle,\r
+                                                  1,\r
+                                                  &FormSetId,\r
+                                                  FormId,\r
+                                                  NULL,\r
+                                                  NULL\r
+                                                  );\r
+          if (EFI_ERROR (Status)) {\r
+            return Status;\r
+          }                                            \r
+        }        \r
+      }\r
+\r
+      Status = UserCredential->User (UserCredential, User, &UserId);\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+\r
+      Status = UserCredential->Deselect (UserCredential);\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+\r
+      if (User == NULL) {\r
+        return EFI_SUCCESS;\r
+      }\r
+      \r
+      //\r
+      // Get user ID information.\r
+      //\r
+      IdInfo  = NULL;\r
+      Status  = FindUserInfoByType (User, &IdInfo, EFI_USER_INFO_IDENTIFIER_RECORD);\r
+      ASSERT (IdInfo != NULL);\r
+\r
+      if (CompareMem ((UINT8 *) (IdInfo + 1), UserId, sizeof (EFI_USER_INFO_IDENTIFIER)) != 0) {\r
+        //\r
+        // One user name is selected, but the other's credential is given. Here no user passed.\r
+        //\r
+        break;\r
+      }\r
+      return EFI_SUCCESS;\r
+    }\r
+  }\r
+\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+\r
+/**\r
+  Update user information when user is logon on successfully.\r
+\r
+  @param[in]  User         Points to user profile.\r
+\r
+  @retval EFI_SUCCESS      Update user information successfully.\r
+  @retval Others           Fail to update user information.\r
+\r
+**/\r
+EFI_STATUS\r
+UpdateUserInfo (\r
+  IN  USER_PROFILE_ENTRY                        *User\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  EFI_USER_INFO             *Info;\r
+  EFI_USER_INFO             *NewInfo;\r
+  EFI_USER_INFO_CREATE_DATE Date;\r
+  EFI_USER_INFO_USAGE_COUNT UsageCount;\r
+  UINTN                     InfoLen;\r
+\r
+  //\r
+  // Allocate a buffer to update user's date record and usage record.\r
+  //\r
+  InfoLen  = MAX (sizeof (EFI_USER_INFO_CREATE_DATE), sizeof (EFI_USER_INFO_USAGE_COUNT));\r
+  Info     = AllocateZeroPool (sizeof (EFI_USER_INFO) + InfoLen);\r
+  if (Info == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  \r
+  //\r
+  // Check create date record.\r
+  //\r
+  NewInfo = NULL;\r
+  Status  = FindUserInfoByType (User, &NewInfo, EFI_USER_INFO_CREATE_DATE_RECORD);\r
+  if (Status == EFI_NOT_FOUND) {\r
+    Info->InfoType    = EFI_USER_INFO_CREATE_DATE_RECORD;\r
+    Info->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV | EFI_USER_INFO_PUBLIC | EFI_USER_INFO_EXCLUSIVE;\r
+    Info->InfoSize    = sizeof (EFI_USER_INFO) + sizeof (EFI_USER_INFO_CREATE_DATE);\r
+    Status            = gRT->GetTime (&Date, NULL);\r
+    if (EFI_ERROR (Status)) {\r
+      FreePool (Info);\r
+      return Status;\r
+    }\r
+\r
+    CopyMem ((UINT8 *) (Info + 1), &Date, sizeof (EFI_USER_INFO_CREATE_DATE));\r
+    NewInfo = NULL;\r
+    Status  = ModifyUserInfo (User, &NewInfo, Info, Info->InfoSize);\r
+    if (EFI_ERROR (Status)) {\r
+      FreePool (Info);\r
+      return Status;\r
+    }\r
+  }\r
+  \r
+  //\r
+  // Update usage date record.\r
+  //\r
+  NewInfo = NULL;\r
+  Status  = FindUserInfoByType (User, &NewInfo, EFI_USER_INFO_USAGE_DATE_RECORD);\r
+  if ((Status == EFI_SUCCESS) || (Status == EFI_NOT_FOUND)) {\r
+    Info->InfoType    = EFI_USER_INFO_USAGE_DATE_RECORD;\r
+    Info->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV | EFI_USER_INFO_PUBLIC | EFI_USER_INFO_EXCLUSIVE;\r
+    Info->InfoSize    = sizeof (EFI_USER_INFO) + sizeof (EFI_USER_INFO_USAGE_DATE);\r
+    Status            = gRT->GetTime (&Date, NULL);\r
+    if (EFI_ERROR (Status)) {\r
+      FreePool (Info);\r
+      return Status;\r
+    }\r
+\r
+    CopyMem ((UINT8 *) (Info + 1), &Date, sizeof (EFI_USER_INFO_USAGE_DATE));\r
+    Status = ModifyUserInfo (User, &NewInfo, Info, Info->InfoSize);\r
+    if (EFI_ERROR (Status)) {\r
+      FreePool (Info);\r
+      return Status;\r
+    }\r
+  }\r
+  \r
+  //\r
+  // Update usage count record.\r
+  //\r
+  UsageCount  = 0;\r
+  NewInfo     = NULL;\r
+  Status      = FindUserInfoByType (User, &NewInfo, EFI_USER_INFO_USAGE_COUNT_RECORD);\r
+  //\r
+  // Get usage count.\r
+  //\r
+  if (Status == EFI_SUCCESS) {\r
+    CopyMem (&UsageCount, (UINT8 *) (NewInfo + 1), sizeof (EFI_USER_INFO_USAGE_COUNT));\r
+  }\r
+\r
+  UsageCount++;\r
+  if ((Status == EFI_SUCCESS) || (Status == EFI_NOT_FOUND)) {\r
+    Info->InfoType    = EFI_USER_INFO_USAGE_COUNT_RECORD;\r
+    Info->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV | EFI_USER_INFO_PUBLIC | EFI_USER_INFO_EXCLUSIVE;\r
+    Info->InfoSize    = sizeof (EFI_USER_INFO) + sizeof (EFI_USER_INFO_USAGE_COUNT);\r
+    CopyMem ((UINT8 *) (Info + 1), &UsageCount, sizeof (EFI_USER_INFO_USAGE_COUNT));\r
+    Status = ModifyUserInfo (User, &NewInfo, Info, Info->InfoSize);\r
+    if (EFI_ERROR (Status)) {\r
+      FreePool (Info);\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  FreePool (Info);\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Add a credenetial provider item in form.\r
+\r
+  @param[in]  ProviderGuid        Points to the identifir of credential provider.\r
+  @param[in]  OpCodeHandle        Points to container for dynamic created opcodes.\r
+\r
+**/\r
+VOID\r
+AddProviderSelection (\r
+  IN     EFI_GUID                               *ProviderGuid,\r
+  IN     VOID                                   *OpCodeHandle\r
+  )\r
+{\r
+  EFI_HII_HANDLE                HiiHandle;\r
+  EFI_STRING_ID                 ProvID;\r
+  CHAR16                        *ProvStr;\r
+  UINTN                         Index;\r
+  EFI_USER_CREDENTIAL_PROTOCOL  *UserCredential;\r
+\r
+  for (Index = 0; Index < mProviderDb->Count; Index++) {\r
+    UserCredential = mProviderDb->Provider[Index];\r
+    if (CompareGuid (&UserCredential->Identifier, ProviderGuid)) {\r
+      //\r
+      // Add credential provider selection.\r
+      //\r
+      UserCredential->Title (UserCredential, &HiiHandle, &ProvID);\r
+      ProvStr = HiiGetString (HiiHandle, ProvID, NULL);\r
+      if (ProvStr == NULL) {\r
+        continue ;\r
+      }\r
+      ProvID  = HiiSetString (mCallbackInfo->HiiHandle, 0, ProvStr, NULL);\r
+      FreePool (ProvStr);\r
+      HiiCreateActionOpCode (\r
+        OpCodeHandle,                          // Container for dynamic created opcodes\r
+        (EFI_QUESTION_ID)(LABEL_PROVIDER_NAME + Index),  // Question ID\r
+        ProvID,                                // Prompt text\r
+        STRING_TOKEN (STR_NULL_STRING),        // Help text\r
+        EFI_IFR_FLAG_CALLBACK,                 // Question flag\r
+        0                                      // Action String ID\r
+        );\r
+      break;\r
+    }\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Add a username item in form.\r
+\r
+  @param[in]  Index            The index of the user in the user name list.\r
+  @param[in]  User             Points to the user profile whose username is added. \r
+  @param[in]  OpCodeHandle     Points to container for dynamic created opcodes.\r
+\r
+  @retval EFI_SUCCESS          Add a username successfully.\r
+  @retval Others               Fail to add a username.\r
+\r
+**/\r
+EFI_STATUS\r
+AddUserSelection (\r
+  IN     UINT16                                 Index,\r
+  IN     USER_PROFILE_ENTRY                     *User,\r
+  IN     VOID                                   *OpCodeHandle\r
+  )\r
+{\r
+  EFI_STRING_ID UserName;\r
+  EFI_STATUS    Status;\r
+  EFI_USER_INFO *UserInfo;\r
+\r
+  UserInfo  = NULL;\r
+  Status    = FindUserInfoByType (User, &UserInfo, EFI_USER_INFO_NAME_RECORD);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  \r
+  //\r
+  // Add user name selection.\r
+  //\r
+  UserName = HiiSetString (mCallbackInfo->HiiHandle, 0, (EFI_STRING) (UserInfo + 1), NULL);\r
+  if (UserName == 0) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  HiiCreateGotoOpCode (\r
+    OpCodeHandle,                   // Container for dynamic created opcodes\r
+    FORMID_PROVIDER_FORM,           // Target Form ID\r
+    UserName,                       // Prompt text\r
+    STRING_TOKEN (STR_NULL_STRING), // Help text\r
+    EFI_IFR_FLAG_CALLBACK,          // Question flag\r
+    (UINT16) Index                  // Question ID\r
+    );\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Identify the user whose identity policy does not contain the operator 'OR'.\r
+  \r
+  @param[in]  User             Points to the user profile.\r
+\r
+  @retval EFI_SUCCESS          The specified user is identified successfully.\r
+  @retval Others               Fail to identify the user.\r
+  \r
+**/\r
+EFI_STATUS\r
+IdentifyAndTypeUser (\r
+  IN  USER_PROFILE_ENTRY                        *User\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  EFI_USER_INFO                 *IdentifyInfo;\r
+  BOOLEAN                       Success;\r
+  UINTN                         TotalLen;\r
+  UINTN                         ValueLen;\r
+  EFI_USER_INFO_IDENTITY_POLICY *Identity;\r
+\r
+  //\r
+  // Get user identify policy information.\r
+  //\r
+  IdentifyInfo  = NULL;\r
+  Status        = FindUserInfoByType (User, &IdentifyInfo, EFI_USER_INFO_IDENTITY_POLICY_RECORD);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  ASSERT (IdentifyInfo != NULL);\r
+  \r
+  //\r
+  // Check each part of identification policy expression.\r
+  //\r
+  Success   = FALSE;\r
+  TotalLen  = 0;\r
+  while (TotalLen < IdentifyInfo->InfoSize - sizeof (EFI_USER_INFO)) {\r
+    Identity  = (EFI_USER_INFO_IDENTITY_POLICY *) ((UINT8 *) (IdentifyInfo + 1) + TotalLen);\r
+    ValueLen  = Identity->Length - sizeof (EFI_USER_INFO_IDENTITY_POLICY);\r
+    switch (Identity->Type) {\r
+\r
+    case EFI_USER_INFO_IDENTITY_FALSE:\r
+      //\r
+      // Check False option.\r
+      //\r
+      Success = FALSE;\r
+      break;\r
+\r
+    case EFI_USER_INFO_IDENTITY_TRUE:\r
+      //\r
+      // Check True option.\r
+      //\r
+      Success = TRUE;\r
+      break;\r
+\r
+    case EFI_USER_INFO_IDENTITY_NOT:\r
+      //\r
+      // Check negative operation.\r
+      //\r
+      break;\r
+\r
+    case EFI_USER_INFO_IDENTITY_AND:\r
+      //\r
+      // Check and operation.\r
+      //\r
+      if (!Success) {\r
+        return EFI_NOT_READY;\r
+      }\r
+\r
+      Success = FALSE;\r
+      break;\r
+\r
+    case EFI_USER_INFO_IDENTITY_OR:\r
+      //\r
+      // Check or operation.\r
+      //\r
+      if (Success) {\r
+        return EFI_SUCCESS;\r
+      }\r
+      break;\r
+\r
+    case EFI_USER_INFO_IDENTITY_CREDENTIAL_TYPE:\r
+      //\r
+      // Check credential provider by type.\r
+      //\r
+      break;\r
+\r
+    case EFI_USER_INFO_IDENTITY_CREDENTIAL_PROVIDER:\r
+      //\r
+      // Check credential provider by ID.\r
+      //\r
+      if (ValueLen != sizeof (EFI_GUID)) {\r
+        return EFI_INVALID_PARAMETER;\r
+      }\r
+\r
+      Status = IdentifyByProviderId (User, (EFI_GUID *) (Identity + 1));\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+\r
+      Success = TRUE;\r
+      break;\r
+\r
+    default:\r
+      return EFI_INVALID_PARAMETER;\r
+      break;\r
+    }\r
+\r
+    TotalLen += Identity->Length;\r
+  }\r
+\r
+  if (TotalLen != IdentifyInfo->InfoSize - sizeof (EFI_USER_INFO)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (!Success) {\r
+    return EFI_NOT_READY;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Identify the user whose identity policy does not contain the operator 'AND'.\r
+  \r
+  @param[in]  User             Points to the user profile.\r
+\r
+  @retval EFI_SUCCESS          The specified user is identified successfully.\r
+  @retval Others               Fail to identify the user.\r
+  \r
+**/\r
+EFI_STATUS\r
+IdentifyOrTypeUser (\r
+  IN  USER_PROFILE_ENTRY                        *User\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  EFI_USER_INFO                 *IdentifyInfo;\r
+  UINTN                         TotalLen;\r
+  UINTN                         ValueLen;\r
+  EFI_USER_INFO_IDENTITY_POLICY *Identity;\r
+  VOID                          *StartOpCodeHandle;\r
+  VOID                          *EndOpCodeHandle;\r
+  EFI_IFR_GUID_LABEL            *StartLabel;\r
+  EFI_IFR_GUID_LABEL            *EndLabel;\r
+\r
+  //\r
+  // Get user identify policy information.\r
+  //\r
+  IdentifyInfo  = NULL;\r
+  Status        = FindUserInfoByType (User, &IdentifyInfo, EFI_USER_INFO_IDENTITY_POLICY_RECORD);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  ASSERT (IdentifyInfo != NULL);\r
+  \r
+  //\r
+  // Initialize the container for dynamic opcodes.\r
+  //\r
+  StartOpCodeHandle = HiiAllocateOpCodeHandle ();\r
+  ASSERT (StartOpCodeHandle != NULL);\r
+\r
+  EndOpCodeHandle = HiiAllocateOpCodeHandle ();\r
+  ASSERT (EndOpCodeHandle != NULL);\r
+\r
+  //\r
+  // Create Hii Extend Label OpCode.\r
+  //\r
+  StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (\r
+                                        StartOpCodeHandle,\r
+                                        &gEfiIfrTianoGuid,\r
+                                        NULL,\r
+                                        sizeof (EFI_IFR_GUID_LABEL)\r
+                                        );\r
+  StartLabel->ExtendOpCode  = EFI_IFR_EXTEND_OP_LABEL;\r
+  StartLabel->Number        = LABEL_PROVIDER_NAME;\r
+\r
+  EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (\r
+                                      EndOpCodeHandle,\r
+                                      &gEfiIfrTianoGuid,\r
+                                      NULL,\r
+                                      sizeof (EFI_IFR_GUID_LABEL)\r
+                                      );\r
+  EndLabel->ExtendOpCode  = EFI_IFR_EXTEND_OP_LABEL;\r
+  EndLabel->Number        = LABEL_END;\r
+\r
+  //\r
+  // Add the providers that exists in the user's policy.\r
+  //\r
+  TotalLen = 0;\r
+  while (TotalLen < IdentifyInfo->InfoSize - sizeof (EFI_USER_INFO)) {\r
+    Identity  = (EFI_USER_INFO_IDENTITY_POLICY *) ((UINT8 *) (IdentifyInfo + 1) + TotalLen);\r
+    ValueLen  = Identity->Length - sizeof (EFI_USER_INFO_IDENTITY_POLICY);\r
+    if (Identity->Type == EFI_USER_INFO_IDENTITY_CREDENTIAL_PROVIDER) {\r
+      AddProviderSelection ((EFI_GUID *) (Identity + 1), StartOpCodeHandle);\r
+    }\r
+\r
+    TotalLen += Identity->Length;\r
+  }\r
+\r
+  HiiUpdateForm (\r
+    mCallbackInfo->HiiHandle, // HII handle\r
+    &mUserManagerGuid,        // Formset GUID\r
+    FORMID_PROVIDER_FORM,     // Form ID\r
+    StartOpCodeHandle,        // Label for where to insert opcodes\r
+    EndOpCodeHandle           // Replace data\r
+    );\r
+\r
+  HiiFreeOpCodeHandle (StartOpCodeHandle);\r
+  HiiFreeOpCodeHandle (EndOpCodeHandle);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  This function processes the results of changes in configuration.\r
+\r
+  @param  This                   Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
+  @param  Action                 Specifies the type of action taken by the browser.\r
+  @param  QuestionId             A unique value which is sent to the original\r
+                                 exporting driver so that it can identify the type\r
+                                 of data to expect.\r
+  @param  Type                   The type of value for the question.\r
+  @param  Value                  A pointer to the data being sent to the original\r
+                                 exporting driver.\r
+  @param  ActionRequest          On return, points to the action requested by the\r
+                                 callback function.\r
+\r
+  @retval EFI_SUCCESS            The callback successfully handled the action.\r
+  @retval Others                 Fail to handle the action.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UserIdentifyManagerCallback (\r
+  IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL      *This,\r
+  IN  EFI_BROWSER_ACTION                        Action,\r
+  IN  EFI_QUESTION_ID                           QuestionId,\r
+  IN  UINT8                                     Type,\r
+  IN  EFI_IFR_TYPE_VALUE                        *Value,\r
+  OUT EFI_BROWSER_ACTION_REQUEST                *ActionRequest\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  USER_PROFILE_ENTRY      *User;\r
+  UINT8                   PolicyType;\r
+  UINT16                  Index;\r
+  VOID                    *StartOpCodeHandle;\r
+  VOID                    *EndOpCodeHandle;\r
+  EFI_IFR_GUID_LABEL      *StartLabel;\r
+  EFI_IFR_GUID_LABEL      *EndLabel;\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+  switch (Action) {\r
+  case EFI_BROWSER_ACTION_FORM_OPEN:\r
+    {\r
+      //\r
+      // Update user Form when user Form is opened.\r
+      // This will be done only in FORM_OPEN CallBack of question with FORM_OPEN_QUESTION_ID from user Form.\r
+      //\r
+      if (QuestionId != FORM_OPEN_QUESTION_ID) {\r
+        return EFI_SUCCESS;\r
+      }\r
+  \r
+      //\r
+      // Initialize the container for dynamic opcodes.\r
+      //\r
+      StartOpCodeHandle = HiiAllocateOpCodeHandle ();\r
+      ASSERT (StartOpCodeHandle != NULL);\r
+  \r
+      EndOpCodeHandle = HiiAllocateOpCodeHandle ();\r
+      ASSERT (EndOpCodeHandle != NULL);\r
+  \r
+      //\r
+      // Create Hii Extend Label OpCode.\r
+      //\r
+      StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (\r
+                                            StartOpCodeHandle,\r
+                                            &gEfiIfrTianoGuid,\r
+                                            NULL,\r
+                                            sizeof (EFI_IFR_GUID_LABEL)\r
+                                            );\r
+      StartLabel->ExtendOpCode  = EFI_IFR_EXTEND_OP_LABEL;\r
+      StartLabel->Number        = LABEL_USER_NAME;\r
+  \r
+      EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (\r
+                                          EndOpCodeHandle,\r
+                                          &gEfiIfrTianoGuid,\r
+                                          NULL,\r
+                                          sizeof (EFI_IFR_GUID_LABEL)\r
+                                          );\r
+      EndLabel->ExtendOpCode  = EFI_IFR_EXTEND_OP_LABEL;\r
+      EndLabel->Number        = LABEL_END;\r
+  \r
+      //\r
+      // Add all the user profile in the user profile database.\r
+      //\r
+      for (Index = 0; Index < mUserProfileDb->UserProfileNum; Index++) {\r
+        User = (USER_PROFILE_ENTRY *) mUserProfileDb->UserProfile[Index];\r
+        AddUserSelection ((UINT16)(LABEL_USER_NAME + Index), User, StartOpCodeHandle);\r
+      }\r
+  \r
+      HiiUpdateForm (\r
+        mCallbackInfo->HiiHandle, // HII handle\r
+        &mUserManagerGuid,        // Formset GUID\r
+        FORMID_USER_FORM,         // Form ID\r
+        StartOpCodeHandle,        // Label for where to insert opcodes\r
+        EndOpCodeHandle           // Replace data\r
+        );\r
+  \r
+      HiiFreeOpCodeHandle (StartOpCodeHandle);\r
+      HiiFreeOpCodeHandle (EndOpCodeHandle);\r
+  \r
+      return EFI_SUCCESS;\r
+    }\r
+    break;\r
+\r
+  case EFI_BROWSER_ACTION_FORM_CLOSE:\r
+    Status = EFI_SUCCESS;\r
+    break;\r
+\r
+  case EFI_BROWSER_ACTION_CHANGING:\r
+  {\r
+    if (QuestionId >= LABEL_PROVIDER_NAME) {\r
+      //\r
+      // QuestionId comes from the second Form (Select a Credential Provider if identity  \r
+      // policy is OR type). Identify the user by the selected provider.\r
+      //\r
+      Status = IdentifyByProviderId (mCurrentUser, &mProviderDb->Provider[QuestionId & 0xFFF]->Identifier);\r
+      if (Status == EFI_SUCCESS) {\r
+        mIdentified     = TRUE;\r
+        *ActionRequest  = EFI_BROWSER_ACTION_REQUEST_EXIT;\r
+      }\r
+      return EFI_SUCCESS;\r
+    }\r
+\r
+    //\r
+    // QuestionId comes from the first Form (Select a user to identify).\r
+    //\r
+    User   = (USER_PROFILE_ENTRY *) mUserProfileDb->UserProfile[QuestionId & 0xFFF];\r
+    Status = GetIdentifyType (User, &PolicyType);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    if (PolicyType == EFI_USER_INFO_IDENTITY_OR) {\r
+      //\r
+      // Identify the user by "OR" logical.\r
+      //\r
+      Status = IdentifyOrTypeUser (User);\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+\r
+      mCurrentUser = (EFI_USER_PROFILE_HANDLE) User;\r
+    } else {\r
+      //\r
+      // Identify the user by "AND" logical.\r
+      //\r
+      Status = IdentifyAndTypeUser (User);\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+\r
+      mCurrentUser    = (EFI_USER_PROFILE_HANDLE) User;\r
+      mIdentified     = TRUE;\r
+      *ActionRequest  = EFI_BROWSER_ACTION_REQUEST_EXIT;\r
+    }\r
+  }\r
+  break;\r
+\r
+  default:\r
+    //\r
+    // All other action return unsupported.\r
+    //\r
+    Status = EFI_UNSUPPORTED;\r
+    break;\r
+  }\r
+\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  This function construct user profile database from user data saved in the Flash.\r
+  If no user is found in Flash, add one default user "administrator" in the user \r
+  profile database.\r
+\r
+  @retval EFI_SUCCESS            Init user profile database successfully.\r
+  @retval Others                 Fail to init user profile database.\r
+  \r
+**/\r
+EFI_STATUS\r
+InitUserProfileDb (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  UINT8       *VarData;\r
+  UINTN       VarSize;\r
+  UINTN       CurVarSize;\r
+  CHAR16      VarName[10];\r
+  UINTN       Index;\r
+  UINT32      VarAttr;\r
+\r
+  if (mUserProfileDb != NULL) {\r
+    //\r
+    // The user profiles had been already initialized.\r
+    //\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // Init user profile database structure.\r
+  //\r
+  if (!ExpandUsermUserProfileDb ()) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  CurVarSize = DEFAULT_PROFILE_SIZE;\r
+  VarData    = AllocateZeroPool (CurVarSize);\r
+  if (VarData == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  \r
+  //\r
+  // Get all user proifle entries.\r
+  //\r
+  Index = 0;\r
+  while (TRUE) {\r
+    //\r
+    // Get variable name.\r
+    //\r
+    UnicodeSPrint (\r
+      VarName, \r
+      sizeof (VarName),\r
+      L"User%04x", \r
+      Index\r
+      );\r
+    Index++;\r
+\r
+    //\r
+    // Get variable value.\r
+    //\r
+    VarSize = CurVarSize;\r
+    Status  = gRT->GetVariable (VarName, &mUserManagerGuid, &VarAttr, &VarSize, VarData);\r
+    if (Status == EFI_BUFFER_TOO_SMALL) {\r
+      FreePool (VarData);\r
+      VarData = AllocatePool (VarSize);\r
+      if (VarData == NULL) {\r
+        Status = EFI_OUT_OF_RESOURCES;\r
+        break;\r
+      }\r
+\r
+      CurVarSize  = VarSize;\r
+      Status      = gRT->GetVariable (VarName, &mUserManagerGuid, &VarAttr, &VarSize, VarData);\r
+    }\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      if (Status == EFI_NOT_FOUND) {\r
+        Status = EFI_SUCCESS;\r
+      }\r
+      break;\r
+    }\r
+    \r
+    //\r
+    // Check variable attributes.\r
+    //\r
+    if (VarAttr != (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS)) {\r
+      Status = gRT->SetVariable (VarName, &mUserManagerGuid, VarAttr, 0, NULL);\r
+      continue;\r
+    }\r
+    \r
+    //\r
+    // Add user profile to the user profile database.\r
+    //\r
+    Status = AddUserProfile (NULL, VarSize, VarData, FALSE);\r
+    if (EFI_ERROR (Status)) {\r
+      if (Status == EFI_SECURITY_VIOLATION) {\r
+        //\r
+        // Delete invalid user profile\r
+        //\r
+        gRT->SetVariable (VarName, &mUserManagerGuid, VarAttr, 0, NULL);\r
+      } else if (Status == EFI_OUT_OF_RESOURCES) {\r
+        break;\r
+      }\r
+    } else {\r
+      //\r
+      // Delete and save the profile again if some invalid profiles are deleted.\r
+      //\r
+      if (mUserProfileDb->UserProfileNum < Index) {\r
+        gRT->SetVariable (VarName, &mUserManagerGuid, VarAttr, 0, NULL);\r
+        SaveNvUserProfile (mUserProfileDb->UserProfile[mUserProfileDb->UserProfileNum - 1], FALSE);\r
+      }\r
+    }\r
+  }\r
+\r
+  if (VarData != NULL) {\r
+    FreePool (VarData);\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  \r
+  //\r
+  // Check whether the user profile database is empty.\r
+  //\r
+  if (mUserProfileDb->UserProfileNum == 0) {\r
+    Status = AddDefaultUserProfile ();\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  This function collects all the credential providers and saves to mProviderDb.\r
+\r
+  @retval EFI_SUCCESS            Collect credential providers successfully.\r
+  @retval Others                 Fail to collect credential providers.\r
+\r
+**/\r
+EFI_STATUS\r
+InitProviderInfo (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  UINTN       HandleCount;\r
+  EFI_HANDLE  *HandleBuf;\r
+  UINTN       Index; \r
+\r
+  if (mProviderDb != NULL) {\r
+    //\r
+    // The credential providers had been collected before.\r
+    //\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // Try to find all the user credential provider driver.\r
+  //\r
+  HandleCount = 0;\r
+  HandleBuf   = NULL;\r
+  Status = gBS->LocateHandleBuffer (\r
+                  ByProtocol,\r
+                  &gEfiUserCredentialProtocolGuid,\r
+                  NULL,\r
+                  &HandleCount,\r
+                  &HandleBuf\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Get provider infomation.\r
+  //\r
+  mProviderDb = AllocateZeroPool (\r
+                  sizeof (CREDENTIAL_PROVIDER_INFO) - \r
+                  sizeof (EFI_USER_CREDENTIAL_PROTOCOL *) + \r
+                  HandleCount * sizeof (EFI_USER_CREDENTIAL_PROTOCOL *)\r
+                  );\r
+  if (mProviderDb == NULL) {\r
+    FreePool (HandleBuf);\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+ mProviderDb->Count = HandleCount;\r
+  for (Index = 0; Index < HandleCount; Index++) {\r
+    Status = gBS->HandleProtocol (\r
+                    HandleBuf[Index],\r
+                    &gEfiUserCredentialProtocolGuid,\r
+                    (VOID **) &mProviderDb->Provider[Index]\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      FreePool (HandleBuf);\r
+      FreePool (mProviderDb);\r
+      mProviderDb = NULL;\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  FreePool (HandleBuf);\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  This function allows a caller to extract the current configuration for one\r
+  or more named elements from the target driver.\r
+\r
+\r
+  @param This            Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
+  @param Request         A null-terminated Unicode string in <ConfigRequest> format.\r
+  @param Progress        On return, points to a character in the Request string.\r
+                         Points to the string's null terminator if request was successful.\r
+                         Points to the most recent '&' before the first failing name/value\r
+                         pair (or the beginning of the string if the failure is in the\r
+                         first name/value pair) if the request was not successful.\r
+  @param Results         A null-terminated Unicode string in <ConfigAltResp> format which\r
+                         has all values filled in for the names in the Request string.\r
+                         String to be allocated by the called function.\r
+\r
+  @retval  EFI_SUCCESS            The Results is filled with the requested values.\r
+  @retval  EFI_OUT_OF_RESOURCES   Not enough memory to store the results.\r
+  @retval  EFI_INVALID_PARAMETER  Request is illegal syntax, or unknown name.\r
+  @retval  EFI_NOT_FOUND          Routing data doesn't match any storage in this driver.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FakeExtractConfig (\r
+  IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,\r
+  IN  CONST EFI_STRING                       Request,\r
+  OUT EFI_STRING                             *Progress,\r
+  OUT EFI_STRING                             *Results\r
+  )\r
+{\r
+  if (Progress == NULL || Results == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  *Progress = Request;\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+/**\r
+  This function processes the results of changes in configuration.\r
+\r
+\r
+  @param This            Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
+  @param Configuration   A null-terminated Unicode string in <ConfigResp> format.\r
+  @param Progress        A pointer to a string filled in with the offset of the most\r
+                         recent '&' before the first failing name/value pair (or the\r
+                         beginning of the string if the failure is in the first\r
+                         name/value pair) or the terminating NULL if all was successful.\r
+\r
+  @retval  EFI_SUCCESS            The Results is processed successfully.\r
+  @retval  EFI_INVALID_PARAMETER  Configuration is NULL.\r
+  @retval  EFI_NOT_FOUND          Routing data doesn't match any storage in this driver.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FakeRouteConfig (\r
+  IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,\r
+  IN  CONST EFI_STRING                       Configuration,\r
+  OUT EFI_STRING                             *Progress\r
+  )\r
+{\r
+  if (Configuration == NULL || Progress == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+\r
+/**\r
+  This function initialize the data mainly used in form browser.\r
+\r
+  @retval EFI_SUCCESS          Initialize form data successfully.\r
+  @retval Others               Fail to Initialize form data.\r
+\r
+**/\r
+EFI_STATUS\r
+InitFormBrowser (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  USER_MANAGER_CALLBACK_INFO  *CallbackInfo;\r
+  EFI_HII_DATABASE_PROTOCOL   *HiiDatabase;\r
+  EFI_HII_STRING_PROTOCOL     *HiiString;\r
+  EFI_FORM_BROWSER2_PROTOCOL  *FormBrowser2;\r
+\r
+  //\r
+  // Initialize driver private data.\r
+  //\r
+  CallbackInfo = AllocateZeroPool (sizeof (USER_MANAGER_CALLBACK_INFO));\r
+  if (CallbackInfo == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  CallbackInfo->Signature                   = USER_MANAGER_SIGNATURE;\r
+  CallbackInfo->ConfigAccess.ExtractConfig  = FakeExtractConfig;\r
+  CallbackInfo->ConfigAccess.RouteConfig    = FakeRouteConfig;\r
+  CallbackInfo->ConfigAccess.Callback       = UserIdentifyManagerCallback;\r
+\r
+  //\r
+  // Locate Hii Database protocol.\r
+  //\r
+  Status = gBS->LocateProtocol (&gEfiHiiDatabaseProtocolGuid, NULL, (VOID **) &HiiDatabase);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  CallbackInfo->HiiDatabase = HiiDatabase;\r
+\r
+  //\r
+  // Locate HiiString protocol.\r
+  //\r
+  Status = gBS->LocateProtocol (&gEfiHiiStringProtocolGuid, NULL, (VOID **) &HiiString);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  CallbackInfo->HiiString = HiiString;\r
+\r
+  //\r
+  // Locate Formbrowser2 protocol.\r
+  //\r
+  Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &FormBrowser2);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  CallbackInfo->FormBrowser2  = FormBrowser2;\r
+  CallbackInfo->DriverHandle  = NULL;\r
+  \r
+  //\r
+  // Install Device Path Protocol and Config Access protocol to driver handle.\r
+  //\r
+  Status = gBS->InstallMultipleProtocolInterfaces (\r
+                  &CallbackInfo->DriverHandle,\r
+                  &gEfiDevicePathProtocolGuid,\r
+                  &mHiiVendorDevicePath,\r
+                  &gEfiHiiConfigAccessProtocolGuid,\r
+                  &CallbackInfo->ConfigAccess,\r
+                  NULL\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // Publish HII data.\r
+  //\r
+  CallbackInfo->HiiHandle = HiiAddPackages (\r
+                              &mUserManagerGuid,\r
+                              CallbackInfo->DriverHandle,\r
+                              UserIdentifyManagerStrings,\r
+                              UserIdentifyManagerVfrBin,\r
+                              NULL\r
+                              );\r
+  if (CallbackInfo->HiiHandle == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  mCallbackInfo = CallbackInfo;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Identify the user whose identification policy supports auto logon.\r
+\r
+  @param[in]   ProviderIndex   The provider index in the provider list.\r
+  @param[out]  User            Points to user user profile if a user is identified successfully.\r
+\r
+  @retval EFI_SUCCESS          Identify a user with the specified provider successfully.\r
+  @retval Others               Fail to identify a user.\r
+\r
+**/\r
+EFI_STATUS\r
+IdentifyAutoLogonUser (\r
+  IN  UINTN                                     ProviderIndex,\r
+  OUT USER_PROFILE_ENTRY                        **User\r
+  )\r
+{\r
+  EFI_STATUS    Status;\r
+  EFI_USER_INFO *Info;\r
+  UINT8         PolicyType;\r
+\r
+  Info = AllocateZeroPool (sizeof (EFI_USER_INFO) + sizeof (EFI_USER_INFO_IDENTIFIER));\r
+  if (Info == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Info->InfoType  = EFI_USER_INFO_IDENTIFIER_RECORD;\r
+  Info->InfoSize  = sizeof (EFI_USER_INFO) + sizeof (EFI_USER_INFO_IDENTIFIER);\r
+\r
+  //\r
+  // Identify the specified credential provider's auto logon user.\r
+  //\r
+  Status = mProviderDb->Provider[ProviderIndex]->User (\r
+                                                   mProviderDb->Provider[ProviderIndex],\r
+                                                   NULL,\r
+                                                   (EFI_USER_INFO_IDENTIFIER *) (Info + 1)\r
+                                                   );\r
+  if (EFI_ERROR (Status)) {\r
+    FreePool (Info);\r
+    return Status;\r
+  }\r
+  \r
+  //\r
+  // Find user with the specified user ID.\r
+  //\r
+  *User   = NULL;\r
+  Status  = FindUserProfileByInfo (User, NULL, Info, Info->InfoSize);\r
+  FreePool (Info);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = GetIdentifyType ((EFI_USER_PROFILE_HANDLE) * User, &PolicyType);\r
+  if (PolicyType == EFI_USER_INFO_IDENTITY_AND) {\r
+    //\r
+    // The identified user need also identified by other credential provider.\r
+    // This can handle through select user.\r
+    //\r
+    return EFI_NOT_READY;\r
+  }\r
+  \r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Check whether the given console is ready.\r
+\r
+  @param[in]   ProtocolGuid   Points to the protocol guid of sonsole .\r
+  \r
+  @retval TRUE     The given console is ready.\r
+  @retval FALSE    The given console is not ready.\r
+  \r
+**/\r
+BOOLEAN\r
+CheckConsole (\r
+  EFI_GUID                     *ProtocolGuid  \r
+  )\r
+{\r
+  EFI_STATUS                   Status;\r
+  UINTN                        HandleCount;\r
+  EFI_HANDLE                   *HandleBuf;\r
+  UINTN                        Index; \r
+  EFI_DEVICE_PATH_PROTOCOL     *DevicePath;\r
+  \r
+  //\r
+  // Try to find all the handle driver.\r
+  //\r
+  HandleCount = 0;\r
+  HandleBuf   = NULL;\r
+  Status = gBS->LocateHandleBuffer (\r
+                  ByProtocol,\r
+                  ProtocolGuid,\r
+                  NULL,\r
+                  &HandleCount,\r
+                  &HandleBuf\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return FALSE;\r
+  }\r
+\r
+  for (Index = 0; Index < HandleCount; Index++) {\r
+    DevicePath = DevicePathFromHandle (HandleBuf[Index]);\r
+    if (DevicePath != NULL) {\r
+      FreePool (HandleBuf);\r
+      return TRUE;\r
+    }\r
+  }\r
+  FreePool (HandleBuf);  \r
+  return FALSE;\r
+}\r
+\r
+\r
+/**\r
+  Check whether the console is ready.\r
+\r
+  @retval TRUE     The console is ready.\r
+  @retval FALSE    The console is not ready.\r
+  \r
+**/\r
+BOOLEAN\r
+IsConsoleReady (\r
+  VOID\r
+  )\r
+{\r
+  if (!CheckConsole (&gEfiSimpleTextOutProtocolGuid)) {\r
+    return FALSE;\r
+  }\r
+\r
+  if (!CheckConsole (&gEfiSimpleTextInProtocolGuid)) {\r
+    if (!CheckConsole (&gEfiSimpleTextInputExProtocolGuid)) {\r
+    return FALSE;\r
+    }\r
+  }\r
+  \r
+  return TRUE;\r
+}\r
+\r
+\r
+/**\r
+  Identify a user to logon.\r
+\r
+  @param[out]  User          Points to user user profile if a user is identified successfully.\r
+\r
+  @retval EFI_SUCCESS        Identify a user successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+IdentifyUser (\r
+  OUT USER_PROFILE_ENTRY                        **User\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  UINTN                         Index;\r
+  EFI_CREDENTIAL_LOGON_FLAGS    AutoLogon;\r
+  EFI_USER_INFO                 *IdentifyInfo;\r
+  EFI_USER_INFO_IDENTITY_POLICY *Identity;\r
+  EFI_USER_CREDENTIAL_PROTOCOL  *UserCredential;\r
+  USER_PROFILE_ENTRY            *UserEntry;\r
+\r
+  //\r
+  // Initialize credential providers.\r
+  //\r
+  InitProviderInfo ();\r
+\r
+  //\r
+  // Initialize user profile database.\r
+  //\r
+  InitUserProfileDb ();\r
+\r
+  //\r
+  // If only one user in system, and its identify policy is TRUE, then auto logon.\r
+  //\r
+  if (mUserProfileDb->UserProfileNum == 1) {\r
+    UserEntry     = (USER_PROFILE_ENTRY *) mUserProfileDb->UserProfile[0];\r
+    IdentifyInfo  = NULL;\r
+    Status        = FindUserInfoByType (UserEntry, &IdentifyInfo, EFI_USER_INFO_IDENTITY_POLICY_RECORD);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    ASSERT (IdentifyInfo != NULL);\r
+\r
+    Identity = (EFI_USER_INFO_IDENTITY_POLICY *) ((UINT8 *) (IdentifyInfo + 1));\r
+    if (Identity->Type == EFI_USER_INFO_IDENTITY_TRUE) {\r
+      mCurrentUser = (EFI_USER_PROFILE_HANDLE) UserEntry;\r
+      UpdateUserInfo (UserEntry);\r
+      *User = UserEntry;\r
+      return EFI_SUCCESS;\r
+    }\r
+  }\r
+  \r
+  //\r
+  // Find and login the default & AutoLogon user.\r
+  //\r
+  for (Index = 0; Index < mProviderDb->Count; Index++) {\r
+    UserCredential = mProviderDb->Provider[Index];\r
+    Status = UserCredential->Default (UserCredential, &AutoLogon);\r
+    if (EFI_ERROR (Status)) {\r
+      continue;\r
+    }\r
+\r
+    if ((AutoLogon & (EFI_CREDENTIAL_LOGON_FLAG_DEFAULT | EFI_CREDENTIAL_LOGON_FLAG_AUTO)) != 0) {\r
+      Status = IdentifyAutoLogonUser (Index, &UserEntry);\r
+      if (Status == EFI_SUCCESS) {\r
+        mCurrentUser = (EFI_USER_PROFILE_HANDLE) UserEntry;\r
+        UpdateUserInfo (UserEntry);\r
+        *User = UserEntry;\r
+        return EFI_SUCCESS;\r
+      }\r
+    }\r
+  }\r
+  \r
+  if (!IsConsoleReady ()) {\r
+    //\r
+    // The console is still not ready for user selection.\r
+    //\r
+    return EFI_ACCESS_DENIED;\r
+  }\r
+\r
+  //\r
+  // Select a user and identify it.\r
+  //\r
+  mCallbackInfo->FormBrowser2->SendForm (\r
+                                 mCallbackInfo->FormBrowser2,\r
+                                 &mCallbackInfo->HiiHandle,\r
+                                 1,\r
+                                 &mUserManagerGuid,\r
+                                 0,\r
+                                 NULL,\r
+                                 NULL\r
+                                 );\r
+  \r
+  if (mIdentified) {\r
+    *User = (USER_PROFILE_ENTRY *) mCurrentUser;\r
+    UpdateUserInfo (*User);\r
+    return EFI_SUCCESS;\r
+  }\r
+  \r
+  return EFI_ACCESS_DENIED;\r
+}\r
+\r
+\r
+/**\r
+  An empty function to pass error checking of CreateEventEx ().\r
\r
+  @param  Event         Event whose notification function is being invoked.\r
+  @param  Context       Pointer to the notification function's context,\r
+                        which is implementation-dependent.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+InternalEmptyFuntion (\r
+  IN EFI_EVENT                Event,\r
+  IN VOID                     *Context\r
+  )\r
+{\r
+}\r
+\r
+\r
+/**\r
+  Create, Signal, and Close the User Profile Changed event.\r
+\r
+**/\r
+VOID\r
+SignalEventUserProfileChanged (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS    Status;\r
+  EFI_EVENT     Event;\r
+\r
+  Status = gBS->CreateEventEx (\r
+                  EVT_NOTIFY_SIGNAL,\r
+                  TPL_CALLBACK,\r
+                  InternalEmptyFuntion,\r
+                  NULL,\r
+                  &gEfiEventUserProfileChangedGuid,\r
+                  &Event\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+  gBS->SignalEvent (Event);\r
+  gBS->CloseEvent (Event);\r
+}\r
+\r
+\r
+/**\r
+  Create a new user profile.\r
+\r
+  This function creates a new user profile with only a new user identifier attached and returns \r
+  its handle. The user profile is non-volatile, but the handle User can change across reboots.\r
+\r
+  @param[in]  This               Points to this instance of the EFI_USER_MANAGER_PROTOCOL.\r
+  @param[out] User               On return, points to the new user profile handle. \r
+                                 The user profile handle is unique only during this boot.\r
\r
+  @retval EFI_SUCCESS            User profile was successfully created.\r
+  @retval EFI_ACCESS_DENIED      Current user does not have sufficient permissions to create a \r
+                                 user profile.\r
+  @retval EFI_UNSUPPORTED        Creation of new user profiles is not supported.\r
+  @retval EFI_INVALID_PARAMETER  The User parameter is NULL.\r
+  \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UserProfileCreate (\r
+  IN CONST  EFI_USER_MANAGER_PROTOCOL           *This,\r
+  OUT       EFI_USER_PROFILE_HANDLE             *User\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  if ((This == NULL) || (User == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Check the right of the current user.\r
+  //\r
+  if (!CheckCurrentUserAccessRight (EFI_USER_INFO_ACCESS_MANAGE)) {\r
+    if (!CheckCurrentUserAccessRight (EFI_USER_INFO_ACCESS_ENROLL_OTHERS)) {\r
+      return EFI_ACCESS_DENIED;\r
+    }\r
+  }\r
+  \r
+  //\r
+  // Create new user profile\r
+  //\r
+  Status = CreateUserProfile ((USER_PROFILE_ENTRY **) User);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_ACCESS_DENIED;\r
+  }\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Delete an existing user profile.\r
+\r
+  @param[in] This                Points to this instance of the EFI_USER_MANAGER_PROTOCOL.\r
+  @param[in] User                User profile handle. \r
+\r
+  @retval EFI_SUCCESS            User profile was successfully deleted.\r
+  @retval EFI_ACCESS_DENIED      Current user does not have sufficient permissions to delete a user\r
+                                 profile or there is only one user profile.\r
+  @retval EFI_UNSUPPORTED        Deletion of new user profiles is not supported.\r
+  @retval EFI_INVALID_PARAMETER  User does not refer to a valid user profile.\r
+  \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UserProfileDelete (\r
+  IN CONST  EFI_USER_MANAGER_PROTOCOL           *This,\r
+  IN        EFI_USER_PROFILE_HANDLE             User\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  if (This == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  \r
+  //\r
+  // Check the right of the current user.\r
+  //\r
+  if (!CheckCurrentUserAccessRight (EFI_USER_INFO_ACCESS_MANAGE)) {\r
+    return EFI_ACCESS_DENIED;\r
+  }\r
+  \r
+  //\r
+  // Delete user profile.\r
+  //\r
+  Status = DelUserProfile (User);\r
+  if (EFI_ERROR (Status)) {\r
+    if (Status != EFI_INVALID_PARAMETER) {\r
+      return EFI_ACCESS_DENIED;\r
+    }\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Enumerate all of the enrolled users on the platform.\r
+\r
+  This function returns the next enrolled user profile. To retrieve the first user profile handle,  \r
+  point User at a NULL. Each subsequent call will retrieve another user profile handle until there \r
+  are no more, at which point User will point to NULL. \r
+\r
+  @param[in]      This           Points to this instance of the EFI_USER_MANAGER_PROTOCOL.\r
+  @param[in, out] User           On entry, points to the previous user profile handle or NULL to \r
+                                 start enumeration. On exit, points to the next user profile handle\r
+                                 or NULL if there are no more user profiles.\r
+\r
+  @retval EFI_SUCCESS            Next enrolled user profile successfully returned. \r
+  @retval EFI_ACCESS_DENIED      Next enrolled user profile was not successfully returned.\r
+  @retval EFI_INVALID_PARAMETER  The User parameter is NULL.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UserProfileGetNext (\r
+  IN CONST  EFI_USER_MANAGER_PROTOCOL           *This,\r
+  IN OUT    EFI_USER_PROFILE_HANDLE             *User\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  if ((This == NULL) || (User == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  \r
+  Status = FindUserProfile ((USER_PROFILE_ENTRY **) User, TRUE, NULL);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_ACCESS_DENIED;\r
+  }\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Return the current user profile handle.\r
+\r
+  @param[in]  This               Points to this instance of the EFI_USER_MANAGER_PROTOCOL.\r
+  @param[out] CurrentUser        On return, points to the current user profile handle.\r
+\r
+  @retval EFI_SUCCESS            Current user profile handle returned successfully. \r
+  @retval EFI_INVALID_PARAMETER  The CurrentUser parameter is NULL.\r
+  \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UserProfileCurrent (\r
+  IN CONST  EFI_USER_MANAGER_PROTOCOL           *This,\r
+  OUT       EFI_USER_PROFILE_HANDLE             *CurrentUser\r
+  )\r
+{  \r
+  //\r
+  // Get current user profile.\r
+  //\r
+  if ((This == NULL) || (CurrentUser == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  *CurrentUser = mCurrentUser;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Identify a user.\r
+\r
+  Identify the user and, if authenticated, returns the user handle and changes the current\r
+  user profile. All user information marked as private in a previously selected profile\r
+  is no longer available for inspection. \r
+  Whenever the current user profile is changed then the an event with the GUID \r
+  EFI_EVENT_GROUP_USER_PROFILE_CHANGED is signaled.\r
+\r
+  @param[in]  This               Points to this instance of the EFI_USER_MANAGER_PROTOCOL.\r
+  @param[out] User               On return, points to the user profile handle for the current\r
+                                 user profile.\r
+\r
+  @retval EFI_SUCCESS            User was successfully identified.\r
+  @retval EFI_ACCESS_DENIED      User was not successfully identified.\r
+  @retval EFI_INVALID_PARAMETER  The User parameter is NULL.\r
+  \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UserProfileIdentify (\r
+  IN CONST  EFI_USER_MANAGER_PROTOCOL           *This,\r
+  OUT       EFI_USER_PROFILE_HANDLE             *User\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  if ((This == NULL) || (User == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (mCurrentUser != NULL) {\r
+    *User = mCurrentUser;\r
+    return EFI_SUCCESS;\r
+  }\r
+  \r
+  //\r
+  // Identify user\r
+  //\r
+  Status = IdentifyUser ((USER_PROFILE_ENTRY **) User);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_ACCESS_DENIED;\r
+  }\r
+  \r
+  //\r
+  // Publish the user info into the EFI system configuration table.\r
+  //\r
+  PublishUserTable ();\r
+\r
+  //\r
+  // Signal User Profile Changed event.\r
+  //\r
+  SignalEventUserProfileChanged ();\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Find a user using a user information record.\r
+\r
+  This function searches all user profiles for the specified user information record.\r
+  The search starts with the user information record handle following UserInfo and \r
+  continues until either the information is found or there are no more user profiles.\r
+  A match occurs when the Info.InfoType field matches the user information record\r
+  type and the user information record data matches the portion of Info.\r
+\r
+  @param[in]      This           Points to this instance of the EFI_USER_MANAGER_PROTOCOL.\r
+  @param[in, out] User           On entry, points to the previously returned user profile \r
+                                 handle, or NULL to start searching with the first user profile.\r
+                                 On return, points to the user profile handle, or NULL if not\r
+                                 found.\r
+  @param[in, out] UserInfo       On entry, points to the previously returned user information\r
+                                 handle, or NULL to start searching with the first. On return, \r
+                                 points to the user information handle of the user information\r
+                                 record, or NULL if not found. Can be NULL, in which case only \r
+                                 one user information record per user can be returned. \r
+  @param[in]      Info           Points to the buffer containing the user information to be \r
+                                 compared to the user information record. If the user information \r
+                                 record data is empty, then only the user information record type \r
+                                 is compared. If InfoSize is 0, then the user information record \r
+                                 must be empty.\r
+\r
+  @param[in]      InfoSize       The size of Info, in bytes. \r
+\r
+  @retval EFI_SUCCESS            User information was found. User points to the user profile\r
+                                 handle, and UserInfo points to the user information handle.\r
+  @retval EFI_NOT_FOUND          User information was not found. User points to NULL, and  \r
+                                 UserInfo points to NULL.\r
+  @retval EFI_INVALID_PARAMETER  User is NULL. Or Info is NULL.                           \r
+  \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UserProfileFind (\r
+  IN     CONST EFI_USER_MANAGER_PROTOCOL        *This,\r
+  IN OUT EFI_USER_PROFILE_HANDLE                *User,\r
+  IN OUT EFI_USER_INFO_HANDLE                   *UserInfo OPTIONAL,\r
+  IN     CONST EFI_USER_INFO                    *Info,\r
+  IN     UINTN                                  InfoSize\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  UINTN       Size;\r
+\r
+  if ((This == NULL) || (User == NULL) || (Info == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (InfoSize == 0) {\r
+    //\r
+    // If InfoSize is 0, then the user information record must be empty.\r
+    //\r
+    if (Info->InfoSize != sizeof (EFI_USER_INFO)) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+  } else {\r
+    if (InfoSize != Info->InfoSize) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+  }\r
+  Size = Info->InfoSize;  \r
+  \r
+  //\r
+  // Find user profile accdoring to user information.\r
+  //\r
+  Status = FindUserProfileByInfo (\r
+            (USER_PROFILE_ENTRY **) User,\r
+            (EFI_USER_INFO **) UserInfo,\r
+            (EFI_USER_INFO *) Info,\r
+            Size\r
+            );\r
+  if (EFI_ERROR (Status)) {\r
+    *User = NULL;\r
+    if (UserInfo != NULL) {\r
+      *UserInfo = NULL;\r
+    }\r
+    return EFI_NOT_FOUND;\r
+  }\r
+  \r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Return information attached to the user.\r
+\r
+  This function returns user information. The format of the information is described in User \r
+  Information. The function may return EFI_ACCESS_DENIED if the information is marked private \r
+  and the handle specified by User is not the current user profile. The function may return \r
+  EFI_ACCESS_DENIED if the information is marked protected and the information is associated \r
+  with a credential provider for which the user has not been authenticated.\r
+\r
+  @param[in]      This           Points to this instance of the EFI_USER_MANAGER_PROTOCOL.\r
+  @param[in]      User           Handle of the user whose profile will be retrieved. \r
+  @param[in]      UserInfo       Handle of the user information data record.   \r
+  @param[out]     Info           On entry, points to a buffer of at least *InfoSize bytes. On exit,  \r
+                                 holds the user information. If the buffer is too small to hold the  \r
+                                 information, then EFI_BUFFER_TOO_SMALL is returned and InfoSize is \r
+                                 updated to contain the number of bytes actually required. \r
+  @param[in, out] InfoSize       On entry, points to the size of Info. On return, points to the size  \r
+                                 of the user information. \r
+\r
+  @retval EFI_SUCCESS            Information returned successfully.\r
+  @retval EFI_ACCESS_DENIED      The information about the specified user cannot be accessed by the \r
+                                 current user.\r
+  @retval EFI_BUFFER_TOO_SMALL   The number of bytes specified by *InfoSize is too small to hold the \r
+                                 returned data. The actual size required is returned in *InfoSize.\r
+  @retval EFI_NOT_FOUND          User does not refer to a valid user profile or UserInfo does not refer \r
+                                 to a valid user info handle.\r
+  @retval EFI_INVALID_PARAMETER  Info is NULL or InfoSize is NULL.\r
+  \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UserProfileGetInfo (\r
+  IN CONST  EFI_USER_MANAGER_PROTOCOL           *This,\r
+  IN        EFI_USER_PROFILE_HANDLE             User,\r
+  IN        EFI_USER_INFO_HANDLE                UserInfo,\r
+  OUT       EFI_USER_INFO                       *Info,\r
+  IN OUT    UINTN                               *InfoSize\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  if ((This == NULL) || (InfoSize == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((*InfoSize != 0) && (Info == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  \r
+  if ((User == NULL) || (UserInfo == NULL)) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+  \r
+  Status = GetUserInfo (User, UserInfo, Info, InfoSize, TRUE);\r
+  if (EFI_ERROR (Status)) {\r
+    if (Status == EFI_BUFFER_TOO_SMALL) {\r
+      return EFI_BUFFER_TOO_SMALL;\r
+    }\r
+    return EFI_ACCESS_DENIED;\r
+  }\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Add or update user information.\r
+\r
+  This function changes user information.  If NULL is pointed to by UserInfo, then a new user \r
+  information record is created and its handle is returned in UserInfo. Otherwise, the existing  \r
+  one is replaced.\r
+  If EFI_USER_INFO_EXCLUSIVE is specified in Info and a user information record of the same \r
+  type already exists in the user profile, then EFI_ACCESS_DENIED will be returned and UserInfo\r
+  will point to the handle of the existing record.\r
+\r
+  @param[in]      This            Points to this instance of the EFI_USER_MANAGER_PROTOCOL.\r
+  @param[in]      User            Handle of the user whose profile will be retrieved. \r
+  @param[in, out] UserInfo        Handle of the user information data record.   \r
+  @param[in]      Info            On entry, points to a buffer of at least *InfoSize bytes. On exit, \r
+                                  holds the user information. If the buffer is too small to hold the \r
+                                  information, then EFI_BUFFER_TOO_SMALL is returned and InfoSize is \r
+                                  updated to contain the number of bytes actually required. \r
+  @param[in]      InfoSize        On entry, points to the size of Info. On return, points to the size \r
+                                  of the user information. \r
+\r
+  @retval EFI_SUCCESS             Information returned successfully.\r
+  @retval EFI_ACCESS_DENIED       The record is exclusive.\r
+  @retval EFI_SECURITY_VIOLATION  The current user does not have permission to change the specified \r
+                                  user profile or user information record.\r
+  @retval EFI_NOT_FOUND           User does not refer to a valid user profile or UserInfo does not  \r
+                                  refer to a valid user info handle.\r
+  @retval EFI_INVALID_PARAMETER   UserInfo is NULL or Info is NULL. \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UserProfileSetInfo (\r
+  IN CONST  EFI_USER_MANAGER_PROTOCOL           *This,\r
+  IN        EFI_USER_PROFILE_HANDLE             User,\r
+  IN OUT    EFI_USER_INFO_HANDLE                *UserInfo,\r
+  IN CONST  EFI_USER_INFO                       *Info,\r
+  IN        UINTN                               InfoSize\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  if ((This == NULL) || (User == NULL) || (UserInfo == NULL) || (Info == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  \r
+  //\r
+  // Check the right of the current user.\r
+  //\r
+  if (User != mCurrentUser) {\r
+    if (!CheckCurrentUserAccessRight (EFI_USER_INFO_ACCESS_MANAGE)) {\r
+      if (*UserInfo != NULL) {\r
+        //\r
+        // Can't update info in other profiles without MANAGE right.\r
+        //\r
+        return EFI_SECURITY_VIOLATION;\r
+      }\r
+      \r
+      if (!CheckCurrentUserAccessRight (EFI_USER_INFO_ACCESS_ENROLL_OTHERS)) {\r
+        //\r
+        // Can't add info into other profiles.\r
+        //\r
+        return EFI_SECURITY_VIOLATION;\r
+      }\r
+    }\r
+  }\r
+\r
+  if (User == mCurrentUser) {\r
+    if (CheckCurrentUserAccessRight (EFI_USER_INFO_ACCESS_ENROLL_SELF)) {\r
+      //\r
+      // Only identify policy can be added/updated.\r
+      //\r
+      if (Info->InfoType != EFI_USER_INFO_IDENTITY_POLICY_RECORD) {\r
+        return EFI_SECURITY_VIOLATION;\r
+      }\r
+    }\r
+  }\r
+  \r
+  //\r
+  // Modify user information.\r
+  //\r
+  Status = ModifyUserInfo (User, (EFI_USER_INFO **) UserInfo, Info, InfoSize);\r
+  if (EFI_ERROR (Status)) {\r
+    if (Status == EFI_ACCESS_DENIED) {\r
+      return EFI_ACCESS_DENIED;      \r
+    }\r
+    return EFI_SECURITY_VIOLATION;\r
+  }\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Called by credential provider to notify of information change.\r
+\r
+  This function allows the credential provider to notify the User Identity Manager when user status  \r
+  has changed while deselected.\r
+  If the User Identity Manager doesn't support asynchronous changes in credentials, then this function \r
+  should return EFI_UNSUPPORTED. \r
+  If the User Identity Manager supports this, it will call User() to get the user identifier and then \r
+  GetNextInfo() and GetInfo() in the User Credential Protocol to get all of the information from the \r
+  credential and add it.\r
+\r
+  @param[in] This          Points to this instance of the EFI_USER_MANAGER_PROTOCOL.\r
+  @param[in] Changed       Handle on which is installed an instance of the EFI_USER_CREDENTIAL_PROTOCOL \r
+                           where the user has changed.\r
+\r
+  @retval EFI_SUCCESS      The User Identity Manager has handled the notification.\r
+  @retval EFI_NOT_READY    The function was called while the specified credential provider was not selected.\r
+  @retval EFI_UNSUPPORTED  The User Identity Manager doesn't support asynchronous notifications.\r
+  \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UserProfileNotify (\r
+  IN CONST  EFI_USER_MANAGER_PROTOCOL           *This,\r
+  IN        EFI_HANDLE                          Changed\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  EFI_USER_CREDENTIAL_PROTOCOL  *Provider;\r
+  EFI_USER_INFO_IDENTIFIER      UserId;\r
+  EFI_USER_INFO_HANDLE          UserInfo;\r
+  EFI_USER_INFO_HANDLE          UserInfo2;\r
+  UINTN                         InfoSize;\r
+  EFI_USER_INFO                 *Info;\r
+  USER_PROFILE_ENTRY            *User;\r
+\r
+  if (This == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  \r
+  Status = gBS->HandleProtocol (\r
+                  Changed,\r
+                  &gEfiUserCredentialProtocolGuid,\r
+                  (VOID **) &Provider\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = Provider->User (Provider, NULL, &UserId);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_NOT_READY;\r
+  }\r
+\r
+  //\r
+  // Find user with the UserId.\r
+  //\r
+  User = NULL;\r
+  while (TRUE) {\r
+    //\r
+    // Find next user profile.\r
+    // \r
+    Status = FindUserProfile (&User, TRUE, NULL);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  \r
+    //\r
+    // Find the user information.\r
+    //\r
+    Info = NULL;\r
+    FindUserInfoByType (User, &Info, EFI_USER_INFO_IDENTIFIER_RECORD);\r
+    if (CompareMem ((UINT8 *) (Info + 1), UserId, sizeof (UserId)) == 0) {\r
+      //\r
+      // Found the infomation record. \r
+      //\r
+      break;\r
+    }\r
+  }\r
+\r
+  UserInfo = NULL;\r
+  do {\r
+    //\r
+    // Get user info handle.\r
+    //\r
+    Status = Provider->GetNextInfo(Provider, &UserInfo);\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_SUCCESS;\r
+    }\r
+\r
+    //\r
+    // Get the user information from the user info handle.\r
+    // \r
+    InfoSize = 0;\r
+    Status = Provider->GetInfo(Provider, UserInfo, NULL, &InfoSize);\r
+    if (EFI_ERROR (Status)) {\r
+      if (Status == EFI_BUFFER_TOO_SMALL) {\r
+        Info = AllocateZeroPool (InfoSize);\r
+        if (Info == NULL) {\r
+          return EFI_OUT_OF_RESOURCES;\r
+        }\r
+        Status = Provider->GetInfo(Provider, UserInfo, Info, &InfoSize);\r
+        if (EFI_ERROR (Status)) {\r
+          FreePool (Info);\r
+          break;\r
+        }\r
+      }\r
+      break;\r
+    }\r
+\r
+    //\r
+    // Save the user information.\r
+    // \r
+    UserInfo2 = NULL;\r
+    Status = UserProfileSetInfo (&gUserIdentifyManager, (EFI_USER_PROFILE_HANDLE)User, &UserInfo2, Info, InfoSize);\r
+    FreePool (Info);\r
+    if (EFI_ERROR (Status)) {\r
+      break;\r
+    }\r
+  } while (TRUE);\r
+  \r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Delete user information.\r
+\r
+  Delete the user information attached to the user profile specified by the UserInfo.\r
+\r
+  @param[in] This            Points to this instance of the EFI_USER_MANAGER_PROTOCOL.\r
+  @param[in] User            Handle of the user whose information will be deleted.\r
+  @param[in] UserInfo        Handle of the user information to remove.\r
+\r
+  @retval EFI_SUCCESS        User information deleted successfully.\r
+  @retval EFI_NOT_FOUND      User information record UserInfo does not exist in the user profile.\r
+  @retval EFI_ACCESS_DENIED  The current user does not have permission to delete this user information. \r
+  \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UserProfileDeleteInfo (\r
+  IN CONST  EFI_USER_MANAGER_PROTOCOL           *This,\r
+  IN        EFI_USER_PROFILE_HANDLE             User,\r
+  IN        EFI_USER_INFO_HANDLE                UserInfo\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  if (This == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  \r
+  //\r
+  // Check the right of the current user.\r
+  //\r
+  if (User != mCurrentUser) {\r
+    if (!CheckCurrentUserAccessRight (EFI_USER_INFO_ACCESS_MANAGE)) {\r
+      return EFI_ACCESS_DENIED;\r
+    }\r
+  }\r
+  \r
+  //\r
+  // Delete user information.\r
+  //\r
+  Status = DelUserInfo (User, UserInfo, TRUE);\r
+  if (EFI_ERROR (Status)) {\r
+    if (Status == EFI_NOT_FOUND) {\r
+      return EFI_NOT_FOUND;\r
+    }\r
+    return EFI_ACCESS_DENIED;\r
+  } \r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Enumerate user information of all the enrolled users on the platform.\r
+\r
+  This function returns the next user information record. To retrieve the first user   \r
+  information record handle, point UserInfo at a NULL. Each subsequent call will retrieve \r
+  another user information record handle until there are no more, at which point UserInfo \r
+  will point to NULL. \r
+\r
+  @param[in]      This           Points to this instance of the EFI_USER_MANAGER_PROTOCOL.\r
+  @param[in]      User           Handle of the user whose information will be deleted.\r
+  @param[in, out] UserInfo       Handle of the user information to remove.\r
+\r
+  @retval EFI_SUCCESS            User information returned.\r
+  @retval EFI_NOT_FOUND          No more user information found.\r
+  @retval EFI_INVALID_PARAMETER  UserInfo is NULL.\r
+  \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UserProfileGetNextInfo (\r
+  IN CONST  EFI_USER_MANAGER_PROTOCOL           *This,\r
+  IN        EFI_USER_PROFILE_HANDLE             User,\r
+  IN OUT    EFI_USER_INFO_HANDLE                *UserInfo\r
+  )\r
+{\r
+  if ((This == NULL) || (UserInfo == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  //\r
+  // Get next user information entry.\r
+  //\r
+  return FindUserInfo (User, (EFI_USER_INFO **) UserInfo, TRUE, NULL);\r
+}\r
+\r
+\r
+/**\r
+  Main entry for this driver.\r
+\r
+  @param[in] ImageHandle     Image handle this driver.\r
+  @param[in] SystemTable     Pointer to SystemTable.\r
+\r
+  @retval EFI_SUCESS         This function always complete successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UserIdentifyManagerInit (\r
+  IN EFI_HANDLE        ImageHandle,\r
+  IN EFI_SYSTEM_TABLE  *SystemTable\r
+  )\r
+{\r
+\r
+  EFI_STATUS  Status;\r
+\r
+  //\r
+  // Initiate form browser.\r
+  //\r
+  InitFormBrowser ();\r
+\r
+  //\r
+  // Install protocol interfaces for the User Identity Manager.\r
+  //\r
+  Status = gBS->InstallProtocolInterface (\r
+                  &mCallbackInfo->DriverHandle,\r
+                  &gEfiUserManagerProtocolGuid,\r
+                  EFI_NATIVE_INTERFACE,\r
+                  &gUserIdentifyManager\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);  \r
+\r
+  LoadDeferredImageInit (ImageHandle);\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
diff --git a/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManager.h b/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManager.h
new file mode 100644 (file)
index 0000000..b1e078a
--- /dev/null
@@ -0,0 +1,413 @@
+/** @file\r
+  The header file for User identify Manager driver.\r
+    \r
+Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _USER_IDENTIFY_MANAGER_H_\r
+#define _USER_IDENTIFY_MANAGER_H_\r
+\r
+#include <Uefi.h>\r
+\r
+#include <Guid/GlobalVariable.h>\r
+#include <Guid/MdeModuleHii.h>\r
+\r
+#include <Protocol/FormBrowser2.h>\r
+#include <Protocol/HiiDatabase.h>\r
+#include <Protocol/HiiConfigAccess.h>\r
+#include <Protocol/HiiString.h>\r
+#include <Protocol/HiiConfigRouting.h>\r
+#include <Protocol/UserCredential.h>\r
+#include <Protocol/UserManager.h>\r
+#include <Protocol/DeferredImageLoad.h>\r
+#include <Protocol/SimpleTextOut.h>\r
+#include <Protocol/SimpleTextIn.h>\r
+#include <Protocol/SimpleTextInEx.h>\r
+\r
+#include <Library/UefiRuntimeServicesTableLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/DevicePathLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/PrintLib.h>\r
+#include <Library/HiiLib.h>\r
+\r
+#include "UserIdentifyManagerData.h"\r
+\r
+//\r
+// This is the generated IFR binary data for each formset defined in VFR.\r
+// This data array is ready to be used as input of HiiAddPackages() to\r
+// create a packagelist.\r
+//\r
+extern UINT8                UserIdentifyManagerVfrBin[];\r
+\r
+//\r
+// This is the generated String package data for all .UNI files.\r
+// This data array is ready to be used as input of HiiAddPackages() to\r
+// create a packagelist.\r
+//\r
+extern UINT8                UserIdentifyManagerStrings[];\r
+\r
+#define   USER_NUMBER_INC           32\r
+#define   DEFAULT_PROFILE_SIZE      512\r
+#define   INFO_PAYLOAD_SIZE         64\r
+\r
+//\r
+// Credential Provider Information.\r
+//\r
+typedef struct {\r
+  UINTN                         Count;\r
+  EFI_USER_CREDENTIAL_PROTOCOL  *Provider[1];\r
+} CREDENTIAL_PROVIDER_INFO;\r
+\r
+//\r
+// Internal user profile entry.\r
+//\r
+typedef struct {\r
+  UINTN   MaxProfileSize;\r
+  UINTN   UserProfileSize;\r
+  CHAR16  UserVarName[9];\r
+  UINT8   *ProfileInfo;\r
+} USER_PROFILE_ENTRY;\r
+\r
+//\r
+// Internal user profile database.\r
+//\r
+typedef struct {\r
+  UINTN                   UserProfileNum;\r
+  UINTN                   MaxProfileNum;\r
+  EFI_USER_PROFILE_HANDLE UserProfile[1];\r
+} USER_PROFILE_DB;\r
+\r
+#define USER_MANAGER_SIGNATURE  SIGNATURE_32 ('U', 'I', 'M', 'S')\r
+\r
+typedef struct {\r
+  UINTN                           Signature;\r
+  EFI_HANDLE                      DriverHandle;\r
+  EFI_HII_HANDLE                  HiiHandle;\r
+\r
+  //\r
+  // Consumed protocol.\r
+  //\r
+  EFI_HII_DATABASE_PROTOCOL       *HiiDatabase;\r
+  EFI_HII_STRING_PROTOCOL         *HiiString;\r
+  EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;\r
+  EFI_FORM_BROWSER2_PROTOCOL      *FormBrowser2;\r
+\r
+  //\r
+  // Produced protocol.\r
+  //\r
+  EFI_HII_CONFIG_ACCESS_PROTOCOL  ConfigAccess;\r
+} USER_MANAGER_CALLBACK_INFO;\r
+\r
+///\r
+/// HII specific Vendor Device Path definition.\r
+///\r
+typedef struct {\r
+  VENDOR_DEVICE_PATH        VendorDevicePath;\r
+  EFI_DEVICE_PATH_PROTOCOL  End;\r
+} HII_VENDOR_DEVICE_PATH;\r
+\r
+/**\r
+  Register an event notification function for the user profile changed.\r
+\r
+  @param[in]  ImageHandle     Image handle this driver.\r
+\r
+**/\r
+VOID\r
+LoadDeferredImageInit (\r
+  IN EFI_HANDLE        ImageHandle\r
+  );\r
+\r
+\r
+/**\r
+  This function creates a new user profile with only\r
+  a new user identifier attached and returns its handle.\r
+  The user profile is non-volatile, but the handle User\r
+  can change across reboots.\r
+\r
+  @param[in]   This               Protocol EFI_USER_MANAGER_PROTOCOL instance\r
+                                  pointer.\r
+  @param[out]  User               Handle of a new user profile.\r
+\r
+  @retval EFI_SUCCESS             User profile was successfully created.\r
+  @retval EFI_ACCESS_DENIED       Current user does not have sufficient permissions\r
+                                  to create a user profile.\r
+  @retval EFI_UNSUPPORTED         Creation of new user profiles is not supported.\r
+  @retval EFI_INVALID_PARAMETER   User is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UserProfileCreate (\r
+  IN CONST  EFI_USER_MANAGER_PROTOCOL           *This,\r
+  OUT       EFI_USER_PROFILE_HANDLE             *User\r
+  );\r
+\r
+\r
+/**\r
+  Delete an existing user profile.\r
+\r
+  @param  This                    Protocol EFI_USER_MANAGER_PROTOCOL instance\r
+                                  pointer.\r
+  @param  User                    User profile handle.\r
+\r
+  @retval EFI_SUCCESS             User profile was successfully deleted.\r
+  @retval EFI_ACCESS_DENIED       Current user does not have sufficient permissions\r
+                                  to delete a user profile or there is only one\r
+                                  user profile.\r
+  @retval EFI_UNSUPPORTED         Deletion of new user profiles is not supported.\r
+  @retval EFI_INVALID_PARAMETER   User does not refer to a valid user profile.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UserProfileDelete (\r
+  IN CONST  EFI_USER_MANAGER_PROTOCOL           *This,\r
+  IN        EFI_USER_PROFILE_HANDLE             User\r
+  );\r
+\r
+\r
+/**\r
+  Get next user profile from the user profile database.\r
+\r
+  @param[in]       This           Protocol EFI_USER_MANAGER_PROTOCOL instance\r
+                                  pointer.\r
+  @param[in, out]  User           User profile handle.\r
+\r
+  @retval EFI_SUCCESS             Next enrolled user profile successfully returned.\r
+  @retval EFI_INVALID_PARAMETER   User is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UserProfileGetNext (\r
+  IN CONST  EFI_USER_MANAGER_PROTOCOL           *This,\r
+  IN OUT    EFI_USER_PROFILE_HANDLE             *User\r
+  );\r
+\r
+\r
+/**\r
+  This function returns the current user profile handle.\r
+\r
+  @param[in]  This                Protocol EFI_USER_MANAGER_PROTOCOL instance pointer.\r
+  @param[out]  CurrentUser        User profile handle.\r
+\r
+  @retval EFI_SUCCESS             Current user profile handle returned successfully.\r
+  @retval EFI_INVALID_PARAMETER   CurrentUser is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UserProfileCurrent (\r
+  IN CONST  EFI_USER_MANAGER_PROTOCOL           *This,\r
+  OUT       EFI_USER_PROFILE_HANDLE             *CurrentUser\r
+  );\r
+\r
+\r
+/**\r
+  Identify the user and, if authenticated, returns the user handle and changes\r
+  the current user profile.\r
+\r
+  @param  This                    Protocol EFI_USER_MANAGER_PROTOCOL instance pointer.\r
+  @param  CurrentUser             User profile handle.\r
+\r
+  @retval EFI_SUCCESS             User was successfully identified.\r
+  @retval EFI_INVALID_PARAMETER   User is NULL.\r
+  @retval EFI_ACCESS_DENIED       User was not successfully identified.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UserProfileIdentify (\r
+  IN CONST  EFI_USER_MANAGER_PROTOCOL           *This,\r
+  OUT       EFI_USER_PROFILE_HANDLE             *User\r
+  );\r
+\r
+\r
+/**\r
+  Find a user using a user information record.\r
+\r
+  This function searches all user profiles for the specified user information record.\r
+  The search starts with the user information record handle following UserInfo and \r
+  continues until either the information is found or there are no more user profiles.\r
+  A match occurs when the Info.InfoType field matches the user information record\r
+  type and the user information record data matches the portion of Info passed the \r
+  EFI_USER_INFO header.\r
+\r
+  @param[in]      This     Points to this instance of the EFI_USER_MANAGER_PROTOCOL.\r
+  @param[in, out] User     On entry, points to the previously returned user profile \r
+                           handle, or NULL to start searching with the first user profile.\r
+                           On return, points to the user profile handle, or NULL if not\r
+                           found.\r
+  @param[in, out] UserInfo On entry, points to the previously returned user information\r
+                           handle, or NULL to start searching with the first. On return, \r
+                           points to the user information handle of the user information\r
+                           record, or NULL if not found. Can be NULL, in which case only \r
+                           one user information record per user can be returned. \r
+  @param[in]      Info     Points to the buffer containing the user information to be \r
+                           compared to the user information record. If NULL, then only \r
+                           the user information record type is compared. If InfoSize is 0, \r
+                           then the user information record must be empty.\r
+\r
+  @param[in]      InfoSize The size of Info, in bytes. \r
+\r
+  @retval EFI_SUCCESS      User information was found. User points to the user profile handle,\r
+                           and UserInfo points to the user information handle.\r
+  @retval EFI_NOT_FOUND    User information was not found. User points to NULL and UserInfo \r
+                           points to NULL.\r
+  \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UserProfileFind (\r
+  IN     CONST EFI_USER_MANAGER_PROTOCOL        *This,\r
+  IN OUT EFI_USER_PROFILE_HANDLE                *User,\r
+  IN OUT EFI_USER_INFO_HANDLE                   *UserInfo OPTIONAL,\r
+  IN     CONST EFI_USER_INFO                    *Info,\r
+  IN     UINTN                                  InfoSize\r
+  );\r
+\r
+\r
+/**\r
+  This function returns user information.\r
+\r
+  @param  This                    Protocol EFI_USER_MANAGER_PROTOCOL instance\r
+                                  pointer.\r
+  @param  User                    Handle of the user whose profile will be\r
+                                  retrieved.\r
+  @param  UserInfo                Handle of the user information data record.\r
+  @param  Info                    On entry, points to a buffer of at least\r
+                                  *InfoSize bytes.  On exit, holds the user\r
+                                  information.\r
+  @param  InfoSize                On entry, points to the size of Info. On return,\r
+                                  points to the size of the user information.\r
+\r
+  @retval EFI_SUCCESS             Information returned successfully.\r
+  @retval EFI_ACCESS_DENIED       The information about the specified user cannot\r
+                                  be accessed  by the current user.\r
+                                  EFI_BUFFER_TOO_SMALL- The number of bytes\r
+                                  specified by *InfoSize is too small to hold the\r
+                                  returned data.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UserProfileGetInfo (\r
+  IN CONST  EFI_USER_MANAGER_PROTOCOL           *This,\r
+  IN        EFI_USER_PROFILE_HANDLE             User,\r
+  IN        EFI_USER_INFO_HANDLE                UserInfo,\r
+  OUT       EFI_USER_INFO                       *Info,\r
+  IN OUT    UINTN                               *InfoSize\r
+  );\r
+\r
+\r
+/**\r
+  This function changes user information.\r
+\r
+  @param  This                    Protocol EFI_USER_MANAGER_PROTOCOL instance\r
+                                  pointer.\r
+  @param  User                    Handle of the user whose profile will be\r
+                                  retrieved.\r
+  @param  UserInfo                Handle of the user information data record.\r
+  @param  Info                    Points to the user information.\r
+  @param  InfoSize                The size of Info, in bytes.\r
+\r
+  @retval EFI_SUCCESS             User profile information was successfully\r
+                                  changed/added.\r
+  @retval EFI_ACCESS_DENIED       The record is exclusive.\r
+  @retval EFI_SECURITY_VIOLATION  The current user does not have permission to\r
+                                  change  the specified user profile or user\r
+                                  information record.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UserProfileSetInfo (\r
+  IN CONST  EFI_USER_MANAGER_PROTOCOL           *This,\r
+  IN        EFI_USER_PROFILE_HANDLE             User,\r
+  IN OUT    EFI_USER_INFO_HANDLE                *UserInfo,\r
+  IN CONST  EFI_USER_INFO                       *Info,\r
+  IN        UINTN                               InfoSize\r
+  );\r
+\r
+\r
+/**\r
+  This function allows the credential provider to notify the User Identity Manager\r
+  when user status has changed while deselected.\r
+\r
+  @param  This                    Protocol EFI_USER_MANAGER_PROTOCOL instance\r
+                                  pointer.\r
+  @param  Changed                 Points to the instance of the\r
+                                  EFI_USER_CREDENTIAL_PROTOCOL  where the user has\r
+                                  changed.\r
+\r
+  @retval EFI_SUCCESS             The User Identity Manager has handled the\r
+                                  notification.\r
+  @retval EFI_NOT_READY           The function was called while the specified\r
+                                  credential  provider was not selected.\r
+  @retval EFI_UNSUPPORTED         The User Identity Manager doesn't support\r
+                                  asynchronous  notifications.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UserProfileNotify (\r
+  IN CONST  EFI_USER_MANAGER_PROTOCOL           *This,\r
+  IN        EFI_HANDLE                          Changed\r
+  );\r
+\r
+\r
+/**\r
+  Delete the user information attached to the user profile specified by the UserInfo.\r
+\r
+  @param  This                    Protocol EFI_USER_MANAGER_PROTOCOL instance pointer.\r
+  @param  User                    Handle of the user whose profile will be retrieved.\r
+  @param  UserInfo                Handle of the user information data record.\r
+\r
+  @retval EFI_SUCCESS             User information deleted successfully.\r
+  @retval EFI_ACCESS_DENIED       The current user does not have permission to\r
+                                  delete this user in-formation.\r
+  @retval EFI_NOT_FOUND           User information record UserInfo does not exist\r
+                                  in the user pro-file.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UserProfileDeleteInfo (\r
+  IN CONST  EFI_USER_MANAGER_PROTOCOL           *This,\r
+  IN        EFI_USER_PROFILE_HANDLE             User,\r
+  IN        EFI_USER_INFO_HANDLE                UserInfo\r
+  );\r
+\r
+\r
+/**\r
+  This function returns the next user information record.\r
+\r
+  @param  This                    Protocol EFI_USER_MANAGER_PROTOCOL instance pointer.\r
+  @param  User                    Handle of the user whose profile will be retrieved.\r
+  @param  UserInfo                Handle of the user information data record.\r
+\r
+  @retval EFI_SUCCESS             User information returned.\r
+  @retval EFI_NOT_FOUND           No more user information found.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UserProfileGetNextInfo (\r
+  IN CONST  EFI_USER_MANAGER_PROTOCOL           *This,\r
+  IN        EFI_USER_PROFILE_HANDLE             User,\r
+  IN OUT    EFI_USER_INFO_HANDLE                *UserInfo\r
+  );\r
+  \r
+#endif\r
diff --git a/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManagerData.h b/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManagerData.h
new file mode 100644 (file)
index 0000000..d91de10
--- /dev/null
@@ -0,0 +1,42 @@
+/** @file\r
+  Data structure used by the user identify manager driver.\r
+    \r
+Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _USER_IDENTIFY_MANAGER_DATA_H_\r
+#define _USER_IDENTIFY_MANAGER_DATA_H_\r
+\r
+#include "UserIdentifyManagerStrDefs.h"\r
+\r
+//\r
+// Guid used in user profile saving and in form browser.\r
+//\r
+#define USER_IDENTIFY_MANAGER_GUID \\r
+  { \\r
+    0x3ccd3dd8, 0x8d45, 0x4fed, { 0x96, 0x2d, 0x2b, 0x38, 0xcd, 0x82, 0xb3, 0xc4 } \\r
+  }\r
+\r
+//\r
+// Forms definition.\r
+//\r
+#define FORMID_USER_FORM      1\r
+#define FORMID_PROVIDER_FORM  2\r
+\r
+//\r
+// Labels definition.\r
+//\r
+#define LABEL_USER_NAME       0x1000\r
+#define LABEL_PROVIDER_NAME   0x3000\r
+#define LABEL_END             0xffff\r
+#define FORM_OPEN_QUESTION_ID 0xfffe\r
+\r
+#endif\r
diff --git a/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManagerDxe.inf b/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManagerDxe.inf
new file mode 100644 (file)
index 0000000..d5fccea
--- /dev/null
@@ -0,0 +1,62 @@
+## @file\r
+#  Component description file for user identify manager driver.\r
+# \r
+# Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = UserIdentifyManager\r
+  FILE_GUID                      = C5D3191B-27D5-4873-8DF2-628136991A21\r
+  MODULE_TYPE                    = DXE_DRIVER\r
+  VERSION_STRING                 = 1.0\r
+  ENTRY_POINT                    = UserIdentifyManagerInit\r
+\r
+[sources]\r
+  UserIdentifyManager.c\r
+  LoadDeferredImage.c\r
+  UserIdentifyManager.h\r
+  UserIdentifyManagerData.h\r
+  UserIdentifyManagerStrings.uni\r
+  UserIdentifyManagerVfr.Vfr\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+\r
+[LibraryClasses]\r
+  UefiRuntimeServicesTableLib\r
+  UefiBootServicesTableLib\r
+  UefiDriverEntryPoint\r
+  MemoryAllocationLib\r
+  BaseMemoryLib\r
+  DebugLib\r
+  HiiLib\r
+  UefiLib\r
+\r
+[Guids]\r
+  gEfiIfrTianoGuid                              ## CONSUMES ## Guid\r
+  gEfiEventUserProfileChangedGuid               ## CONSUMES ## Guid \r
+\r
+[Protocols]\r
+  gEfiFormBrowser2ProtocolGuid                  ## CONSUMES\r
+  gEfiHiiDatabaseProtocolGuid                   ## CONSUMES\r
+  gEfiUserCredentialProtocolGuid                ## CONSUMES\r
+  gEfiDeferredImageLoadProtocolGuid             ## CONSUMES\r
+  gEfiHiiConfigAccessProtocolGuid               ## PRODUCES\r
+  gEfiUserManagerProtocolGuid                   ## PRODUCES\r
+  gEfiSimpleTextOutProtocolGuid\r
+  gEfiSimpleTextInProtocolGuid\r
+  gEfiSimpleTextInputExProtocolGuid\r
+\r
+[Depex]\r
+  gEfiHiiDatabaseProtocolGuid   AND \r
+  gEfiHiiStringProtocolGuid     AND \r
+  gEfiFormBrowser2ProtocolGuid \r
diff --git a/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManagerStrings.uni b/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManagerStrings.uni
new file mode 100644 (file)
index 0000000..8ae4489
Binary files /dev/null and b/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManagerStrings.uni differ
diff --git a/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManagerVfr.Vfr b/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManagerVfr.Vfr
new file mode 100644 (file)
index 0000000..ebe8195
--- /dev/null
@@ -0,0 +1,44 @@
+/** @file\r
+  User identify manager formset.\r
+\r
+Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "UserIdentifyManagerData.h"\r
+\r
+formset \r
+  guid      = USER_IDENTIFY_MANAGER_GUID,\r
+  title     = STRING_TOKEN(STR_TITLE),  \r
+  help      = STRING_TOKEN(STR_NULL_STRING), \r
+  classguid = USER_IDENTIFY_MANAGER_GUID,\r
+  \r
+  form formid = FORMID_USER_FORM,\r
+    title = STRING_TOKEN(STR_USER_SELECT);      \r
+\r
+    suppressif TRUE;\r
+      text\r
+        help   = STRING_TOKEN(STR_NULL_STRING),\r
+        text   = STRING_TOKEN(STR_NULL_STRING),\r
+          text   = STRING_TOKEN(STR_NULL_STRING),\r
+        flags  = INTERACTIVE,\r
+        key    = FORM_OPEN_QUESTION_ID;\r
+    endif;\r
+\r
+    label LABEL_USER_NAME;\r
+    label LABEL_END;  \r
+  endform;\r
+  \r
+  form formid = FORMID_PROVIDER_FORM,\r
+    title = STRING_TOKEN(STR_PROVIDER_SELECT);\r
+    label LABEL_PROVIDER_NAME;\r
+    label LABEL_END;\r
+  endform;  \r
+endformset;
\ No newline at end of file
diff --git a/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileAdd.c b/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileAdd.c
new file mode 100644 (file)
index 0000000..eb96c8e
--- /dev/null
@@ -0,0 +1,372 @@
+/** @file\r
+  The functions to add a user profile.\r
+    \r
+Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "UserProfileManager.h"\r
+\r
+\r
+/**\r
+  Get user name from the popup windows.\r
+  \r
+  @param[in, out]  UserNameLen  On entry, point to UserName buffer lengh, in bytes.\r
+                                On exit, point to input user name length, in bytes.\r
+  @param[out]      UserName     The buffer to hold the input user name.\r
\r
+  @retval EFI_ABORTED           It is given up by pressing 'ESC' key.\r
+  @retval EFI_NOT_READY         Not a valid input at all.\r
+  @retval EFI_SUCCESS           Get a user name successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+GetUserNameInput (\r
+  IN OUT  UINTN         *UserNameLen,\r
+     OUT  CHAR16        *UserName\r
+  )\r
+{\r
+  EFI_INPUT_KEY Key;\r
+  UINTN         NameLen;\r
+  CHAR16        Name[USER_NAME_LENGTH];\r
+\r
+  NameLen = 0;\r
+  while (TRUE) {\r
+    Name[NameLen]     = L'_';\r
+    Name[NameLen + 1] = L'\0';\r
+    CreatePopUp (\r
+      EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+      &Key,\r
+      L"Input User Name",\r
+      L"---------------------",\r
+      Name,\r
+      NULL\r
+      );\r
+    //\r
+    // Check key.\r
+    //\r
+    if (Key.ScanCode == SCAN_NULL) {\r
+      if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {\r
+        //\r
+        // Add the null terminator.\r
+        //\r
+        Name[NameLen] = 0;\r
+        NameLen++;\r
+        break;\r
+      } else if ((Key.UnicodeChar == CHAR_NULL) ||\r
+                 (Key.UnicodeChar == CHAR_TAB) ||\r
+                 (Key.UnicodeChar == CHAR_LINEFEED)\r
+                 ) {\r
+        continue;\r
+      } else {\r
+        if (Key.UnicodeChar == CHAR_BACKSPACE) {\r
+          if (NameLen > 0) {\r
+            NameLen--;\r
+          }\r
+        } else {\r
+          Name[NameLen] = Key.UnicodeChar;\r
+          NameLen++;\r
+          if (NameLen + 1 == USER_NAME_LENGTH) {\r
+            //\r
+            // Add the null terminator.\r
+            //\r
+            Name[NameLen] = 0;\r
+            NameLen++;\r
+            break;\r
+          }\r
+        }\r
+      }\r
+    }\r
+\r
+    if (Key.ScanCode == SCAN_ESC) {\r
+      return EFI_ABORTED;\r
+    }\r
+  }\r
+\r
+  if (NameLen <= 1) {\r
+    return EFI_NOT_READY;\r
+  }\r
+\r
+  if (*UserNameLen < NameLen * sizeof (CHAR16)) {\r
+    return EFI_NOT_READY;\r
+  }\r
+\r
+  *UserNameLen = NameLen * sizeof (CHAR16);\r
+  CopyMem (UserName, Name, *UserNameLen);\r
+  \r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Set a user's username.\r
+\r
+  @param[in]   User          Handle of a user profile .\r
+  @param[in]   UserNameLen   The lengh of UserName.\r
+  @param[in]   UserName      Point to the buffer of user name.\r
+\r
+  @retval EFI_NOT_READY      The usernme in mAddUserName had been used.\r
+  @retval EFI_SUCCESS        Change the user's username successfully with \r
+                             username in mAddUserName.\r
+\r
+**/\r
+EFI_STATUS\r
+SetUserName (\r
+  IN  EFI_USER_PROFILE_HANDLE    User,\r
+  IN  UINTN                      UserNameLen,\r
+  IN  CHAR16                     *UserName\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  EFI_USER_INFO_HANDLE    UserInfo;\r
+  EFI_USER_PROFILE_HANDLE TempUser;\r
+  EFI_USER_INFO           *NewUserInfo;\r
+   \r
+  NewUserInfo = AllocateZeroPool (sizeof (EFI_USER_INFO) + UserNameLen);\r
+  ASSERT (NewUserInfo != NULL);\r
+\r
+  NewUserInfo->InfoType    = EFI_USER_INFO_NAME_RECORD;\r
+  NewUserInfo->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV | \r
+                             EFI_USER_INFO_PUBLIC | \r
+                             EFI_USER_INFO_EXCLUSIVE;\r
+  NewUserInfo->InfoSize    = (UINT32) (sizeof (EFI_USER_INFO) + UserNameLen);\r
+  CopyMem ((UINT8 *) (NewUserInfo + 1), UserName, UserNameLen);\r
+  TempUser  = NULL;\r
+  Status    = mUserManager->Find (\r
+                              mUserManager,\r
+                              &TempUser,\r
+                              NULL,\r
+                              NewUserInfo,\r
+                              NewUserInfo->InfoSize\r
+                              );\r
+  if (!EFI_ERROR (Status)) {\r
+    //\r
+    // The user name had been used, return error.\r
+    //\r
+    FreePool (NewUserInfo);\r
+    return EFI_NOT_READY;\r
+  }\r
+\r
+  UserInfo = NULL;\r
+  mUserManager->SetInfo (\r
+                  mUserManager,\r
+                  User,\r
+                  &UserInfo,\r
+                  NewUserInfo,\r
+                  NewUserInfo->InfoSize\r
+                  );\r
+  FreePool (NewUserInfo);\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Set create date of the specified user.\r
+\r
+  @param[in]  User               Handle of a user profile.\r
+\r
+**/\r
+VOID\r
+SetCreateDate (\r
+  IN        EFI_USER_PROFILE_HANDLE   User\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  EFI_USER_INFO_HANDLE      UserInfo;\r
+  EFI_USER_INFO_CREATE_DATE Date;\r
+  EFI_USER_INFO             *NewUserInfo;\r
+  \r
+  NewUserInfo = AllocateZeroPool (\r
+                  sizeof (EFI_USER_INFO) +\r
+                  sizeof (EFI_USER_INFO_CREATE_DATE)\r
+                  );\r
+  ASSERT (NewUserInfo != NULL);\r
+\r
+  NewUserInfo->InfoType    = EFI_USER_INFO_CREATE_DATE_RECORD;\r
+  NewUserInfo->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV | \r
+                             EFI_USER_INFO_PUBLIC | \r
+                             EFI_USER_INFO_EXCLUSIVE;\r
+  NewUserInfo->InfoSize    = sizeof (EFI_USER_INFO) + sizeof (EFI_USER_INFO_CREATE_DATE);\r
+  Status                   = gRT->GetTime (&Date, NULL);\r
+  if (EFI_ERROR (Status)) {\r
+    FreePool (NewUserInfo);\r
+    return ;\r
+  }\r
+\r
+  CopyMem ((UINT8 *) (NewUserInfo + 1), &Date, sizeof (EFI_USER_INFO_CREATE_DATE));\r
+  UserInfo = NULL;\r
+  mUserManager->SetInfo (\r
+                  mUserManager,\r
+                  User,\r
+                  &UserInfo,\r
+                  NewUserInfo,\r
+                  NewUserInfo->InfoSize\r
+                  );\r
+  FreePool (NewUserInfo);\r
+}\r
+\r
+\r
+/**\r
+  Set the default identity policy of the specified user.\r
+\r
+  @param[in]  User               Handle of a user profile. \r
+\r
+**/\r
+VOID\r
+SetIdentityPolicy (\r
+  IN        EFI_USER_PROFILE_HANDLE   User\r
+  )\r
+{\r
+  EFI_USER_INFO_IDENTITY_POLICY *Policy;\r
+  EFI_USER_INFO_HANDLE          UserInfo;\r
+  EFI_USER_INFO                 *NewUserInfo;\r
+  \r
+  NewUserInfo = AllocateZeroPool (\r
+                  sizeof (EFI_USER_INFO) + \r
+                  sizeof (EFI_USER_INFO_IDENTITY_POLICY)\r
+                  );\r
+  ASSERT (NewUserInfo != NULL);\r
+  \r
+  Policy                   = (EFI_USER_INFO_IDENTITY_POLICY *) (NewUserInfo + 1);\r
+  Policy->Type             = EFI_USER_INFO_IDENTITY_TRUE;\r
+  Policy->Length           = sizeof (EFI_USER_INFO_IDENTITY_POLICY);\r
+\r
+  NewUserInfo->InfoType    = EFI_USER_INFO_IDENTITY_POLICY_RECORD;\r
+  NewUserInfo->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV | \r
+                             EFI_USER_INFO_PRIVATE | \r
+                             EFI_USER_INFO_EXCLUSIVE;\r
+  NewUserInfo->InfoSize    = sizeof (EFI_USER_INFO) + Policy->Length;\r
+  UserInfo                 = NULL;\r
+  mUserManager->SetInfo (\r
+                  mUserManager,\r
+                  User,\r
+                  &UserInfo,\r
+                  NewUserInfo,\r
+                  NewUserInfo->InfoSize\r
+                  );\r
+  FreePool (NewUserInfo);\r
+}\r
+\r
+\r
+/**\r
+  Set the default access policy of the specified user.\r
+\r
+  @param[in]  User               Handle of a user profile. \r
+\r
+**/\r
+VOID\r
+SetAccessPolicy (\r
+  IN        EFI_USER_PROFILE_HANDLE   User\r
+  )\r
+{\r
+  EFI_USER_INFO_ACCESS_CONTROL  *Control;\r
+  EFI_USER_INFO_HANDLE          UserInfo;\r
+  EFI_USER_INFO                 *NewUserInfo;\r
+  \r
+  NewUserInfo = AllocateZeroPool (\r
+                  sizeof (EFI_USER_INFO) + \r
+                  sizeof (EFI_USER_INFO_ACCESS_CONTROL)\r
+                  );\r
+  ASSERT (NewUserInfo != NULL);\r
+  \r
+  Control                  = (EFI_USER_INFO_ACCESS_CONTROL *) (NewUserInfo + 1);\r
+  Control->Type            = EFI_USER_INFO_ACCESS_ENROLL_SELF;\r
+  Control->Size            = sizeof (EFI_USER_INFO_ACCESS_CONTROL);\r
+\r
+  NewUserInfo->InfoType    = EFI_USER_INFO_ACCESS_POLICY_RECORD;\r
+  NewUserInfo->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV | \r
+                             EFI_USER_INFO_PUBLIC | \r
+                             EFI_USER_INFO_EXCLUSIVE;\r
+  NewUserInfo->InfoSize    = sizeof (EFI_USER_INFO) + Control->Size;\r
+  UserInfo                 = NULL;\r
+  mUserManager->SetInfo (\r
+                  mUserManager,\r
+                  User,\r
+                  &UserInfo,\r
+                  NewUserInfo,\r
+                  NewUserInfo->InfoSize\r
+                  );\r
+  FreePool (NewUserInfo);\r
+}\r
+\r
+\r
+/**\r
+  Add a new user profile into the user profile database.\r
+\r
+**/\r
+VOID\r
+CallAddUser (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  EFI_INPUT_KEY           Key;\r
+  EFI_USER_PROFILE_HANDLE User;\r
+  UINTN                   UserNameLen;\r
+  CHAR16                  UserName[USER_NAME_LENGTH];\r
+  CHAR16                  *QuestionStr;\r
+  CHAR16                  *PromptStr;\r
+\r
+  QuestionStr = NULL;\r
+  PromptStr   = NULL;\r
+  \r
+  //\r
+  // Get user name to add.\r
+  //\r
+  UserNameLen = sizeof (UserName);\r
+  Status = GetUserNameInput (&UserNameLen, UserName);\r
+  if (EFI_ERROR (Status)) {\r
+    if (Status != EFI_ABORTED) {\r
+      QuestionStr = GetStringById (STRING_TOKEN (STR_GET_USERNAME_FAILED));\r
+      PromptStr   = GetStringById (STRING_TOKEN (STR_STROKE_KEY_CONTINUE)); \r
+      goto Done;\r
+    }\r
+    return ;\r
+  }\r
+\r
+  //\r
+  // Create a new user profile.\r
+  //\r
+  User    = NULL;\r
+  Status  = mUserManager->Create (mUserManager, &User);\r
+  if (EFI_ERROR (Status)) {\r
+    QuestionStr = GetStringById (STRING_TOKEN (STR_CREATE_PROFILE_FAILED));\r
+    PromptStr   = GetStringById (STRING_TOKEN (STR_STROKE_KEY_CONTINUE)); \r
+  } else {\r
+    //\r
+    // Add default user information.\r
+    //\r
+    Status = SetUserName (User, UserNameLen, UserName);\r
+    if (EFI_ERROR (Status)) {\r
+      QuestionStr = GetStringById (STRING_TOKEN (STR_USER_ALREADY_EXISTED));\r
+      PromptStr   = GetStringById (STRING_TOKEN (STR_STROKE_KEY_CONTINUE)); \r
+      goto Done;\r
+    }\r
+\r
+    SetCreateDate (User);\r
+    SetIdentityPolicy (User);\r
+    SetAccessPolicy (User);\r
+\r
+    QuestionStr = GetStringById (STRING_TOKEN (STR_CREATE_PROFILE_SUCCESS));\r
+    PromptStr   = GetStringById (STRING_TOKEN (STR_STROKE_KEY_CONTINUE)); \r
+  }\r
+\r
+Done:\r
+  CreatePopUp (\r
+    EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+    &Key,\r
+    QuestionStr,\r
+    L"",\r
+    PromptStr,\r
+    NULL\r
+    );\r
+  FreePool (QuestionStr);\r
+  FreePool (PromptStr);\r
+}\r
+\r
diff --git a/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileDelete.c b/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileDelete.c
new file mode 100644 (file)
index 0000000..d0295b7
--- /dev/null
@@ -0,0 +1,314 @@
+/** @file\r
+  The functions to delete a user profile.\r
+    \r
+Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "UserProfileManager.h"\r
+\r
+/**\r
+  Get the username from the specified user.\r
+\r
+  @param[in]   User              Handle of a user profile. \r
+\r
+  @retval EFI_STRING_ID          The String Id of the user's username.\r
+\r
+**/\r
+EFI_STRING_ID \r
+GetUserName (\r
+  IN  EFI_USER_PROFILE_HANDLE                   User\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  EFI_USER_INFO_HANDLE  UserInfo;\r
+  EFI_USER_INFO         *Info;\r
+  UINTN                 InfoSize;\r
+  UINTN                 MemSize;\r
+  UINTN                 NameLen;\r
+  CHAR16                UserName[USER_NAME_LENGTH];\r
+  EFI_STRING_ID         UserId;\r
+  \r
+  //\r
+  // Allocate user information memory.\r
+  //\r
+  MemSize = sizeof (EFI_USER_INFO) + 63;\r
+  Info    = AllocateZeroPool (MemSize);\r
+  ASSERT (Info != NULL);\r
+  \r
+  //\r
+  // Get user name information.\r
+  //\r
+  UserInfo = NULL;\r
+  while (TRUE) {\r
+    InfoSize = MemSize;\r
+    //\r
+    // Get next user information.\r
+    //\r
+    Status = mUserManager->GetNextInfo (\r
+                             mUserManager,\r
+                             User,\r
+                             &UserInfo\r
+                             );\r
+    if (EFI_ERROR (Status)) {\r
+      break;\r
+    }\r
+\r
+    Status = mUserManager->GetInfo (\r
+                             mUserManager,\r
+                             User,\r
+                             UserInfo,\r
+                             Info,\r
+                             &InfoSize\r
+                             );\r
+    if (Status == EFI_BUFFER_TOO_SMALL) {\r
+      MemSize = InfoSize;\r
+      FreePool (Info);\r
+      Info = AllocateZeroPool (MemSize);\r
+      ASSERT (Info != NULL);\r
+\r
+      Status = mUserManager->GetInfo (\r
+                               mUserManager,\r
+                               User,\r
+                               UserInfo,\r
+                               Info,\r
+                               &InfoSize\r
+                               );\r
+    }\r
+    //\r
+    // Check user information.\r
+    //\r
+    if (Status == EFI_SUCCESS) {\r
+      if (Info->InfoType == EFI_USER_INFO_NAME_RECORD) {\r
+        NameLen = Info->InfoSize - sizeof (EFI_USER_INFO);\r
+        if (NameLen > USER_NAME_LENGTH * sizeof (CHAR16)) {\r
+          NameLen = USER_NAME_LENGTH * sizeof (CHAR16);\r
+        }\r
+        ASSERT (NameLen >= sizeof (CHAR16));\r
+        CopyMem (UserName, (UINT8 *) (Info + 1), NameLen);\r
+        UserName[NameLen / sizeof (CHAR16) - 1] = 0;\r
+        UserId = HiiSetString (\r
+                   mCallbackInfo->HiiHandle,\r
+                   0,\r
+                   UserName,\r
+                   NULL\r
+                   );\r
+        if (UserId != 0) {\r
+          FreePool (Info);\r
+          return UserId;\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
+  FreePool (Info);\r
+  return 0;\r
+}\r
+\r
+\r
+/**\r
+  Add a username item in form.\r
+\r
+  @param[in]  User          Points to the user profile whose username is added. \r
+  @param[in]  Index         The index of the user in the user name list\r
+  @param[in]  OpCodeHandle  Points to container for dynamic created opcodes.\r
+\r
+**/\r
+VOID\r
+AddUserToForm (\r
+  IN  EFI_USER_PROFILE_HANDLE                   User,\r
+  IN  UINT16                                    Index,\r
+  IN  VOID                                      *OpCodeHandle\r
+  )\r
+{\r
+  EFI_STRING_ID NameId;\r
+\r
+  //\r
+  // Get user name\r
+  //\r
+  NameId = GetUserName (User);\r
+  if (NameId == 0) {\r
+    return ;\r
+  }\r
+  \r
+  //\r
+  // Create user name option.\r
+  //\r
+  switch (Index & KEY_FIRST_FORM_MASK) {\r
+  case KEY_MODIFY_USER:\r
+    HiiCreateGotoOpCode (\r
+      OpCodeHandle,                   // Container for dynamic created opcodes\r
+      FORMID_USER_INFO,               // Target Form ID\r
+      NameId,                         // Prompt text\r
+      STRING_TOKEN (STR_NULL_STRING), // Help text\r
+      EFI_IFR_FLAG_CALLBACK,          // Question flag\r
+      Index                           // Question ID\r
+      );\r
+    break;\r
+\r
+  case KEY_DEL_USER:\r
+    HiiCreateActionOpCode (\r
+      OpCodeHandle,                   // Container for dynamic created opcodes\r
+      Index,                          // Question ID\r
+      NameId,                         // Prompt text\r
+      STRING_TOKEN (STR_NULL_STRING), // Help text\r
+      EFI_IFR_FLAG_CALLBACK,          // Question flag\r
+      0                               // Action String ID\r
+      );\r
+    break;\r
+\r
+  default:\r
+    break;\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Delete the user specified by UserIndex in user profile database.\r
+\r
+  @param[in]  UserIndex       The index of user in the user name list \r
+                              to be deleted.\r
+\r
+**/\r
+VOID\r
+DeleteUser (\r
+  IN UINT8                                      UserIndex\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  EFI_USER_PROFILE_HANDLE User;\r
+  EFI_INPUT_KEY           Key;\r
+\r
+  //\r
+  // Find specified user profile and delete it.\r
+  //\r
+  User    = NULL;\r
+  Status  = mUserManager->GetNext (mUserManager, &User);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+  \r
+  while (UserIndex > 1) {\r
+    Status = mUserManager->GetNext (mUserManager, &User);\r
+    if (EFI_ERROR (Status)) {\r
+      goto Done;\r
+    }\r
+    UserIndex--;\r
+  }\r
+\r
+  if (UserIndex == 1) {\r
+    Status = mUserManager->Delete (mUserManager, User);\r
+    if (EFI_ERROR (Status)) {\r
+      goto Done;\r
+    }\r
+    CreatePopUp (\r
+      EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+      &Key,\r
+      L"Delete User Succeed!",\r
+      L"",\r
+      L"Please Press Any Key to Continue ...",\r
+      NULL\r
+      );\r
+    return ;  \r
+  }\r
+\r
+Done:\r
+  CreatePopUp (\r
+    EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+    &Key,\r
+    L"Delete User Failed!",\r
+    L"",\r
+    L"Please Press Any Key to Continue ...",\r
+    NULL\r
+    );\r
+}\r
+\r
+\r
+/**\r
+  Display user select form, cab select a user to delete.\r
+\r
+**/\r
+VOID\r
+SelectUserToDelete (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  UINT8                   Index;\r
+  EFI_USER_PROFILE_HANDLE User;\r
+  EFI_USER_PROFILE_HANDLE CurrentUser;\r
+  VOID                    *StartOpCodeHandle;\r
+  VOID                    *EndOpCodeHandle;\r
+  EFI_IFR_GUID_LABEL      *StartLabel;\r
+  EFI_IFR_GUID_LABEL      *EndLabel;\r
+\r
+  //\r
+  // Initialize the container for dynamic opcodes.\r
+  //\r
+  StartOpCodeHandle = HiiAllocateOpCodeHandle ();\r
+  ASSERT (StartOpCodeHandle != NULL);\r
+\r
+  EndOpCodeHandle = HiiAllocateOpCodeHandle ();\r
+  ASSERT (EndOpCodeHandle != NULL);\r
+\r
+  //\r
+  // Create Hii Extend Label OpCode.\r
+  //\r
+  StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (\r
+                                        StartOpCodeHandle,\r
+                                        &gEfiIfrTianoGuid,\r
+                                        NULL,\r
+                                        sizeof (EFI_IFR_GUID_LABEL)\r
+                                        );\r
+  StartLabel->ExtendOpCode  = EFI_IFR_EXTEND_OP_LABEL;\r
+  StartLabel->Number        = LABEL_USER_DEL_FUNC;\r
+\r
+  EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (\r
+                                      EndOpCodeHandle,\r
+                                      &gEfiIfrTianoGuid,\r
+                                      NULL,\r
+                                      sizeof (EFI_IFR_GUID_LABEL)\r
+                                      );\r
+  EndLabel->ExtendOpCode  = EFI_IFR_EXTEND_OP_LABEL;\r
+  EndLabel->Number        = LABEL_END;\r
+\r
+  //\r
+  // Add each user can be deleted.\r
+  //\r
+  User  = NULL;\r
+  Index = 1;\r
+  mUserManager->Current (mUserManager, &CurrentUser);\r
+  while (TRUE) {\r
+    Status = mUserManager->GetNext (mUserManager, &User);\r
+    if (EFI_ERROR (Status)) {\r
+      break;\r
+    }\r
+\r
+    if (User != CurrentUser) {\r
+      AddUserToForm (\r
+        User,\r
+        (UINT16)(KEY_DEL_USER | KEY_SELECT_USER | Index),\r
+        StartOpCodeHandle\r
+        );\r
+    }\r
+    Index++;\r
+  }\r
+\r
+  HiiUpdateForm (\r
+    mCallbackInfo->HiiHandle, // HII handle\r
+    &mUserProfileManagerGuid, // Formset GUID\r
+    FORMID_DEL_USER,          // Form ID\r
+    StartOpCodeHandle,        // Label for where to insert opcodes\r
+    EndOpCodeHandle           // Replace data\r
+    );\r
+\r
+  HiiFreeOpCodeHandle (StartOpCodeHandle);\r
+  HiiFreeOpCodeHandle (EndOpCodeHandle);\r
+}\r
diff --git a/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManager.c b/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManager.c
new file mode 100644 (file)
index 0000000..74c979d
--- /dev/null
@@ -0,0 +1,806 @@
+/** @file\r
+  This driver is a configuration tool for adding, deleting or modifying user \r
+  profiles, including gathering the necessary information to ascertain their \r
+  identity in the future, updating user access policy and identification \r
+  policy, etc.\r
+\r
+Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "UserProfileManager.h"\r
+\r
+EFI_GUID                  mUserProfileManagerGuid = USER_PROFILE_MANAGER_GUID;\r
+EFI_USER_MANAGER_PROTOCOL *mUserManager           = NULL;\r
+CREDENTIAL_PROVIDER_INFO  *mProviderInfo          = NULL;\r
+UINT8                     mProviderChoice;\r
+UINT8                     mConncetLogical;\r
+USER_INFO_ACCESS          mAccessInfo;\r
+USER_INFO                 mUserInfo;\r
+USER_PROFILE_MANAGER_CALLBACK_INFO  *mCallbackInfo;\r
+HII_VENDOR_DEVICE_PATH  mHiiVendorDevicePath = {\r
+  {\r
+    {\r
+      HARDWARE_DEVICE_PATH,\r
+      HW_VENDOR_DP,\r
+      {\r
+        (UINT8) (sizeof (VENDOR_DEVICE_PATH)),\r
+        (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)\r
+      }\r
+    },\r
+    {0xad2e3474, 0x93e6, 0x488b, {0x93, 0x19, 0x64, 0x88, 0xfc, 0x68, 0x1f, 0x16}}\r
+  },\r
+  {\r
+    END_DEVICE_PATH_TYPE,\r
+    END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
+    {\r
+      (UINT8) (END_DEVICE_PATH_LENGTH),\r
+      (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)\r
+    }\r
+  }\r
+};\r
+\r
+\r
+/**\r
+  Get string by string id from HII Interface.\r
+\r
+\r
+  @param[in] Id      String ID to get the string from.\r
+\r
+  @retval  CHAR16 *  String from ID.\r
+  @retval  NULL      If error occurs.\r
+\r
+**/\r
+CHAR16 *\r
+GetStringById (\r
+  IN EFI_STRING_ID             Id\r
+  )\r
+{\r
+  //\r
+  // Get the current string for the current Language.\r
+  //\r
+  return HiiGetString (mCallbackInfo->HiiHandle, Id, NULL);\r
+}\r
+\r
+\r
+/**\r
+  This function gets all the credential providers in the system and saved them \r
+  to mProviderInfo.\r
+\r
+  @retval EFI_SUCESS     Init credential provider database successfully.\r
+  @retval Others         Fail to init credential provider database.\r
+  \r
+**/\r
+EFI_STATUS\r
+InitProviderInfo (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  UINTN       HandleCount;\r
+  EFI_HANDLE  *HandleBuf;\r
+  UINTN       Index;  \r
+  \r
+  //\r
+  // Try to find all the user credential provider driver.\r
+  //\r
+  HandleCount = 0;\r
+  HandleBuf   = NULL;\r
+  Status = gBS->LocateHandleBuffer (\r
+                  ByProtocol,\r
+                  &gEfiUserCredentialProtocolGuid,\r
+                  NULL,\r
+                  &HandleCount,\r
+                  &HandleBuf\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  \r
+  //\r
+  // Get provider infomation.\r
+  //\r
+  if (mProviderInfo != NULL) {\r
+    FreePool (mProviderInfo);\r
+  }\r
+  mProviderInfo = AllocateZeroPool (\r
+                    sizeof (CREDENTIAL_PROVIDER_INFO) - \r
+                    sizeof (EFI_USER_CREDENTIAL_PROTOCOL *) +\r
+                    HandleCount * sizeof (EFI_USER_CREDENTIAL_PROTOCOL *)\r
+                    );\r
+  if (mProviderInfo == NULL) {\r
+    FreePool (HandleBuf);\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  mProviderInfo->Count = HandleCount;\r
+  for (Index = 0; Index < HandleCount; Index++) {\r
+    Status = gBS->HandleProtocol (\r
+                    HandleBuf[Index],\r
+                    &gEfiUserCredentialProtocolGuid,\r
+                    (VOID **) &mProviderInfo->Provider[Index]\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      FreePool (HandleBuf);\r
+      FreePool (mProviderInfo);\r
+      mProviderInfo = NULL;\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  FreePool (HandleBuf);\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  This function processes changes in user profile configuration.\r
+\r
+  @param  This                   Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
+  @param  Action                 Specifies the type of action taken by the browser.\r
+  @param  QuestionId             A unique value which is sent to the original\r
+                                 exporting driver so that it can identify the type\r
+                                 of data to expect.\r
+  @param  Type                   The type of value for the question.\r
+  @param  Value                  A pointer to the data being sent to the original\r
+                                 exporting driver.\r
+  @param  ActionRequest          On return, points to the action requested by the\r
+                                 callback function.\r
+\r
+  @retval EFI_SUCCESS            The callback successfully handled the action.\r
+  @retval Others                 Fail to handle the action.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UserProfileManagerCallback (\r
+  IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL      *This,\r
+  IN  EFI_BROWSER_ACTION                        Action,\r
+  IN  EFI_QUESTION_ID                           QuestionId,\r
+  IN  UINT8                                     Type,\r
+  IN  EFI_IFR_TYPE_VALUE                        *Value,\r
+  OUT EFI_BROWSER_ACTION_REQUEST                *ActionRequest\r
+  )\r
+{\r
+  EFI_STATUS               Status;\r
+  EFI_INPUT_KEY            Key;\r
+  UINT32                   CurrentAccessRight;\r
+  CHAR16                   *QuestionStr;\r
+  CHAR16                   *PromptStr;\r
+  VOID                     *StartOpCodeHandle;\r
+  VOID                     *EndOpCodeHandle;\r
+  EFI_IFR_GUID_LABEL       *StartLabel;\r
+  EFI_IFR_GUID_LABEL       *EndLabel;\r
+  EFI_USER_PROFILE_HANDLE  CurrentUser;\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+  switch (Action) {\r
+  case EFI_BROWSER_ACTION_FORM_OPEN:\r
+    {\r
+      //\r
+      // Update user manage Form when user manage Form is opened.\r
+      // This will be done only in FORM_OPEN CallBack of question with QUESTIONID_USER_MANAGE from user manage Form.\r
+      //\r
+      if (QuestionId != QUESTIONID_USER_MANAGE) {\r
+        return EFI_SUCCESS;\r
+      }\r
+  \r
+      //\r
+      // Get current user\r
+      //\r
+      CurrentUser = NULL;\r
+      mUserManager->Current (mUserManager, &CurrentUser);\r
+      if (CurrentUser == NULL) {\r
+        DEBUG ((DEBUG_ERROR, "Error: current user does not exist!\n"));\r
+        return EFI_NOT_READY;\r
+      }\r
+      \r
+      //\r
+      // Get current user's right information.\r
+      //\r
+      Status = GetAccessRight (&CurrentAccessRight);\r
+      if (EFI_ERROR (Status)) {\r
+        CurrentAccessRight = EFI_USER_INFO_ACCESS_ENROLL_SELF;\r
+      }\r
+  \r
+      //\r
+      // Init credential provider information.\r
+      //\r
+      Status = InitProviderInfo ();\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+      \r
+      //\r
+      // Initialize the container for dynamic opcodes.\r
+      //\r
+      StartOpCodeHandle = HiiAllocateOpCodeHandle ();\r
+      ASSERT (StartOpCodeHandle != NULL);\r
+  \r
+      EndOpCodeHandle = HiiAllocateOpCodeHandle ();\r
+      ASSERT (EndOpCodeHandle != NULL);\r
+  \r
+      //\r
+      // Create Hii Extend Label OpCode.\r
+      //\r
+      StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (\r
+                                            StartOpCodeHandle,\r
+                                            &gEfiIfrTianoGuid,\r
+                                            NULL,\r
+                                            sizeof (EFI_IFR_GUID_LABEL)\r
+                                            );\r
+      StartLabel->ExtendOpCode  = EFI_IFR_EXTEND_OP_LABEL;\r
+      StartLabel->Number        = LABEL_USER_MANAGE_FUNC;\r
+  \r
+      EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (\r
+                                          EndOpCodeHandle,\r
+                                          &gEfiIfrTianoGuid,\r
+                                          NULL,\r
+                                          sizeof (EFI_IFR_GUID_LABEL)\r
+                                          );\r
+      EndLabel->ExtendOpCode  = EFI_IFR_EXTEND_OP_LABEL;\r
+      EndLabel->Number        = LABEL_END;\r
+  \r
+      //\r
+      // Add user profile option.\r
+      //\r
+      if ((CurrentAccessRight == EFI_USER_INFO_ACCESS_MANAGE) ||\r
+          (CurrentAccessRight == EFI_USER_INFO_ACCESS_ENROLL_OTHERS)\r
+          ) {\r
+        HiiCreateActionOpCode (\r
+          StartOpCodeHandle,                  // Container for dynamic created opcodes\r
+          KEY_ADD_USER,                       // Question ID\r
+          STRING_TOKEN (STR_ADD_USER_TITLE),  // Prompt text\r
+          STRING_TOKEN (STR_ADD_USER_HELP),   // Help text\r
+          EFI_IFR_FLAG_CALLBACK,              // Question flag\r
+          0                                   // Action String ID\r
+          );\r
+      }\r
+      \r
+      //\r
+      // Add modify user profile option.\r
+      //\r
+      HiiCreateGotoOpCode (\r
+        StartOpCodeHandle,                    // Container for dynamic created opcodes\r
+        FORMID_MODIFY_USER,                   // Target Form ID\r
+        STRING_TOKEN (STR_MODIFY_USER_TITLE), // Prompt text\r
+        STRING_TOKEN (STR_MODIFY_USER_HELP),  // Help text\r
+        EFI_IFR_FLAG_CALLBACK,                // Question flag\r
+        KEY_MODIFY_USER                       // Question ID\r
+        );\r
+  \r
+      //\r
+      // Add delete user profile option\r
+      //\r
+      if (CurrentAccessRight == EFI_USER_INFO_ACCESS_MANAGE) {\r
+        HiiCreateGotoOpCode (\r
+          StartOpCodeHandle,                    // Container for dynamic created opcodes\r
+          FORMID_DEL_USER,                      // Target Form ID\r
+          STRING_TOKEN (STR_DELETE_USER_TITLE), // Prompt text\r
+          STRING_TOKEN (STR_DELETE_USER_HELP),  // Help text\r
+          EFI_IFR_FLAG_CALLBACK,                // Question flag\r
+          KEY_DEL_USER                          // Question ID\r
+          );\r
+      }\r
+  \r
+      HiiUpdateForm (\r
+        mCallbackInfo->HiiHandle,               // HII handle\r
+        &mUserProfileManagerGuid,               // Formset GUID\r
+        FORMID_USER_MANAGE,                     // Form ID\r
+        StartOpCodeHandle,                      // Label for where to insert opcodes\r
+        EndOpCodeHandle                         // Replace data\r
+        );\r
+  \r
+      HiiFreeOpCodeHandle (StartOpCodeHandle);\r
+      HiiFreeOpCodeHandle (EndOpCodeHandle);\r
+  \r
+      return EFI_SUCCESS;\r
+    }\r
+    break;\r
+\r
+  case EFI_BROWSER_ACTION_FORM_CLOSE:\r
+    Status = EFI_SUCCESS;\r
+    break;\r
+\r
+  case EFI_BROWSER_ACTION_CHANGING:\r
+  {  \r
+    //\r
+    // Handle the request from form.\r
+    //\r
+    if ((Value == NULL) || (ActionRequest == NULL)) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+    \r
+    //\r
+    // Judge first 2 bits.\r
+    //\r
+    switch (QuestionId & KEY_FIRST_FORM_MASK) {\r
+    //\r
+    // Add user profile operation.\r
+    //\r
+    case KEY_ADD_USER:\r
+      CallAddUser ();\r
+      break;\r
+\r
+    //\r
+    // Delete user profile operation.\r
+    //\r
+    case KEY_DEL_USER:\r
+      //\r
+      // Judge next 2 bits.\r
+      //\r
+      switch (QuestionId & KEY_SECOND_FORM_MASK) {\r
+      //\r
+      // Enter delete user profile form.\r
+      //\r
+      case KEY_ENTER_NEXT_FORM:\r
+        SelectUserToDelete ();\r
+        break;\r
+\r
+      //\r
+      // Delete specified user profile.\r
+      //\r
+      case KEY_SELECT_USER:\r
+        DeleteUser ((UINT8) QuestionId);\r
+        //\r
+        // Update select user form after delete a user.\r
+        //\r
+        SelectUserToDelete ();\r
+        break;\r
+\r
+      default:\r
+        break;\r
+      }\r
+      break;\r
+\r
+    //\r
+    // Modify user profile operation.\r
+    //\r
+    case KEY_MODIFY_USER:\r
+      //\r
+      // Judge next 2 bits.\r
+      //\r
+      switch (QuestionId & KEY_SECOND_FORM_MASK) {\r
+      //\r
+      // Enter modify user profile form.\r
+      //\r
+      case KEY_ENTER_NEXT_FORM:\r
+        SelectUserToModify ();\r
+        break;\r
+\r
+      //\r
+      // Enter user profile information form.\r
+      //\r
+      case KEY_SELECT_USER:\r
+        //\r
+        // Judge next 3 bits.\r
+        //\r
+        switch (QuestionId & KEY_MODIFY_INFO_MASK) {\r
+        //\r
+        // Display user information form.\r
+        //\r
+        case KEY_ENTER_NEXT_FORM:\r
+          ModifyUserInfo ((UINT8) QuestionId);\r
+          break;\r
+\r
+        //\r
+        // Modify user name.\r
+        //\r
+        case KEY_MODIFY_NAME:\r
+          ModifyUserName ();\r
+          //\r
+          // Update username in parent form.\r
+          //\r
+          SelectUserToModify ();\r
+          break;\r
+\r
+        //\r
+        // Modify identity policy.\r
+        //\r
+        case KEY_MODIFY_IP:\r
+          //\r
+          // Judge next 3 bits\r
+          //\r
+          switch (QuestionId & KEY_MODIFY_IP_MASK) {\r
+          //\r
+          // Display identity policy modify form.\r
+          //\r
+          case KEY_ENTER_NEXT_FORM:\r
+            ModifyIdentityPolicy ();\r
+            break;\r
+\r
+          //\r
+          // Change credential provider option.\r
+          //\r
+          case KEY_MODIFY_PROV:         \r
+            mProviderChoice = Value->u8;\r
+            *ActionRequest  = EFI_BROWSER_ACTION_REQUEST_SUBMIT;\r
+            break;\r
+\r
+          //\r
+          // Change logical connector.\r
+          //\r
+          case KEY_MODIFY_CONN:\r
+            mConncetLogical = Value->u8;\r
+            *ActionRequest  = EFI_BROWSER_ACTION_REQUEST_SUBMIT;\r
+            break;\r
+\r
+          //\r
+          // Save option.\r
+          //\r
+          case KEY_ADD_IP_OP:\r
+            AddIdentityPolicyItem ();\r
+            break;\r
+\r
+          //\r
+          // Return to user profile information form.\r
+          //\r
+          case KEY_IP_RETURN_UIF:\r
+            SaveIdentityPolicy ();\r
+            *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT;\r
+            break;\r
+\r
+          default:\r
+            break;\r
+          }\r
+          break;\r
+\r
+        //\r
+        // Modify access policy.\r
+        //\r
+        case KEY_MODIFY_AP:\r
+          //\r
+          // Judge next 3 bits.\r
+          //\r
+          switch (QuestionId & KEY_MODIFY_AP_MASK) {\r
+          //\r
+          // Display access policy modify form.\r
+          //\r
+          case KEY_ENTER_NEXT_FORM:\r
+            ModidyAccessPolicy ();\r
+            break;\r
+\r
+          //\r
+          // Change access right choice.\r
+          //\r
+          case KEY_MODIFY_RIGHT:\r
+            mAccessInfo.AccessRight = Value->u8;\r
+            *ActionRequest  = EFI_BROWSER_ACTION_REQUEST_SUBMIT;\r
+            break;\r
+\r
+          //\r
+          // Change setup choice.\r
+          //\r
+          case KEY_MODIFY_SETUP:\r
+            mAccessInfo.AccessSetup= Value->u8;\r
+            *ActionRequest  = EFI_BROWSER_ACTION_REQUEST_SUBMIT;\r
+            break;\r
+\r
+          //\r
+          // Change boot order choice.\r
+          //\r
+          case KEY_MODIFY_BOOT:\r
+            mAccessInfo.AccessBootOrder = Value->u32;\r
+            *ActionRequest  = EFI_BROWSER_ACTION_REQUEST_SUBMIT;\r
+            break;\r
+\r
+          //\r
+          // Load device path form.\r
+          //\r
+          case KEY_MODIFY_LOAD:\r
+            //\r
+            // Judge next 2 bits.\r
+            //\r
+            switch (QuestionId & KEY_DISPLAY_DP_MASK) {\r
+            //\r
+            // Permit load device path.\r
+            //\r
+            case KEY_PERMIT_MODIFY:\r
+              DisplayLoadPermit ();\r
+              break;\r
+\r
+            //\r
+            // Forbid load device path.\r
+            //\r
+            case KEY_FORBID_MODIFY:\r
+              DisplayLoadForbid ();\r
+              break;\r
+\r
+            default:\r
+              break;\r
+            }\r
+            break;\r
+\r
+          //\r
+          // Connect device path form.\r
+          //\r
+          case KEY_MODIFY_CONNECT:\r
+            //\r
+            // Judge next 2 bits.\r
+            //\r
+            switch (QuestionId & KEY_DISPLAY_DP_MASK) {\r
+            //\r
+            // Permit connect device path.\r
+            //\r
+            case KEY_PERMIT_MODIFY:\r
+              DisplayConnectPermit ();\r
+              break;\r
+\r
+            //\r
+            // Forbid connect device path.\r
+            //\r
+            case KEY_FORBID_MODIFY:\r
+              DisplayConnectForbid ();\r
+              break;\r
+\r
+            default:\r
+              break;\r
+            }\r
+            break;\r
+\r
+          //\r
+          // Return to user profile information form.\r
+          //\r
+          case KEY_AP_RETURN_UIF:\r
+            SaveAccessPolicy ();\r
+            *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT;\r
+            break;\r
+\r
+          default:\r
+            break;\r
+          }\r
+          break;\r
+\r
+        default:\r
+          break;\r
+        }\r
+        break;\r
+\r
+      //\r
+      // Access policy device path modified.\r
+      //\r
+      case KEY_MODIFY_AP_DP:\r
+        //\r
+        // Judge next 2 bits.\r
+        //\r
+        switch (QuestionId & KEY_MODIFY_DP_MASK) {\r
+        //\r
+        // Load permit device path modified.\r
+        //\r
+        case KEY_LOAD_PERMIT_MODIFY:\r
+          QuestionStr = GetStringById (STRING_TOKEN (STR_MOVE_TO_FORBID_LIST));\r
+          PromptStr   = GetStringById (STRING_TOKEN (STR_PRESS_KEY_CONTINUE));\r
+          CreatePopUp (\r
+            EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+            &Key,\r
+            QuestionStr,\r
+            L"",\r
+            PromptStr,\r
+            NULL\r
+            );\r
+          FreePool (QuestionStr);\r
+          FreePool (PromptStr);\r
+          if (Key.UnicodeChar != CHAR_CARRIAGE_RETURN) {\r
+            break;\r
+          }\r
+\r
+          AddToForbidLoad ((UINT16)(QuestionId & (KEY_MODIFY_DP_MASK - 1)));\r
+          DisplayLoadPermit ();\r
+          break;\r
+\r
+        //\r
+        // Load forbid device path modified.\r
+        //\r
+        case KEY_LOAD_FORBID_MODIFY:\r
+          QuestionStr = GetStringById (STRING_TOKEN (STR_MOVE_TO_PERMIT_LIST));\r
+          PromptStr   = GetStringById (STRING_TOKEN (STR_PRESS_KEY_CONTINUE));\r
+          CreatePopUp (\r
+            EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+            &Key,\r
+            QuestionStr,\r
+            L"",\r
+            PromptStr,\r
+            NULL\r
+            );\r
+          FreePool (QuestionStr);\r
+          FreePool (PromptStr);\r
+          if (Key.UnicodeChar != CHAR_CARRIAGE_RETURN) {\r
+            break;\r
+          }\r
+\r
+          DeleteFromForbidLoad ((UINT16)(QuestionId & (KEY_MODIFY_DP_MASK - 1)));\r
+          DisplayLoadForbid ();\r
+          break;\r
+\r
+        //\r
+        // Connect permit device path modified.\r
+        //\r
+        case KEY_CONNECT_PERMIT_MODIFY:\r
+          break;\r
+\r
+        //\r
+        // Connect forbid device path modified.\r
+        //\r
+        case KEY_CONNECT_FORBID_MODIFY:\r
+          break;\r
+\r
+        default:\r
+          break;\r
+        }\r
+        break;\r
+\r
+      default:\r
+        break;\r
+      }\r
+      break;\r
+\r
+    default:\r
+      break;\r
+    }\r
+  }\r
+  break;\r
+\r
+  default:\r
+    //\r
+    // All other action return unsupported.\r
+    //\r
+    Status = EFI_UNSUPPORTED;\r
+    break;\r
+  }\r
+\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  This function allows a caller to extract the current configuration for one\r
+  or more named elements from the target driver.\r
+\r
+\r
+  @param This            Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
+  @param Request         A null-terminated Unicode string in <ConfigRequest> format.\r
+  @param Progress        On return, points to a character in the Request string.\r
+                         Points to the string's null terminator if request was successful.\r
+                         Points to the most recent '&' before the first failing name/value\r
+                         pair (or the beginning of the string if the failure is in the\r
+                         first name/value pair) if the request was not successful.\r
+  @param Results         A null-terminated Unicode string in <ConfigAltResp> format which\r
+                         has all values filled in for the names in the Request string.\r
+                         String to be allocated by the called function.\r
+\r
+  @retval  EFI_SUCCESS            The Results is filled with the requested values.\r
+  @retval  EFI_OUT_OF_RESOURCES   Not enough memory to store the results.\r
+  @retval  EFI_INVALID_PARAMETER  Request is illegal syntax, or unknown name.\r
+  @retval  EFI_NOT_FOUND          Routing data doesn't match any storage in this driver.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FakeExtractConfig (\r
+  IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,\r
+  IN  CONST EFI_STRING                       Request,\r
+  OUT EFI_STRING                             *Progress,\r
+  OUT EFI_STRING                             *Results\r
+  )\r
+{\r
+  if (Progress == NULL || Results == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  *Progress = Request;\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+/**\r
+  This function processes the results of changes in configuration.\r
+\r
+\r
+  @param This            Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
+  @param Configuration   A null-terminated Unicode string in <ConfigResp> format.\r
+  @param Progress        A pointer to a string filled in with the offset of the most\r
+                         recent '&' before the first failing name/value pair (or the\r
+                         beginning of the string if the failure is in the first\r
+                         name/value pair) or the terminating NULL if all was successful.\r
+\r
+  @retval  EFI_SUCCESS            The Results is processed successfully.\r
+  @retval  EFI_INVALID_PARAMETER  Configuration is NULL.\r
+  @retval  EFI_NOT_FOUND          Routing data doesn't match any storage in this driver.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FakeRouteConfig (\r
+  IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,\r
+  IN  CONST EFI_STRING                       Configuration,\r
+  OUT EFI_STRING                             *Progress\r
+  )\r
+{\r
+  if (Configuration == NULL || Progress == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+\r
+/**\r
+  Main entry for this driver.\r
+\r
+  @param ImageHandle     Image handle this driver.\r
+  @param SystemTable     Pointer to SystemTable.\r
+\r
+  @retval EFI_SUCESS     This function always complete successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UserProfileManagerInit (\r
+  IN EFI_HANDLE                       ImageHandle,\r
+  IN EFI_SYSTEM_TABLE                 *SystemTable\r
+  )\r
+{\r
+  EFI_STATUS                          Status;\r
+  USER_PROFILE_MANAGER_CALLBACK_INFO  *CallbackInfo;\r
+\r
+  Status = gBS->LocateProtocol (\r
+                  &gEfiUserManagerProtocolGuid,\r
+                  NULL,\r
+                  (VOID **) &mUserManager\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_SUCCESS;\r
+  }\r
+  \r
+  //\r
+  // Initialize driver private data.\r
+  //\r
+  ZeroMem (&mUserInfo, sizeof (mUserInfo));\r
+  ZeroMem (&mAccessInfo, sizeof (mAccessInfo));\r
+\r
+  CallbackInfo = AllocateZeroPool (sizeof (USER_PROFILE_MANAGER_CALLBACK_INFO));\r
+  ASSERT (CallbackInfo != NULL);  \r
+\r
+  CallbackInfo->Signature                   = USER_PROFILE_MANAGER_SIGNATURE;\r
+  CallbackInfo->ConfigAccess.ExtractConfig  = FakeExtractConfig;\r
+  CallbackInfo->ConfigAccess.RouteConfig    = FakeRouteConfig;\r
+  CallbackInfo->ConfigAccess.Callback       = UserProfileManagerCallback;\r
+  CallbackInfo->DriverHandle                = NULL;\r
+  \r
+  //\r
+  // Install Device Path Protocol and Config Access protocol to driver handle.\r
+  //\r
+  Status = gBS->InstallMultipleProtocolInterfaces (\r
+                  &CallbackInfo->DriverHandle,\r
+                  &gEfiDevicePathProtocolGuid,\r
+                  &mHiiVendorDevicePath,\r
+                  &gEfiHiiConfigAccessProtocolGuid,\r
+                  &CallbackInfo->ConfigAccess,\r
+                  NULL\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // Publish HII data.\r
+  //\r
+  CallbackInfo->HiiHandle = HiiAddPackages (\r
+                              &mUserProfileManagerGuid,\r
+                              CallbackInfo->DriverHandle,\r
+                              UserProfileManagerStrings,\r
+                              UserProfileManagerVfrBin,\r
+                              NULL\r
+                              );\r
+  ASSERT (CallbackInfo->HiiHandle != NULL);                              \r
+  mCallbackInfo = CallbackInfo;\r
+\r
+  return Status;\r
+}\r
+\r
+  \r
diff --git a/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManager.h b/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManager.h
new file mode 100644 (file)
index 0000000..b7098dc
--- /dev/null
@@ -0,0 +1,387 @@
+/** @file\r
+  The header file for user profile manager driver.\r
+    \r
+Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef __EFI_USER_PROFILE_MANAGER_H__\r
+#define __EFI_USER_PROFILE_MANAGER_H__\r
+\r
+#include <Uefi.h>\r
+\r
+#include <Guid/GlobalVariable.h>\r
+#include <Guid/MdeModuleHii.h>\r
+\r
+#include <Protocol/HiiConfigAccess.h>\r
+#include <Protocol/DevicePathToText.h>\r
+#include <Protocol/UserCredential.h>\r
+#include <Protocol/UserManager.h>\r
+\r
+#include <Library/UefiRuntimeServicesTableLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/DevicePathLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/PrintLib.h>\r
+#include <Library/HiiLib.h>\r
+\r
+#include "UserProfileManagerData.h"\r
+\r
+#define  USER_NAME_LENGTH          17\r
+\r
+//\r
+// Credential Provider Information.\r
+//\r
+typedef struct {\r
+  UINTN                         Count;\r
+  EFI_USER_CREDENTIAL_PROTOCOL  *Provider[1];\r
+} CREDENTIAL_PROVIDER_INFO;\r
+\r
+//\r
+// User profile information structure.\r
+//\r
+typedef struct {\r
+  UINT64    UsageCount;\r
+  EFI_TIME  CreateDate;\r
+  EFI_TIME  UsageDate;\r
+  UINTN     AccessPolicyLen;\r
+  UINTN     IdentityPolicyLen;\r
+  UINTN     NewIdentityPolicyLen;    \r
+  UINT8     *AccessPolicy;\r
+  UINT8     *IdentityPolicy;\r
+  UINT8     *NewIdentityPolicy;\r
+  CHAR16    UserName[USER_NAME_LENGTH];\r
+  BOOLEAN   CreateDateExist;\r
+  BOOLEAN   UsageDateExist;\r
+  BOOLEAN   AccessPolicyModified;\r
+  BOOLEAN   IdentityPolicyModified;\r
+  BOOLEAN   NewIdentityPolicyModified;\r
+} USER_INFO;\r
+\r
+//\r
+// User access information structure.\r
+//\r
+typedef struct {\r
+  UINTN  LoadPermitLen;\r
+  UINTN  LoadForbidLen;\r
+  UINTN  ConnectPermitLen;\r
+  UINTN  ConnectForbidLen;\r
+  UINT8  *LoadPermit;\r
+  UINT8  *LoadForbid;\r
+  UINT8  *ConnectPermit;\r
+  UINT8  *ConnectForbid;\r
+  UINT32 AccessBootOrder;\r
+  UINT8  AccessRight;\r
+  UINT8  AccessSetup;\r
+} USER_INFO_ACCESS;\r
+\r
+#define USER_PROFILE_MANAGER_SIGNATURE  SIGNATURE_32 ('U', 'P', 'M', 'S')\r
+\r
+typedef struct {\r
+  UINTN                           Signature;\r
+  EFI_HANDLE                      DriverHandle;\r
+  EFI_HII_HANDLE                  HiiHandle;\r
+  EFI_HII_CONFIG_ACCESS_PROTOCOL  ConfigAccess;\r
+} USER_PROFILE_MANAGER_CALLBACK_INFO;\r
+\r
+//\r
+// HII specific Vendor Device Path definition.\r
+//\r
+typedef struct {\r
+  VENDOR_DEVICE_PATH        VendorDevicePath;\r
+  EFI_DEVICE_PATH_PROTOCOL  End;\r
+} HII_VENDOR_DEVICE_PATH;\r
+\r
+//\r
+// This is the generated IFR binary data for each formset defined in VFR.\r
+//\r
+extern UINT8                               UserProfileManagerVfrBin[];\r
+\r
+//\r
+// This is the generated String package data for .UNI file.\r
+//\r
+extern UINT8                               UserProfileManagerStrings[];\r
+\r
+//\r
+// Guid used in the form browse.\r
+//\r
+extern EFI_GUID                            mUserProfileManagerGuid;\r
+\r
+//\r
+// The user manager protocol, used in several function.\r
+//\r
+extern EFI_USER_MANAGER_PROTOCOL           *mUserManager;\r
+\r
+//\r
+// The credential providers database in system.\r
+//\r
+extern CREDENTIAL_PROVIDER_INFO            *mProviderInfo;\r
+\r
+//\r
+// The variables used to update identity policy.\r
+//\r
+extern UINT8                               mProviderChoice;\r
+extern UINT8                               mConncetLogical;\r
+\r
+//\r
+// The variables used to update access policy.\r
+//\r
+extern USER_INFO_ACCESS                    mAccessInfo;\r
+\r
+//\r
+// The user information used to record all data in UI.\r
+//\r
+extern USER_INFO                           mUserInfo;\r
+\r
+extern USER_PROFILE_MANAGER_CALLBACK_INFO  *mCallbackInfo;\r
+\r
+\r
+/**\r
+  Get string by string id from HII Interface.\r
+\r
+\r
+  @param[in] Id      String ID to get the string from.\r
+\r
+  @retval  CHAR16 *  String from ID.\r
+  @retval  NULL      If error occurs.\r
+\r
+**/\r
+CHAR16 *\r
+GetStringById (\r
+  IN EFI_STRING_ID             Id\r
+  );\r
+\r
+/**\r
+  Add a new user profile into the user profile database.\r
+\r
+**/\r
+VOID\r
+CallAddUser (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Display user select form; can select a user to modify.\r
+\r
+**/\r
+VOID\r
+SelectUserToModify  (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Display user select form, cab select a user to delete.\r
+\r
+**/\r
+VOID\r
+SelectUserToDelete (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Delete the user specified by UserIndex in user profile database.\r
+\r
+  @param[in]  UserIndex    The index of user in the user name list to be deleted.\r
+\r
+**/\r
+VOID\r
+DeleteUser (\r
+  IN UINT8                                      UserIndex\r
+  );\r
+\r
+/**\r
+  Add a username item in form.\r
+\r
+  @param[in]  User             Points to the user profile whose username is added. \r
+  @param[in]  Index            The index of the user in the user name list.\r
+  @param[in]  OpCodeHandle     Points to container for dynamic created opcodes.\r
+\r
+**/\r
+VOID\r
+AddUserToForm (\r
+  IN  EFI_USER_PROFILE_HANDLE                   User,\r
+  IN  UINT16                                    Index,\r
+  IN  VOID                                      *OpCodeHandle\r
+  );\r
+\r
+/**\r
+  Display modify user information form\r
+\r
+  In this form, username, create Date, usage date, usage count, identity policy,\r
+  and access policy are displayed.\r
+\r
+  @param[in] UserIndex       The index of the user in display list to modify.\r
+  \r
+**/\r
+VOID\r
+ModifyUserInfo (\r
+  IN UINT8                                      UserIndex\r
+  );\r
+\r
+/**\r
+  Get the username from user input and update username string in Hii \r
+  database with it.\r
+\r
+**/\r
+VOID\r
+ModifyUserName (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Display the form of modifying user identity policy.\r
+\r
+**/\r
+VOID\r
+ModifyIdentityPolicy (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Update the mUserInfo.NewIdentityPolicy and UI when 'add option' is pressed.\r
+\r
+**/\r
+VOID\r
+AddIdentityPolicyItem (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Save the identity policy and update UI with it.\r
+  \r
+  This funciton will verify the new identity policy, in current implementation, \r
+  the identity policy can be:  T, P & P & P & ..., P | P | P | ...\r
+  Here, "T" means "True", "P" means "Credential Provider", "&" means "and", "|" means "or".\r
+  Other identity policies are not supported.  \r
+\r
+**/\r
+VOID\r
+SaveIdentityPolicy (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Display modify user access policy form\r
+\r
+  In this form, access right, access setu,p and access boot order are dynamically\r
+  added. Load devicepath and connect devicepath are displayed too.\r
+  \r
+**/\r
+VOID\r
+ModidyAccessPolicy (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Collect all the access policy data to mUserInfo.AccessPolicy, \r
+  and save it to user profile.\r
+\r
+**/\r
+VOID\r
+SaveAccessPolicy (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Get current user's access rights.\r
+\r
+  @param[out]  AccessRight   Points to the buffer used for user's access rights.\r
+\r
+  @retval EFI_SUCCESS        Get current user access rights successfully.\r
+  @retval others             Fail to get current user access rights.\r
+\r
+**/\r
+EFI_STATUS\r
+GetAccessRight (\r
+  OUT  UINT32                                    *AccessRight\r
+  );\r
+\r
+/**\r
+  Display the permit load device path in the loadable device path list.\r
+\r
+**/\r
+VOID\r
+DisplayLoadPermit(\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Display the forbid load device path list (mAccessInfo.LoadForbid).\r
+\r
+**/\r
+VOID\r
+DisplayLoadForbid (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Display the permit connect device path.\r
+\r
+**/\r
+VOID\r
+DisplayConnectPermit (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Display the forbid connect device path list.\r
+\r
+**/\r
+VOID\r
+DisplayConnectForbid (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Delete the specified device path by DriverIndex from the forbid device path \r
+  list (mAccessInfo.LoadForbid).\r
+\r
+  @param[in]  DriverIndex   The index of driver in a forbidden device path list.\r
+  \r
+**/\r
+VOID\r
+DeleteFromForbidLoad (\r
+  IN  UINT16                                    DriverIndex\r
+  );\r
+  \r
+/**\r
+  Add the specified device path by DriverIndex to the forbid device path \r
+  list (mAccessInfo.LoadForbid).\r
+\r
+  @param[in]  DriverIndex   The index of driver saved in driver options.\r
+  \r
+**/\r
+VOID\r
+AddToForbidLoad (\r
+  IN  UINT16                                    DriverIndex\r
+  );\r
+\r
+/**\r
+  Get user name from the popup windows.\r
+  \r
+  @param[in, out]  UserNameLen   On entry, point to the buffer lengh of UserName.\r
+                                 On exit, point to the input user name length.\r
+  @param[out]      UserName      The buffer to hold the input user name.\r
\r
+  @retval EFI_ABORTED            It is given up by pressing 'ESC' key.\r
+  @retval EFI_NOT_READY          Not a valid input at all.\r
+  @retval EFI_SUCCESS            Get a user name successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+GetUserNameInput (\r
+  IN OUT  UINTN         *UserNameLen,\r
+     OUT  CHAR16        *UserName\r
+  );\r
+  \r
+#endif\r
diff --git a/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManagerData.h b/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManagerData.h
new file mode 100644 (file)
index 0000000..58b6cb8
--- /dev/null
@@ -0,0 +1,161 @@
+/** @file\r
+  The form data for user profile manager driver.\r
+    \r
+Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef __USER_PROFILE_MANAGER_DATA_H__\r
+#define __USER_PROFILE_MANAGER_DATA_H__\r
+\r
+#define USER_PROFILE_MANAGER_GUID \\r
+  { \\r
+    0xc35f272c, 0x97c2, 0x465a, { 0xa2, 0x16, 0x69, 0x6b, 0x66, 0x8a, 0x8c, 0xfe } \\r
+  }\r
+\r
+//\r
+// Form ID\r
+//\r
+#define FORMID_USER_MANAGE          0x0001\r
+#define FORMID_MODIFY_USER          0x0002\r
+#define FORMID_DEL_USER             0x0003\r
+#define FORMID_USER_INFO            0x0004\r
+#define FORMID_MODIFY_IP            0x0005\r
+#define FORMID_MODIFY_AP            0x0006\r
+#define FORMID_LOAD_DP              0x0007\r
+#define FORMID_CONNECT_DP           0x0008\r
+#define FORMID_PERMIT_LOAD_DP       0x0009\r
+#define FORMID_FORBID_LOAD_DP       0x000A\r
+#define FORMID_PERMIT_CONNECT_DP    0x000B\r
+#define FORMID_FORBID_CONNECT_DP    0x000C\r
+\r
+//\r
+// Label ID\r
+//\r
+#define  LABEL_USER_MANAGE_FUNC     0x0010\r
+#define  LABEL_USER_DEL_FUNC        0x0020\r
+#define  LABEL_USER_MOD_FUNC        0x0030\r
+#define  LABEL_USER_INFO_FUNC       0x0040\r
+#define  LABEL_IP_MOD_FUNC          0x0050\r
+#define  LABEL_AP_MOD_FUNC          0x0060\r
+#define  LABEL_PERMIT_LOAD_FUNC     0x0070\r
+#define  LABLE_FORBID_LOAD_FUNC     0x0080\r
+#define  LABEL_END                  0x00F0\r
+\r
+//\r
+// First form key (Add/modify/del user profile). \r
+// First 2 bits (bit 16~15).\r
+//\r
+#define  KEY_MODIFY_USER            0x4000\r
+#define  KEY_DEL_USER               0x8000\r
+#define  KEY_ADD_USER               0xC000\r
+#define  KEY_FIRST_FORM_MASK        0xC000\r
+\r
+//\r
+// Second form key (Display new form /Select user / modify device path in access policy).\r
+// Next 2 bits (bit 14~13).\r
+//\r
+#define  KEY_ENTER_NEXT_FORM        0x0000\r
+#define  KEY_SELECT_USER            0x1000\r
+#define  KEY_MODIFY_AP_DP           0x2000\r
+#define  KEY_OPEN_CLOSE_FORM_ACTION 0x3000\r
+#define  KEY_SECOND_FORM_MASK       0x3000\r
+\r
+//\r
+// User profile information form key.\r
+// Next 3 bits (bit 12~10).\r
+//\r
+#define  KEY_MODIFY_NAME            0x0200\r
+#define  KEY_MODIFY_IP              0x0400\r
+#define  KEY_MODIFY_AP              0x0600\r
+#define  KEY_MODIFY_INFO_MASK       0x0E00\r
+\r
+//\r
+// Specified key, used in VFR (KEY_MODIFY_USER | KEY_SELECT_USER | KEY_MODIFY_NAME).\r
+//\r
+#define  KEY_MODIFY_USER_NAME       0x5200 \r
+\r
+//\r
+// Modify identity policy form key.\r
+// Next 3 bits (bit 9~7).\r
+//\r
+#define  KEY_MODIFY_PROV            0x0040\r
+#define  KEY_MODIFY_MTYPE           0x0080\r
+#define  KEY_MODIFY_CONN            0x00C0\r
+#define  KEY_ADD_IP_OP              0x0100\r
+#define  KEY_IP_RETURN_UIF          0x0140\r
+#define  KEY_MODIFY_IP_MASK         0x01C0\r
+\r
+//\r
+// Specified key.\r
+//\r
+#define  KEY_ADD_LOGICAL_OP         0x5500\r
+#define  KEY_IP_RETURN              0x5540\r
+\r
+//\r
+// Modify access policy form key.\r
+// Next 3 bits (bit 9~7).\r
+//\r
+#define  KEY_MODIFY_RIGHT           0x0040\r
+#define  KEY_MODIFY_SETUP           0x0080\r
+#define  KEY_MODIFY_BOOT            0x00C0\r
+#define  KEY_MODIFY_LOAD            0x0100\r
+#define  KEY_MODIFY_CONNECT         0x0140\r
+#define  KEY_AP_RETURN_UIF          0x0180\r
+#define  KEY_MODIFY_AP_MASK         0x01C0\r
+\r
+//\r
+// Specified key.\r
+//\r
+#define  KEY_LOAD_DP                0x5700\r
+#define  KEY_CONN_DP                0x5740\r
+#define  KEY_AP_RETURN              0x5780\r
+\r
+//\r
+// Device path form key.\r
+// Next 2 bits (bit 6~5).\r
+//\r
+#define  KEY_PERMIT_MODIFY          0x0010\r
+#define  KEY_FORBID_MODIFY          0x0020\r
+#define  KEY_DISPLAY_DP_MASK        0x0030\r
+\r
+//\r
+// Specified key.\r
+//\r
+#define  KEY_LOAD_PERMIT            0x5710\r
+#define  KEY_LOAD_FORBID            0x5720\r
+#define  KEY_CONNECT_PERMIT         0x5750\r
+#define  KEY_CONNECT_FORBID         0x5760\r
+\r
+//\r
+// Device path modify key.\r
+// 2 bits (bit 12~11).\r
+// \r
+#define KEY_LOAD_PERMIT_MODIFY      0x0000\r
+#define KEY_LOAD_FORBID_MODIFY      0x0400\r
+#define KEY_CONNECT_PERMIT_MODIFY   0x0800\r
+#define KEY_CONNECT_FORBID_MODIFY   0x0C00\r
+#define KEY_MODIFY_DP_MASK          0x0C00\r
+\r
+\r
+//\r
+// The permissions usable when configuring the platform.\r
+//\r
+#define  ACCESS_SETUP_RESTRICTED   1\r
+#define  ACCESS_SETUP_NORMAL       2\r
+#define  ACCESS_SETUP_ADMIN        3\r
+\r
+//\r
+// Question ID for the question used in each form (KEY_OPEN_CLOSE_FORM_ACTION | FORMID_FORM_USER_MANAGE)\r
+// This ID is used in FORM OPEN/CLOSE CallBack action.\r
+//\r
+#define QUESTIONID_USER_MANAGE      0x3001\r
+\r
+#endif\r
diff --git a/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManagerDxe.inf b/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManagerDxe.inf
new file mode 100644 (file)
index 0000000..27b3464
--- /dev/null
@@ -0,0 +1,60 @@
+## @file\r
+#  Component description file for user profile manager driver.\r
+#\r
+# Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = UserProfileManager\r
+  FILE_GUID                      = E38CB52D-A74D-45db-A8D0-290C9B21BBF2\r
+  MODULE_TYPE                    = DXE_DRIVER\r
+  VERSION_STRING                 = 1.0\r
+  ENTRY_POINT                    = UserProfileManagerInit\r
+\r
+[Sources]\r
+  UserProfileManager.c\r
+  UserProfileManager.h\r
+  UserProfileAdd.c\r
+  UserProfileDelete.c\r
+  UserProfileModify.c\r
+  UserProfileManagerData.h\r
+  UserProfileManagerStrings.uni\r
+  UserProfileManagerVfr.Vfr\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+\r
+[LibraryClasses]\r
+  UefiRuntimeServicesTableLib\r
+  UefiBootServicesTableLib\r
+  UefiDriverEntryPoint\r
+  MemoryAllocationLib\r
+  BaseMemoryLib\r
+  DebugLib\r
+  HiiLib\r
+  UefiLib\r
+  \r
+  [Guids]\r
+  gEfiIfrTianoGuid                              ## CONSUMES ## Guid\r
+  gEfiUserInfoAccessSetupAdminGuid              ## CONSUMES ## Guid\r
+  gEfiUserInfoAccessSetupNormalGuid             ## CONSUMES ## Guid\r
+  gEfiUserInfoAccessSetupRestrictedGuid         ## CONSUMES ## Guid\r
+\r
+[Protocols]\r
+  gEfiDevicePathProtocolGuid                    # PROTOCOL ALWAYS_CONSUMED\r
+  gEfiHiiConfigAccessProtocolGuid\r
+  gEfiUserCredentialProtocolGuid\r
+  gEfiUserManagerProtocolGuid\r
+  gEfiDevicePathToTextProtocolGuid\r
+\r
+[Depex]\r
+  gEfiUserManagerProtocolGuid
\ No newline at end of file
diff --git a/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManagerStrings.uni b/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManagerStrings.uni
new file mode 100644 (file)
index 0000000..64631bb
Binary files /dev/null and b/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManagerStrings.uni differ
diff --git a/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManagerVfr.Vfr b/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManagerVfr.Vfr
new file mode 100644 (file)
index 0000000..d094d78
--- /dev/null
@@ -0,0 +1,247 @@
+/** @file\r
+  User Profile Manager formset.\r
+\r
+Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "UserProfileManagerData.h"\r
+\r
+#define USER_MANAGER_CLASS       0x00\r
+#define USER_MANAGER_SUBCLASS    0x04\r
+\r
+formset \r
+  guid     = USER_PROFILE_MANAGER_GUID,\r
+  title    = STRING_TOKEN(STR_FORMSET_TITLE),  \r
+  help     = STRING_TOKEN(STR_TITLE_HELP),\r
+  class    = USER_MANAGER_CLASS,\r
+  subclass = USER_MANAGER_SUBCLASS,\r
+    \r
+  // User manager form\r
+  form formid = FORMID_USER_MANAGE,\r
+    title     = STRING_TOKEN(STR_USERMAN_TITLE);\r
+\r
+    label LABEL_USER_MANAGE_FUNC;\r
+    label LABEL_END;\r
+\r
+    suppressif TRUE;\r
+      text\r
+        help   = STRING_TOKEN(STR_NULL_STRING),\r
+        text   = STRING_TOKEN(STR_NULL_STRING),\r
+          text   = STRING_TOKEN(STR_NULL_STRING),\r
+        flags  = INTERACTIVE,\r
+        key    = QUESTIONID_USER_MANAGE;\r
+    endif;\r
+     \r
+  endform;\r
+  \r
+  // Modify user profile form\r
+  form formid = FORMID_MODIFY_USER,\r
+    title     = STRING_TOKEN(STR_MODIFY_USER_TITLE);\r
+\r
+    label LABEL_USER_MOD_FUNC;\r
+    label LABEL_END;\r
+\r
+  endform;\r
+  \r
+  // Delete user profile form\r
+  form formid = FORMID_DEL_USER,\r
+    title     = STRING_TOKEN(STR_DELETE_USER_TITLE);\r
+  \r
+    label LABEL_USER_DEL_FUNC;\r
+    label LABEL_END;\r
+    \r
+    subtitle \r
+      text   = STRING_TOKEN(STR_NULL_STRING);\r
+  endform;\r
+  \r
+  //\r
+  // User profile information form\r
+  //\r
+  form formid = FORMID_USER_INFO,\r
+    title     = STRING_TOKEN(STR_USER_INFO);\r
+\r
+    text \r
+      help   = STRING_TOKEN(STR_USER_NAME_VAL),  \r
+      text   = STRING_TOKEN(STR_USER_NAME),\r
+      flags  = INTERACTIVE,\r
+      key    = KEY_MODIFY_USER_NAME;\r
+      \r
+    text \r
+      help   = STRING_TOKEN(STR_CREATE_DATE_VAL),  \r
+      text   = STRING_TOKEN(STR_CREATE_DATE);\r
+      \r
+    text \r
+      help   = STRING_TOKEN(STR_USAGE_DATE_VAL),  \r
+      text   = STRING_TOKEN(STR_USAGE_DATE);\r
+      \r
+    text \r
+      help   = STRING_TOKEN(STR_USAGE_COUNT_VAL),  \r
+      text   = STRING_TOKEN(STR_USAGE_COUNT);\r
+      \r
+    label LABEL_USER_INFO_FUNC; \r
+    label LABEL_END;\r
+\r
+  endform;\r
+  \r
+  //\r
+  // Identify policy modify form\r
+  //\r
+  form formid = FORMID_MODIFY_IP,\r
+    title     = STRING_TOKEN(STR_IDENTIFY_POLICY);\r
+\r
+    text \r
+      help   = STRING_TOKEN(STR_IDENTIFY_POLICY_HELP),\r
+      text   = STRING_TOKEN(STR_IDENTIFY_POLICY),\r
+        text   = STRING_TOKEN(STR_IDENTIFY_POLICY_VALUE);\r
+      \r
+    label LABEL_IP_MOD_FUNC;\r
+    label LABEL_END;\r
+    \r
+    text \r
+      help   = STRING_TOKEN(STR_ADD_OPTION_HELP),  \r
+      text   = STRING_TOKEN(STR_ADD_OPTION),\r
+      flags  = INTERACTIVE,\r
+      key    = KEY_ADD_LOGICAL_OP;\r
+      \r
+    subtitle \r
+      text   = STRING_TOKEN(STR_NULL_STRING);\r
+\r
+    goto FORMID_USER_INFO,\r
+      prompt  = STRING_TOKEN(STR_SAVE),\r
+      help    = STRING_TOKEN(STR_IDENTIFY_SAVE_HELP),\r
+      flags   = INTERACTIVE,\r
+      key     = KEY_IP_RETURN;\r
+      \r
+  endform;\r
+  \r
+  //\r
+  // Access policy modify form\r
+  //\r
+  form formid = FORMID_MODIFY_AP,\r
+    title     = STRING_TOKEN(STR_ACCESS_POLICY);\r
+\r
+    label LABEL_AP_MOD_FUNC;\r
+    label LABEL_END;\r
+\r
+    goto FORMID_LOAD_DP,\r
+      prompt  = STRING_TOKEN(STR_LOAD),\r
+      help    = STRING_TOKEN(STR_LOAD_HELP),\r
+      flags   = INTERACTIVE,\r
+      key     = KEY_LOAD_DP;\r
+\r
+    goto FORMID_CONNECT_DP,\r
+      prompt  = STRING_TOKEN(STR_CONNECT),\r
+      help    = STRING_TOKEN(STR_CONNECT_HELP),\r
+      flags   = INTERACTIVE,\r
+      key     = KEY_CONN_DP;\r
+\r
+    subtitle \r
+      text   = STRING_TOKEN(STR_NULL_STRING);\r
+   \r
+    goto FORMID_USER_INFO,\r
+      prompt  = STRING_TOKEN(STR_SAVE),\r
+      help    = STRING_TOKEN(STR_ACCESS_SAVE_HELP),\r
+      flags   = INTERACTIVE,\r
+      key     = KEY_AP_RETURN;\r
+    \r
+  endform;\r
+\r
+  //\r
+  // Load device path form\r
+  //\r
+  form formid = FORMID_LOAD_DP,\r
+    title     = STRING_TOKEN(STR_LOAD);\r
+\r
+    goto FORMID_PERMIT_LOAD_DP,\r
+      prompt  = STRING_TOKEN(STR_LOAD_PERMIT),\r
+      help    = STRING_TOKEN(STR_LOAD_PERMIT_HELP),\r
+      flags   = INTERACTIVE,\r
+      key     = KEY_LOAD_PERMIT;\r
+    \r
+    goto FORMID_FORBID_LOAD_DP,\r
+      prompt  = STRING_TOKEN(STR_LOAD_FORBID),\r
+      help    = STRING_TOKEN(STR_LOAD_FORBID_HELP),\r
+      flags   = INTERACTIVE,\r
+      key     = KEY_LOAD_FORBID;\r
\r
+  endform;\r
+  \r
+  //\r
+  // Permit load device path form\r
+  //\r
+  form formid = FORMID_PERMIT_LOAD_DP,\r
+    title     = STRING_TOKEN(STR_LOAD_PERMIT);\r
+  \r
+    label LABEL_PERMIT_LOAD_FUNC;\r
+    label LABEL_END;\r
+  \r
+    subtitle \r
+      text   = STRING_TOKEN(STR_NULL_STRING);\r
+\r
+  endform;\r
+  \r
+  //\r
+  // Forbid load device path form\r
+  //\r
+  form formid = FORMID_FORBID_LOAD_DP,\r
+    title     = STRING_TOKEN(STR_LOAD_FORBID);\r
+  \r
+    label LABLE_FORBID_LOAD_FUNC;\r
+    label LABEL_END;\r
+   \r
+    subtitle \r
+      text   = STRING_TOKEN(STR_NULL_STRING);\r
+\r
+  endform;\r
+  \r
+  //\r
+  // Connect device path form\r
+  //\r
+  form formid = FORMID_CONNECT_DP,\r
+    title     = STRING_TOKEN(STR_CONNECT);\r
+\r
+    goto FORMID_PERMIT_CONNECT_DP,\r
+      prompt  = STRING_TOKEN(STR_CONNECT_PERMIT),\r
+      help    = STRING_TOKEN(STR_CONNECT_PERMIT_HELP),\r
+      flags   = INTERACTIVE,\r
+      key     = KEY_CONNECT_PERMIT;\r
+      \r
+    goto FORMID_FORBID_CONNECT_DP,\r
+      prompt  = STRING_TOKEN(STR_CONNECT_FORBID),\r
+      help    = STRING_TOKEN(STR_CONNECT_FORBID_HELP),\r
+      flags   = INTERACTIVE,\r
+      key     = KEY_CONNECT_FORBID;\r
+      \r
+  endform;\r
+  \r
+  //\r
+  // Permit connect device path form\r
+  //\r
+  form formid = FORMID_PERMIT_CONNECT_DP,\r
+    title     = STRING_TOKEN(STR_CONNECT_PERMIT);\r
+     \r
+    subtitle \r
+      text   = STRING_TOKEN(STR_NULL_STRING);\r
+\r
+  endform;\r
+  \r
+  //\r
+  // Forbid connect device path form\r
+  //\r
+  form formid = FORMID_FORBID_CONNECT_DP,\r
+    title     = STRING_TOKEN(STR_CONNECT_FORBID);\r
+     \r
+   subtitle \r
+     text   = STRING_TOKEN(STR_NULL_STRING);\r
+\r
+  endform;\r
+  \r
+endformset;\r
diff --git a/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileModify.c b/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileModify.c
new file mode 100644 (file)
index 0000000..156c155
--- /dev/null
@@ -0,0 +1,2511 @@
+/** @file\r
+  The functions to modify a user profile.\r
+    \r
+Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "UserProfileManager.h"\r
+\r
+EFI_USER_PROFILE_HANDLE           mModifyUser = NULL;\r
+\r
+/**\r
+  Display user select form, cab select a user to modify.\r
+\r
+**/\r
+VOID\r
+SelectUserToModify  (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  UINT8                   Index;\r
+  EFI_USER_PROFILE_HANDLE User;\r
+  EFI_USER_PROFILE_HANDLE CurrentUser;\r
+  UINT32                  CurrentAccessRight;\r
+  VOID                    *StartOpCodeHandle;\r
+  VOID                    *EndOpCodeHandle;\r
+  EFI_IFR_GUID_LABEL      *StartLabel;\r
+  EFI_IFR_GUID_LABEL      *EndLabel;\r
+\r
+  //\r
+  // Initialize the container for dynamic opcodes.\r
+  //\r
+  StartOpCodeHandle = HiiAllocateOpCodeHandle ();\r
+  ASSERT (StartOpCodeHandle != NULL);\r
+\r
+  EndOpCodeHandle = HiiAllocateOpCodeHandle ();\r
+  ASSERT (EndOpCodeHandle != NULL);\r
+\r
+  //\r
+  // Create Hii Extend Label OpCode.\r
+  //\r
+  StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (\r
+                                        StartOpCodeHandle,\r
+                                        &gEfiIfrTianoGuid,\r
+                                        NULL,\r
+                                        sizeof (EFI_IFR_GUID_LABEL)\r
+                                        );\r
+  StartLabel->ExtendOpCode  = EFI_IFR_EXTEND_OP_LABEL;\r
+  StartLabel->Number        = LABEL_USER_MOD_FUNC;\r
+\r
+  EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (\r
+                                      EndOpCodeHandle,\r
+                                      &gEfiIfrTianoGuid,\r
+                                      NULL,\r
+                                      sizeof (EFI_IFR_GUID_LABEL)\r
+                                      );\r
+  EndLabel->ExtendOpCode  = EFI_IFR_EXTEND_OP_LABEL;\r
+  EndLabel->Number        = LABEL_END;\r
+\r
+  //\r
+  // Add each user can be modified.\r
+  //\r
+  User  = NULL;\r
+  Index = 1;\r
+  mUserManager->Current (mUserManager, &CurrentUser);\r
+  while (TRUE) {\r
+    Status = mUserManager->GetNext (mUserManager, &User);\r
+    if (EFI_ERROR (Status)) {\r
+      break;\r
+    }\r
+\r
+    Status = GetAccessRight (&CurrentAccessRight);\r
+    if (EFI_ERROR (Status)) {\r
+      CurrentAccessRight = EFI_USER_INFO_ACCESS_ENROLL_SELF;\r
+    }\r
+\r
+    if ((CurrentAccessRight == EFI_USER_INFO_ACCESS_MANAGE) || (User == CurrentUser)) {\r
+      AddUserToForm (User, (UINT16)(KEY_MODIFY_USER | KEY_SELECT_USER | Index), StartOpCodeHandle);\r
+    }\r
+    Index++;\r
+  }\r
+\r
+  HiiUpdateForm (\r
+    mCallbackInfo->HiiHandle, // HII handle\r
+    &mUserProfileManagerGuid, // Formset GUID\r
+    FORMID_MODIFY_USER,       // Form ID\r
+    StartOpCodeHandle,        // Label for where to insert opcodes\r
+    EndOpCodeHandle           // Replace data\r
+    );\r
+\r
+  HiiFreeOpCodeHandle (StartOpCodeHandle);\r
+  HiiFreeOpCodeHandle (EndOpCodeHandle);\r
+}\r
+\r
+\r
+/**\r
+  Get all the user info from mModifyUser in the user manager, and save on the\r
+  global variable.\r
+\r
+**/\r
+VOID\r
+GetAllUserInfo (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  EFI_USER_INFO_HANDLE  UserInfo;\r
+  EFI_USER_INFO         *Info;\r
+  UINTN                 InfoSize;\r
+  UINTN                 MemSize;\r
+  UINTN                 DataLen;\r
+\r
+  //\r
+  // Init variable to default value.\r
+  //\r
+  mProviderChoice                   = 0;\r
+  mConncetLogical                   = 0;\r
+\r
+  mUserInfo.CreateDateExist         = FALSE;\r
+  mUserInfo.UsageDateExist          = FALSE;\r
+  mUserInfo.UsageCount              = 0;\r
+  \r
+  mUserInfo.AccessPolicyLen         = 0;\r
+  mUserInfo.AccessPolicyModified    = FALSE;\r
+  if (mUserInfo.AccessPolicy != NULL) {\r
+    FreePool (mUserInfo.AccessPolicy);\r
+    mUserInfo.AccessPolicy = NULL;\r
+  }\r
+  mUserInfo.IdentityPolicyLen       = 0;\r
+  mUserInfo.IdentityPolicyModified  = FALSE;\r
+  if (mUserInfo.IdentityPolicy != NULL) {\r
+    FreePool (mUserInfo.IdentityPolicy);\r
+    mUserInfo.IdentityPolicy = NULL;\r
+  }\r
+  \r
+  //\r
+  // Allocate user information memory.\r
+  //\r
+  MemSize = sizeof (EFI_USER_INFO) + 63;\r
+  Info    = AllocateZeroPool (MemSize);\r
+  if (Info == NULL) {\r
+    return ;\r
+  }\r
+  \r
+  //\r
+  // Get each user information.\r
+  //\r
+  UserInfo = NULL;\r
+  while (TRUE) {\r
+    Status = mUserManager->GetNextInfo (mUserManager, mModifyUser, &UserInfo);\r
+    if (EFI_ERROR (Status)) {\r
+      break;\r
+    }\r
+    //\r
+    // Get information.\r
+    //\r
+    InfoSize  = MemSize;\r
+    Status    = mUserManager->GetInfo (\r
+                                mUserManager, \r
+                                mModifyUser, \r
+                                UserInfo, \r
+                                Info, \r
+                                &InfoSize\r
+                                );\r
+    if (Status == EFI_BUFFER_TOO_SMALL) {\r
+      MemSize = InfoSize;\r
+      FreePool (Info);\r
+      Info = AllocateZeroPool (MemSize);\r
+      if (Info == NULL) {\r
+        return ;\r
+      }\r
+\r
+      Status = mUserManager->GetInfo (\r
+                               mUserManager,\r
+                               mModifyUser,\r
+                               UserInfo,\r
+                               Info,\r
+                               &InfoSize\r
+                               );\r
+    }\r
+\r
+    if (Status == EFI_SUCCESS) {\r
+      //\r
+      // Deal with each information according to informaiton type.\r
+      //\r
+      DataLen = Info->InfoSize - sizeof (EFI_USER_INFO);\r
+      switch (Info->InfoType) {\r
+      case EFI_USER_INFO_NAME_RECORD:\r
+        CopyMem (&mUserInfo.UserName, (UINT8 *) (Info + 1), DataLen);\r
+        break;\r
+\r
+      case EFI_USER_INFO_CREATE_DATE_RECORD:\r
+        CopyMem (&mUserInfo.CreateDate, (UINT8 *) (Info + 1), DataLen);\r
+        mUserInfo.CreateDateExist = TRUE;\r
+        break;\r
+\r
+      case EFI_USER_INFO_USAGE_DATE_RECORD:\r
+        CopyMem (&mUserInfo.UsageDate, (UINT8 *) (Info + 1), DataLen);\r
+        mUserInfo.UsageDateExist = TRUE;\r
+        break;\r
+\r
+      case EFI_USER_INFO_USAGE_COUNT_RECORD:\r
+        CopyMem (&mUserInfo.UsageCount, (UINT8 *) (Info + 1), DataLen);\r
+        break;\r
+\r
+      case EFI_USER_INFO_ACCESS_POLICY_RECORD:\r
+        mUserInfo.AccessPolicy = AllocateZeroPool (DataLen);\r
+        if (mUserInfo.AccessPolicy == NULL) {\r
+          break;\r
+        }\r
+\r
+        CopyMem (mUserInfo.AccessPolicy, (UINT8 *) (Info + 1), DataLen);\r
+        mUserInfo.AccessPolicyLen = DataLen;\r
+        break;\r
+\r
+      case EFI_USER_INFO_IDENTITY_POLICY_RECORD:\r
+        mUserInfo.IdentityPolicy = AllocateZeroPool (DataLen);\r
+        if (mUserInfo.IdentityPolicy == NULL) {\r
+          break;\r
+        }\r
+\r
+        CopyMem (mUserInfo.IdentityPolicy, (UINT8 *) (Info + 1), DataLen);\r
+        mUserInfo.IdentityPolicyLen = DataLen;\r
+        break;\r
+\r
+      default:\r
+        break;\r
+      }\r
+    }\r
+  }\r
+  FreePool (Info);\r
+}\r
+\r
+\r
+/**\r
+  Convert the Date to a string, and update the Hii database DateID string with it.\r
+\r
+  @param[in] Date       Points to the date to be converted.\r
+  @param[in] DateId     String ID in the HII database to be replaced.\r
+\r
+**/\r
+VOID\r
+ResolveDate (\r
+  IN EFI_TIME                                   *Date,\r
+  IN EFI_STRING_ID                              DateId\r
+  )\r
+{\r
+  CHAR16  *Str;\r
+  UINTN   DateBufLen;\r
+\r
+  //\r
+  // Convert date to string.\r
+  //\r
+  DateBufLen = 64;\r
+  Str        = AllocateZeroPool (DateBufLen);\r
+  if (Str == NULL) {\r
+    return ;\r
+  }\r
+\r
+  UnicodeSPrint (\r
+    Str,\r
+    DateBufLen,\r
+    L"%4d-%2d-%2d ",\r
+    Date->Year,\r
+    Date->Month,\r
+    Date->Day\r
+    );\r
+\r
+  //\r
+  // Convert time to string.\r
+  //\r
+  DateBufLen -= StrLen (Str);\r
+  UnicodeSPrint (\r
+    Str + StrLen (Str),\r
+    DateBufLen,\r
+    L"%2d:%2d:%2d", \r
+    Date->Hour,\r
+    Date->Minute,\r
+    Date->Second\r
+    );\r
+  \r
+  HiiSetString (mCallbackInfo->HiiHandle, DateId, Str, NULL);\r
+  FreePool (Str);\r
+}\r
+\r
+\r
+/**\r
+  Convert the CountVal to a string, and update the Hii database CountId string\r
+  with it.\r
+\r
+  @param[in]  CountVal   The hex value to convert.\r
+  @param[in]  CountId    String ID in the HII database to be replaced.\r
+\r
+**/\r
+VOID\r
+ResolveCount (\r
+  IN UINT32                                     CountVal,\r
+  IN EFI_STRING_ID                              CountId\r
+  )\r
+{\r
+  CHAR16  Count[10];\r
+\r
+  UnicodeSPrint (Count, 20, L"%d", CountVal);  \r
+  HiiSetString (mCallbackInfo->HiiHandle, CountId, Count, NULL);\r
+}\r
+\r
+\r
+/**\r
+  Concatenates one Null-terminated Unicode string to another Null-terminated\r
+  Unicode string.\r
+\r
+  @param[in, out]  Source1      On entry, point to a Null-terminated Unicode string.\r
+                                On exit, point to a new concatenated Unicode string                                \r
+  @param[in]       Source2      Pointer to a Null-terminated Unicode string.\r
+\r
+**/\r
+VOID\r
+AddStr (\r
+  IN OUT  CHAR16                  **Source1,\r
+  IN      CONST CHAR16            *Source2\r
+  )\r
+{\r
+  CHAR16                        *TmpStr;\r
+  UINTN                         StrLength;\r
+\r
+  ASSERT (Source1 != NULL);\r
+  ASSERT (Source2 != NULL);\r
+\r
+  if (*Source1 == NULL) {\r
+    StrLength = StrSize (Source2);\r
+  } else {\r
+    StrLength  = StrSize (*Source1);\r
+    StrLength += StrSize (Source2) -1;\r
+  }\r
+\r
+  TmpStr     = AllocateZeroPool (StrLength);\r
+  ASSERT (TmpStr != NULL);\r
+\r
+  if (*Source1 == NULL) {\r
+    StrCpy (TmpStr, Source2);;\r
+  } else {\r
+    StrCpy (TmpStr, *Source1);\r
+    FreePool (*Source1);\r
+    StrCat (TmpStr, Source2);\r
+  }\r
+\r
+  *Source1 = TmpStr;\r
+}\r
+\r
+\r
+/**\r
+  Convert the identity policy to a unicode string and update the Hii database\r
+  IpStringId string with it.\r
+\r
+  @param[in]  Ip         Points to identity policy.\r
+  @param[in]  IpLen      The identity policy length.\r
+  @param[in]  IpStringId String ID in the HII database to be replaced.\r
+\r
+**/\r
+VOID\r
+ResolveIdentityPolicy (\r
+  IN  UINT8                                     *Ip,\r
+  IN  UINTN                                     IpLen,\r
+  IN  EFI_STRING_ID                             IpStringId\r
+  )\r
+{\r
+  CHAR16                        *TmpStr;\r
+  UINTN                         ChkLen;\r
+  EFI_USER_INFO_IDENTITY_POLICY *Identity;\r
+  UINT16                        Index;\r
+  CHAR16                        *ProvStr;\r
+  EFI_STRING_ID                 ProvId;\r
+  EFI_HII_HANDLE                HiiHandle;\r
+  EFI_USER_CREDENTIAL_PROTOCOL  *UserCredential;\r
\r
+  TmpStr = NULL;\r
+  \r
+  //\r
+  // Resolve each policy.\r
+  //\r
+  ChkLen  = 0;\r
+  while (ChkLen < IpLen) {\r
+    Identity = (EFI_USER_INFO_IDENTITY_POLICY *) (Ip + ChkLen);\r
+    switch (Identity->Type) {\r
+    case EFI_USER_INFO_IDENTITY_FALSE:\r
+      AddStr (&TmpStr, L"False");\r
+      break;\r
+\r
+    case EFI_USER_INFO_IDENTITY_TRUE:\r
+      AddStr (&TmpStr, L"None");\r
+      break;\r
+\r
+    case EFI_USER_INFO_IDENTITY_NOT:\r
+      AddStr (&TmpStr, L"! ");\r
+      break;\r
+\r
+    case EFI_USER_INFO_IDENTITY_AND:\r
+      AddStr (&TmpStr, L" && ");\r
+      break;\r
+\r
+    case EFI_USER_INFO_IDENTITY_OR:\r
+      AddStr (&TmpStr, L" || ");\r
+      break;\r
+\r
+    case EFI_USER_INFO_IDENTITY_CREDENTIAL_TYPE:\r
+      for (Index = 0; Index < mProviderInfo->Count; Index++) {\r
+        UserCredential = mProviderInfo->Provider[Index];\r
+        if (CompareGuid ((EFI_GUID *) (Identity + 1), &UserCredential->Type)) {     \r
+          UserCredential->Title (\r
+                            UserCredential, \r
+                            &HiiHandle, \r
+                            &ProvId\r
+                            );\r
+          ProvStr = HiiGetString (HiiHandle, ProvId, NULL);\r
+          if (ProvStr != NULL) {\r
+            AddStr (&TmpStr, ProvStr);\r
+            FreePool (ProvStr);\r
+          }\r
+          break;\r
+        }\r
+      }\r
+      break;\r
+\r
+    case EFI_USER_INFO_IDENTITY_CREDENTIAL_PROVIDER:\r
+      for (Index = 0; Index < mProviderInfo->Count; Index++) {\r
+        UserCredential = mProviderInfo->Provider[Index];\r
+        if (CompareGuid ((EFI_GUID *) (Identity + 1), &UserCredential->Identifier)) {          \r
+          UserCredential->Title (\r
+                            UserCredential,\r
+                            &HiiHandle,\r
+                            &ProvId\r
+                            );\r
+          ProvStr = HiiGetString (HiiHandle, ProvId, NULL);\r
+          if (ProvStr != NULL) {\r
+            AddStr (&TmpStr, ProvStr);\r
+            FreePool (ProvStr);\r
+          }\r
+          break;\r
+        }\r
+      }\r
+      break;\r
+    }\r
+\r
+    ChkLen += Identity->Length;\r
+  }\r
+\r
+  if (TmpStr != NULL) {\r
+    HiiSetString (mCallbackInfo->HiiHandle, IpStringId, TmpStr, NULL);\r
+    FreePool (TmpStr);\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Display modify user information form.\r
+\r
+  This form displays, username, create Date, usage date, usage count, identity policy,\r
+  and access policy.\r
+\r
+  @param[in] UserIndex       The index of the user in display list to modify.\r
+  \r
+**/\r
+VOID\r
+ModifyUserInfo (\r
+  IN UINT8                                      UserIndex\r
+  )\r
+{\r
+  EFI_STATUS               Status;\r
+  EFI_USER_PROFILE_HANDLE  CurrentUser;\r
+  UINT32                   CurrentAccessRight;\r
+  VOID                     *StartOpCodeHandle;\r
+  VOID                     *EndOpCodeHandle;\r
+  EFI_IFR_GUID_LABEL       *StartLabel;\r
+  EFI_IFR_GUID_LABEL       *EndLabel;\r
+\r
+  //\r
+  // Initialize the container for dynamic opcodes.\r
+  //\r
+  StartOpCodeHandle = HiiAllocateOpCodeHandle ();\r
+  ASSERT (StartOpCodeHandle != NULL);\r
+\r
+  EndOpCodeHandle = HiiAllocateOpCodeHandle ();\r
+  ASSERT (EndOpCodeHandle != NULL);\r
+\r
+  //\r
+  // Create Hii Extend Label OpCode.\r
+  //\r
+  StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (\r
+                                        StartOpCodeHandle,\r
+                                        &gEfiIfrTianoGuid,\r
+                                        NULL,\r
+                                        sizeof (EFI_IFR_GUID_LABEL)\r
+                                        );\r
+  StartLabel->ExtendOpCode  = EFI_IFR_EXTEND_OP_LABEL;\r
+  StartLabel->Number        = LABEL_USER_INFO_FUNC;\r
+\r
+  EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (\r
+                                      EndOpCodeHandle,\r
+                                      &gEfiIfrTianoGuid,\r
+                                      NULL,\r
+                                      sizeof (EFI_IFR_GUID_LABEL)\r
+                                      );\r
+  EndLabel->ExtendOpCode  = EFI_IFR_EXTEND_OP_LABEL;\r
+  EndLabel->Number        = LABEL_END;\r
+\r
+  //\r
+  // Find the user profile to be modified.\r
+  //\r
+  mModifyUser = NULL;\r
+  Status      = mUserManager->GetNext (mUserManager, &mModifyUser);\r
+  if (EFI_ERROR (Status)) {\r
+    return ;\r
+  }\r
+\r
+  while (UserIndex > 1) {\r
+    Status = mUserManager->GetNext (mUserManager, &mModifyUser);\r
+    if (EFI_ERROR (Status)) {\r
+      return ;\r
+    }\r
+    UserIndex--;\r
+  }\r
+  \r
+  //\r
+  // Get user profile information.\r
+  //\r
+  GetAllUserInfo ();\r
+\r
+  //\r
+  // Update user name.\r
+  HiiSetString (\r
+    mCallbackInfo->HiiHandle,\r
+    STRING_TOKEN (STR_USER_NAME_VAL),\r
+    mUserInfo.UserName,\r
+    NULL\r
+    );\r
+  \r
+  //\r
+  // Update create date.\r
+  //\r
+  if (mUserInfo.CreateDateExist) {\r
+    ResolveDate (&mUserInfo.CreateDate, STRING_TOKEN (STR_CREATE_DATE_VAL));\r
+  } else {\r
+    HiiSetString (\r
+      mCallbackInfo->HiiHandle,\r
+      STRING_TOKEN (STR_CREATE_DATE_VAL),\r
+      L"",\r
+      NULL\r
+      );\r
+  }\r
+  \r
+  //\r
+  // Add usage date.\r
+  //\r
+  if (mUserInfo.UsageDateExist) {\r
+    ResolveDate (&mUserInfo.UsageDate, STRING_TOKEN (STR_USAGE_DATE_VAL));\r
+  } else {\r
+    HiiSetString (\r
+      mCallbackInfo->HiiHandle,\r
+      STRING_TOKEN (STR_USAGE_DATE_VAL),\r
+      L"",\r
+      NULL\r
+      );\r
+  }\r
+  \r
+  //\r
+  // Add usage count.\r
+  //\r
+  ResolveCount ((UINT32) mUserInfo.UsageCount, STRING_TOKEN (STR_USAGE_COUNT_VAL));\r
+  \r
+  //\r
+  // Add identity policy.\r
+  //\r
+  mUserManager->Current (mUserManager, &CurrentUser);\r
+  if (mModifyUser == CurrentUser) {\r
+    ResolveIdentityPolicy (\r
+      mUserInfo.IdentityPolicy,\r
+      mUserInfo.IdentityPolicyLen,\r
+      STRING_TOKEN (STR_IDENTIFY_POLICY_VAL)\r
+      );\r
+    HiiCreateGotoOpCode (\r
+      StartOpCodeHandle,                                  // Container for opcodes\r
+      FORMID_MODIFY_IP,                                   // Target Form ID\r
+      STRING_TOKEN (STR_IDENTIFY_POLICY),                 // Prompt text\r
+      STRING_TOKEN (STR_IDENTIFY_POLICY_VAL),             // Help text\r
+      EFI_IFR_FLAG_CALLBACK,                              // Question flag\r
+      KEY_MODIFY_USER | KEY_SELECT_USER | KEY_MODIFY_IP   // Question ID\r
+      );\r
+  }\r
+  \r
+  //\r
+  // Add access policy.\r
+  //\r
+  Status = GetAccessRight (&CurrentAccessRight);\r
+  if (EFI_ERROR (Status)) {\r
+    CurrentAccessRight = EFI_USER_INFO_ACCESS_ENROLL_SELF;\r
+  }\r
+\r
+  if (CurrentAccessRight == EFI_USER_INFO_ACCESS_MANAGE) {\r
+    HiiCreateGotoOpCode (\r
+      StartOpCodeHandle,                                  // Container for opcodes\r
+      FORMID_MODIFY_AP,                                   // Target Form ID\r
+      STRING_TOKEN (STR_ACCESS_POLICY),                   // Prompt text\r
+      STRING_TOKEN (STR_NULL_STRING),                     // Help text\r
+      EFI_IFR_FLAG_CALLBACK,                              // Question flag\r
+      KEY_MODIFY_USER | KEY_SELECT_USER | KEY_MODIFY_AP   // Question ID\r
+      );\r
+  }\r
+\r
+  HiiUpdateForm (\r
+    mCallbackInfo->HiiHandle,                             // HII handle\r
+    &mUserProfileManagerGuid,                             // Formset GUID\r
+    FORMID_USER_INFO,                                     // Form ID\r
+    StartOpCodeHandle,                                    // Label\r
+    EndOpCodeHandle                                       // Replace data\r
+    );\r
+\r
+  HiiFreeOpCodeHandle (StartOpCodeHandle);\r
+  HiiFreeOpCodeHandle (EndOpCodeHandle);\r
+}\r
+\r
+\r
+/**\r
+  Get all the access policy info from current user info, and save in the global\r
+  variable.\r
+\r
+**/\r
+VOID\r
+ResolveAccessPolicy (\r
+  VOID\r
+  )\r
+{\r
+  UINTN                         OffSet;\r
+  EFI_USER_INFO_ACCESS_CONTROL  Control;\r
+  UINTN                         ValLen;\r
+  UINT8                         *AccessData;\r
+\r
+  //\r
+  // Set default value \r
+  //\r
+  mAccessInfo.AccessRight       = EFI_USER_INFO_ACCESS_ENROLL_SELF;\r
+  mAccessInfo.AccessSetup       = ACCESS_SETUP_RESTRICTED;\r
+  mAccessInfo.AccessBootOrder   = EFI_USER_INFO_ACCESS_BOOT_ORDER_INSERT;\r
+\r
+  mAccessInfo.LoadPermitLen     = 0;\r
+  mAccessInfo.LoadForbidLen     = 0;\r
+  mAccessInfo.ConnectPermitLen  = 0;\r
+  mAccessInfo.ConnectForbidLen  = 0;\r
+  \r
+  //\r
+  // Get each user access policy.\r
+  //\r
+  OffSet = 0;\r
+  while (OffSet < mUserInfo.AccessPolicyLen) {\r
+    CopyMem (&Control, mUserInfo.AccessPolicy + OffSet, sizeof (Control));    \r
+    ValLen = Control.Size - sizeof (Control);\r
+    switch (Control.Type) {\r
+    case EFI_USER_INFO_ACCESS_ENROLL_SELF:\r
+      mAccessInfo.AccessRight = EFI_USER_INFO_ACCESS_ENROLL_SELF;\r
+      break;\r
+\r
+    case EFI_USER_INFO_ACCESS_ENROLL_OTHERS:\r
+      mAccessInfo.AccessRight = EFI_USER_INFO_ACCESS_ENROLL_OTHERS;\r
+      break;\r
+\r
+    case EFI_USER_INFO_ACCESS_MANAGE:\r
+      mAccessInfo.AccessRight = EFI_USER_INFO_ACCESS_MANAGE;\r
+      break;\r
+\r
+    case EFI_USER_INFO_ACCESS_SETUP:\r
+      AccessData = mUserInfo.AccessPolicy + OffSet + sizeof (Control);\r
+      if (CompareGuid ((EFI_GUID *) AccessData, &gEfiUserInfoAccessSetupNormalGuid)) {\r
+        mAccessInfo.AccessSetup = ACCESS_SETUP_NORMAL;\r
+      } else if (CompareGuid ((EFI_GUID *) AccessData, &gEfiUserInfoAccessSetupRestrictedGuid)) {\r
+        mAccessInfo.AccessSetup = ACCESS_SETUP_RESTRICTED;\r
+      } else if (CompareGuid ((EFI_GUID *) AccessData, &gEfiUserInfoAccessSetupAdminGuid)) {\r
+        mAccessInfo.AccessSetup = ACCESS_SETUP_ADMIN;\r
+      }\r
+      break;\r
+\r
+    case EFI_USER_INFO_ACCESS_BOOT_ORDER:\r
+      AccessData = mUserInfo.AccessPolicy + OffSet + sizeof (Control);\r
+      CopyMem (&mAccessInfo.AccessBootOrder, AccessData, sizeof (UINT32));\r
+      break;\r
+\r
+    case EFI_USER_INFO_ACCESS_FORBID_LOAD:\r
+      if (mAccessInfo.LoadForbid != NULL) {\r
+        FreePool (mAccessInfo.LoadForbid);\r
+      }\r
+\r
+      mAccessInfo.LoadForbid = AllocateZeroPool (ValLen);\r
+      if (mAccessInfo.LoadForbid != NULL) {\r
+        AccessData = mUserInfo.AccessPolicy + OffSet + sizeof (Control);\r
+        CopyMem (mAccessInfo.LoadForbid, AccessData, ValLen);\r
+        mAccessInfo.LoadForbidLen = ValLen;\r
+      }\r
+      break;\r
+\r
+    case EFI_USER_INFO_ACCESS_PERMIT_LOAD:\r
+      if (mAccessInfo.LoadPermit != NULL) {\r
+        FreePool (mAccessInfo.LoadPermit);\r
+      }\r
+\r
+      mAccessInfo.LoadPermit = AllocateZeroPool (ValLen);\r
+      if (mAccessInfo.LoadPermit != NULL) {\r
+        AccessData = mUserInfo.AccessPolicy + OffSet + sizeof (Control);\r
+        CopyMem (mAccessInfo.LoadPermit, AccessData, ValLen);\r
+        mAccessInfo.LoadPermitLen = ValLen;\r
+      }\r
+      break;\r
+\r
+    case EFI_USER_INFO_ACCESS_FORBID_CONNECT:\r
+      if (mAccessInfo.ConnectForbid != NULL) {\r
+        FreePool (mAccessInfo.ConnectForbid);\r
+      }\r
+\r
+      mAccessInfo.ConnectForbid = AllocateZeroPool (ValLen);\r
+      if (mAccessInfo.ConnectForbid != NULL) {\r
+        AccessData = mUserInfo.AccessPolicy + OffSet + sizeof (Control);\r
+        CopyMem (mAccessInfo.ConnectForbid, AccessData, ValLen);\r
+        mAccessInfo.ConnectForbidLen = ValLen;\r
+      }\r
+      break;\r
+\r
+    case EFI_USER_INFO_ACCESS_PERMIT_CONNECT:\r
+      if (mAccessInfo.ConnectPermit != NULL) {\r
+        FreePool (mAccessInfo.ConnectPermit);\r
+      }\r
+\r
+      mAccessInfo.ConnectPermit = AllocateZeroPool (ValLen);\r
+      if (mAccessInfo.ConnectPermit != NULL) {\r
+        AccessData = mUserInfo.AccessPolicy + OffSet + sizeof (Control);\r
+        CopyMem (mAccessInfo.ConnectPermit, AccessData, ValLen);\r
+        mAccessInfo.ConnectPermitLen = ValLen;\r
+      }\r
+      break;\r
+    }\r
+\r
+    OffSet += Control.Size;\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Find the specified info in profile mModifyUser by the InfoType.\r
+\r
+  @param[in]  InfoType     The user information type to find.\r
+  @param[out] UserInfo     Points to user information handle found.\r
+  \r
+  @retval EFI_SUCCESS      Find the user information successfully.\r
+  @retval Others           Fail to find the user information.\r
+\r
+**/\r
+EFI_STATUS\r
+FindInfoByType (\r
+  IN  UINT8                                     InfoType,\r
+  OUT EFI_USER_INFO_HANDLE                      *UserInfo\r
+  )\r
+{\r
+  EFI_STATUS    Status;\r
+  EFI_USER_INFO *Info;\r
+  UINTN         InfoSize;\r
+  UINTN         MemSize;\r
+\r
+  if (UserInfo == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  *UserInfo = NULL;\r
+  //\r
+  // Allocate user information memory.\r
+  //\r
+  MemSize = sizeof (EFI_USER_INFO) + 63;\r
+  Info    = AllocateZeroPool (MemSize);\r
+  if (Info == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  \r
+  //\r
+  // Get each user information.\r
+  //\r
+  while (TRUE) {\r
+    Status = mUserManager->GetNextInfo (mUserManager, mModifyUser, UserInfo);\r
+    if (EFI_ERROR (Status)) {\r
+      break;\r
+    }\r
+    //\r
+    // Get information.\r
+    //\r
+    InfoSize  = MemSize;\r
+    Status    = mUserManager->GetInfo (\r
+                                mUserManager,\r
+                                mModifyUser,\r
+                                *UserInfo,\r
+                                Info,\r
+                                &InfoSize\r
+                                );\r
+    if (Status == EFI_BUFFER_TOO_SMALL) {\r
+      MemSize = InfoSize;\r
+      FreePool (Info);\r
+      Info = AllocateZeroPool (MemSize);\r
+      if (Info == NULL) {\r
+        return EFI_OUT_OF_RESOURCES;\r
+      }\r
+      Status = mUserManager->GetInfo (\r
+                               mUserManager,\r
+                               mModifyUser,\r
+                               *UserInfo,\r
+                               Info,\r
+                               &InfoSize\r
+                               );\r
+    }\r
+    if (Status == EFI_SUCCESS) {\r
+      if (Info->InfoType == InfoType) {\r
+        break;\r
+      }\r
+    }\r
+  }\r
+\r
+  FreePool (Info);\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Display modify user access policy form.\r
+\r
+  In this form, access right, access setup and access boot order are dynamically\r
+  added. Load devicepath and connect devicepath are displayed too.\r
+  \r
+**/\r
+VOID\r
+ModidyAccessPolicy (\r
+  VOID\r
+  )\r
+{\r
+  VOID                *StartOpCodeHandle;\r
+  VOID                *EndOpCodeHandle;\r
+  VOID                *OptionsOpCodeHandle;\r
+  EFI_IFR_GUID_LABEL  *StartLabel;\r
+  EFI_IFR_GUID_LABEL  *EndLabel;\r
+  VOID                *DefaultOpCodeHandle;\r
+  \r
+  //\r
+  // Initialize the container for dynamic opcodes.\r
+  //\r
+  StartOpCodeHandle = HiiAllocateOpCodeHandle ();\r
+  ASSERT (StartOpCodeHandle != NULL);\r
+\r
+  EndOpCodeHandle = HiiAllocateOpCodeHandle ();\r
+  ASSERT (EndOpCodeHandle != NULL);\r
+\r
+  //\r
+  // Create Hii Extend Label OpCode.\r
+  //\r
+  StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (\r
+                                        StartOpCodeHandle,\r
+                                        &gEfiIfrTianoGuid,\r
+                                        NULL,\r
+                                        sizeof (EFI_IFR_GUID_LABEL)\r
+                                        );\r
+  StartLabel->ExtendOpCode  = EFI_IFR_EXTEND_OP_LABEL;\r
+  StartLabel->Number        = LABEL_AP_MOD_FUNC;\r
+\r
+  EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (\r
+                                      EndOpCodeHandle,\r
+                                      &gEfiIfrTianoGuid,\r
+                                      NULL,\r
+                                      sizeof (EFI_IFR_GUID_LABEL)\r
+                                      );\r
+  EndLabel->ExtendOpCode  = EFI_IFR_EXTEND_OP_LABEL;\r
+  EndLabel->Number        = LABEL_END;\r
+\r
+\r
+  //\r
+  // Resolve access policy information.\r
+  //\r
+  ResolveAccessPolicy ();\r
+\r
+  //\r
+  // Add access right one-of-code.\r
+  //\r
+  OptionsOpCodeHandle = HiiAllocateOpCodeHandle ();\r
+  ASSERT (OptionsOpCodeHandle != NULL);\r
+  DefaultOpCodeHandle = HiiAllocateOpCodeHandle ();\r
+  ASSERT (DefaultOpCodeHandle != NULL);\r
+  \r
+  HiiCreateOneOfOptionOpCode (\r
+    OptionsOpCodeHandle,\r
+    STRING_TOKEN (STR_NORMAL),\r
+    0,\r
+    EFI_IFR_NUMERIC_SIZE_1,\r
+    EFI_USER_INFO_ACCESS_ENROLL_SELF\r
+    );\r
+\r
+  HiiCreateOneOfOptionOpCode (\r
+    OptionsOpCodeHandle,\r
+    STRING_TOKEN (STR_ENROLL),\r
+    0,\r
+    EFI_IFR_NUMERIC_SIZE_1,\r
+    EFI_USER_INFO_ACCESS_ENROLL_OTHERS\r
+    );\r
+\r
+  HiiCreateOneOfOptionOpCode (\r
+    OptionsOpCodeHandle,\r
+    STRING_TOKEN (STR_MANAGE),\r
+    0,\r
+    EFI_IFR_NUMERIC_SIZE_1,\r
+    EFI_USER_INFO_ACCESS_MANAGE\r
+    );\r
+\r
+  HiiCreateDefaultOpCode (\r
+    DefaultOpCodeHandle, \r
+    EFI_HII_DEFAULT_CLASS_STANDARD, \r
+    EFI_IFR_NUMERIC_SIZE_1, \r
+    mAccessInfo.AccessRight\r
+    );\r
\r
+  HiiCreateOneOfOpCode (\r
+    StartOpCodeHandle,                    // Container for dynamic created opcodes\r
+    KEY_MODIFY_USER | KEY_SELECT_USER | KEY_MODIFY_AP | KEY_MODIFY_RIGHT, // Question ID\r
+    0,                                    // VarStore ID\r
+    0,                                    // Offset in Buffer Storage\r
+    STRING_TOKEN (STR_ACCESS_RIGHT),      // Question prompt text\r
+    STRING_TOKEN (STR_ACCESS_RIGHT_HELP), // Question help text\r
+    EFI_IFR_FLAG_CALLBACK,                // Question flag\r
+    EFI_IFR_NUMERIC_SIZE_1,               // Data type of Question Value\r
+    OptionsOpCodeHandle,                  // Option Opcode list\r
+    DefaultOpCodeHandle                   // Default Opcode\r
+    );\r
+  HiiFreeOpCodeHandle (DefaultOpCodeHandle);\r
+  HiiFreeOpCodeHandle (OptionsOpCodeHandle);\r
+\r
+\r
+  //\r
+  // Add setup type one-of-code.\r
+  //\r
+  OptionsOpCodeHandle = HiiAllocateOpCodeHandle ();\r
+  ASSERT (OptionsOpCodeHandle != NULL);\r
+  DefaultOpCodeHandle = HiiAllocateOpCodeHandle ();\r
+  ASSERT (DefaultOpCodeHandle != NULL);\r
+  \r
+  HiiCreateOneOfOptionOpCode (\r
+    OptionsOpCodeHandle,\r
+    STRING_TOKEN (STR_RESTRICTED),\r
+    0,\r
+    EFI_IFR_NUMERIC_SIZE_1,\r
+    ACCESS_SETUP_RESTRICTED\r
+    );\r
+    \r
+  HiiCreateOneOfOptionOpCode (\r
+    OptionsOpCodeHandle,\r
+    STRING_TOKEN (STR_NORMAL),\r
+    0,\r
+    EFI_IFR_NUMERIC_SIZE_1,\r
+    ACCESS_SETUP_NORMAL\r
+    );\r
+\r
+  HiiCreateOneOfOptionOpCode (\r
+    OptionsOpCodeHandle,\r
+    STRING_TOKEN (STR_ADMIN),\r
+    0,\r
+    EFI_IFR_NUMERIC_SIZE_1,\r
+    ACCESS_SETUP_ADMIN\r
+    );\r
+\r
+  HiiCreateDefaultOpCode (\r
+    DefaultOpCodeHandle, \r
+    EFI_HII_DEFAULT_CLASS_STANDARD, \r
+    EFI_IFR_NUMERIC_SIZE_1, \r
+    mAccessInfo.AccessSetup\r
+    );    \r
+\r
+  HiiCreateOneOfOpCode (\r
+    StartOpCodeHandle,                    // Container for dynamic created opcodes\r
+    KEY_MODIFY_USER | KEY_SELECT_USER | KEY_MODIFY_AP | KEY_MODIFY_SETUP, // Question ID\r
+    0,                                    // VarStore ID\r
+    0,                                    // Offset in Buffer Storage\r
+    STRING_TOKEN (STR_ACCESS_SETUP),      // Question prompt text\r
+    STRING_TOKEN (STR_ACCESS_SETUP_HELP), // Question help text\r
+    EFI_IFR_FLAG_CALLBACK,                // Question flag\r
+    EFI_IFR_NUMERIC_SIZE_1,               // Data type of Question Value\r
+    OptionsOpCodeHandle,                  // Option Opcode list\r
+    DefaultOpCodeHandle                   // Default Opcode\r
+    );\r
+  HiiFreeOpCodeHandle (DefaultOpCodeHandle);\r
+  HiiFreeOpCodeHandle (OptionsOpCodeHandle);\r
+  \r
+  //\r
+  // Add boot order one-of-code.\r
+  //\r
+  OptionsOpCodeHandle = HiiAllocateOpCodeHandle ();\r
+  ASSERT (OptionsOpCodeHandle != NULL);\r
+  DefaultOpCodeHandle = HiiAllocateOpCodeHandle ();\r
+  ASSERT (DefaultOpCodeHandle != NULL);\r
+  \r
+  HiiCreateOneOfOptionOpCode (\r
+    OptionsOpCodeHandle,\r
+    STRING_TOKEN (STR_INSERT),\r
+    0,\r
+    EFI_IFR_NUMERIC_SIZE_4,\r
+    EFI_USER_INFO_ACCESS_BOOT_ORDER_INSERT\r
+    );\r
+\r
+  HiiCreateOneOfOptionOpCode (\r
+    OptionsOpCodeHandle,\r
+    STRING_TOKEN (STR_APPEND),\r
+    0,\r
+    EFI_IFR_NUMERIC_SIZE_4,\r
+    EFI_USER_INFO_ACCESS_BOOT_ORDER_APPEND\r
+    );\r
+\r
+  HiiCreateOneOfOptionOpCode (\r
+    OptionsOpCodeHandle,\r
+    STRING_TOKEN (STR_REPLACE),\r
+    0,\r
+    EFI_IFR_NUMERIC_SIZE_4,\r
+    EFI_USER_INFO_ACCESS_BOOT_ORDER_REPLACE\r
+    );\r
+    \r
+  HiiCreateOneOfOptionOpCode (\r
+    OptionsOpCodeHandle,\r
+    STRING_TOKEN (STR_NODEFAULT),\r
+    0,\r
+    EFI_IFR_NUMERIC_SIZE_4,\r
+    EFI_USER_INFO_ACCESS_BOOT_ORDER_NODEFAULT\r
+    );\r
+\r
+  HiiCreateDefaultOpCode (\r
+    DefaultOpCodeHandle, \r
+    EFI_HII_DEFAULT_CLASS_STANDARD, \r
+    EFI_IFR_NUMERIC_SIZE_4, \r
+    mAccessInfo.AccessBootOrder\r
+    );\r
+    \r
+  HiiCreateOneOfOpCode (\r
+    StartOpCodeHandle,                  // Container for dynamic created opcodes\r
+    KEY_MODIFY_USER | KEY_SELECT_USER | KEY_MODIFY_AP | KEY_MODIFY_BOOT, // Question ID\r
+    0,                                  // VarStore ID\r
+    0,                                  // Offset in Buffer Storage\r
+    STRING_TOKEN (STR_BOOR_ORDER),      // Question prompt text\r
+    STRING_TOKEN (STR_BOOT_ORDER_HELP), // Question help text\r
+    EFI_IFR_FLAG_CALLBACK,              // Question flag\r
+    EFI_IFR_NUMERIC_SIZE_1,             // Data type of Question Value\r
+    OptionsOpCodeHandle,                // Option Opcode list\r
+    DefaultOpCodeHandle                 // Default Opcode\r
+    );\r
+  HiiFreeOpCodeHandle (DefaultOpCodeHandle);    \r
+  HiiFreeOpCodeHandle (OptionsOpCodeHandle);\r
+\r
+  //\r
+  // Update Form.\r
+  //\r
+  HiiUpdateForm (\r
+    mCallbackInfo->HiiHandle,           // HII handle\r
+    &mUserProfileManagerGuid,           // Formset GUID\r
+    FORMID_MODIFY_AP,                   // Form ID\r
+    StartOpCodeHandle,                  // Label for where to insert opcodes\r
+    EndOpCodeHandle                     // Replace data\r
+    );\r
+\r
+  HiiFreeOpCodeHandle (StartOpCodeHandle);\r
+  HiiFreeOpCodeHandle (EndOpCodeHandle);\r
+}\r
+\r
+\r
+/**\r
+  Expand access policy memory size.\r
+\r
+  @param[in] ValidLen       The valid access policy length.\r
+  @param[in] ExpandLen      The length that is needed to expand.\r
+    \r
+**/\r
+VOID\r
+ExpandMemory (\r
+  IN      UINTN                                 ValidLen,\r
+  IN      UINTN                                 ExpandLen\r
+  )\r
+{\r
+  UINT8 *Mem;\r
+  UINTN Len;\r
+\r
+  //\r
+  // Expand memory.\r
+  //\r
+  Len = mUserInfo.AccessPolicyLen + (ExpandLen / 64 + 1) * 64;\r
+  Mem = AllocateZeroPool (Len);\r
+  ASSERT (Mem != NULL);\r
+\r
+  if (mUserInfo.AccessPolicy != NULL) {\r
+    CopyMem (Mem, mUserInfo.AccessPolicy, ValidLen);\r
+    FreePool (mUserInfo.AccessPolicy);\r
+  }\r
+\r
+  mUserInfo.AccessPolicy    = Mem;\r
+  mUserInfo.AccessPolicyLen = Len;\r
+}\r
+\r
+\r
+/**\r
+  Collect all the access policy data to mUserInfo.AccessPolicy, \r
+  and save it to user profile.\r
+\r
+**/\r
+VOID\r
+SaveAccessPolicy (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  UINTN                         OffSet;\r
+  UINTN                         Size;\r
+  EFI_USER_INFO_ACCESS_CONTROL  Control;\r
+  EFI_USER_INFO_HANDLE          UserInfo;\r
+  EFI_USER_INFO                 *Info;\r
+\r
+  if (mUserInfo.AccessPolicy != NULL) {\r
+    FreePool (mUserInfo.AccessPolicy);\r
+  }\r
+  mUserInfo.AccessPolicy          = NULL;\r
+  mUserInfo.AccessPolicyLen       = 0;\r
+  mUserInfo.AccessPolicyModified  = TRUE;\r
+  OffSet                          = 0;\r
+  \r
+  //\r
+  // Save access right.\r
+  //\r
+  Size = sizeof (EFI_USER_INFO_ACCESS_CONTROL);\r
+  if (mUserInfo.AccessPolicyLen - OffSet < Size) {\r
+    ExpandMemory (OffSet, Size);\r
+  }\r
+\r
+  Control.Type = mAccessInfo.AccessRight;\r
+  Control.Size = (UINT32) Size;\r
+  CopyMem (mUserInfo.AccessPolicy + OffSet, &Control, sizeof (Control));\r
+  OffSet += sizeof (Control);\r
+  \r
+  //\r
+  // Save access setup.\r
+  //\r
+  Size = sizeof (EFI_USER_INFO_ACCESS_CONTROL) + sizeof (EFI_GUID);\r
+  if (mUserInfo.AccessPolicyLen - OffSet < Size) {\r
+    ExpandMemory (OffSet, Size);\r
+  }\r
+\r
+  Control.Type = EFI_USER_INFO_ACCESS_SETUP;\r
+  Control.Size = (UINT32) Size;  \r
+  CopyMem (mUserInfo.AccessPolicy + OffSet, &Control, sizeof (Control));\r
+  OffSet += sizeof (Control);\r
+  \r
+  if (mAccessInfo.AccessSetup == ACCESS_SETUP_NORMAL) {\r
+    CopyGuid ((EFI_GUID *) (mUserInfo.AccessPolicy + OffSet), &gEfiUserInfoAccessSetupNormalGuid);\r
+  } else if (mAccessInfo.AccessSetup == ACCESS_SETUP_RESTRICTED) {\r
+    CopyGuid ((EFI_GUID *) (mUserInfo.AccessPolicy + OffSet), &gEfiUserInfoAccessSetupRestrictedGuid);\r
+  } else if (mAccessInfo.AccessSetup == ACCESS_SETUP_ADMIN) {\r
+    CopyGuid ((EFI_GUID *) (mUserInfo.AccessPolicy + OffSet), &gEfiUserInfoAccessSetupAdminGuid);\r
+  }\r
+  OffSet += sizeof (EFI_GUID);\r
+  \r
+  //\r
+  // Save access of boot order.\r
+  //\r
+  Size = sizeof (EFI_USER_INFO_ACCESS_CONTROL) + sizeof (UINT32);\r
+  if (mUserInfo.AccessPolicyLen - OffSet < Size) {\r
+    ExpandMemory (OffSet, Size);\r
+  }\r
+\r
+  Control.Type = EFI_USER_INFO_ACCESS_BOOT_ORDER;\r
+  Control.Size = (UINT32) Size;  \r
+  CopyMem (mUserInfo.AccessPolicy + OffSet, &Control, sizeof (Control));\r
+  OffSet += sizeof (Control);\r
+\r
+  CopyMem ((UINT8 *) (mUserInfo.AccessPolicy + OffSet), &mAccessInfo.AccessBootOrder, sizeof (UINT32));\r
+  OffSet += sizeof (UINT32);\r
+  \r
+  //\r
+  // Save permit load.\r
+  //\r
+  if (mAccessInfo.LoadPermitLen > 0) {\r
+    Size = sizeof (EFI_USER_INFO_ACCESS_CONTROL) + mAccessInfo.LoadPermitLen;\r
+    if (mUserInfo.AccessPolicyLen - OffSet < Size) {\r
+      ExpandMemory (OffSet, Size);\r
+    }\r
+\r
+    Control.Type = EFI_USER_INFO_ACCESS_PERMIT_LOAD;\r
+    Control.Size = (UINT32) Size;  \r
+    CopyMem (mUserInfo.AccessPolicy + OffSet, &Control, sizeof (Control));\r
+    OffSet += sizeof (Control);\r
+  \r
+    CopyMem (mUserInfo.AccessPolicy + OffSet, mAccessInfo.LoadPermit, mAccessInfo.LoadPermitLen);\r
+    OffSet += mAccessInfo.LoadPermitLen;\r
+  }\r
+  \r
+  //\r
+  // Save forbid load.\r
+  //\r
+  if (mAccessInfo.LoadForbidLen > 0) {\r
+    Size = sizeof (EFI_USER_INFO_ACCESS_CONTROL) + mAccessInfo.LoadForbidLen;\r
+    if (mUserInfo.AccessPolicyLen - OffSet < Size) {\r
+      ExpandMemory (OffSet, Size);\r
+    }\r
+\r
+    Control.Type = EFI_USER_INFO_ACCESS_FORBID_LOAD;\r
+    Control.Size = (UINT32) Size;  \r
+    CopyMem (mUserInfo.AccessPolicy + OffSet, &Control, sizeof (Control));\r
+    OffSet += sizeof (Control);\r
+    \r
+    CopyMem (mUserInfo.AccessPolicy + OffSet, mAccessInfo.LoadForbid, mAccessInfo.LoadForbidLen);\r
+    OffSet += mAccessInfo.LoadForbidLen;\r
+  }\r
+  \r
+  //\r
+  // Save permit connect.\r
+  //\r
+  if (mAccessInfo.ConnectPermitLen > 0) {\r
+    Size = sizeof (EFI_USER_INFO_ACCESS_CONTROL) + mAccessInfo.ConnectPermitLen;\r
+    if (mUserInfo.AccessPolicyLen - OffSet < Size) {\r
+      ExpandMemory (OffSet, Size);\r
+    }\r
+\r
+    Control.Type = EFI_USER_INFO_ACCESS_PERMIT_CONNECT;\r
+    Control.Size = (UINT32) Size;  \r
+    CopyMem (mUserInfo.AccessPolicy + OffSet, &Control, sizeof (Control));\r
+    OffSet += sizeof (Control);\r
+    \r
+    CopyMem (mUserInfo.AccessPolicy + OffSet, mAccessInfo.ConnectPermit, mAccessInfo.ConnectPermitLen);\r
+    OffSet += mAccessInfo.ConnectPermitLen;\r
+  }\r
+  \r
+  //\r
+  // Save forbid connect.\r
+  //\r
+  if (mAccessInfo.ConnectForbidLen > 0) {\r
+    Size = sizeof (EFI_USER_INFO_ACCESS_CONTROL) + mAccessInfo.ConnectForbidLen;\r
+    if (mUserInfo.AccessPolicyLen - OffSet < Size) {\r
+      ExpandMemory (OffSet, Size);\r
+    }\r
+\r
+    Control.Type = EFI_USER_INFO_ACCESS_FORBID_CONNECT;\r
+    Control.Size = (UINT32) Size;  \r
+    CopyMem (mUserInfo.AccessPolicy + OffSet, &Control, sizeof (Control));\r
+    OffSet += sizeof (Control);\r
+    \r
+    CopyMem (mUserInfo.AccessPolicy + OffSet, mAccessInfo.ConnectForbid, mAccessInfo.ConnectForbidLen);\r
+    OffSet += mAccessInfo.ConnectForbidLen;\r
+  }\r
+\r
+  mUserInfo.AccessPolicyLen = OffSet;\r
+\r
+  //\r
+  // Save access policy.\r
+  //\r
+  if (mUserInfo.AccessPolicyModified && (mUserInfo.AccessPolicyLen > 0)) {\r
+    Info = AllocateZeroPool (sizeof (EFI_USER_INFO) + mUserInfo.AccessPolicyLen);\r
+    if (Info == NULL) {\r
+      return ;\r
+    }\r
+\r
+    Status = FindInfoByType (EFI_USER_INFO_ACCESS_POLICY_RECORD, &UserInfo);\r
+    if (!EFI_ERROR (Status)) {\r
+      Info->InfoType    = EFI_USER_INFO_ACCESS_POLICY_RECORD;\r
+      Info->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV |\r
+                          EFI_USER_INFO_PUBLIC |\r
+                          EFI_USER_INFO_EXCLUSIVE;\r
+      Info->InfoSize    = (UINT32) (sizeof (EFI_USER_INFO) + mUserInfo.AccessPolicyLen);\r
+      CopyMem ((UINT8 *) (Info + 1), mUserInfo.AccessPolicy, mUserInfo.AccessPolicyLen);\r
+      Status = mUserManager->SetInfo (\r
+                               mUserManager,\r
+                               mModifyUser,\r
+                               &UserInfo,\r
+                               Info,\r
+                               Info->InfoSize\r
+                               );\r
+      mUserInfo.AccessPolicyModified = FALSE;\r
+    }\r
+    FreePool (Info);\r
+  }\r
+\r
+  if (mAccessInfo.ConnectForbid != NULL) {\r
+    FreePool (mAccessInfo.ConnectForbid);\r
+    mAccessInfo.ConnectForbid = NULL;\r
+  }\r
+\r
+  if (mAccessInfo.ConnectPermit != NULL) {\r
+    FreePool (mAccessInfo.ConnectPermit);\r
+    mAccessInfo.ConnectPermit = NULL;\r
+  }\r
+\r
+  if (mAccessInfo.LoadForbid != NULL) {\r
+    FreePool (mAccessInfo.LoadForbid);\r
+    mAccessInfo.LoadForbid = NULL;\r
+  }\r
+\r
+  if (mAccessInfo.LoadPermit != NULL) {\r
+    FreePool (mAccessInfo.LoadPermit);\r
+    mAccessInfo.LoadPermit = NULL;\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Get the username from user input, and update username string in the Hii \r
+  database with it.\r
+\r
+**/\r
+VOID\r
+ModifyUserName (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  CHAR16                  UserName[USER_NAME_LENGTH];\r
+  UINTN                   Len;\r
+  EFI_INPUT_KEY           Key;\r
+  EFI_USER_INFO_HANDLE    UserInfo;\r
+  EFI_USER_INFO           *Info;\r
+  EFI_USER_PROFILE_HANDLE TempUser;\r
+\r
+  //\r
+  // Get the new user name.\r
+  //\r
+  Len = sizeof (UserName);\r
+  Status = GetUserNameInput (&Len, UserName);\r
+  if (EFI_ERROR (Status)) {\r
+    if (Status != EFI_ABORTED) {\r
+      CreatePopUp (\r
+        EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+        &Key,\r
+        L"Failed To Get User Name.",\r
+        L"",\r
+        L"Please Press Any Key to Continue ...",\r
+        NULL\r
+        );\r
+    }\r
+    return ;\r
+  }\r
+  \r
+  //\r
+  // Check whether the username had been used or not.\r
+  //\r
+  Info = AllocateZeroPool (sizeof (EFI_USER_INFO) + Len);\r
+  if (Info == NULL) {\r
+    return ;\r
+  }\r
+\r
+  Info->InfoType    = EFI_USER_INFO_NAME_RECORD;\r
+  Info->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV |\r
+                      EFI_USER_INFO_PUBLIC |\r
+                      EFI_USER_INFO_EXCLUSIVE;\r
+  Info->InfoSize    = (UINT32) (sizeof (EFI_USER_INFO) + Len);\r
+  CopyMem ((UINT8 *) (Info + 1), UserName, Len);\r
+\r
+  TempUser  = NULL;\r
+  Status    = mUserManager->Find (\r
+                              mUserManager,\r
+                              &TempUser,\r
+                              NULL,\r
+                              Info,\r
+                              Info->InfoSize\r
+                              );\r
+  if (!EFI_ERROR (Status)) {\r
+    CreatePopUp (\r
+      EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+      &Key,\r
+      L"The User Name Had Been Used.",\r
+      L"",\r
+      L"Please Use Other User Name",\r
+      NULL\r
+      );\r
+    FreePool (Info);\r
+    return ;\r
+  }\r
+  \r
+  //\r
+  // Update username display in the form.\r
+  //\r
+  CopyMem (mUserInfo.UserName, UserName, Len);\r
+  HiiSetString (\r
+    mCallbackInfo->HiiHandle, \r
+    STRING_TOKEN (STR_USER_NAME_VAL), \r
+    mUserInfo.UserName, \r
+    NULL\r
+    );\r
+\r
+  //\r
+  // Save the user name.\r
+  //\r
+  Status = FindInfoByType (EFI_USER_INFO_NAME_RECORD, &UserInfo);\r
+  if (!EFI_ERROR (Status)) {\r
+    mUserManager->SetInfo (\r
+                    mUserManager,\r
+                    mModifyUser,\r
+                    &UserInfo,\r
+                    Info,\r
+                    Info->InfoSize\r
+                    );\r
+  }\r
+  FreePool (Info);\r
+}\r
+\r
+\r
+/**\r
+  Display the form of the modifying user identity policy.\r
+\r
+**/\r
+VOID\r
+ModifyIdentityPolicy (\r
+  VOID\r
+  )\r
+{\r
+  UINTN               Index;\r
+  CHAR16              *ProvStr;\r
+  EFI_STRING_ID       ProvID;\r
+  EFI_HII_HANDLE      HiiHandle;\r
+  VOID                *OptionsOpCodeHandle;\r
+  VOID                *StartOpCodeHandle;\r
+  VOID                *EndOpCodeHandle;\r
+  EFI_IFR_GUID_LABEL  *StartLabel;\r
+  EFI_IFR_GUID_LABEL  *EndLabel;\r
+\r
+  //\r
+  // Initialize the container for dynamic opcodes.\r
+  //\r
+  StartOpCodeHandle = HiiAllocateOpCodeHandle ();\r
+  ASSERT (StartOpCodeHandle != NULL);\r
+\r
+  EndOpCodeHandle = HiiAllocateOpCodeHandle ();\r
+  ASSERT (EndOpCodeHandle != NULL);\r
+\r
+  //\r
+  // Create Hii Extend Label OpCode.\r
+  //\r
+  StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (\r
+                                        StartOpCodeHandle,\r
+                                        &gEfiIfrTianoGuid,\r
+                                        NULL,\r
+                                        sizeof (EFI_IFR_GUID_LABEL)\r
+                                        );\r
+  StartLabel->ExtendOpCode  = EFI_IFR_EXTEND_OP_LABEL;\r
+  StartLabel->Number        = LABEL_IP_MOD_FUNC;\r
+\r
+  EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (\r
+                                      EndOpCodeHandle,\r
+                                      &gEfiIfrTianoGuid,\r
+                                      NULL,\r
+                                      sizeof (EFI_IFR_GUID_LABEL)\r
+                                      );\r
+  EndLabel->ExtendOpCode  = EFI_IFR_EXTEND_OP_LABEL;\r
+  EndLabel->Number        = LABEL_END;\r
+\r
+  //\r
+  // Add credential providers\r
+  //.\r
+  if (mProviderInfo->Count > 0) {\r
+    OptionsOpCodeHandle = HiiAllocateOpCodeHandle ();\r
+    ASSERT (OptionsOpCodeHandle != NULL);\r
+\r
+    //\r
+    // Add credential provider Option OpCode.\r
+    //\r
+    for (Index = 0; Index < mProviderInfo->Count; Index++) {\r
+      mProviderInfo->Provider[Index]->Title (\r
+                                        mProviderInfo->Provider[Index],\r
+                                        &HiiHandle,\r
+                                        &ProvID\r
+                                        );\r
+      ProvStr = HiiGetString (HiiHandle, ProvID, NULL);\r
+      ProvID  = HiiSetString (mCallbackInfo->HiiHandle, 0, ProvStr, NULL);\r
+      FreePool (ProvStr);\r
+      if (ProvID == 0) {\r
+        return ;\r
+      }\r
+\r
+      HiiCreateOneOfOptionOpCode (\r
+        OptionsOpCodeHandle,\r
+        ProvID,\r
+        0,\r
+        EFI_IFR_NUMERIC_SIZE_1,\r
+        (UINT8) Index\r
+        );\r
+    }\r
+\r
+    HiiCreateOneOfOpCode (\r
+      StartOpCodeHandle,                // Container for dynamic created opcodes\r
+      KEY_MODIFY_USER | KEY_SELECT_USER | KEY_MODIFY_IP | KEY_MODIFY_PROV,  // Question ID\r
+      0,                                // VarStore ID\r
+      0,                                // Offset in Buffer Storage\r
+      STRING_TOKEN (STR_PROVIDER),      // Question prompt text\r
+      STRING_TOKEN (STR_PROVIDER_HELP), // Question help text\r
+      EFI_IFR_FLAG_CALLBACK,            // Question flag\r
+      EFI_IFR_NUMERIC_SIZE_1,           // Data type of Question Value\r
+      OptionsOpCodeHandle,              // Option Opcode list\r
+      NULL                              // Default Opcode is NULl\r
+      );\r
+\r
+    HiiFreeOpCodeHandle (OptionsOpCodeHandle);\r
+  }\r
+  \r
+  //\r
+  // Add logical connector Option OpCode.\r
+  //\r
+  OptionsOpCodeHandle = HiiAllocateOpCodeHandle ();\r
+  ASSERT (OptionsOpCodeHandle != NULL);\r
+\r
+  HiiCreateOneOfOptionOpCode (\r
+    OptionsOpCodeHandle,\r
+    STRING_TOKEN (STR_AND_CON),\r
+    0,\r
+    EFI_IFR_NUMERIC_SIZE_1,\r
+    0\r
+    );\r
+\r
+  HiiCreateOneOfOptionOpCode (\r
+    OptionsOpCodeHandle,\r
+    STRING_TOKEN (STR_OR_CON),\r
+    0,\r
+    EFI_IFR_NUMERIC_SIZE_1,\r
+    1\r
+    );\r
+\r
+  HiiCreateOneOfOpCode (\r
+    StartOpCodeHandle,                  // Container for dynamic created opcodes\r
+    KEY_MODIFY_USER | KEY_SELECT_USER | KEY_MODIFY_IP | KEY_MODIFY_CONN,  // Question ID\r
+    0,                                  // VarStore ID\r
+    0,                                  // Offset in Buffer Storage\r
+    STRING_TOKEN (STR_CONNECTOR),       // Question prompt text\r
+    STRING_TOKEN (STR_CONNECTOR_HELP),  // Question help text\r
+    EFI_IFR_FLAG_CALLBACK,              // Question flag\r
+    EFI_IFR_NUMERIC_SIZE_1,             // Data type of Question Value\r
+    OptionsOpCodeHandle,                // Option Opcode list\r
+    NULL                                // Default Opcode is NULl\r
+    );\r
+\r
+  HiiFreeOpCodeHandle (OptionsOpCodeHandle);\r
+\r
+  //\r
+  // Update identity policy in the form.\r
+  //\r
+  ResolveIdentityPolicy (\r
+    mUserInfo.IdentityPolicy, \r
+    mUserInfo.IdentityPolicyLen, \r
+    STRING_TOKEN (STR_IDENTIFY_POLICY_VALUE)\r
+    );\r
+\r
+  if (mUserInfo.NewIdentityPolicy != NULL) {\r
+    FreePool (mUserInfo.NewIdentityPolicy);\r
+    mUserInfo.NewIdentityPolicy         = NULL;\r
+    mUserInfo.NewIdentityPolicyLen      = 0;\r
+    mUserInfo.NewIdentityPolicyModified = FALSE;\r
+  }\r
+  mProviderChoice = 0;\r
+  mConncetLogical = 0;\r
+\r
+  HiiUpdateForm (\r
+    mCallbackInfo->HiiHandle, // HII handle\r
+    &mUserProfileManagerGuid, // Formset GUID\r
+    FORMID_MODIFY_IP,         // Form ID\r
+    StartOpCodeHandle,        // Label for where to insert opcodes\r
+    EndOpCodeHandle           // Replace data\r
+    );\r
+\r
+  HiiFreeOpCodeHandle (StartOpCodeHandle);\r
+  HiiFreeOpCodeHandle (EndOpCodeHandle);\r
+}\r
+\r
+\r
+/**\r
+  Save the identity policy and update UI with it.\r
+  \r
+  This funciton will verify the new identity policy, in current implementation, \r
+  the identity policy can be:  T, P & P & P & ..., P | P | P | ...\r
+  Here, "T" means "True", "P" means "Credential Provider", "&" means "and", "|" means "or".\r
+  Other identity policies are not supported.  \r
+\r
+**/\r
+VOID\r
+SaveIdentityPolicy (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  EFI_USER_INFO_IDENTITY_POLICY *Identity;\r
+  EFI_USER_INFO_HANDLE          UserInfo;\r
+  EFI_USER_INFO                 *Info;\r
+  EFI_INPUT_KEY                 Key;\r
+  UINTN                         Offset;\r
+  UINT32                        OpCode;\r
+  UINTN                         InfoSize;\r
+\r
+  if (!mUserInfo.NewIdentityPolicyModified || (mUserInfo.NewIdentityPolicyLen == 0)) {\r
+    return;\r
+  }\r
+  \r
+  //\r
+  // Check policy expression.\r
+  //\r
+  OpCode  = EFI_USER_INFO_IDENTITY_FALSE;\r
+  Offset  = 0;\r
+  while (Offset < mUserInfo.NewIdentityPolicyLen) {\r
+    //\r
+    // Check access policy according to type\r
+    //\r
+    Identity = (EFI_USER_INFO_IDENTITY_POLICY *) (mUserInfo.NewIdentityPolicy + Offset);\r
+    switch (Identity->Type) {\r
+\r
+    case EFI_USER_INFO_IDENTITY_TRUE:\r
+      break;\r
+\r
+    case EFI_USER_INFO_IDENTITY_OR:\r
+      if (OpCode == EFI_USER_INFO_IDENTITY_AND) {\r
+        CreatePopUp (\r
+          EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+          &Key,\r
+          L"Invalid Identity Policy, Mixed Connector Unsupport!",\r
+          L"",\r
+          L"Press Any Key to Continue ...",\r
+          NULL\r
+          );\r
+        return ;\r
+      }\r
+\r
+      OpCode = EFI_USER_INFO_IDENTITY_OR;\r
+      break;\r
+\r
+    case EFI_USER_INFO_IDENTITY_AND:\r
+      if (OpCode == EFI_USER_INFO_IDENTITY_OR) {\r
+        CreatePopUp (\r
+          EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+          &Key,\r
+          L"Invalid Identity Policy, Mixed Connector Unsupport!",\r
+          L"",\r
+          L"Press Any Key to Continue ...",\r
+          NULL\r
+          );\r
+        return ;\r
+      }\r
+\r
+      OpCode = EFI_USER_INFO_IDENTITY_AND;\r
+      break;\r
+\r
+    case EFI_USER_INFO_IDENTITY_CREDENTIAL_PROVIDER:\r
+      break;\r
+\r
+    default:\r
+      CreatePopUp (\r
+        EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+        &Key,\r
+        L"Unsupport parameter",\r
+        L"",\r
+        L"Press Any Key to Continue ...",\r
+        NULL\r
+        );\r
+      return ;\r
+    }\r
+    Offset += Identity->Length;\r
+  }\r
+\r
+  //\r
+  // Save identity policy.\r
+  //\r
+  Info = AllocateZeroPool (\r
+           sizeof (EFI_USER_INFO) + \r
+           mUserInfo.NewIdentityPolicyLen\r
+           );\r
+  if (Info == NULL) {\r
+    return ;\r
+  }\r
+\r
+  Status = FindInfoByType (EFI_USER_INFO_IDENTITY_POLICY_RECORD, &UserInfo);\r
+  if (EFI_ERROR (Status)) {\r
+    FreePool (Info);\r
+    return ;\r
+  }\r
+  \r
+  Info->InfoType    = EFI_USER_INFO_IDENTITY_POLICY_RECORD;\r
+  Info->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV |\r
+                      EFI_USER_INFO_PRIVATE |\r
+                      EFI_USER_INFO_EXCLUSIVE;\r
+  Info->InfoSize    = (UINT32) (sizeof (EFI_USER_INFO) + mUserInfo.NewIdentityPolicyLen);\r
+  CopyMem ((UINT8 *) (Info + 1), mUserInfo.NewIdentityPolicy, mUserInfo.NewIdentityPolicyLen);\r
+  Status = mUserManager->SetInfo (\r
+                           mUserManager,\r
+                           mModifyUser,\r
+                           &UserInfo,\r
+                           Info,\r
+                           Info->InfoSize\r
+                           );\r
+  FreePool (Info);                           \r
+  if (EFI_ERROR (Status)) {\r
+    //\r
+    // Get the user information again, it may be changed during saving it.\r
+    //\r
+    InfoSize = 0;\r
+    Status = mUserManager->GetInfo (\r
+                             mUserManager,\r
+                             mModifyUser,\r
+                             UserInfo,\r
+                             Info,\r
+                             &InfoSize\r
+                             );\r
+    if (Status == EFI_BUFFER_TOO_SMALL) {\r
+      Info = AllocateZeroPool (InfoSize);\r
+      ASSERT (Info != NULL);\r
+      Status = mUserManager->GetInfo (\r
+                               mUserManager,\r
+                               mModifyUser,\r
+                               UserInfo,\r
+                               Info,\r
+                               &InfoSize\r
+                               );\r
+    }\r
+    ASSERT_EFI_ERROR (Status);\r
+    \r
+    //\r
+    // Save current identification policy to mUserInfo.IdentityPolicy. \r
+    //\r
+    ASSERT (Info != NULL);\r
+    if (mUserInfo.IdentityPolicy != NULL) {\r
+      FreePool (mUserInfo.IdentityPolicy);\r
+    }\r
+\r
+    mUserInfo.IdentityPolicyLen = Info->InfoSize - sizeof (EFI_USER_INFO);\r
+    mUserInfo.IdentityPolicy    = AllocateCopyPool (mUserInfo.IdentityPolicyLen, Info + 1);    \r
+    ASSERT (mUserInfo.IdentityPolicy != NULL);  \r
+\r
+    //\r
+    // Free the memory\r
+    //\r
+    FreePool (Info);\r
+    FreePool (mUserInfo.NewIdentityPolicy);\r
+  } else {  \r
+    //\r
+    // Update the mUserInfo.IdentityPolicy by mUserInfo.NewIdentityPolicy\r
+    //\r
+    if (mUserInfo.IdentityPolicy != NULL) {\r
+      FreePool (mUserInfo.IdentityPolicy);\r
+    }\r
+    mUserInfo.IdentityPolicy    = mUserInfo.NewIdentityPolicy;\r
+    mUserInfo.IdentityPolicyLen = mUserInfo.NewIdentityPolicyLen;\r
+  }\r
+\r
+  mUserInfo.NewIdentityPolicy         = NULL;\r
+  mUserInfo.NewIdentityPolicyLen      = 0;\r
+  mUserInfo.NewIdentityPolicyModified = FALSE;   \r
+\r
+  //\r
+  // Update identity policy choice.\r
+  //\r
+  ResolveIdentityPolicy (\r
+    mUserInfo.IdentityPolicy, \r
+    mUserInfo.IdentityPolicyLen, \r
+    STRING_TOKEN (STR_IDENTIFY_POLICY_VAL)\r
+    );\r
+}\r
+\r
+\r
+/**\r
+  Verify the new identity policy in the current implementation. The same credential\r
+  provider can't appear twice in one identity policy.\r
+\r
+  @param[in] NewGuid       Points to the credential provider guid.\r
+  \r
+  @retval TRUE     The NewGuid was found in the identity policy.\r
+  @retval FALSE    The NewGuid was not found.\r
+\r
+**/\r
+BOOLEAN\r
+CheckIdentityPolicy (\r
+  IN EFI_GUID                                      *NewGuid\r
+  )\r
+{\r
+  UINTN                         Offset;\r
+  EFI_USER_INFO_IDENTITY_POLICY *Identity;\r
+  EFI_INPUT_KEY                 Key;\r
+\r
+  Offset = 0;\r
+  while (Offset < mUserInfo.NewIdentityPolicyLen) {\r
+    //\r
+    // Check access policy according to type.\r
+    //\r
+    Identity = (EFI_USER_INFO_IDENTITY_POLICY *) (mUserInfo.NewIdentityPolicy + Offset);\r
+    switch (Identity->Type) {\r
+\r
+    case EFI_USER_INFO_IDENTITY_TRUE:\r
+    case EFI_USER_INFO_IDENTITY_OR:\r
+    case EFI_USER_INFO_IDENTITY_AND:\r
+      break;\r
+\r
+    case EFI_USER_INFO_IDENTITY_CREDENTIAL_PROVIDER:\r
+      if (CompareGuid (NewGuid, (EFI_GUID *) (Identity + 1))) {\r
+        CreatePopUp (\r
+          EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+          &Key,\r
+          L"This Credential Provider Are Already Used!",\r
+          L"",\r
+          L"Press Any Key to Continue ...",\r
+          NULL\r
+          );\r
+        return FALSE;\r
+      }\r
+      break;\r
+\r
+    default:\r
+      CreatePopUp (\r
+        EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+        &Key,\r
+        L"Unsupport parameter",\r
+        L"",\r
+        L"Press Any Key to Continue ...",\r
+        NULL\r
+        );\r
+      return FALSE;\r
+    }\r
+\r
+    Offset += Identity->Length;\r
+  }\r
+  return TRUE;\r
+}\r
+\r
+\r
+/**\r
+  Update the mUserInfo.NewIdentityPolicy, and UI when 'add option' is pressed.\r
+\r
+**/\r
+VOID\r
+AddIdentityPolicyItem (\r
+  VOID\r
+  )\r
+{\r
+  UINT8                         *NewInfo;\r
+  EFI_USER_INFO_IDENTITY_POLICY *Policy;\r
+\r
+  if (mProviderInfo->Count == 0) {\r
+    return ;\r
+  }\r
+\r
+  if (!mUserInfo.NewIdentityPolicyModified && (mUserInfo.NewIdentityPolicyLen > 0)) {\r
+    FreePool (mUserInfo.NewIdentityPolicy);\r
+    mUserInfo.NewIdentityPolicy     = NULL;\r
+    mUserInfo.NewIdentityPolicyLen  = 0;\r
+  }\r
+  //\r
+  // Expand the identity policy memory for the newly added policy info.\r
+  //\r
+  if (mUserInfo.NewIdentityPolicyLen > 0) {\r
+    //\r
+    // The new policy is not empty, expand space for connetor and provider.\r
+    //\r
+    if (!CheckIdentityPolicy (&mProviderInfo->Provider[mProviderChoice]->Identifier)) {\r
+      return ;\r
+    }\r
+    NewInfo = AllocateZeroPool (\r
+                mUserInfo.NewIdentityPolicyLen + \r
+                sizeof (EFI_USER_INFO_IDENTITY_POLICY) * 2 + \r
+                sizeof (EFI_GUID)\r
+                );\r
+  } else {\r
+    //\r
+    // The new policy is empty, only expand space for provider.\r
+    //\r
+    NewInfo = AllocateZeroPool (\r
+                mUserInfo.NewIdentityPolicyLen + \r
+                sizeof (EFI_USER_INFO_IDENTITY_POLICY) + \r
+                sizeof (EFI_GUID)\r
+                );\r
+  }\r
+\r
+  if (NewInfo == NULL) {\r
+    return ;\r
+  }\r
+\r
+  if (mUserInfo.NewIdentityPolicyLen > 0) {\r
+    CopyMem (NewInfo, mUserInfo.NewIdentityPolicy, mUserInfo.NewIdentityPolicyLen);\r
+    FreePool (mUserInfo.NewIdentityPolicy);\r
+  }\r
+  mUserInfo.NewIdentityPolicy = NewInfo;\r
+\r
+  //\r
+  // Save logical connector.\r
+  //\r
+  if (mUserInfo.NewIdentityPolicyLen > 0) {\r
+    Policy = (EFI_USER_INFO_IDENTITY_POLICY *) (mUserInfo.NewIdentityPolicy +\r
+                                                mUserInfo.NewIdentityPolicyLen);\r
+    if (mConncetLogical == 0) {\r
+      Policy->Type = EFI_USER_INFO_IDENTITY_AND;\r
+    } else {\r
+      Policy->Type = EFI_USER_INFO_IDENTITY_OR;\r
+    }\r
+\r
+    Policy->Length = sizeof (EFI_USER_INFO_IDENTITY_POLICY);\r
+    mUserInfo.NewIdentityPolicyLen += Policy->Length;\r
+  }\r
+  \r
+  //\r
+  // Save credential provider.\r
+  //\r
+  Policy = (EFI_USER_INFO_IDENTITY_POLICY *) (mUserInfo.NewIdentityPolicy + \r
+                                              mUserInfo.NewIdentityPolicyLen);\r
+  Policy->Length = sizeof (EFI_USER_INFO_IDENTITY_POLICY) + sizeof (EFI_GUID);\r
+  Policy->Type   = EFI_USER_INFO_IDENTITY_CREDENTIAL_PROVIDER;\r
+  CopyGuid ((EFI_GUID *) (Policy + 1), &mProviderInfo->Provider[mProviderChoice]->Identifier);\r
+  mUserInfo.NewIdentityPolicyLen += Policy->Length;\r
+\r
+  //\r
+  // Update identity policy choice.\r
+  //\r
+  mUserInfo.NewIdentityPolicyModified = TRUE;\r
+  ResolveIdentityPolicy (\r
+    mUserInfo.NewIdentityPolicy, \r
+    mUserInfo.NewIdentityPolicyLen, \r
+    STRING_TOKEN (STR_IDENTIFY_POLICY_VALUE)\r
+    );\r
+}\r
+\r
+\r
+/**\r
+  Create an action OpCode with QuestionID and DevicePath on a given OpCodeHandle.\r
+\r
+  @param[in]  QuestionID            The question ID.\r
+  @param[in]  DevicePath            Points to device path.\r
+  @param[in]  OpCodeHandle          Points to container for dynamic created opcodes.\r
+\r
+**/\r
+VOID\r
+AddDevicePath (\r
+  IN  UINTN                                     QuestionID,\r
+  IN  EFI_DEVICE_PATH_PROTOCOL                  *DevicePath,\r
+  IN     VOID                                   *OpCodeHandle\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  EFI_DEVICE_PATH_PROTOCOL          *Next;\r
+  EFI_STRING_ID                     NameID;\r
+  EFI_STRING                        DriverName;\r
+  EFI_DEVICE_PATH_TO_TEXT_PROTOCOL  *DevicePathText;\r
+\r
+  //\r
+  // Locate device path to text protocol.\r
+  //\r
+  Status = gBS->LocateProtocol (\r
+                  &gEfiDevicePathToTextProtocolGuid,\r
+                  NULL,\r
+                  (VOID **) &DevicePathText\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return ;\r
+  }\r
+  \r
+  //\r
+  // Get driver file name node.\r
+  //\r
+  Next = DevicePath;\r
+  while (!IsDevicePathEnd (Next)) {\r
+    DevicePath  = Next;\r
+    Next        = NextDevicePathNode (Next);\r
+  }\r
+\r
+  //\r
+  // Display the device path in form.\r
+  //\r
+  DriverName = DevicePathText->ConvertDevicePathToText (DevicePath, FALSE, FALSE);\r
+  NameID = HiiSetString (mCallbackInfo->HiiHandle, 0, DriverName, NULL);\r
+  FreePool (DriverName);\r
+  if (NameID == 0) {\r
+    return ;\r
+  }\r
+\r
+  HiiCreateActionOpCode (\r
+    OpCodeHandle,                   // Container for dynamic created opcodes\r
+    (UINT16) QuestionID,            // Question ID\r
+    NameID,                         // Prompt text\r
+    STRING_TOKEN (STR_NULL_STRING), // Help text\r
+    EFI_IFR_FLAG_CALLBACK,          // Question flag\r
+    0                               // Action String ID\r
+    );\r
+}\r
+\r
+\r
+/**\r
+  Check whether the DevicePath is in the device path forbid list \r
+  (mAccessInfo.LoadForbid).\r
+\r
+  @param[in]  DevicePath           Points to device path.\r
+  \r
+  @retval TRUE     The DevicePath is in the device path forbid list.\r
+  @retval FALSE    The DevicePath is not in the device path forbid list.\r
+\r
+**/\r
+BOOLEAN\r
+IsLoadForbidden (\r
+  IN  EFI_DEVICE_PATH_PROTOCOL                  *DevicePath\r
+  )\r
+{\r
+  UINTN                     OffSet;\r
+  UINTN                     DPSize;\r
+  UINTN                     Size;\r
+  EFI_DEVICE_PATH_PROTOCOL  *Dp;\r
+\r
+  OffSet = 0;\r
+  Size   = GetDevicePathSize (DevicePath);\r
+  //\r
+  // Check each device path.\r
+  //\r
+  while (OffSet < mAccessInfo.LoadForbidLen) {\r
+    Dp      = (EFI_DEVICE_PATH_PROTOCOL *) (mAccessInfo.LoadForbid + OffSet);\r
+    DPSize  = GetDevicePathSize (Dp);\r
+    //\r
+    // Compare device path.\r
+    //\r
+    if ((DPSize == Size) && (CompareMem (DevicePath, Dp, Size) == 0)) {\r
+      return TRUE;\r
+    }\r
+    OffSet += DPSize;\r
+  }\r
+  return FALSE;\r
+}\r
+\r
+\r
+/**\r
+  Display the permit load device path in the loadable device path list.\r
+\r
+**/\r
+VOID\r
+DisplayLoadPermit(\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS          Status;\r
+  CHAR16              *Order;\r
+  UINTN               OrderSize;\r
+  UINTN               ListCount;\r
+  UINTN               Index;\r
+  UINT8               *Var;\r
+  UINT8               *VarPtr;\r
+  CHAR16              VarName[12];\r
+  VOID                *StartOpCodeHandle;\r
+  VOID                *EndOpCodeHandle;\r
+  EFI_IFR_GUID_LABEL  *StartLabel;\r
+  EFI_IFR_GUID_LABEL  *EndLabel;\r
+\r
+  //\r
+  // Get DriverOrder.\r
+  //\r
+  OrderSize = 0;\r
+  Status    = gRT->GetVariable (\r
+                     L"DriverOrder", \r
+                     &gEfiGlobalVariableGuid, \r
+                     NULL, \r
+                     &OrderSize, \r
+                     NULL\r
+                     );\r
+  if (Status != EFI_BUFFER_TOO_SMALL) {\r
+    return ;\r
+  }\r
+\r
+  Order = AllocateZeroPool (OrderSize);\r
+  if (Order == NULL) {\r
+    return ;\r
+  }\r
+\r
+  Status = gRT->GetVariable (\r
+                  L"DriverOrder", \r
+                  &gEfiGlobalVariableGuid, \r
+                  NULL, \r
+                  &OrderSize, \r
+                  Order\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return ;\r
+  }\r
+  \r
+  //\r
+  // Initialize the container for dynamic opcodes.\r
+  //\r
+  StartOpCodeHandle = HiiAllocateOpCodeHandle ();\r
+  ASSERT (StartOpCodeHandle != NULL);\r
+\r
+  EndOpCodeHandle = HiiAllocateOpCodeHandle ();\r
+  ASSERT (EndOpCodeHandle != NULL);\r
+\r
+  //\r
+  // Create Hii Extend Label OpCode.\r
+  //\r
+  StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (\r
+                                        StartOpCodeHandle,\r
+                                        &gEfiIfrTianoGuid,\r
+                                        NULL,\r
+                                        sizeof (EFI_IFR_GUID_LABEL)\r
+                                        );\r
+  StartLabel->ExtendOpCode  = EFI_IFR_EXTEND_OP_LABEL;\r
+  StartLabel->Number        = LABEL_PERMIT_LOAD_FUNC;\r
+\r
+  EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (\r
+                                      EndOpCodeHandle,\r
+                                      &gEfiIfrTianoGuid,\r
+                                      NULL,\r
+                                      sizeof (EFI_IFR_GUID_LABEL)\r
+                                      );\r
+  EndLabel->ExtendOpCode  = EFI_IFR_EXTEND_OP_LABEL;\r
+  EndLabel->Number        = LABEL_END;\r
+\r
+  //\r
+  // Add each driver option.\r
+  //\r
+  Var       = NULL;\r
+  ListCount = OrderSize / sizeof (UINT16);\r
+  for (Index = 0; Index < ListCount; Index++) {\r
+    //\r
+    // Get driver device path.\r
+    //\r
+    UnicodeSPrint (VarName, sizeof (VarName), L"Driver%04x", Order[Index]);\r
+    Var = GetEfiGlobalVariable (VarName);\r
+    if (Var == NULL) {\r
+      continue;\r
+    }\r
+    \r
+    //\r
+    // Check whether the driver is already forbidden.\r
+    //\r
+    \r
+    VarPtr = Var;\r
+    //\r
+    // Skip attribute.\r
+    //\r
+    VarPtr += sizeof (UINT32);\r
+\r
+    //\r
+    // Skip device path lenth.\r
+    //\r
+    VarPtr += sizeof (UINT16);\r
+\r
+    //\r
+    // Skip descript string.\r
+    //\r
+    VarPtr += StrSize ((UINT16 *) VarPtr);\r
+\r
+    if (IsLoadForbidden ((EFI_DEVICE_PATH_PROTOCOL *) VarPtr)) {\r
+      FreePool (Var);\r
+      Var = NULL;\r
+      continue;\r
+    }\r
+\r
+    AddDevicePath (\r
+      KEY_MODIFY_USER | KEY_MODIFY_AP_DP | KEY_LOAD_PERMIT_MODIFY | Order[Index],\r
+      (EFI_DEVICE_PATH_PROTOCOL *) VarPtr,\r
+      StartOpCodeHandle\r
+      );\r
+    FreePool (Var);\r
+    Var = NULL;\r
+  }\r
+\r
+  HiiUpdateForm (\r
+    mCallbackInfo->HiiHandle, // HII handle\r
+    &mUserProfileManagerGuid, // Formset GUID\r
+    FORMID_PERMIT_LOAD_DP,    // Form ID\r
+    StartOpCodeHandle,        // Label for where to insert opcodes\r
+    EndOpCodeHandle           // Replace data\r
+    );\r
+\r
+  HiiFreeOpCodeHandle (StartOpCodeHandle);\r
+  HiiFreeOpCodeHandle (EndOpCodeHandle);\r
+\r
+  //\r
+  // Clear Environment.\r
+  //\r
+  if (Var != NULL) {\r
+    FreePool (Var);\r
+  }\r
+  FreePool (Order);\r
+}\r
+\r
+\r
+/**\r
+  Display the forbid load device path list (mAccessInfo.LoadForbid).\r
+\r
+**/\r
+VOID\r
+DisplayLoadForbid (\r
+  VOID\r
+  )\r
+{\r
+  UINTN                     Offset;\r
+  UINTN                     DPSize;\r
+  UINTN                     Index;\r
+  EFI_DEVICE_PATH_PROTOCOL  *Dp;\r
+  VOID                      *StartOpCodeHandle;\r
+  VOID                      *EndOpCodeHandle;\r
+  EFI_IFR_GUID_LABEL        *StartLabel;\r
+  EFI_IFR_GUID_LABEL        *EndLabel;\r
+\r
+  //\r
+  // Initialize the container for dynamic opcodes.\r
+  //\r
+  StartOpCodeHandle = HiiAllocateOpCodeHandle ();\r
+  ASSERT (StartOpCodeHandle != NULL);\r
+\r
+  EndOpCodeHandle = HiiAllocateOpCodeHandle ();\r
+  ASSERT (EndOpCodeHandle != NULL);\r
+\r
+  //\r
+  // Create Hii Extend Label OpCode.\r
+  //\r
+  StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (\r
+                                        StartOpCodeHandle,\r
+                                        &gEfiIfrTianoGuid,\r
+                                        NULL,\r
+                                        sizeof (EFI_IFR_GUID_LABEL)\r
+                                        );\r
+  StartLabel->ExtendOpCode  = EFI_IFR_EXTEND_OP_LABEL;\r
+  StartLabel->Number        = LABLE_FORBID_LOAD_FUNC;\r
+\r
+  EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (\r
+                                      EndOpCodeHandle,\r
+                                      &gEfiIfrTianoGuid,\r
+                                      NULL,\r
+                                      sizeof (EFI_IFR_GUID_LABEL)\r
+                                      );\r
+  EndLabel->ExtendOpCode  = EFI_IFR_EXTEND_OP_LABEL;\r
+  EndLabel->Number        = LABEL_END;\r
+\r
+  //\r
+  // Add each forbid load drivers.\r
+  //\r
+  Offset  = 0;\r
+  Index   = 0;\r
+  while (Offset < mAccessInfo.LoadForbidLen) {\r
+    Dp      = (EFI_DEVICE_PATH_PROTOCOL *) (mAccessInfo.LoadForbid + Offset);\r
+    DPSize  = GetDevicePathSize (Dp);\r
+    AddDevicePath (\r
+      KEY_MODIFY_USER | KEY_MODIFY_AP_DP | KEY_LOAD_FORBID_MODIFY | Index,\r
+      Dp,\r
+      StartOpCodeHandle\r
+      );\r
+    Index++;\r
+    Offset += DPSize;\r
+  }\r
+\r
+  HiiUpdateForm (\r
+    mCallbackInfo->HiiHandle, // HII handle\r
+    &mUserProfileManagerGuid, // Formset GUID\r
+    FORMID_FORBID_LOAD_DP,    // Form ID\r
+    StartOpCodeHandle,        // Label for where to insert opcodes\r
+    EndOpCodeHandle           // Replace data\r
+    );\r
+\r
+  HiiFreeOpCodeHandle (StartOpCodeHandle);\r
+  HiiFreeOpCodeHandle (EndOpCodeHandle);\r
+}\r
+\r
+\r
+/**\r
+  Display the permit connect device path.\r
+\r
+**/\r
+VOID\r
+DisplayConnectPermit (\r
+  VOID\r
+  )\r
+{\r
+  //\r
+  // Note: \r
+  // As no architect protocol/interface to be called in ConnectController()\r
+  // to verify the device path, just add a place holder for permitted connect\r
+  // device path.\r
+  //\r
+}\r
+\r
+\r
+/**\r
+  Display the forbid connect device path list.\r
+\r
+**/\r
+VOID\r
+DisplayConnectForbid (\r
+  VOID\r
+  )\r
+{\r
+  //\r
+  // Note: \r
+  // As no architect protocol/interface to be called in ConnectController()\r
+  // to verify the device path, just add a place holder for forbidden connect\r
+  // device path.\r
+  //\r
+}\r
+\r
+\r
+/**\r
+  Delete the specified device path by DriverIndex from the forbid device path \r
+  list (mAccessInfo.LoadForbid).\r
+\r
+  @param[in]  DriverIndex   The index of driver in forbidden device path list.\r
+  \r
+**/\r
+VOID\r
+DeleteFromForbidLoad (\r
+  IN  UINT16                                    DriverIndex\r
+  )\r
+{\r
+  UINTN                     OffSet;\r
+  UINTN                     DPSize;\r
+  UINTN                     OffLen;\r
+  EFI_DEVICE_PATH_PROTOCOL  *Dp;\r
+\r
+  OffSet = 0;\r
+  //\r
+  // Find the specified device path.\r
+  //\r
+  while ((OffSet < mAccessInfo.LoadForbidLen) && (DriverIndex > 0)) {\r
+    Dp      = (EFI_DEVICE_PATH_PROTOCOL *) (mAccessInfo.LoadForbid + OffSet);\r
+    DPSize  = GetDevicePathSize (Dp);\r
+    OffSet += DPSize;\r
+    DriverIndex--;\r
+  }\r
+  \r
+  //\r
+  // Specified device path found.\r
+  //\r
+  if (DriverIndex == 0) {\r
+    Dp      = (EFI_DEVICE_PATH_PROTOCOL *) (mAccessInfo.LoadForbid + OffSet);\r
+    DPSize  = GetDevicePathSize (Dp);\r
+    OffLen  = mAccessInfo.LoadForbidLen - OffSet - DPSize;\r
+    if (OffLen > 0) {\r
+      CopyMem (\r
+        mAccessInfo.LoadForbid + OffSet, \r
+        mAccessInfo.LoadForbid + OffSet + DPSize, \r
+        OffLen\r
+        );\r
+    }\r
+    mAccessInfo.LoadForbidLen -= DPSize;\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Add the specified device path by DriverIndex to the forbid device path \r
+  list (mAccessInfo.LoadForbid).\r
+\r
+  @param[in]  DriverIndex   The index of driver saved in driver options.\r
+  \r
+**/\r
+VOID\r
+AddToForbidLoad (\r
+  IN  UINT16                                    DriverIndex\r
+  )\r
+{\r
+  UINTN       DevicePathLen;\r
+  UINT8       *Var;\r
+  UINT8       *VarPtr;\r
+  UINTN       NewLen;\r
+  UINT8       *NewFL;\r
+  CHAR16      VarName[13];\r
+\r
+  //\r
+  // Get loadable driver device path.\r
+  //\r
+  UnicodeSPrint  (VarName, sizeof (VarName), L"Driver%04x", DriverIndex);\r
+  Var = GetEfiGlobalVariable (VarName);\r
+  if (Var == NULL) {\r
+    return;\r
+  }\r
+  \r
+  //\r
+  // Save forbid load driver.\r
+  //\r
+  \r
+  VarPtr = Var;\r
+  //\r
+  // Skip attribute.\r
+  //\r
+  VarPtr += sizeof (UINT32);\r
+\r
+  DevicePathLen = *(UINT16 *) VarPtr;\r
+  //\r
+  // Skip device path length.\r
+  //\r
+  VarPtr += sizeof (UINT16);\r
+\r
+  //\r
+  // Skip description string.\r
+  //\r
+  VarPtr += StrSize ((UINT16 *) VarPtr);\r
+\r
+  NewLen  = mAccessInfo.LoadForbidLen + DevicePathLen;\r
+  NewFL   = AllocateZeroPool (NewLen);\r
+  if (NewFL == NULL) {\r
+    FreePool (Var);\r
+    return ;\r
+  }\r
+\r
+  if (mAccessInfo.LoadForbidLen > 0) {\r
+    CopyMem (NewFL, mAccessInfo.LoadForbid, mAccessInfo.LoadForbidLen);\r
+    FreePool (mAccessInfo.LoadForbid);\r
+  }\r
+\r
+  CopyMem (NewFL + mAccessInfo.LoadForbidLen, VarPtr, DevicePathLen);\r
+  mAccessInfo.LoadForbidLen = NewLen;\r
+  mAccessInfo.LoadForbid    = NewFL;\r
+  FreePool (Var);\r
+}\r
+\r
+\r
+/**\r
+  Get current user's access right.\r
+\r
+  @param[out]  AccessRight  Points to the buffer used for user's access right.\r
+\r
+  @retval EFI_SUCCESS       Get current user access right successfully.\r
+  @retval others            Fail to get current user access right.\r
+\r
+**/\r
+EFI_STATUS\r
+GetAccessRight (\r
+  OUT  UINT32                                    *AccessRight\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  EFI_USER_INFO_HANDLE          UserInfo;\r
+  EFI_USER_INFO                 *Info;\r
+  UINTN                         InfoSize;\r
+  UINTN                         MemSize;\r
+  EFI_USER_INFO_ACCESS_CONTROL  Access;\r
+  EFI_USER_PROFILE_HANDLE       CurrentUser;\r
+  UINTN                         TotalLen;\r
+  UINTN                         CheckLen;\r
+\r
+  //\r
+  // Allocate user information memory.\r
+  //\r
+  MemSize = sizeof (EFI_USER_INFO) + 63;\r
+  Info    = AllocateZeroPool (MemSize);\r
+  if (Info == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
\r
+  //\r
+  // Get user access information.\r
+  //\r
+  UserInfo = NULL;\r
+  mUserManager->Current (mUserManager, &CurrentUser);\r
+  while (TRUE) {\r
+    InfoSize = MemSize;\r
+    //\r
+    // Get next user information.\r
+    //\r
+    Status = mUserManager->GetNextInfo (mUserManager, CurrentUser, &UserInfo);\r
+    if (EFI_ERROR (Status)) {\r
+      break;\r
+    }\r
+\r
+    Status = mUserManager->GetInfo (\r
+                             mUserManager,\r
+                             CurrentUser,\r
+                             UserInfo,\r
+                             Info,\r
+                             &InfoSize\r
+                             );\r
+    if (Status == EFI_BUFFER_TOO_SMALL) {\r
+      MemSize = InfoSize;\r
+      FreePool (Info);\r
+      Info = AllocateZeroPool (MemSize);\r
+      if (Info == NULL) {\r
+        return EFI_OUT_OF_RESOURCES;\r
+      }\r
+      Status = mUserManager->GetInfo (\r
+                               mUserManager,\r
+                               CurrentUser,\r
+                               UserInfo,\r
+                               Info,\r
+                               &InfoSize\r
+                               );\r
+    }\r
+    if (EFI_ERROR (Status)) {\r
+      break;\r
+    }\r
+    \r
+    //\r
+    // Check user information.\r
+    //\r
+    if (Info->InfoType == EFI_USER_INFO_ACCESS_POLICY_RECORD) {\r
+      TotalLen  = Info->InfoSize - sizeof (EFI_USER_INFO);\r
+      CheckLen  = 0;\r
+      //\r
+      // Get specified access information.\r
+      //\r
+      while (CheckLen < TotalLen) {\r
+        CopyMem (&Access, (UINT8 *) (Info + 1) + CheckLen, sizeof (Access));\r
+        if ((Access.Type == EFI_USER_INFO_ACCESS_ENROLL_SELF) ||\r
+            (Access.Type == EFI_USER_INFO_ACCESS_ENROLL_OTHERS) ||\r
+            (Access.Type == EFI_USER_INFO_ACCESS_MANAGE)\r
+            ) {\r
+          *AccessRight = Access.Type;\r
+          FreePool (Info);\r
+          return EFI_SUCCESS;\r
+        }\r
+        CheckLen += Access.Size;\r
+      }\r
+    }\r
+  }\r
+  FreePool (Info);\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+\r
+\r
diff --git a/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/AuthService.c b/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/AuthService.c
new file mode 100644 (file)
index 0000000..38f4626
--- /dev/null
@@ -0,0 +1,882 @@
+/** @file\r
+  Implement authentication services for the authenticated variable\r
+  service in UEFI2.2.\r
+\r
+Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "Variable.h"\r
+#include "AuthService.h"\r
+\r
+///\r
+/// Global database array for scratch\r
+///\r
+UINT32   mPubKeyNumber;\r
+UINT32   mPlatformMode;\r
+EFI_GUID mSignatureSupport[SIGSUPPORT_NUM] = {EFI_CERT_RSA2048_SHA256_GUID, EFI_CERT_RSA2048_SHA1_GUID};\r
+//\r
+// Public Exponent of RSA Key.\r
+//\r
+CONST UINT8 mRsaE[] = { 0x01, 0x00, 0x01 };\r
+\r
+/**\r
+  Initializes for authenticated varibale service.\r
+\r
+  @retval EFI_SUCCESS           The function successfully executed.\r
+  @retval EFI_OUT_OF_RESOURCES  Failed to allocate enough memory resources.\r
+\r
+**/\r
+EFI_STATUS\r
+AutenticatedVariableServiceInitialize (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  VARIABLE_POINTER_TRACK  Variable;\r
+  UINT8                   VarValue;\r
+  UINT32                  VarAttr;\r
+  UINTN                   DataSize;\r
+  UINTN                   CtxSize;\r
+  VARIABLE_HEADER         VariableHeader;\r
+  BOOLEAN                 Valid;\r
+\r
+  mVariableModuleGlobal->AuthenticatedVariableGuid[Physical] = &gEfiAuthenticatedVariableGuid;\r
+  mVariableModuleGlobal->CertRsa2048Sha256Guid[Physical]     = &gEfiCertRsa2048Sha256Guid;\r
+  mVariableModuleGlobal->ImageSecurityDatabaseGuid[Physical] = &gEfiImageSecurityDatabaseGuid;\r
+\r
+  //\r
+  // Initialize hash context.\r
+  //\r
+  CtxSize   = Sha256GetContextSize ();\r
+  mVariableModuleGlobal->HashContext[Physical] = AllocateRuntimePool (CtxSize);\r
+  ASSERT (mVariableModuleGlobal->HashContext[Physical] != NULL);\r
+  //\r
+  // Check "AuthVarKeyDatabase" variable's existence. \r
+  // If it doesn't exist, create a new one with initial value of 0 and EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set. \r
+  //\r
+  Status = FindVariable (\r
+             mVariableModuleGlobal->VariableName[Physical][VAR_AUTH_KEY_DB], \r
+             &gEfiAuthenticatedVariableGuid, \r
+             &Variable, \r
+             &mVariableModuleGlobal->VariableGlobal[Physical],\r
+             mVariableModuleGlobal->FvbInstance\r
+             );\r
+\r
+  if (Variable.CurrPtr == 0x0) {\r
+    VarAttr       = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;\r
+    VarValue      = 0;\r
+    mPubKeyNumber = 0;\r
+    Status        = UpdateVariable (\r
+                      mVariableModuleGlobal->VariableName[Physical][VAR_AUTH_KEY_DB],\r
+                      &gEfiAuthenticatedVariableGuid,\r
+                      &VarValue,\r
+                      sizeof(UINT8),\r
+                      VarAttr,\r
+                      0,\r
+                      0,\r
+                      FALSE,\r
+                      mVariableModuleGlobal,\r
+                      &Variable\r
+                      );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  } else {\r
+    //\r
+    // Load database in global variable for cache.\r
+    //\r
+    Valid = IsValidVariableHeader (\r
+              Variable.CurrPtr, \r
+              Variable.Volatile, \r
+              &mVariableModuleGlobal->VariableGlobal[Physical], \r
+              mVariableModuleGlobal->FvbInstance, \r
+              &VariableHeader\r
+              );\r
+    ASSERT (Valid);\r
+\r
+    DataSize  = DataSizeOfVariable (&VariableHeader);\r
+    ASSERT (DataSize <= MAX_KEYDB_SIZE);\r
+    GetVariableDataPtr (\r
+      Variable.CurrPtr,\r
+      Variable.Volatile,\r
+      &mVariableModuleGlobal->VariableGlobal[Physical],\r
+      mVariableModuleGlobal->FvbInstance,\r
+      (CHAR16 *) mVariableModuleGlobal->PubKeyStore\r
+      );\r
+\r
+    mPubKeyNumber = (UINT32) (DataSize / EFI_CERT_TYPE_RSA2048_SIZE);\r
+  }\r
+  //\r
+  // Check "SetupMode" variable's existence. \r
+  // If it doesn't exist, check PK database's existence to determine the value.\r
+  // Then create a new one with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set. \r
+  //\r
+  Status = FindVariable (\r
+             mVariableModuleGlobal->VariableName[Physical][VAR_SETUP_MODE], \r
+             &gEfiGlobalVariableGuid, \r
+             &Variable, \r
+             &mVariableModuleGlobal->VariableGlobal[Physical],\r
+             mVariableModuleGlobal->FvbInstance\r
+             );\r
+\r
+  if (Variable.CurrPtr == 0x0) {\r
+    Status = FindVariable (\r
+               mVariableModuleGlobal->VariableName[Physical][VAR_PLATFORM_KEY], \r
+               &gEfiGlobalVariableGuid, \r
+               &Variable, \r
+               &mVariableModuleGlobal->VariableGlobal[Physical],\r
+               mVariableModuleGlobal->FvbInstance\r
+               );\r
+    if (Variable.CurrPtr == 0x0) {\r
+      mPlatformMode = SETUP_MODE;\r
+    } else {\r
+      mPlatformMode = USER_MODE;\r
+    }\r
+\r
+    VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;\r
+    Status  = UpdateVariable (\r
+                mVariableModuleGlobal->VariableName[Physical][VAR_SETUP_MODE],\r
+                &gEfiGlobalVariableGuid,\r
+                &mPlatformMode,\r
+                sizeof(UINT8),\r
+                VarAttr,\r
+                0,\r
+                0,\r
+                FALSE,\r
+                mVariableModuleGlobal,\r
+                &Variable\r
+                );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  } else {\r
+    GetVariableDataPtr (\r
+      Variable.CurrPtr,\r
+      Variable.Volatile,\r
+      &mVariableModuleGlobal->VariableGlobal[Physical],\r
+      mVariableModuleGlobal->FvbInstance,\r
+      (CHAR16 *) &mPlatformMode\r
+      );\r
+  }\r
+  //\r
+  // Check "SignatureSupport" variable's existence. \r
+  // If it doesn't exist, then create a new one with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set. \r
+  //\r
+  Status = FindVariable (\r
+             EFI_SIGNATURE_SUPPORT_NAME, \r
+             &gEfiGlobalVariableGuid, \r
+             &Variable, \r
+             &mVariableModuleGlobal->VariableGlobal[Physical],\r
+             mVariableModuleGlobal->FvbInstance\r
+             );\r
+\r
+  if (Variable.CurrPtr == 0x0) {\r
+    VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;\r
+    Status  = UpdateVariable (\r
+                EFI_SIGNATURE_SUPPORT_NAME,\r
+                &gEfiGlobalVariableGuid,\r
+                mSignatureSupport,\r
+                SIGSUPPORT_NUM * sizeof(EFI_GUID),\r
+                VarAttr,\r
+                0,\r
+                0,\r
+                FALSE,\r
+                mVariableModuleGlobal,\r
+                &Variable\r
+                );\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Add public key in store and return its index.\r
+\r
+  @param[in]  VirtualMode             The current calling mode for this function.\r
+  @param[in]  Global                  The context of this Extended SAL Variable Services Class call.\r
+  @param[in]  PubKey                  The input pointer to Public Key data.\r
+\r
+  @return                             The index of new added item.\r
+\r
+**/\r
+UINT32\r
+AddPubKeyInStore (\r
+  IN  BOOLEAN                   VirtualMode,\r
+  IN  ESAL_VARIABLE_GLOBAL      *Global,\r
+  IN  UINT8                     *PubKey\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  BOOLEAN                 IsFound;\r
+  UINT32                  Index;\r
+  VARIABLE_POINTER_TRACK  Variable;\r
+  UINT8                   *Ptr;\r
+\r
+  if (PubKey == NULL) {\r
+    return 0;\r
+  }\r
+\r
+  Status = FindVariable (\r
+             Global->VariableName[VirtualMode][VAR_AUTH_KEY_DB],\r
+             Global->AuthenticatedVariableGuid[VirtualMode],\r
+             &Variable,\r
+             &Global->VariableGlobal[VirtualMode],\r
+             Global->FvbInstance\r
+             );\r
+  ASSERT_EFI_ERROR (Status);\r
+  //\r
+  // Check whether the public key entry does exist.\r
+  //\r
+  IsFound = FALSE;\r
+  for (Ptr = Global->PubKeyStore, Index = 1; Index <= mPubKeyNumber; Index++) {\r
+    if (CompareMem (Ptr, PubKey, EFI_CERT_TYPE_RSA2048_SIZE) == 0) {\r
+      IsFound = TRUE;\r
+      break;\r
+    }\r
+    Ptr += EFI_CERT_TYPE_RSA2048_SIZE;\r
+  }\r
+\r
+  if (!IsFound) {\r
+    //\r
+    // Add public key in database.\r
+    //\r
+    if (mPubKeyNumber == MAX_KEY_NUM) {\r
+      //\r
+      // Notes: Database is full, need enhancement here, currently just return 0.\r
+      //\r
+      return 0;\r
+    }\r
+\r
+    CopyMem (Global->PubKeyStore + mPubKeyNumber * EFI_CERT_TYPE_RSA2048_SIZE, PubKey, EFI_CERT_TYPE_RSA2048_SIZE);\r
+    Index = ++mPubKeyNumber;\r
+    //\r
+    // Update public key database variable.\r
+    //\r
+    Status = UpdateVariable (\r
+               Global->VariableName[VirtualMode][VAR_AUTH_KEY_DB],\r
+               Global->AuthenticatedVariableGuid[VirtualMode],\r
+               Global->PubKeyStore,\r
+               mPubKeyNumber * EFI_CERT_TYPE_RSA2048_SIZE,\r
+               EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS,\r
+               0,\r
+               0,\r
+               VirtualMode,\r
+               Global,\r
+               &Variable\r
+               );\r
+    ASSERT_EFI_ERROR (Status);\r
+  }\r
+\r
+  return Index;\r
+}\r
+\r
+/**\r
+  Verify data payload with AuthInfo in EFI_CERT_TYPE_RSA2048_SHA256 type.\r
+  Follow the steps in UEFI2.2.\r
+\r
+  @param[in]  VirtualMode             The current calling mode for this function.\r
+  @param[in]  Global                  The context of this Extended SAL Variable Services Class call.\r
+  @param[in]  Data                    The pointer to data with AuthInfo.\r
+  @param[in]  DataSize                The size of Data.\r
+  @param[in]  PubKey                  The public key used for verification.\r
+\r
+  @retval EFI_INVALID_PARAMETER       Invalid parameter.\r
+  @retval EFI_SECURITY_VIOLATION      Authentication failed.\r
+  @retval EFI_SUCCESS                 Authentication successful.\r
+\r
+**/\r
+EFI_STATUS\r
+VerifyDataPayload (\r
+  IN  BOOLEAN                   VirtualMode,\r
+  IN  ESAL_VARIABLE_GLOBAL      *Global,\r
+  IN  UINT8                     *Data,\r
+  IN  UINTN                     DataSize,\r
+  IN  UINT8                     *PubKey\r
+  )\r
+{\r
+  BOOLEAN                         Status;\r
+  EFI_VARIABLE_AUTHENTICATION     *CertData;\r
+  EFI_CERT_BLOCK_RSA_2048_SHA256  *CertBlock;\r
+  UINT8                           Digest[SHA256_DIGEST_SIZE];\r
+  VOID                            *Rsa;\r
+  VOID                            *HashContext;\r
+\r
+  Rsa         = NULL;\r
+  CertData    = NULL;\r
+  CertBlock   = NULL;\r
+\r
+  if (Data == NULL || PubKey == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  CertData  = (EFI_VARIABLE_AUTHENTICATION *) Data;\r
+  CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);\r
+\r
+  //\r
+  // wCertificateType should be WIN_CERT_TYPE_EFI_GUID.\r
+  // Cert type should be EFI_CERT_TYPE_RSA2048_SHA256.\r
+  //\r
+  if ((CertData->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) ||\r
+      !CompareGuid (&CertData->AuthInfo.CertType, Global->CertRsa2048Sha256Guid[VirtualMode])\r
+        ) {\r
+    //\r
+    // Invalid AuthInfo type, return EFI_SECURITY_VIOLATION.\r
+    //\r
+    return EFI_SECURITY_VIOLATION;\r
+  }\r
+\r
+  //\r
+  // Hash data payload with SHA256.\r
+  //\r
+  ZeroMem (Digest, SHA256_DIGEST_SIZE);\r
+  HashContext = Global->HashContext[VirtualMode];\r
+  Status  = Sha256Init (HashContext);\r
+  if (!Status) {\r
+    goto Done;\r
+  }\r
+  Status  = Sha256Update (HashContext, Data + AUTHINFO_SIZE, (UINTN) (DataSize - AUTHINFO_SIZE));\r
+  if (!Status) {\r
+    goto Done;\r
+  }\r
+  //\r
+  // Hash Monotonic Count.\r
+  //\r
+  Status  = Sha256Update (HashContext, &CertData->MonotonicCount, sizeof (UINT64));\r
+  if (!Status) {\r
+    goto Done;\r
+  }\r
+  Status  = Sha256Final (HashContext, Digest);\r
+  if (!Status) {\r
+    goto Done;\r
+  }\r
+  //\r
+  // Generate & Initialize RSA Context.\r
+  //\r
+  Rsa = RsaNew ();\r
+  ASSERT (Rsa != NULL);\r
+  // \r
+  // Set RSA Key Components.\r
+  // NOTE: Only N and E are needed to be set as RSA public key for signature verification.\r
+  //\r
+  Status = RsaSetKey (Rsa, RsaKeyN, PubKey, EFI_CERT_TYPE_RSA2048_SIZE);\r
+  if (!Status) {\r
+    goto Done;\r
+  }\r
+  Status = RsaSetKey (Rsa, RsaKeyE, mRsaE, sizeof (mRsaE));\r
+  if (!Status) {\r
+    goto Done;\r
+  }\r
+  //\r
+  // Verify the signature.\r
+  //\r
+  Status = RsaPkcs1Verify (\r
+             Rsa, \r
+             Digest, \r
+             SHA256_DIGEST_SIZE, \r
+             CertBlock->Signature, \r
+             EFI_CERT_TYPE_RSA2048_SHA256_SIZE\r
+             );\r
+\r
+Done:\r
+  if (Rsa != NULL) {\r
+    RsaFree (Rsa);\r
+  }\r
+  if (Status) {\r
+    return EFI_SUCCESS;\r
+  } else {\r
+    return EFI_SECURITY_VIOLATION;\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Update platform mode.\r
+\r
+  @param[in]  VirtualMode             The current calling mode for this function.\r
+  @param[in]  Global                  The context of this Extended SAL Variable Services Class call.\r
+  @param[in]  Mode                    SETUP_MODE or USER_MODE.\r
+\r
+**/\r
+VOID\r
+UpdatePlatformMode (\r
+  IN  BOOLEAN                   VirtualMode,\r
+  IN  ESAL_VARIABLE_GLOBAL      *Global,\r
+  IN  UINT32                    Mode\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  VARIABLE_POINTER_TRACK  Variable;\r
+  UINT32                  VarAttr;\r
+\r
+  Status = FindVariable (\r
+             Global->VariableName[VirtualMode][VAR_SETUP_MODE], \r
+             Global->GlobalVariableGuid[VirtualMode], \r
+             &Variable, \r
+             &Global->VariableGlobal[VirtualMode],\r
+             Global->FvbInstance\r
+             );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  mPlatformMode  = Mode;\r
+  VarAttr        = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;\r
+  Status         = UpdateVariable (\r
+                     Global->VariableName[VirtualMode][VAR_SETUP_MODE],\r
+                     Global->GlobalVariableGuid[VirtualMode],\r
+                     &mPlatformMode,\r
+                     sizeof(UINT8),\r
+                     VarAttr,\r
+                     0,\r
+                     0,\r
+                     VirtualMode,\r
+                     Global,\r
+                     &Variable\r
+                     );\r
+  ASSERT_EFI_ERROR (Status);\r
+}\r
+\r
+/**\r
+  Process variable with platform key for verification.\r
+\r
+  @param[in]  VariableName                The name of Variable to be found.\r
+  @param[in]  VendorGuid                  The variable vendor GUID.\r
+  @param[in]  Data                        The data pointer.\r
+  @param[in]  DataSize                    The size of Data found. If size is less than the\r
+                                          data, this value contains the required size.\r
+  @param[in]  VirtualMode                 The current calling mode for this function.\r
+  @param[in]  Global                      The context of this Extended SAL Variable Services Class call.\r
+  @param[in]  Variable                    The variable information which is used to keep track of variable usage.\r
+  @param[in]  Attributes                  The attribute value of the variable.\r
+  @param[in]  IsPk                        Indicates whether to process pk.\r
+\r
+  @retval EFI_INVALID_PARAMETER           Invalid parameter.\r
+  @retval EFI_SECURITY_VIOLATION          The variable does NOT pass the validation \r
+                                          check carried out by the firmware. \r
+  @retval EFI_SUCCESS                     The variable passed validation successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+ProcessVarWithPk (\r
+  IN  CHAR16                    *VariableName,\r
+  IN  EFI_GUID                  *VendorGuid,\r
+  IN  VOID                      *Data,\r
+  IN  UINTN                     DataSize,\r
+  IN  BOOLEAN                   VirtualMode,\r
+  IN  ESAL_VARIABLE_GLOBAL      *Global,\r
+  IN  VARIABLE_POINTER_TRACK    *Variable,\r
+  IN  UINT32                    Attributes OPTIONAL,\r
+  IN  BOOLEAN                   IsPk\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  VARIABLE_POINTER_TRACK      PkVariable;\r
+  EFI_SIGNATURE_LIST          *OldPkList;\r
+  EFI_SIGNATURE_DATA          *OldPkData;\r
+  EFI_VARIABLE_AUTHENTICATION *CertData;\r
+  VARIABLE_HEADER             VariableHeader;\r
+  BOOLEAN                     Valid;\r
+\r
+  OldPkList = NULL;\r
+\r
+  if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {\r
+    //\r
+    // PK and KEK should set EFI_VARIABLE_NON_VOLATILE attribute.\r
+    //\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (mPlatformMode == USER_MODE) {\r
+    if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == 0) {\r
+      //\r
+      // In user mode, PK and KEK should set EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute.\r
+      //\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    CertData = (EFI_VARIABLE_AUTHENTICATION *) Data;\r
+\r
+    if (Variable->CurrPtr != 0x0) {\r
+      Valid = IsValidVariableHeader (\r
+                Variable->CurrPtr, \r
+                Variable->Volatile, \r
+                &Global->VariableGlobal[VirtualMode], \r
+                Global->FvbInstance, \r
+                &VariableHeader\r
+                );\r
+      ASSERT (Valid);\r
+\r
+      if (CertData->MonotonicCount <= VariableHeader.MonotonicCount) {\r
+        //\r
+        // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.\r
+        //\r
+        return EFI_SECURITY_VIOLATION;\r
+      }\r
+    }\r
+    //\r
+    // Get platform key from variable.\r
+    //\r
+    Status = FindVariable (\r
+               Global->VariableName[VirtualMode][VAR_PLATFORM_KEY], \r
+               Global->GlobalVariableGuid[VirtualMode], \r
+               &PkVariable, \r
+               &Global->VariableGlobal[VirtualMode],\r
+               Global->FvbInstance\r
+               );\r
+    ASSERT_EFI_ERROR (Status);\r
+\r
+    ZeroMem (Global->KeyList, MAX_KEYDB_SIZE);\r
+    GetVariableDataPtr (\r
+      PkVariable.CurrPtr,\r
+      PkVariable.Volatile,\r
+      &Global->VariableGlobal[VirtualMode],\r
+      Global->FvbInstance,\r
+      (CHAR16 *) Global->KeyList\r
+      );\r
+\r
+    OldPkList = (EFI_SIGNATURE_LIST *) Global->KeyList;\r
+    OldPkData = (EFI_SIGNATURE_DATA *) ((UINT8 *) OldPkList + sizeof (EFI_SIGNATURE_LIST) + OldPkList->SignatureHeaderSize);\r
+    Status    = VerifyDataPayload (VirtualMode, Global, Data, DataSize, OldPkData->SignatureData);\r
+    if (!EFI_ERROR (Status)) {\r
+      Status = UpdateVariable (\r
+                 VariableName, \r
+                 VendorGuid, \r
+                 (UINT8*)Data + AUTHINFO_SIZE, \r
+                 DataSize - AUTHINFO_SIZE, \r
+                 Attributes, \r
+                 0, \r
+                 CertData->MonotonicCount, \r
+                 VirtualMode, \r
+                 Global,\r
+                 Variable\r
+                 );\r
+\r
+      if (!EFI_ERROR (Status)) {\r
+        //\r
+        // If delete PK in user mode, need change to setup mode.\r
+        //\r
+        if ((DataSize == AUTHINFO_SIZE) && IsPk) {\r
+          UpdatePlatformMode (VirtualMode, Global, SETUP_MODE);\r
+        }\r
+      }\r
+    }\r
+  } else {\r
+    Status = UpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes, 0, 0, VirtualMode, Global, Variable);\r
+    //\r
+    // If enroll PK in setup mode, need change to user mode.\r
+    //\r
+    if ((DataSize != 0) && IsPk) {\r
+      UpdatePlatformMode (VirtualMode, Global, USER_MODE);\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Process variable with key exchange key for verification.\r
+\r
+  @param[in]  VariableName                The name of Variable to be found.\r
+  @param[in]  VendorGuid                  The variable vendor GUID.\r
+  @param[in]  Data                        The data pointer.\r
+  @param[in]  DataSize                    The size of Data found. If size is less than the\r
+                                          data, this value contains the required size.\r
+  @param[in]  VirtualMode                 The current calling mode for this function.\r
+  @param[in]  Global                      The context of this Extended SAL Variable Services Class call.\r
+  @param[in]  Variable                    The variable information which is used to keep track of variable usage.\r
+  @param[in]  Attributes                  The attribute value of the variable.\r
+\r
+  @retval EFI_INVALID_PARAMETER           Invalid parameter.\r
+  @retval EFI_SECURITY_VIOLATION          The variable did NOT pass the validation \r
+                                          check carried out by the firmware. \r
+  @retval EFI_SUCCESS                     The variable passed validation successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+ProcessVarWithKek (\r
+  IN  CHAR16                               *VariableName,\r
+  IN  EFI_GUID                             *VendorGuid,\r
+  IN  VOID                                 *Data,\r
+  IN  UINTN                                DataSize,\r
+  IN  BOOLEAN                              VirtualMode,\r
+  IN  ESAL_VARIABLE_GLOBAL                 *Global,\r
+  IN  VARIABLE_POINTER_TRACK               *Variable,\r
+  IN  UINT32                               Attributes OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  VARIABLE_POINTER_TRACK          KekVariable;\r
+  EFI_SIGNATURE_LIST              *KekList;\r
+  EFI_SIGNATURE_DATA              *KekItem;\r
+  UINT32                          KekCount;\r
+  EFI_VARIABLE_AUTHENTICATION     *CertData;\r
+  EFI_CERT_BLOCK_RSA_2048_SHA256  *CertBlock;\r
+  BOOLEAN                         IsFound;\r
+  UINT32                          Index;\r
+  VARIABLE_HEADER                 VariableHeader;\r
+  BOOLEAN                         Valid;\r
+\r
+  KekList = NULL;\r
+\r
+  if (mPlatformMode == USER_MODE) {\r
+    if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == 0) {\r
+      //\r
+      // In user mode, should set EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute.\r
+      //\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    CertData  = (EFI_VARIABLE_AUTHENTICATION *) Data;\r
+    CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);\r
+    if (Variable->CurrPtr != 0x0) {\r
+      Valid = IsValidVariableHeader (\r
+                Variable->CurrPtr, \r
+                Variable->Volatile, \r
+                &Global->VariableGlobal[VirtualMode], \r
+                Global->FvbInstance, \r
+                &VariableHeader\r
+                );\r
+      ASSERT (Valid);\r
+\r
+      if (CertData->MonotonicCount <= VariableHeader.MonotonicCount) {\r
+        //\r
+        // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.\r
+        //\r
+        return EFI_SECURITY_VIOLATION;\r
+      }\r
+    }\r
+    //\r
+    // Get KEK database from variable.\r
+    //\r
+    Status = FindVariable (\r
+               Global->VariableName[VirtualMode][VAR_KEY_EXCHANGE_KEY], \r
+               Global->GlobalVariableGuid[VirtualMode], \r
+               &KekVariable, \r
+               &Global->VariableGlobal[VirtualMode],\r
+               Global->FvbInstance\r
+               );\r
+    ASSERT_EFI_ERROR (Status);\r
+\r
+    ZeroMem (Global->KeyList, MAX_KEYDB_SIZE);\r
+    GetVariableDataPtr (\r
+      KekVariable.CurrPtr,\r
+      KekVariable.Volatile,\r
+      &Global->VariableGlobal[VirtualMode],\r
+      Global->FvbInstance,\r
+      (CHAR16 *) Global->KeyList\r
+      );\r
+    //\r
+    // Enumerate all Kek items in this list to verify the variable certificate data.\r
+    // If anyone is authenticated successfully, it means the variable is correct!\r
+    //\r
+    KekList   = (EFI_SIGNATURE_LIST *) Global->KeyList;\r
+    IsFound   = FALSE;\r
+    KekCount  = (KekList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - KekList->SignatureHeaderSize) / KekList->SignatureSize;\r
+    KekItem   = (EFI_SIGNATURE_DATA *) ((UINT8 *) KekList + sizeof (EFI_SIGNATURE_LIST) + KekList->SignatureHeaderSize);\r
+    for (Index = 0; Index < KekCount; Index++) {\r
+      if (CompareMem (KekItem->SignatureData, CertBlock->PublicKey, EFI_CERT_TYPE_RSA2048_SIZE) == 0) {\r
+        IsFound = TRUE;\r
+        break;\r
+      }\r
+      KekItem = (EFI_SIGNATURE_DATA *) ((UINT8 *) KekItem + KekList->SignatureSize);\r
+    }\r
+\r
+    if (!IsFound) {\r
+      return EFI_SECURITY_VIOLATION;\r
+    }\r
+\r
+    Status = VerifyDataPayload (VirtualMode, Global, Data, DataSize, CertBlock->PublicKey);\r
+    if (!EFI_ERROR (Status)) {\r
+      Status = UpdateVariable (\r
+                 VariableName, \r
+                 VendorGuid, \r
+                 (UINT8*)Data + AUTHINFO_SIZE, \r
+                 DataSize - AUTHINFO_SIZE, \r
+                 Attributes, \r
+                 0, \r
+                 CertData->MonotonicCount, \r
+                 VirtualMode,\r
+                 Global,\r
+                 Variable\r
+                 );\r
+    }\r
+  } else {\r
+    //\r
+    // If in setup mode, no authentication needed.\r
+    //\r
+    Status = UpdateVariable (\r
+               VariableName, \r
+               VendorGuid, \r
+               Data, \r
+               DataSize, \r
+               Attributes, \r
+               0, \r
+               0, \r
+               VirtualMode,\r
+               Global,\r
+               Variable\r
+               );\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Process variable with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set, and return the index of associated public key.\r
+\r
+  @param[in]  Data                        The data pointer.\r
+  @param[in]  DataSize                    The size of Data found. If size is less than the\r
+                                          data, this value contains the required size.\r
+  @param[in]  VirtualMode                 The current calling mode for this function.\r
+  @param[in]  Global                      The context of this Extended SAL Variable Services Class call.\r
+  @param[in]  Variable                    The variable information which is used to keep track of variable usage.\r
+  @param[in]  Attributes                  The attribute value of the variable.\r
+  @param[out] KeyIndex                    The output index of corresponding public key in database.\r
+  @param[out] MonotonicCount              The output value of corresponding Monotonic Count.\r
+\r
+  @retval EFI_INVALID_PARAMETER           Invalid parameter.\r
+  @retval EFI_WRITE_PROTECTED             The variable is write-protected and needs authentication with\r
+                                          EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.\r
+  @retval EFI_SECURITY_VIOLATION          The variable is with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS\r
+                                          set, but the AuthInfo does NOT pass the validation \r
+                                          check carried out by the firmware. \r
+  @retval EFI_SUCCESS                     The variable is not write-protected, or passed validation successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+VerifyVariable (\r
+  IN  VOID                      *Data,\r
+  IN  UINTN                     DataSize,\r
+  IN  BOOLEAN                   VirtualMode,\r
+  IN  ESAL_VARIABLE_GLOBAL      *Global,\r
+  IN  VARIABLE_POINTER_TRACK    *Variable,\r
+  IN  UINT32                    Attributes OPTIONAL,\r
+  OUT UINT32                    *KeyIndex OPTIONAL,\r
+  OUT UINT64                    *MonotonicCount OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  BOOLEAN                         IsDeletion;\r
+  BOOLEAN                         IsFirstTime;\r
+  UINT8                           *PubKey;\r
+  EFI_VARIABLE_AUTHENTICATION     *CertData;\r
+  EFI_CERT_BLOCK_RSA_2048_SHA256  *CertBlock;\r
+  VARIABLE_HEADER                 VariableHeader;\r
+  BOOLEAN                         Valid;\r
+\r
+  CertData    = NULL;\r
+  CertBlock   = NULL;\r
+  PubKey      = NULL;\r
+  IsDeletion  = FALSE;\r
+  Valid       = FALSE;\r
+\r
+  if (KeyIndex != NULL) {\r
+    *KeyIndex = 0;\r
+  }\r
+  //\r
+  // Determine if first time SetVariable with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS.\r
+  //\r
+  ZeroMem (&VariableHeader, sizeof (VARIABLE_HEADER));\r
+  if (Variable->CurrPtr != 0x0) {\r
+    Valid = IsValidVariableHeader (\r
+              Variable->CurrPtr, \r
+              Variable->Volatile, \r
+              &Global->VariableGlobal[VirtualMode], \r
+              Global->FvbInstance, \r
+              &VariableHeader\r
+              );\r
+    ASSERT (Valid);\r
+  }\r
+\r
+  if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
+    if (KeyIndex == NULL) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    //\r
+    // Determine current operation type.\r
+    //\r
+    if (DataSize == AUTHINFO_SIZE) {\r
+      IsDeletion = TRUE;\r
+    }\r
+    //\r
+    // Determine whether this is the first time with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.\r
+    //\r
+    if (Variable->CurrPtr == 0x0) {\r
+      IsFirstTime = TRUE;\r
+    } else if (Valid &&(VariableHeader.Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == 0) {\r
+      IsFirstTime = TRUE;\r
+    } else {\r
+      *KeyIndex   = VariableHeader.PubKeyIndex;\r
+      IsFirstTime = FALSE;\r
+    }\r
+  } else if (Valid && (VariableHeader.Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) { \r
+      //\r
+      // If the variable is already write-protected, it always needs authentication before update.\r
+      //\r
+      return EFI_WRITE_PROTECTED;\r
+  } else {\r
+    //\r
+    // If without EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, set and attributes collision.\r
+    // That means it is not authenticated variable, just return EFI_SUCCESS.\r
+    //\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // Get PubKey and check Monotonic Count value corresponding to the variable.\r
+  //\r
+  CertData  = (EFI_VARIABLE_AUTHENTICATION *) Data;\r
+  CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);\r
+  PubKey    = CertBlock->PublicKey;\r
+\r
+  if (MonotonicCount != NULL) {\r
+    //\r
+    // Update Monotonic Count value.\r
+    //\r
+    *MonotonicCount = CertData->MonotonicCount;\r
+  }\r
+\r
+  if (!IsFirstTime) {\r
+    //\r
+    // Check input PubKey.\r
+    //\r
+    if (CompareMem (PubKey, Global->PubKeyStore + (*KeyIndex - 1) * EFI_CERT_TYPE_RSA2048_SIZE, EFI_CERT_TYPE_RSA2048_SIZE) != 0) {\r
+      return EFI_SECURITY_VIOLATION;\r
+    }\r
+    //\r
+    // Compare the current monotonic count and ensure that it is greater than the last SetVariable\r
+    // operation with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute set.\r
+    //\r
+    if (CertData->MonotonicCount <= VariableHeader.MonotonicCount) {\r
+      //\r
+      // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.\r
+      //\r
+      return EFI_SECURITY_VIOLATION;\r
+    }\r
+  } \r
+  //\r
+  // Verify the certificate in Data payload.\r
+  //\r
+  Status = VerifyDataPayload (VirtualMode, Global, Data, DataSize, PubKey);\r
+  if (!EFI_ERROR (Status)) {\r
+    //\r
+    // Now, the signature has been verified!\r
+    //\r
+    if (IsFirstTime && !IsDeletion) {\r
+      //\r
+      // Update public key database variable if need and return the index.\r
+      //\r
+      *KeyIndex = AddPubKeyInStore (VirtualMode, Global, PubKey);\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
diff --git a/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/AuthService.h b/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/AuthService.h
new file mode 100644 (file)
index 0000000..f3e15f6
--- /dev/null
@@ -0,0 +1,151 @@
+/** @file\r
+  The internal header file includes the common header files, defines\r
+  internal structure and functions used by AuthService module.\r
+\r
+Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _AUTHSERVICE_H_\r
+#define _AUTHSERVICE_H_\r
+\r
+#define EFI_CERT_TYPE_RSA2048_SHA256_SIZE 256\r
+#define EFI_CERT_TYPE_RSA2048_SIZE        256\r
+\r
+///\r
+/// Size of AuthInfo prior to the data payload\r
+///\r
+#define AUTHINFO_SIZE (((UINTN)(((EFI_VARIABLE_AUTHENTICATION *) 0)->AuthInfo.CertData)) + sizeof (EFI_CERT_BLOCK_RSA_2048_SHA256))\r
+\r
+///\r
+/// Item number of support signature types.\r
+///\r
+#define SIGSUPPORT_NUM 2\r
+\r
+/**\r
+  Process variable with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set, and return the index of associated public key.\r
+\r
+  @param[in]  Data                        The data pointer.\r
+  @param[in]  DataSize                    The size of Data found. If size is less than the\r
+                                          data, this value contains the required size.\r
+  @param[in]  VirtualMode                 The current calling mode for this function.\r
+  @param[in]  Global                      The context of this Extended SAL Variable Services Class call.\r
+  @param[in]  Variable                    The variable information which is used to keep track of variable usage.\r
+  @param[in]  Attributes                  The attribute value of the variable.\r
+  @param[out] KeyIndex                    The output index of corresponding public key in database.\r
+  @param[out] MonotonicCount              The output value of corresponding Monotonic Count.\r
+\r
+  @retval EFI_INVALID_PARAMETER           Invalid parameter.\r
+  @retval EFI_WRITE_PROTECTED             The variable is write-protected and needs authentication with\r
+                                          EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.\r
+  @retval EFI_SECURITY_VIOLATION          The variable is with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS\r
+                                          set, but the AuthInfo does NOT pass the validation \r
+                                          check carried out by the firmware. \r
+  @retval EFI_SUCCESS                     The variable is not write-protected, or passed validation successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+VerifyVariable (\r
+  IN  VOID                      *Data,\r
+  IN  UINTN                     DataSize,\r
+  IN  BOOLEAN                   VirtualMode,\r
+  IN  ESAL_VARIABLE_GLOBAL      *Global,\r
+  IN  VARIABLE_POINTER_TRACK    *Variable,\r
+  IN  UINT32                    Attributes OPTIONAL,\r
+  OUT UINT32                    *KeyIndex OPTIONAL,\r
+  OUT UINT64                    *MonotonicCount OPTIONAL\r
+  );\r
+\r
+/**\r
+  Initializes for authenticated varibale service.\r
+\r
+  @retval EFI_SUCCESS           The function successfully executed.\r
+  @retval EFI_OUT_OF_RESOURCES  Failed to allocate enough memory resources.\r
+\r
+**/\r
+EFI_STATUS\r
+AutenticatedVariableServiceInitialize (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Initializes for cryptlib service before use, include register algrithm and allocate scratch.\r
+\r
+**/\r
+VOID\r
+CryptLibraryInitialize (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Process variable with platform key for verification.\r
+\r
+  @param[in]  VariableName                The name of Variable to be found.\r
+  @param[in]  VendorGuid                  Variable vendor GUID.\r
+  @param[in]  Data                        The data pointer.\r
+  @param[in]  DataSize                    The size of Data found. If size is less than the\r
+                                          data, this value contains the required size.\r
+  @param[in]  VirtualMode                 The current calling mode for this function.\r
+  @param[in]  Global                      The context of this Extended SAL Variable Services Class call.\r
+  @param[in]  Variable                    The variable information which is used to keep track of variable usage.\r
+  @param[in]  Attributes                  The attribute value of the variable.\r
+  @param[in]  IsPk                        Indicates whether to process pk.\r
+\r
+  @retval EFI_INVALID_PARAMETER           Invalid parameter.\r
+  @retval EFI_SECURITY_VIOLATION          The variable does NOT pass the validation \r
+                                          check carried out by the firmware. \r
+  @retval EFI_SUCCESS                     The variable passed validation successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+ProcessVarWithPk (\r
+  IN  CHAR16                    *VariableName,\r
+  IN  EFI_GUID                  *VendorGuid,\r
+  IN  VOID                      *Data,\r
+  IN  UINTN                     DataSize,\r
+  IN  BOOLEAN                   VirtualMode,\r
+  IN  ESAL_VARIABLE_GLOBAL      *Global,\r
+  IN  VARIABLE_POINTER_TRACK    *Variable,\r
+  IN  UINT32                    Attributes OPTIONAL,\r
+  IN  BOOLEAN                   IsPk\r
+  );\r
+\r
+/**\r
+  Process variable with key exchange key for verification.\r
+\r
+  @param[in]  VariableName                The name of Variable to be found.\r
+  @param[in]  VendorGuid                  The variable vendor GUID.\r
+  @param[in]  Data                        The data pointer.\r
+  @param[in]  DataSize                    Size of Data found. If size is less than the\r
+                                          data, this value contains the required size.\r
+  @param[in]  VirtualMode                 The current calling mode for this function.\r
+  @param[in]  Global                      The context of this Extended SAL Variable Services Class call.\r
+  @param[in]  Variable                    The variable information which is used to keep track of variable usage.\r
+  @param[in]  Attributes                  The attribute value of the variable.\r
+\r
+  @retval EFI_INVALID_PARAMETER           Invalid parameter.\r
+  @retval EFI_SECURITY_VIOLATION          The variable does NOT pass the validation \r
+                                          check carried out by the firmware. \r
+  @retval EFI_SUCCESS                     The variable passed validation successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+ProcessVarWithKek (\r
+  IN  CHAR16                               *VariableName,\r
+  IN  EFI_GUID                             *VendorGuid,\r
+  IN  VOID                                 *Data,\r
+  IN  UINTN                                DataSize,\r
+  IN  BOOLEAN                              VirtualMode,\r
+  IN  ESAL_VARIABLE_GLOBAL                 *Global,\r
+  IN  VARIABLE_POINTER_TRACK               *Variable,\r
+  IN  UINT32                               Attributes OPTIONAL\r
+  );\r
+\r
+#endif\r
diff --git a/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/EsalVariableDxeSal.inf b/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/EsalVariableDxeSal.inf
new file mode 100644 (file)
index 0000000..dc161c9
--- /dev/null
@@ -0,0 +1,85 @@
+## @file\r
+#  Component description file for Extended SAL authentication variable \r
+#  service module.\r
+#\r
+# Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = EsalVariableDxeSal\r
+  FILE_GUID                      = 14610837-4E97-4427-96E0-21D9B2956996\r
+  MODULE_TYPE                    = DXE_SAL_DRIVER\r
+  VERSION_STRING                 = 1.0\r
+\r
+  ENTRY_POINT                    = VariableServiceInitialize\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IPF\r
+#\r
+#  VIRTUAL_ADDRESS_MAP_CALLBACK  =  VariableClassAddressChangeEvent              \r
+#\r
+\r
+[Sources.common]\r
+  InitVariable.c\r
+  Reclaim.c\r
+  Variable.c\r
+  Variable.h\r
+  AuthService.c\r
+  AuthService.h\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+  CryptoPkg/CryptoPkg.dec\r
+  SecurityPkg/SecurityPkg.dec\r
+\r
+[LibraryClasses]\r
+  MemoryAllocationLib\r
+  BaseLib\r
+  SynchronizationLib\r
+  UefiLib\r
+  UefiBootServicesTableLib\r
+  BaseMemoryLib\r
+  DebugLib\r
+  UefiRuntimeLib\r
+  DxeServicesTableLib\r
+  UefiDriverEntryPoint\r
+  PcdLib\r
+  ExtendedSalLib\r
+  BaseCryptLib\r
+\r
+[Protocols]\r
+  gEfiFirmwareVolumeBlockProtocolGuid           # PROTOCOL SOMETIMES_CONSUMED\r
+  gEfiFaultTolerantWriteProtocolGuid            # PROTOCOL SOMETIMES_CONSUMED\r
+\r
+[Guids]\r
+  gEfiGlobalVariableGuid\r
+  gEfiAuthenticatedVariableGuid\r
+  gEfiEventVirtualAddressChangeGuid\r
+  gEfiCertRsa2048Sha256Guid\r
+  gEfiImageSecurityDatabaseGuid\r
+\r
+[Pcd.common]\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxHardwareErrorVariableSize\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdHwErrStorageSize\r
+\r
+[FeaturePcd.common]\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdVariableCollectStatistics\r
+\r
+[Depex]\r
+  gEfiExtendedSalFvBlockServicesProtocolGuid AND gEfiFaultTolerantWriteProtocolGuid\r
+  \r
diff --git a/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/InitVariable.c b/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/InitVariable.c
new file mode 100644 (file)
index 0000000..0cf8141
--- /dev/null
@@ -0,0 +1,245 @@
+/** @file\r
+  Entrypoint of Extended SAL variable service module.\r
+\r
+Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "Variable.h"\r
+#include "AuthService.h"\r
+\r
+//\r
+// Don't use module globals after the SetVirtualAddress map is signaled\r
+//\r
+EFI_EVENT mEfiVirtualNotifyEvent;\r
+\r
+/**\r
+  Common entry for Extended SAL Variable Services Class.\r
+\r
+  This is the common entry of all functions of Extended SAL Variable Services Class.\r
+\r
+  @param[in]  FunctionId        The Function ID of member function in Extended SAL Variable Services Class.\r
+  @param[in]  Arg2              The 2nd parameter for SAL procedure call.\r
+  @param[in]  Arg3              The 3rd parameter for SAL procedure call.\r
+  @param[in]  Arg4              The 4th parameter for SAL procedure call.\r
+  @param[in]  Arg5              The 5th parameter for SAL procedure call.\r
+  @param[in]  Arg6              The 6th parameter for SAL procedure call.\r
+  @param[in]  Arg7              The 7th parameter for SAL procedure call.\r
+  @param[in]  Arg8              The 8th parameter for SAL procedure call.\r
+  @param[in]  VirtualMode       The current calling mode for this function.\r
+  @param[in]  Global            The context of this Extended SAL Variable Services Class call.\r
+\r
+  @return                       The register of SAL.\r
+\r
+**/\r
+SAL_RETURN_REGS\r
+EFIAPI\r
+EsalVariableCommonEntry (\r
+  IN  UINT64                                      FunctionId,\r
+  IN  UINT64                                      Arg2,\r
+  IN  UINT64                                      Arg3,\r
+  IN  UINT64                                      Arg4,\r
+  IN  UINT64                                      Arg5,\r
+  IN  UINT64                                      Arg6,\r
+  IN  UINT64                                      Arg7,\r
+  IN  UINT64                                      Arg8,\r
+  IN  BOOLEAN                                     VirtualMode,\r
+  IN  ESAL_VARIABLE_GLOBAL                        *Global\r
+  )\r
+{\r
+  SAL_RETURN_REGS ReturnVal;\r
+  \r
+  ReturnVal.r9  = 0;\r
+  ReturnVal.r10 = 0;\r
+  ReturnVal.r11 = 0;\r
+\r
+  switch (FunctionId) {\r
+  case EsalGetVariableFunctionId:\r
+    ReturnVal.Status = EsalGetVariable (\r
+                         (CHAR16 *) Arg2,\r
+                         (EFI_GUID *) Arg3,\r
+                         (UINT32 *) Arg4,\r
+                         (UINTN *) Arg5,\r
+                         (VOID *) Arg6,\r
+                         VirtualMode,\r
+                         Global\r
+                         );\r
+    return ReturnVal;\r
+\r
+  case EsalGetNextVariableNameFunctionId:\r
+    ReturnVal.Status = EsalGetNextVariableName (\r
+                         (UINTN *) Arg2,\r
+                         (CHAR16 *) Arg3,\r
+                         (EFI_GUID *) Arg4,\r
+                         VirtualMode,\r
+                         Global\r
+                         );\r
+    return ReturnVal;\r
+\r
+  case EsalSetVariableFunctionId:\r
+    ReturnVal.Status = EsalSetVariable (\r
+                         (CHAR16 *) Arg2,\r
+                         (EFI_GUID *) Arg3,\r
+                         (UINT32) Arg4,\r
+                         (UINTN) Arg5,\r
+                         (VOID *) Arg6,\r
+                         VirtualMode,\r
+                         Global\r
+                         );\r
+    return ReturnVal;\r
+\r
+  case EsalQueryVariableInfoFunctionId:\r
+    ReturnVal.Status = EsalQueryVariableInfo (\r
+                         (UINT32) Arg2,\r
+                         (UINT64 *) Arg3,\r
+                         (UINT64 *) Arg4,\r
+                         (UINT64 *) Arg5,\r
+                         VirtualMode,\r
+                         Global\r
+                         );\r
+    return ReturnVal;\r
+\r
+  default:\r
+    ReturnVal.Status = EFI_SAL_INVALID_ARGUMENT;\r
+    return ReturnVal;\r
+  }\r
+}\r
+\r
+/**\r
+  Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.\r
+\r
+  This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.\r
+  It convers pointer to new virtual address.\r
+\r
+  @param[in]  Event        The event whose notification function is being invoked.\r
+  @param[in]  Context      The pointer to the notification function's context.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+VariableClassAddressChangeEvent (\r
+  IN EFI_EVENT        Event,\r
+  IN VOID             *Context\r
+  )\r
+{\r
+  UINTN Index;\r
+\r
+  CopyMem (\r
+    &mVariableModuleGlobal->VariableGlobal[Virtual],\r
+    &mVariableModuleGlobal->VariableGlobal[Physical],\r
+    sizeof (VARIABLE_GLOBAL)\r
+    );\r
+\r
+  EfiConvertPointer (\r
+    0x0,\r
+    (VOID **) &mVariableModuleGlobal->VariableGlobal[Virtual].NonVolatileVariableBase\r
+    );\r
+  EfiConvertPointer (\r
+    0x0,\r
+    (VOID **) &mVariableModuleGlobal->VariableGlobal[Virtual].VolatileVariableBase\r
+    );\r
+\r
+  mVariableModuleGlobal->PlatformLangCodes[Virtual] = mVariableModuleGlobal->PlatformLangCodes[Physical];\r
+  EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->PlatformLangCodes[Virtual]);\r
+\r
+  mVariableModuleGlobal->LangCodes[Virtual] = mVariableModuleGlobal->LangCodes[Physical];\r
+  EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->LangCodes[Virtual]);\r
+\r
+  mVariableModuleGlobal->PlatformLang[Virtual] = mVariableModuleGlobal->PlatformLang[Physical];\r
+  EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->PlatformLang[Virtual]);\r
+\r
+  CopyMem (\r
+    mVariableModuleGlobal->VariableName[Virtual],\r
+    mVariableModuleGlobal->VariableName[Physical],\r
+    sizeof (mVariableModuleGlobal->VariableName[Physical])\r
+    );\r
+  for (Index = 0; Index < NUM_VAR_NAME; Index++) {\r
+    EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->VariableName[Virtual][Index]);\r
+  }\r
+\r
+  mVariableModuleGlobal->GlobalVariableGuid[Virtual] = &gEfiGlobalVariableGuid;\r
+  EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->GlobalVariableGuid[Virtual]);\r
+\r
+  mVariableModuleGlobal->AuthenticatedVariableGuid[Virtual] = &gEfiAuthenticatedVariableGuid;\r
+  EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->AuthenticatedVariableGuid[Virtual]);\r
+\r
+  mVariableModuleGlobal->CertRsa2048Sha256Guid[Virtual] = &gEfiCertRsa2048Sha256Guid;\r
+  EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->CertRsa2048Sha256Guid[Virtual]);\r
+\r
+  mVariableModuleGlobal->ImageSecurityDatabaseGuid[Virtual] = &gEfiImageSecurityDatabaseGuid;\r
+  EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->ImageSecurityDatabaseGuid[Virtual]);\r
+\r
+  mVariableModuleGlobal->HashContext[Virtual] = mVariableModuleGlobal->HashContext[Physical];\r
+  EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->HashContext[Virtual]);\r
+}\r
+\r
+/**\r
+  Entry point of Extended SAL Variable service module.\r
+\r
+  This function is the entry point of Extended SAL Variable service module.\r
+  It registers all functions of Extended SAL Variable class, initializes\r
+  variable store for non-volatile and volatile variables, and registers\r
+  notification function for EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.\r
+\r
+  @param[in]  ImageHandle   The Image handle of this driver.\r
+  @param[in]  SystemTable   The pointer of EFI_SYSTEM_TABLE.\r
+\r
+  @retval     EFI_SUCCESS   Extended SAL Variable Services Class successfully registered.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+VariableServiceInitialize (\r
+  IN EFI_HANDLE         ImageHandle,\r
+  IN EFI_SYSTEM_TABLE   *SystemTable\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+\r
+  Status = gBS->CreateEventEx (\r
+                  EVT_NOTIFY_SIGNAL,\r
+                  TPL_NOTIFY,\r
+                  VariableClassAddressChangeEvent,\r
+                  NULL,\r
+                  &gEfiEventVirtualAddressChangeGuid,\r
+                  &mEfiVirtualNotifyEvent\r
+                  );\r
+\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  Status = VariableCommonInitialize (ImageHandle, SystemTable);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // Authenticated variable initialize\r
+  //\r
+  Status = AutenticatedVariableServiceInitialize ();\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // Register All the Functions with Extended SAL Variable Services Class\r
+  //\r
+  RegisterEsalClass (\r
+    EFI_EXTENDED_SAL_VARIABLE_SERVICES_PROTOCOL_GUID_LO,\r
+    EFI_EXTENDED_SAL_VARIABLE_SERVICES_PROTOCOL_GUID_HI,\r
+    mVariableModuleGlobal,\r
+    EsalVariableCommonEntry,\r
+    EsalGetVariableFunctionId,\r
+    EsalVariableCommonEntry,\r
+    EsalGetNextVariableNameFunctionId,\r
+    EsalVariableCommonEntry,\r
+    EsalSetVariableFunctionId,\r
+    EsalVariableCommonEntry,\r
+    EsalQueryVariableInfoFunctionId,\r
+    NULL\r
+    );\r
+\r
+  return EFI_SUCCESS;\r
+}\r
diff --git a/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/Reclaim.c b/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/Reclaim.c
new file mode 100644 (file)
index 0000000..1cbf9ac
--- /dev/null
@@ -0,0 +1,262 @@
+/** @file\r
+  Handles non-volatile variable store garbage collection, using FTW\r
+  (Fault Tolerant Write) protocol.\r
+\r
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "Variable.h"\r
+\r
+/**\r
+  Gets firmware volume block handle by given address.\r
+\r
+  This function gets firmware volume block handle whose\r
+  address range contains the parameter Address.\r
+\r
+  @param[in]  Address    Address which should be contained\r
+                         by returned FVB handle.\r
+  @param[out] FvbHandle  Pointer to FVB handle for output.\r
+\r
+  @retval EFI_SUCCESS    FVB handle successfully returned.\r
+  @retval EFI_NOT_FOUND  Failed to find FVB handle by address.\r
+\r
+**/\r
+EFI_STATUS\r
+GetFvbHandleByAddress (\r
+  IN  EFI_PHYSICAL_ADDRESS   Address,\r
+  OUT EFI_HANDLE             *FvbHandle\r
+  )\r
+{\r
+  EFI_STATUS                          Status;\r
+  EFI_HANDLE                          *HandleBuffer;\r
+  UINTN                               HandleCount;\r
+  UINTN                               Index;\r
+  EFI_PHYSICAL_ADDRESS                FvbBaseAddress;\r
+  EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *Fvb;\r
+  EFI_FIRMWARE_VOLUME_HEADER          *FwVolHeader;\r
+\r
+  *FvbHandle = NULL;\r
+  //\r
+  // Locate all handles with Firmware Volume Block protocol\r
+  //\r
+  Status = gBS->LocateHandleBuffer (\r
+                  ByProtocol,\r
+                  &gEfiFirmwareVolumeBlockProtocolGuid,\r
+                  NULL,\r
+                  &HandleCount,\r
+                  &HandleBuffer\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+  //\r
+  // Traverse all the handles, searching for the one containing parameter Address\r
+  //\r
+  for (Index = 0; Index < HandleCount; Index += 1) {\r
+    Status = gBS->HandleProtocol (\r
+                    HandleBuffer[Index],\r
+                    &gEfiFirmwareVolumeBlockProtocolGuid,\r
+                    (VOID **) &Fvb\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      Status = EFI_NOT_FOUND;\r
+      break;\r
+    }\r
+    //\r
+    // Checks if the address range of this handle contains parameter Address\r
+    //\r
+    Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress);\r
+    if (EFI_ERROR (Status)) {\r
+      continue;\r
+    }\r
+\r
+    FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress);\r
+    if ((Address >= FvbBaseAddress) && (Address <= (FvbBaseAddress + FwVolHeader->FvLength))) {\r
+      *FvbHandle  = HandleBuffer[Index];\r
+      Status      = EFI_SUCCESS;\r
+      break;\r
+    }\r
+  }\r
+\r
+  FreePool (HandleBuffer);\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Gets LBA of block and offset by given address.\r
+\r
+  This function gets the Logical Block Address (LBA) of firmware\r
+  volume block containing the given address, and the offset of\r
+  address on the block.\r
+\r
+  @param[in]  Address    Address which should be contained\r
+                         by returned FVB handle.\r
+  @param[out] Lba        The pointer to LBA for output.\r
+  @param[out] Offset     The pointer to offset for output.\r
+\r
+  @retval EFI_SUCCESS    LBA and offset successfully returned.\r
+  @retval EFI_NOT_FOUND  Failed to find FVB handle by address.\r
+  @retval EFI_ABORTED    Failed to find valid LBA and offset.\r
+\r
+**/\r
+EFI_STATUS\r
+GetLbaAndOffsetByAddress (\r
+  IN  EFI_PHYSICAL_ADDRESS   Address,\r
+  OUT EFI_LBA                *Lba,\r
+  OUT UINTN                  *Offset\r
+  )\r
+{\r
+  EFI_STATUS                          Status;\r
+  EFI_HANDLE                          FvbHandle;\r
+  EFI_PHYSICAL_ADDRESS                FvbBaseAddress;\r
+  EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *Fvb;\r
+  EFI_FIRMWARE_VOLUME_HEADER          *FwVolHeader;\r
+  EFI_FV_BLOCK_MAP_ENTRY              *FvbMapEntry;\r
+  UINT32                              LbaIndex;\r
+\r
+  *Lba    = (EFI_LBA) (-1);\r
+  *Offset = 0;\r
+\r
+  //\r
+  // Gets firmware volume block handle by given address.\r
+  //\r
+  Status = GetFvbHandleByAddress (Address, &FvbHandle);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = gBS->HandleProtocol (\r
+                  FvbHandle,\r
+                  &gEfiFirmwareVolumeBlockProtocolGuid,\r
+                  (VOID **) &Fvb\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Get the Base Address of FV\r
+  //\r
+  Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress);\r
+\r
+  //\r
+  // Get the (LBA, Offset) of Address\r
+  //\r
+  if ((Address >= FvbBaseAddress) && (Address <= (FvbBaseAddress + FwVolHeader->FvLength))) {\r
+    if ((FwVolHeader->FvLength) > (FwVolHeader->HeaderLength)) {\r
+      //\r
+      // BUGBUG: Assume one FV has one type of BlockLength\r
+      //\r
+      FvbMapEntry = &FwVolHeader->BlockMap[0];\r
+      for (LbaIndex = 1; LbaIndex <= FvbMapEntry->NumBlocks; LbaIndex += 1) {\r
+        if (Address < (FvbBaseAddress + FvbMapEntry->Length * LbaIndex)) {\r
+          //\r
+          // Found the (Lba, Offset)\r
+          //\r
+          *Lba    = LbaIndex - 1;\r
+          *Offset = (UINTN) (Address - (FvbBaseAddress + FvbMapEntry->Length * (LbaIndex - 1)));\r
+          return EFI_SUCCESS;\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
+  return EFI_ABORTED;\r
+}\r
+\r
+/**\r
+  Writes a buffer to variable storage space.\r
+\r
+  This function writes a buffer to variable storage space into firmware\r
+  volume block device. The destination is specified by parameter\r
+  VariableBase. Fault Tolerant Write protocol is used for writing.\r
+\r
+  @param[in] VariableBase The base address of the variable to write.\r
+  @param[in] Buffer       Points to the data buffer.\r
+  @param[in] BufferSize   The number of bytes of the data Buffer.\r
+\r
+  @retval EFI_SUCCESS     The function completed successfully.\r
+  @retval EFI_NOT_FOUND   Fail to locate Fault Tolerant Write protocol.\r
+  @retval Other           The function could not complete successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+FtwVariableSpace (\r
+  IN EFI_PHYSICAL_ADDRESS   VariableBase,\r
+  IN UINT8                  *Buffer,\r
+  IN UINTN                  BufferSize\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  EFI_HANDLE            FvbHandle;\r
+  EFI_LBA               VarLba;\r
+  UINTN                 VarOffset;\r
+  UINT8                 *FtwBuffer;\r
+  UINTN                 FtwBufferSize;\r
+  EFI_FAULT_TOLERANT_WRITE_PROTOCOL  *FtwProtocol;\r
+\r
+  //\r
+  // Locate Fault Tolerant Write protocol\r
+  //\r
+  Status = gBS->LocateProtocol (\r
+                  &gEfiFaultTolerantWriteProtocolGuid,\r
+                  NULL,\r
+                  (VOID **) &FtwProtocol\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+  //\r
+  // Gets firmware volume block handle by VariableBase.\r
+  //\r
+  Status = GetFvbHandleByAddress (VariableBase, &FvbHandle);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Gets LBA of block and offset by VariableBase.\r
+  //\r
+  Status = GetLbaAndOffsetByAddress (VariableBase, &VarLba, &VarOffset);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_ABORTED;\r
+  }\r
+  //\r
+  // Prepare for the variable data\r
+  //\r
+  FtwBufferSize = ((VARIABLE_STORE_HEADER *) ((UINTN) VariableBase))->Size;\r
+  FtwBuffer     = AllocatePool (FtwBufferSize);\r
+  if (FtwBuffer == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  SetMem (FtwBuffer, FtwBufferSize, (UINT8) 0xff);\r
+  CopyMem (FtwBuffer, Buffer, BufferSize);\r
+\r
+  //\r
+  // FTW write record\r
+  //\r
+  Status = FtwProtocol->Write (\r
+                          FtwProtocol,\r
+                          VarLba,         // LBA\r
+                          VarOffset,      // Offset\r
+                          FtwBufferSize,  // NumBytes,\r
+                          NULL,\r
+                          FvbHandle,\r
+                          FtwBuffer\r
+                          );\r
+\r
+  FreePool (FtwBuffer);\r
+  return Status;\r
+}\r
diff --git a/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/Variable.c b/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/Variable.c
new file mode 100644 (file)
index 0000000..d6c6686
--- /dev/null
@@ -0,0 +1,3198 @@
+/** @file\r
+  The implementation of Extended SAL variable services.\r
+\r
+Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "Variable.h"\r
+#include "AuthService.h"\r
+\r
+//\r
+// Don't use module globals after the SetVirtualAddress map is signaled\r
+//\r
+ESAL_VARIABLE_GLOBAL  *mVariableModuleGlobal;\r
+CHAR16 *mVariableName[NUM_VAR_NAME] = {\r
+  L"PlatformLangCodes",\r
+  L"LangCodes",\r
+  L"PlatformLang",\r
+  L"Lang",\r
+  L"HwErrRec",\r
+  AUTHVAR_KEYDB_NAME,\r
+  EFI_SETUP_MODE_NAME,\r
+  EFI_PLATFORM_KEY_NAME,\r
+  EFI_KEY_EXCHANGE_KEY_NAME\r
+};\r
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED VARIABLE_INFO_ENTRY *gVariableInfo = NULL;\r
+\r
+//\r
+// The current Hii implementation accesses this variable a larg # of times on every boot.\r
+// Other common variables are only accessed a single time. This is why this cache algorithm\r
+// only targets a single variable. Probably to get an performance improvement out of\r
+// a Cache you would need a cache that improves the search performance for a variable.\r
+//\r
+VARIABLE_CACHE_ENTRY mVariableCache[] = {\r
+  {\r
+    &gEfiGlobalVariableGuid,\r
+    L"Lang",\r
+    0x00000000,\r
+    0x00,\r
+    NULL\r
+  },\r
+  {\r
+    &gEfiGlobalVariableGuid,\r
+    L"PlatformLang",\r
+    0x00000000,\r
+    0x00,\r
+    NULL\r
+  }\r
+};\r
+\r
+/**\r
+  Acquires lock only at boot time. Simply returns at runtime.\r
+\r
+  This is a temperary function which will be removed when\r
+  EfiAcquireLock() in UefiLib can handle the call in UEFI\r
+  Runtimer driver in RT phase.\r
+  It calls EfiAcquireLock() at boot time, and simply returns\r
+  at runtime.\r
+\r
+  @param[in]  Lock     A pointer to the lock to acquire.\r
+\r
+**/\r
+VOID\r
+AcquireLockOnlyAtBootTime (\r
+  IN EFI_LOCK  *Lock\r
+  )\r
+{\r
+  if (!EfiAtRuntime ()) {\r
+    EfiAcquireLock (Lock);\r
+  }\r
+}\r
+\r
+/**\r
+  Releases lock only at boot time. Simply returns at runtime.\r
+\r
+  This is a temperary function which will be removed when\r
+  EfiReleaseLock() in UefiLib can handle the call in UEFI\r
+  Runtimer driver in RT phase.\r
+  It calls EfiReleaseLock() at boot time, and simply returns\r
+  at runtime\r
+\r
+  @param[in]  Lock    A pointer to the lock to release.\r
+\r
+**/\r
+VOID\r
+ReleaseLockOnlyAtBootTime (\r
+  IN EFI_LOCK  *Lock\r
+  )\r
+{\r
+  if (!EfiAtRuntime ()) {\r
+    EfiReleaseLock (Lock);\r
+  }\r
+}\r
+\r
+/**\r
+  Reads/Writes variable storage, volatile or non-volatile.\r
+\r
+  This function reads or writes volatile or non-volatile variable stroage.\r
+  For volatile storage, it performs memory copy.\r
+  For non-volatile storage, it accesses data on firmware storage. Data\r
+  area to access can span multiple firmware blocks.\r
+\r
+  @param[in]      Write           TRUE  - Write variable store.\r
+                                  FALSE - Read variable store.\r
+  @param[in]      Global          Pointer to VARAIBLE_GLOBAL structure.\r
+  @param[in]      Volatile        TRUE  - Variable is volatile.\r
+                                  FALSE - Variable is non-volatile.\r
+  @param[in]      Instance        Instance of FV Block services.\r
+  @param[in]      StartAddress    Start address of data to access.\r
+  @param[in]      DataSize        Size of data to access.\r
+  @param[in, out] Buffer          For write, pointer to the buffer from which data is written.\r
+                                  For read, pointer to the buffer to hold the data read.\r
+\r
+  @retval EFI_SUCCESS            Variable store successfully accessed.\r
+  @retval EFI_INVALID_PARAMETER  Data area to access exceeds valid variable storage.\r
+\r
+**/\r
+EFI_STATUS\r
+AccessVariableStore (\r
+  IN     BOOLEAN                 Write,\r
+  IN     VARIABLE_GLOBAL         *Global,\r
+  IN     BOOLEAN                 Volatile,\r
+  IN     UINTN                   Instance,\r
+  IN     EFI_PHYSICAL_ADDRESS    StartAddress,\r
+  IN     UINT32                  DataSize,\r
+  IN OUT VOID                    *Buffer\r
+  )\r
+{\r
+  EFI_FV_BLOCK_MAP_ENTRY      *PtrBlockMapEntry;\r
+  UINTN                       BlockIndex;\r
+  UINTN                       LinearOffset;\r
+  UINTN                       CurrWriteSize;\r
+  UINTN                       CurrWritePtr;\r
+  UINT8                       *CurrBuffer;\r
+  EFI_LBA                     LbaNumber;\r
+  UINTN                       Size;\r
+  EFI_FIRMWARE_VOLUME_HEADER  *FwVolHeader;\r
+  VARIABLE_STORE_HEADER       *VolatileBase;\r
+  EFI_PHYSICAL_ADDRESS        FvVolHdr;\r
+  EFI_STATUS                  Status;\r
+  VARIABLE_STORE_HEADER       *VariableStoreHeader;\r
+\r
+  FvVolHdr = 0;\r
+  FwVolHeader = NULL;\r
+\r
+  if (Volatile) {\r
+    //\r
+    // If data is volatile, simply calculate the data pointer and copy memory.\r
+    // Data pointer should point to the actual address where data is to be\r
+    // accessed.\r
+    //\r
+    VolatileBase = (VARIABLE_STORE_HEADER *) ((UINTN) Global->VolatileVariableBase);\r
+\r
+    if ((StartAddress + DataSize) > ((UINTN) ((UINT8 *) VolatileBase + VolatileBase->Size))) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+    \r
+    //\r
+    // For volatile variable, a simple memory copy is enough.\r
+    //\r
+    if (Write) {\r
+      CopyMem ((VOID *) StartAddress, Buffer, DataSize);\r
+    } else {\r
+      CopyMem (Buffer, (VOID *) StartAddress, DataSize);\r
+    }\r
+\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // If data is non-volatile, calculate firmware volume header and data pointer.\r
+  //\r
+  Status = (EFI_STATUS) EsalCall (\r
+                          EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID_LO,\r
+                          EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID_HI,\r
+                          GetPhysicalAddressFunctionId, \r
+                          Instance, \r
+                          (UINT64) &FvVolHdr, \r
+                          0, \r
+                          0, \r
+                          0, \r
+                          0, \r
+                          0\r
+                          ).Status;\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvVolHdr);\r
+  ASSERT (FwVolHeader != NULL);\r
+  VariableStoreHeader = (VARIABLE_STORE_HEADER *)(FwVolHeader + 1);\r
+\r
+  if ((StartAddress + DataSize) > ((EFI_PHYSICAL_ADDRESS) (UINTN) ((CHAR8 *)VariableStoreHeader + VariableStoreHeader->Size))) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  \r
+  LinearOffset  = (UINTN) FwVolHeader;\r
+  CurrWritePtr  = StartAddress;\r
+  CurrWriteSize = DataSize;\r
+  CurrBuffer    = Buffer;\r
+  LbaNumber     = 0;\r
+\r
+  if (CurrWritePtr < LinearOffset) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Traverse data blocks of this firmware storage to find the one where CurrWritePtr locates\r
+  //\r
+  for (PtrBlockMapEntry = FwVolHeader->BlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) {\r
+    for (BlockIndex = 0; BlockIndex < PtrBlockMapEntry->NumBlocks; BlockIndex++) {\r
+      if ((CurrWritePtr >= LinearOffset) && (CurrWritePtr < LinearOffset + PtrBlockMapEntry->Length)) {\r
+        //\r
+        // Check to see if the data area to access spans multiple blocks.\r
+        //\r
+        if ((CurrWritePtr + CurrWriteSize) <= (LinearOffset + PtrBlockMapEntry->Length)) {\r
+          //\r
+          // If data area to access is contained in one block, just access and return.\r
+          //\r
+          if (Write) {\r
+            Status = (EFI_STATUS) EsalCall (\r
+                                    EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID_LO,\r
+                                    EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID_HI,\r
+                                    WriteFunctionId, \r
+                                    Instance, \r
+                                    LbaNumber, \r
+                                    (CurrWritePtr - LinearOffset), \r
+                                    (UINT64) &CurrWriteSize, \r
+                                    (UINT64) CurrBuffer, \r
+                                    0, \r
+                                    0\r
+                                    ).Status;\r
+          } else {\r
+            Status = (EFI_STATUS) EsalCall (\r
+                                    EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID_LO,\r
+                                    EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID_HI,\r
+                                    ReadFunctionId, \r
+                                    Instance, \r
+                                    LbaNumber, \r
+                                    (CurrWritePtr - LinearOffset), \r
+                                    (UINT64) &CurrWriteSize, \r
+                                    (UINT64) CurrBuffer, \r
+                                    0, \r
+                                    0\r
+                                    ).Status;\r
+          }\r
+          return Status;\r
+        } else {\r
+          //\r
+          // If data area to access spans multiple blocks, access this one and adjust for the next one.\r
+          //\r
+          Size = (UINT32) (LinearOffset + PtrBlockMapEntry->Length - CurrWritePtr);\r
+          if (Write) {\r
+            Status = (EFI_STATUS) EsalCall (\r
+                                    EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID_LO,\r
+                                    EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID_HI,\r
+                                    WriteFunctionId, \r
+                                    Instance, \r
+                                    LbaNumber, \r
+                                    (CurrWritePtr - LinearOffset), \r
+                                    (UINT64) &Size, \r
+                                    (UINT64) CurrBuffer, \r
+                                    0, \r
+                                    0\r
+                                    ).Status;\r
+          } else {\r
+            Status = (EFI_STATUS) EsalCall (\r
+                                    EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID_LO,\r
+                                    EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID_HI,\r
+                                    ReadFunctionId, \r
+                                    Instance, \r
+                                    LbaNumber, \r
+                                    (CurrWritePtr - LinearOffset), \r
+                                    (UINT64) &Size, \r
+                                    (UINT64) CurrBuffer, \r
+                                    0, \r
+                                    0\r
+                                    ).Status;\r
+          }\r
+          if (EFI_ERROR (Status)) {\r
+            return Status;\r
+          }\r
+          //\r
+          // Adjust for the remaining data.\r
+          //\r
+          CurrWritePtr  = LinearOffset + PtrBlockMapEntry->Length;\r
+          CurrBuffer    = CurrBuffer + Size;\r
+          CurrWriteSize = CurrWriteSize - Size;\r
+        }\r
+      }\r
+\r
+      LinearOffset += PtrBlockMapEntry->Length;\r
+      LbaNumber++;\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Retrieves header of volatile or non-volatile variable stroage.\r
+\r
+  @param[in]  VarStoreAddress    Start address of variable storage.\r
+  @param[in]  Volatile           TRUE  - Variable storage is volatile.\r
+                                 FALSE - Variable storage is non-volatile.\r
+  @param[in]  Global             Pointer to VARAIBLE_GLOBAL structure.\r
+  @param[in]  Instance           Instance of FV Block services.\r
+  @param[out] VarStoreHeader     Pointer to VARIABLE_STORE_HEADER for output.\r
+\r
+**/\r
+VOID\r
+GetVarStoreHeader (\r
+  IN  EFI_PHYSICAL_ADDRESS   VarStoreAddress,\r
+  IN  BOOLEAN                Volatile,\r
+  IN  VARIABLE_GLOBAL        *Global,\r
+  IN  UINTN                  Instance,\r
+  OUT VARIABLE_STORE_HEADER  *VarStoreHeader\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+\r
+  Status = AccessVariableStore (\r
+             FALSE,\r
+             Global,\r
+             Volatile,\r
+             Instance,\r
+             VarStoreAddress,\r
+             sizeof (VARIABLE_STORE_HEADER),\r
+             VarStoreHeader    \r
+             );\r
+  ASSERT_EFI_ERROR (Status);\r
+}\r
+\r
+/**\r
+  Checks variable header.\r
+\r
+  This function checks if variable header is valid or not.\r
+\r
+  @param[in]  VariableAddress    Start address of variable header.\r
+  @param[in]  Volatile           TRUE  - Variable is volatile.\r
+                                 FALSE - Variable is non-volatile.\r
+  @param[in]  Global             Pointer to VARAIBLE_GLOBAL structure.\r
+  @param[in]  Instance           Instance of FV Block services.\r
+  @param[out] VariableHeader     Pointer to VARIABLE_HEADER for output.\r
+\r
+  @retval TRUE                   Variable header is valid.\r
+  @retval FALSE                  Variable header is not valid.\r
+\r
+**/\r
+BOOLEAN\r
+IsValidVariableHeader (\r
+  IN  EFI_PHYSICAL_ADDRESS   VariableAddress,\r
+  IN  BOOLEAN                Volatile,\r
+  IN  VARIABLE_GLOBAL        *Global,\r
+  IN  UINTN                  Instance,\r
+  OUT VARIABLE_HEADER        *VariableHeader  OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  VARIABLE_HEADER       LocalVariableHeader;\r
+\r
+  Status = AccessVariableStore (\r
+             FALSE,\r
+             Global,\r
+             Volatile,\r
+             Instance,\r
+             VariableAddress,\r
+             sizeof (VARIABLE_HEADER),\r
+             &LocalVariableHeader    \r
+             );\r
+\r
+  if (EFI_ERROR (Status) || LocalVariableHeader.StartId != VARIABLE_DATA) {\r
+    return FALSE;\r
+  }\r
+\r
+  if (VariableHeader != NULL) {\r
+    CopyMem (VariableHeader, &LocalVariableHeader, sizeof (VARIABLE_HEADER));\r
+  }\r
+\r
+  return TRUE;\r
+}\r
+\r
+/**\r
+  Gets status of variable store.\r
+\r
+  This function gets the current status of variable store.\r
+\r
+  @param[in] VarStoreHeader  Pointer to header of variable store.\r
+\r
+  @retval EfiRaw          Variable store status is raw.\r
+  @retval EfiValid        Variable store status is valid.\r
+  @retval EfiInvalid      Variable store status is invalid.\r
+\r
+**/\r
+VARIABLE_STORE_STATUS\r
+GetVariableStoreStatus (\r
+  IN VARIABLE_STORE_HEADER *VarStoreHeader\r
+  )\r
+{\r
+\r
+  if (CompareGuid (&VarStoreHeader->Signature, &gEfiAuthenticatedVariableGuid) &&\r
+      VarStoreHeader->Format == VARIABLE_STORE_FORMATTED &&\r
+      VarStoreHeader->State == VARIABLE_STORE_HEALTHY\r
+      ) {\r
+\r
+    return EfiValid;\r
+  } else if (((UINT32 *)(&VarStoreHeader->Signature))[0] == 0xffffffff &&\r
+             ((UINT32 *)(&VarStoreHeader->Signature))[1] == 0xffffffff &&\r
+             ((UINT32 *)(&VarStoreHeader->Signature))[2] == 0xffffffff &&\r
+             ((UINT32 *)(&VarStoreHeader->Signature))[3] == 0xffffffff &&\r
+             VarStoreHeader->Size == 0xffffffff &&\r
+             VarStoreHeader->Format == 0xff &&\r
+             VarStoreHeader->State == 0xff\r
+          ) {\r
+\r
+    return EfiRaw;\r
+  } else {\r
+    return EfiInvalid;\r
+  }\r
+}\r
+\r
+/**\r
+  Gets the size of variable name.\r
+\r
+  This function gets the size of variable name.\r
+  The variable is specified by its variable header.\r
+  If variable header contains raw data, just return 0.\r
+\r
+  @param[in] Variable  Pointer to the variable header.\r
+\r
+  @return              Size of variable name in bytes.\r
+\r
+**/\r
+UINTN\r
+NameSizeOfVariable (\r
+  IN  VARIABLE_HEADER   *Variable\r
+  )\r
+{\r
+  if (Variable->State    == (UINT8) (-1) ||\r
+      Variable->DataSize == (UINT32) -1 ||\r
+      Variable->NameSize == (UINT32) -1 ||\r
+      Variable->Attributes == (UINT32) -1) {\r
+    return 0;\r
+  }\r
+  return (UINTN) Variable->NameSize;\r
+}\r
+\r
+/**\r
+  Gets the size of variable data area.\r
+\r
+  This function gets the size of variable data area.\r
+  The variable is specified by its variable header.\r
+  If variable header contains raw data, just return 0.\r
+\r
+  @param[in]  Variable  Pointer to the variable header.\r
+\r
+  @return               Size of variable data area in bytes.\r
+\r
+**/\r
+UINTN\r
+DataSizeOfVariable (\r
+  IN  VARIABLE_HEADER   *Variable\r
+  )\r
+{\r
+  if (Variable->State    == (UINT8)  -1 ||\r
+      Variable->DataSize == (UINT32) -1 ||\r
+      Variable->NameSize == (UINT32) -1 ||\r
+      Variable->Attributes == (UINT32) -1) {\r
+    return 0;\r
+  }\r
+  return (UINTN) Variable->DataSize;\r
+}\r
+\r
+/**\r
+  Gets the pointer to variable name.\r
+\r
+  This function gets the pointer to variable name.\r
+  The variable is specified by its variable header.\r
+\r
+  @param[in]  VariableAddress    Start address of variable header.\r
+  @param[in]  Volatile           TRUE  - Variable is volatile.\r
+                                 FALSE - Variable is non-volatile.\r
+  @param[in]  Global             Pointer to VARAIBLE_GLOBAL structure.\r
+  @param[in]  Instance           Instance of FV Block services.\r
+  @param[out] VariableName       Buffer to hold variable name for output.\r
+\r
+**/\r
+VOID\r
+GetVariableNamePtr (\r
+  IN  EFI_PHYSICAL_ADDRESS   VariableAddress,\r
+  IN  BOOLEAN                Volatile,\r
+  IN  VARIABLE_GLOBAL        *Global,\r
+  IN  UINTN                  Instance,\r
+  OUT CHAR16                 *VariableName\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  EFI_PHYSICAL_ADDRESS  Address;\r
+  VARIABLE_HEADER       VariableHeader;\r
+  BOOLEAN               IsValid;\r
+\r
+  IsValid = IsValidVariableHeader (VariableAddress, Volatile, Global, Instance, &VariableHeader);\r
+  ASSERT (IsValid);\r
+\r
+  //\r
+  // Name area follows variable header.\r
+  //\r
+  Address = VariableAddress + sizeof (VARIABLE_HEADER);\r
+\r
+  Status = AccessVariableStore (\r
+             FALSE,\r
+             Global,\r
+             Volatile,\r
+             Instance,\r
+             Address,\r
+             VariableHeader.NameSize,\r
+             VariableName    \r
+             );\r
+  ASSERT_EFI_ERROR (Status);\r
+}\r
+\r
+/**\r
+  Gets the pointer to variable data area.\r
+\r
+  This function gets the pointer to variable data area.\r
+  The variable is specified by its variable header.\r
+\r
+  @param[in]  VariableAddress    Start address of variable header.\r
+  @param[in]  Volatile           TRUE  - Variable is volatile.\r
+                                 FALSE - Variable is non-volatile.\r
+  @param[in]  Global             Pointer to VARAIBLE_GLOBAL structure.\r
+  @param[in]  Instance           Instance of FV Block services.\r
+  @param[out] VariableData       Buffer to hold variable data for output.\r
+\r
+**/\r
+VOID\r
+GetVariableDataPtr (\r
+  IN  EFI_PHYSICAL_ADDRESS   VariableAddress,\r
+  IN  BOOLEAN                Volatile,\r
+  IN  VARIABLE_GLOBAL        *Global,\r
+  IN  UINTN                  Instance,\r
+  OUT CHAR16                 *VariableData\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  EFI_PHYSICAL_ADDRESS  Address;\r
+  VARIABLE_HEADER       VariableHeader;\r
+  BOOLEAN               IsValid;\r
+\r
+  IsValid = IsValidVariableHeader (VariableAddress, Volatile, Global, Instance, &VariableHeader);\r
+  ASSERT (IsValid);\r
+\r
+  //\r
+  // Data area follows variable name.\r
+  // Be careful about pad size for alignment\r
+  //\r
+  Address =  VariableAddress + sizeof (VARIABLE_HEADER);\r
+  Address += NameSizeOfVariable (&VariableHeader);\r
+  Address += GET_PAD_SIZE (NameSizeOfVariable (&VariableHeader));\r
+\r
+  Status = AccessVariableStore (\r
+             FALSE,\r
+             Global,\r
+             Volatile,\r
+             Instance,\r
+             Address,\r
+             VariableHeader.DataSize,\r
+             VariableData    \r
+             );\r
+  ASSERT_EFI_ERROR (Status);\r
+}\r
+\r
+\r
+/**\r
+  Gets the pointer to the next variable header.\r
+\r
+  This function gets the pointer to the next variable header.\r
+  The variable is specified by its variable header.\r
+\r
+  @param[in]  VariableAddress    Start address of variable header.\r
+  @param[in]  Volatile           TRUE  - Variable is volatile.\r
+                                 FALSE - Variable is non-volatile.\r
+  @param[in]  Global             Pointer to VARAIBLE_GLOBAL structure.\r
+  @param[in]  Instance           Instance of FV Block services.\r
+\r
+  @return                        Pointer to the next variable header.\r
+                                 NULL if variable header is invalid.\r
+\r
+**/\r
+EFI_PHYSICAL_ADDRESS\r
+GetNextVariablePtr (\r
+  IN  EFI_PHYSICAL_ADDRESS   VariableAddress,\r
+  IN  BOOLEAN                Volatile,\r
+  IN  VARIABLE_GLOBAL        *Global,\r
+  IN  UINTN                  Instance\r
+  )\r
+{\r
+  EFI_PHYSICAL_ADDRESS  Address;\r
+  VARIABLE_HEADER       VariableHeader;\r
+\r
+  if (!IsValidVariableHeader (VariableAddress, Volatile, Global, Instance, &VariableHeader)) {\r
+    return 0x0;\r
+  }\r
+\r
+  //\r
+  // Header of next variable follows data area of this variable\r
+  //\r
+  Address =  VariableAddress + sizeof (VARIABLE_HEADER);\r
+  Address += NameSizeOfVariable (&VariableHeader);\r
+  Address += GET_PAD_SIZE (NameSizeOfVariable (&VariableHeader));\r
+  Address += DataSizeOfVariable (&VariableHeader);\r
+  Address += GET_PAD_SIZE (DataSizeOfVariable (&VariableHeader));\r
+\r
+  //\r
+  // Be careful about pad size for alignment\r
+  //\r
+  return HEADER_ALIGN (Address);\r
+}\r
+\r
+/**\r
+  Gets the pointer to the first variable header in given variable store area.\r
+\r
+  This function gets the pointer to the first variable header in given variable \r
+  store area. The variable store area is given by its start address.\r
+\r
+  @param[in] VarStoreHeaderAddress  Pointer to the header of variable store area.\r
+\r
+  @return                           Pointer to the first variable header.\r
+\r
+**/\r
+EFI_PHYSICAL_ADDRESS\r
+GetStartPointer (\r
+  IN EFI_PHYSICAL_ADDRESS  VarStoreHeaderAddress\r
+  )\r
+{\r
+  return HEADER_ALIGN (VarStoreHeaderAddress + sizeof (VARIABLE_STORE_HEADER));\r
+}\r
+\r
+/**\r
+  Gets the pointer to the end of given variable store area.\r
+\r
+  This function gets the pointer to the end of given variable store area.\r
+  The variable store area is given by its start address.\r
+\r
+  @param[in]  VarStoreHeaderAddress  Pointer to the header of variable store area.\r
+  @param[in]  Volatile               TRUE  - Variable is volatile.\r
+                                     FALSE - Variable is non-volatile.\r
+  @param[in]  Global                 Pointer to VARAIBLE_GLOBAL structure.\r
+  @param[in]  Instance               Instance of FV Block services.\r
+\r
+  @return                            Pointer to the end of given variable store area.\r
+\r
+**/\r
+EFI_PHYSICAL_ADDRESS\r
+GetEndPointer (\r
+  IN EFI_PHYSICAL_ADDRESS  VarStoreHeaderAddress,\r
+  IN  BOOLEAN              Volatile,\r
+  IN  VARIABLE_GLOBAL      *Global,\r
+  IN  UINTN                Instance\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  VARIABLE_STORE_HEADER VariableStoreHeader;\r
+\r
+  Status = AccessVariableStore (\r
+             FALSE,\r
+             Global,\r
+             Volatile,\r
+             Instance,\r
+             VarStoreHeaderAddress,\r
+             sizeof (VARIABLE_STORE_HEADER),\r
+             &VariableStoreHeader    \r
+             );\r
+\r
+  ASSERT_EFI_ERROR (Status);\r
+  return HEADER_ALIGN (VarStoreHeaderAddress + VariableStoreHeader.Size);\r
+}\r
+\r
+/**\r
+  Updates variable info entry in EFI system table for statistical information.\r
+\r
+  Routine used to track statistical information about variable usage. \r
+  The data is stored in the EFI system table so it can be accessed later.\r
+  VariableInfo.efi can dump out the table. Only Boot Services variable \r
+  accesses are tracked by this code. The PcdVariableCollectStatistics\r
+  build flag controls if this feature is enabled. \r
+  A read that hits in the cache will have Read and Cache true for \r
+  the transaction. Data is allocated by this routine, but never\r
+  freed.\r
+\r
+  @param[in]  VariableName   Name of the Variable to track.\r
+  @param[in]  VendorGuid     Guid of the Variable to track.\r
+  @param[in]  Volatile       TRUE if volatile FALSE if non-volatile.\r
+  @param[in]  Read           TRUE if GetVariable() was called.\r
+  @param[in]  Write          TRUE if SetVariable() was called.\r
+  @param[in]  Delete         TRUE if deleted via SetVariable().\r
+  @param[in]  Cache          TRUE for a cache hit.\r
+\r
+**/\r
+VOID\r
+UpdateVariableInfo (\r
+  IN  CHAR16                  *VariableName,\r
+  IN  EFI_GUID                *VendorGuid,\r
+  IN  BOOLEAN                 Volatile,\r
+  IN  BOOLEAN                 Read,\r
+  IN  BOOLEAN                 Write,\r
+  IN  BOOLEAN                 Delete,\r
+  IN  BOOLEAN                 Cache\r
+  )\r
+{\r
+  VARIABLE_INFO_ENTRY   *Entry;\r
+\r
+  if (FeaturePcdGet (PcdVariableCollectStatistics)) {\r
+\r
+    if (EfiAtRuntime ()) {\r
+      //\r
+      // Don't collect statistics at runtime\r
+      //\r
+      return;\r
+    }\r
+\r
+    if (gVariableInfo == NULL) {\r
+      //\r
+      // on the first call allocate a entry and place a pointer to it in\r
+      // the EFI System Table\r
+      //\r
+      gVariableInfo = AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY));\r
+      ASSERT (gVariableInfo != NULL);\r
+\r
+      CopyGuid (&gVariableInfo->VendorGuid, VendorGuid);\r
+      gVariableInfo->Name = AllocatePool (StrSize (VariableName));\r
+      ASSERT (gVariableInfo->Name != NULL);\r
+      StrCpy (gVariableInfo->Name, VariableName);\r
+      gVariableInfo->Volatile = Volatile;\r
+\r
+      gBS->InstallConfigurationTable (&gEfiAuthenticatedVariableGuid, gVariableInfo);\r
+    }\r
+\r
+    \r
+    for (Entry = gVariableInfo; Entry != NULL; Entry = Entry->Next) {\r
+      if (CompareGuid (VendorGuid, &Entry->VendorGuid)) {\r
+        if (StrCmp (VariableName, Entry->Name) == 0) {\r
+          //\r
+          // Find the entry matching both variable name and vender GUID,\r
+          // and update counters for all types.\r
+          //\r
+          if (Read) {\r
+            Entry->ReadCount++;\r
+          }\r
+          if (Write) {\r
+            Entry->WriteCount++;\r
+          }\r
+          if (Delete) {\r
+            Entry->DeleteCount++;\r
+          }\r
+          if (Cache) {\r
+            Entry->CacheCount++;\r
+          }\r
+\r
+          return;\r
+        }\r
+      }\r
+\r
+      if (Entry->Next == NULL) {\r
+        //\r
+        // If the entry is not in the table add it.\r
+        // Next iteration of the loop will fill in the data\r
+        //\r
+        Entry->Next = AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY));\r
+        ASSERT (Entry->Next != NULL);\r
+\r
+        CopyGuid (&Entry->Next->VendorGuid, VendorGuid);\r
+        Entry->Next->Name = AllocatePool (StrSize (VariableName));\r
+        ASSERT (Entry->Next->Name != NULL);\r
+        StrCpy (Entry->Next->Name, VariableName);\r
+        Entry->Next->Volatile = Volatile;\r
+      }\r
+\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+  Updates variable in cache.\r
+\r
+  This function searches the variable cache. If the variable to set exists in the cache,\r
+  it updates the variable in cache. It has the same parameters with UEFI SetVariable()\r
+  service.\r
+\r
+  @param[in]  VariableName  A Null-terminated Unicode string that is the name of the vendor's\r
+                            variable.  Each VariableName is unique for each VendorGuid.\r
+  @param[in]  VendorGuid    A unique identifier for the vendor.\r
+  @param[in]  Attributes    Attributes bitmask to set for the variable.\r
+  @param[in]  DataSize      The size in bytes of the Data buffer.  A size of zero causes the\r
+                            variable to be deleted.\r
+  @param[in]  Data          The contents for the variable.\r
+\r
+**/\r
+VOID\r
+UpdateVariableCache (\r
+  IN      CHAR16            *VariableName,\r
+  IN      EFI_GUID          *VendorGuid,\r
+  IN      UINT32            Attributes,\r
+  IN      UINTN             DataSize,\r
+  IN      VOID              *Data\r
+  )\r
+{\r
+  VARIABLE_CACHE_ENTRY      *Entry;\r
+  UINTN                     Index;\r
+\r
+  if (EfiAtRuntime ()) {\r
+    //\r
+    // Don't use the cache at runtime\r
+    //\r
+    return;\r
+  }\r
+\r
+  //\r
+  // Searches cache for the variable to update. If it exists, update it.\r
+  //\r
+  for (Index = 0, Entry = mVariableCache; Index < sizeof (mVariableCache)/sizeof (VARIABLE_CACHE_ENTRY); Index++, Entry++) {\r
+    if (CompareGuid (VendorGuid, Entry->Guid)) {\r
+      if (StrCmp (VariableName, Entry->Name) == 0) { \r
+        Entry->Attributes = Attributes;\r
+        if (DataSize == 0) {\r
+          //\r
+          // If DataSize is 0, delete the variable.\r
+          //\r
+          if (Entry->DataSize != 0) {\r
+            FreePool (Entry->Data);\r
+          }\r
+          Entry->DataSize = DataSize;\r
+        } else if (DataSize == Entry->DataSize) {\r
+          //\r
+          // If size of data does not change, simply copy data\r
+          //\r
+          CopyMem (Entry->Data, Data, DataSize);\r
+        } else {\r
+          //\r
+          // If size of data changes, allocate pool and copy data.\r
+          //\r
+          Entry->Data = AllocatePool (DataSize);\r
+          Entry->DataSize = DataSize;\r
+          CopyMem (Entry->Data, Data, DataSize);\r
+        }\r
+      }\r
+    }\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Search the cache to check if the variable is in it.\r
+\r
+  This function searches the variable cache. If the variable to find exists, return its data\r
+  and attributes.\r
+\r
+  @param[in]      VariableName   A Null-terminated Unicode string that is the name of the vendor's\r
+                                 variable.  Each VariableName is unique for each VendorGuid.\r
+  @param[in]      VendorGuid     A unique identifier for the vendor\r
+  @param[out]     Attributes     Pointer to the attributes bitmask of the variable for output.\r
+  @param[in, out] DataSize       On input, size of the buffer of Data.\r
+                                 On output, size of the variable's data.\r
+  @param[out]     Data           Pointer to the data buffer for output.\r
+\r
+  @retval EFI_SUCCESS           VariableGuid & VariableName data was returned.\r
+  @retval EFI_NOT_FOUND         No matching variable found in cache.\r
+  @retval EFI_BUFFER_TOO_SMALL  *DataSize is smaller than size of the variable's data to return.\r
+\r
+**/\r
+EFI_STATUS\r
+FindVariableInCache (\r
+  IN      CHAR16            *VariableName,\r
+  IN      EFI_GUID          *VendorGuid,\r
+  OUT     UINT32            *Attributes OPTIONAL,\r
+  IN OUT  UINTN             *DataSize,\r
+  OUT     VOID              *Data\r
+  )\r
+{\r
+  VARIABLE_CACHE_ENTRY      *Entry;\r
+  UINTN                     Index;\r
+\r
+  if (EfiAtRuntime ()) {\r
+    //\r
+    // Don't use the cache at runtime\r
+    //\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  //\r
+  // Searches cache for the variable\r
+  //\r
+  for (Index = 0, Entry = mVariableCache; Index < sizeof (mVariableCache)/sizeof (VARIABLE_CACHE_ENTRY); Index++, Entry++) {\r
+    if (CompareGuid (VendorGuid, Entry->Guid)) {\r
+      if (StrCmp (VariableName, Entry->Name) == 0) {\r
+        if (Entry->DataSize == 0) {\r
+          //\r
+          // Variable has been deleted so return EFI_NOT_FOUND\r
+          //\r
+          return EFI_NOT_FOUND;\r
+        } else if (Entry->DataSize > *DataSize) {\r
+          //\r
+          // If buffer is too small, return the size needed and EFI_BUFFER_TOO_SMALL\r
+          //\r
+          *DataSize = Entry->DataSize;\r
+          return EFI_BUFFER_TOO_SMALL;\r
+        } else {\r
+          //\r
+          // If buffer is large enough, return the data\r
+          //\r
+          *DataSize = Entry->DataSize;\r
+          CopyMem (Data, Entry->Data, Entry->DataSize);\r
+          //\r
+          // If Attributes is not NULL, return the variable's attribute.\r
+          //\r
+          if (Attributes != NULL) {\r
+            *Attributes = Entry->Attributes;\r
+          }\r
+          return EFI_SUCCESS;\r
+        }\r
+      }\r
+    }\r
+  }\r
+  \r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+/**\r
+  Finds variable in volatile and non-volatile storage areas.\r
+\r
+  This code finds variable in volatile and non-volatile storage areas.\r
+  If VariableName is an empty string, then we just return the first\r
+  qualified variable without comparing VariableName and VendorGuid.\r
+  Otherwise, VariableName and VendorGuid are compared.\r
+\r
+  @param[in]  VariableName            Name of the variable to be found.\r
+  @param[in]  VendorGuid              Vendor GUID to be found.\r
+  @param[out] PtrTrack                VARIABLE_POINTER_TRACK structure for output,\r
+                                      including the range searched and the target position.\r
+  @param[in]  Global                  Pointer to VARIABLE_GLOBAL structure, including\r
+                                      base of volatile variable storage area, base of\r
+                                      NV variable storage area, and a lock.\r
+  @param[in]  Instance                Instance of FV Block services.\r
+\r
+  @retval EFI_INVALID_PARAMETER       If VariableName is not an empty string, while\r
+                                      VendorGuid is NULL.\r
+  @retval EFI_SUCCESS                 Variable successfully found.\r
+  @retval EFI_INVALID_PARAMETER       Variable not found.\r
+\r
+**/\r
+EFI_STATUS\r
+FindVariable (\r
+  IN  CHAR16                  *VariableName,\r
+  IN  EFI_GUID                *VendorGuid,\r
+  OUT VARIABLE_POINTER_TRACK  *PtrTrack,\r
+  IN  VARIABLE_GLOBAL         *Global,\r
+  IN  UINTN                   Instance\r
+  )\r
+{\r
+  EFI_PHYSICAL_ADDRESS    Variable[2];\r
+  EFI_PHYSICAL_ADDRESS    InDeletedVariable;\r
+  EFI_PHYSICAL_ADDRESS    VariableStoreHeader[2];\r
+  UINTN                   InDeletedStorageIndex;\r
+  UINTN                   Index;\r
+  CHAR16                  LocalVariableName[MAX_NAME_SIZE];\r
+  BOOLEAN                 Volatile;\r
+  VARIABLE_HEADER         VariableHeader;\r
+\r
+  //\r
+  // 0: Volatile, 1: Non-Volatile\r
+  // The index and attributes mapping must be kept in this order as RuntimeServiceGetNextVariableName\r
+  // make use of this mapping to implement search algorithme.\r
+  //\r
+  VariableStoreHeader[0]  = Global->VolatileVariableBase;\r
+  VariableStoreHeader[1]  = Global->NonVolatileVariableBase;\r
+\r
+  //\r
+  // Start Pointers for the variable.\r
+  // Actual Data Pointer where data can be written.\r
+  //\r
+  Variable[0] = GetStartPointer (VariableStoreHeader[0]);\r
+  Variable[1] = GetStartPointer (VariableStoreHeader[1]);\r
+\r
+  if (VariableName[0] != 0 && VendorGuid == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Find the variable by walk through volatile and then non-volatile variable store\r
+  //\r
+  InDeletedVariable     = 0x0;\r
+  InDeletedStorageIndex = 0;\r
+  Volatile = TRUE;\r
+  for (Index = 0; Index < 2; Index++) {\r
+    if (Index == 1) {\r
+      Volatile = FALSE;\r
+    }\r
+    while (IsValidVariableHeader (Variable[Index], Volatile, Global, Instance, &VariableHeader)) {\r
+      if (VariableHeader.State == VAR_ADDED || \r
+          VariableHeader.State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)\r
+         ) {\r
+        if (!EfiAtRuntime () || ((VariableHeader.Attributes & EFI_VARIABLE_RUNTIME_ACCESS) != 0)) {\r
+          if (VariableName[0] == 0) {\r
+            //\r
+            // If VariableName is an empty string, then we just find the first qualified variable\r
+            // without comparing VariableName and VendorGuid\r
+            //\r
+            if (VariableHeader.State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
+              //\r
+              // If variable is in delete transition, record it.\r
+              //\r
+              InDeletedVariable     = Variable[Index];\r
+              InDeletedStorageIndex = Index;\r
+            } else {\r
+              //\r
+              // If variable is not in delete transition, return it.\r
+              //\r
+              PtrTrack->StartPtr  = GetStartPointer (VariableStoreHeader[Index]);\r
+              PtrTrack->EndPtr    = GetEndPointer (VariableStoreHeader[Index], Volatile, Global, Instance);\r
+              PtrTrack->CurrPtr   = Variable[Index];\r
+              PtrTrack->Volatile  = Volatile;\r
+\r
+              return EFI_SUCCESS;\r
+            }\r
+          } else {\r
+            //\r
+            // If VariableName is not an empty string, then VariableName and VendorGuid are compared.\r
+            //\r
+            if (CompareGuid (VendorGuid, &VariableHeader.VendorGuid)) {\r
+              GetVariableNamePtr (\r
+                Variable[Index],\r
+                Volatile,\r
+                Global,\r
+                Instance,\r
+                LocalVariableName\r
+                );\r
+\r
+              ASSERT (NameSizeOfVariable (&VariableHeader) != 0);\r
+              if (CompareMem (VariableName, LocalVariableName, NameSizeOfVariable (&VariableHeader)) == 0) {\r
+                if (VariableHeader.State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
+                  //\r
+                  // If variable is in delete transition, record it.\r
+                  // We will use if only no VAR_ADDED variable is found.\r
+                  //\r
+                  InDeletedVariable     = Variable[Index];\r
+                  InDeletedStorageIndex = Index;\r
+                } else {\r
+                  //\r
+                  // If variable is not in delete transition, return it.\r
+                  //\r
+                  PtrTrack->StartPtr  = GetStartPointer (VariableStoreHeader[Index]);\r
+                  PtrTrack->EndPtr    = GetEndPointer (VariableStoreHeader[Index], Volatile, Global, Instance);\r
+                  PtrTrack->CurrPtr   = Variable[Index];\r
+                  PtrTrack->Volatile  = Volatile;\r
+\r
+                  return EFI_SUCCESS;\r
+                }\r
+              }\r
+            }\r
+          }\r
+        }\r
+      }\r
+\r
+      Variable[Index] = GetNextVariablePtr (\r
+                          Variable[Index],\r
+                          Volatile,\r
+                          Global,\r
+                          Instance\r
+                          );\r
+    }\r
+    if (InDeletedVariable != 0x0) {\r
+      //\r
+      // If no VAR_ADDED variable is found, and only variable in delete transition, then use this one.\r
+      //\r
+      PtrTrack->StartPtr  = GetStartPointer (VariableStoreHeader[InDeletedStorageIndex]);\r
+      PtrTrack->EndPtr    = GetEndPointer (\r
+                              VariableStoreHeader[InDeletedStorageIndex],\r
+                              (BOOLEAN)(InDeletedStorageIndex == 0),\r
+                              Global,\r
+                              Instance\r
+                              );\r
+      PtrTrack->CurrPtr   = InDeletedVariable;\r
+      PtrTrack->Volatile  = (BOOLEAN)(InDeletedStorageIndex == 0);\r
+      return EFI_SUCCESS;\r
+    }\r
+  }\r
+  PtrTrack->CurrPtr = 0x0;\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+/**\r
+  Variable store garbage collection and reclaim operation.\r
+\r
+  @param[in]  VariableBase        Base address of variable store area.\r
+  @param[out] LastVariableOffset  Offset of last variable.\r
+  @param[in]  IsVolatile          The variable store is volatile or not,\r
+                                  if it is non-volatile, need FTW.\r
+  @param[in]  VirtualMode         Current calling mode for this function.\r
+  @param[in]  Global              Context of this Extended SAL Variable Services Class call.\r
+  @param[in]  UpdatingVariable    Pointer to header of the variable that is being updated.\r
+\r
+  @retval EFI_SUCCESS             Variable store successfully reclaimed.\r
+  @retval EFI_OUT_OF_RESOURCES    Fail to allocate memory buffer to hold all valid variables.\r
+\r
+**/\r
+EFI_STATUS\r
+Reclaim (\r
+  IN  EFI_PHYSICAL_ADDRESS  VariableBase,\r
+  OUT UINTN                 *LastVariableOffset,\r
+  IN  BOOLEAN               IsVolatile,\r
+  IN  BOOLEAN               VirtualMode,\r
+  IN  ESAL_VARIABLE_GLOBAL  *Global,\r
+  IN  EFI_PHYSICAL_ADDRESS  UpdatingVariable\r
+  )\r
+{\r
+  EFI_PHYSICAL_ADDRESS  Variable;\r
+  EFI_PHYSICAL_ADDRESS  AddedVariable;\r
+  EFI_PHYSICAL_ADDRESS  NextVariable;\r
+  EFI_PHYSICAL_ADDRESS  NextAddedVariable;\r
+  VARIABLE_STORE_HEADER VariableStoreHeader;\r
+  VARIABLE_HEADER       VariableHeader;\r
+  VARIABLE_HEADER       AddedVariableHeader;\r
+  CHAR16                VariableName[MAX_NAME_SIZE];\r
+  CHAR16                AddedVariableName[MAX_NAME_SIZE];\r
+  UINT8                 *ValidBuffer;\r
+  UINTN                 MaximumBufferSize;\r
+  UINTN                 VariableSize;\r
+  UINTN                 NameSize;\r
+  UINT8                 *CurrPtr;\r
+  BOOLEAN               FoundAdded;\r
+  EFI_STATUS            Status;\r
+  VARIABLE_GLOBAL       *VariableGlobal;\r
+  UINT32                Instance;\r
+\r
+  VariableGlobal = &Global->VariableGlobal[VirtualMode];\r
+  Instance = Global->FvbInstance;\r
+\r
+  GetVarStoreHeader (VariableBase, IsVolatile, VariableGlobal, Instance, &VariableStoreHeader);\r
+  //\r
+  // recaluate the total size of Common/HwErr type variables in non-volatile area.\r
+  //\r
+  if (!IsVolatile) {\r
+    Global->CommonVariableTotalSize = 0;\r
+    Global->HwErrVariableTotalSize  = 0;\r
+  }\r
+\r
+  //\r
+  // Calculate the size of buffer needed to gather all valid variables\r
+  //\r
+  Variable          = GetStartPointer (VariableBase);\r
+  MaximumBufferSize = sizeof (VARIABLE_STORE_HEADER);\r
+\r
+  while (IsValidVariableHeader (Variable, IsVolatile, VariableGlobal, Instance, &VariableHeader)) {\r
+    NextVariable = GetNextVariablePtr (Variable, IsVolatile, VariableGlobal, Instance);\r
+    //\r
+    // Collect VAR_ADDED variables, and variables in delete transition status.\r
+    //\r
+    if (VariableHeader.State == VAR_ADDED || \r
+        VariableHeader.State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)\r
+       ) {\r
+      VariableSize = NextVariable - Variable;\r
+      MaximumBufferSize += VariableSize;\r
+    }\r
+\r
+    Variable = NextVariable;\r
+  }\r
+\r
+  //\r
+  // Reserve the 1 Bytes with Oxff to identify the \r
+  // end of the variable buffer. \r
+  // \r
+  MaximumBufferSize += 1;\r
+  ValidBuffer = AllocatePool (MaximumBufferSize);\r
+  if (ValidBuffer == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  SetMem (ValidBuffer, MaximumBufferSize, 0xff);\r
+\r
+  //\r
+  // Copy variable store header\r
+  //\r
+  CopyMem (ValidBuffer, &VariableStoreHeader, sizeof (VARIABLE_STORE_HEADER));\r
+  CurrPtr = (UINT8 *) GetStartPointer ((EFI_PHYSICAL_ADDRESS) ValidBuffer);\r
+\r
+  //\r
+  // Reinstall all ADDED variables\r
+  // \r
+  Variable = GetStartPointer (VariableBase);\r
+  while (IsValidVariableHeader (Variable, IsVolatile, VariableGlobal, Instance, &VariableHeader)) {\r
+    NextVariable = GetNextVariablePtr (Variable, IsVolatile, VariableGlobal, Instance);\r
+    if (VariableHeader.State == VAR_ADDED) {\r
+      VariableSize = NextVariable - Variable;\r
+      CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize);\r
+      CurrPtr += VariableSize;\r
+      if ((!IsVolatile) && ((((VARIABLE_HEADER*)Variable)->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
+        Global->HwErrVariableTotalSize += VariableSize;\r
+      } else if ((!IsVolatile) && ((((VARIABLE_HEADER*)Variable)->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
+        Global->CommonVariableTotalSize += VariableSize;\r
+      }\r
+    }\r
+    Variable = NextVariable;\r
+  }\r
+  //\r
+  // Reinstall in delete transition variables\r
+  // \r
+  Variable = GetStartPointer (VariableBase);\r
+  while (IsValidVariableHeader (Variable, IsVolatile, VariableGlobal, Instance, &VariableHeader)) {\r
+    NextVariable = GetNextVariablePtr (Variable, IsVolatile, VariableGlobal, Instance);\r
+    if (VariableHeader.State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
+\r
+      //\r
+      // Buffer has cached all ADDED variable. \r
+      // Per IN_DELETED variable, we have to guarantee that\r
+      // no ADDED one in previous buffer. \r
+      // \r
+      FoundAdded = FALSE;\r
+      AddedVariable = GetStartPointer ((EFI_PHYSICAL_ADDRESS) ValidBuffer);\r
+      while (IsValidVariableHeader (AddedVariable, IsVolatile, VariableGlobal, Instance, &AddedVariableHeader)) {\r
+        NextAddedVariable = GetNextVariablePtr (AddedVariable, IsVolatile, VariableGlobal, Instance);\r
+        NameSize = NameSizeOfVariable (&AddedVariableHeader);\r
+        if (CompareGuid (&AddedVariableHeader.VendorGuid, &VariableHeader.VendorGuid) &&\r
+            NameSize == NameSizeOfVariable (&VariableHeader)\r
+           ) {\r
+          GetVariableNamePtr (Variable, IsVolatile, VariableGlobal, Instance, VariableName);\r
+          GetVariableNamePtr (AddedVariable, IsVolatile, VariableGlobal, Instance, AddedVariableName);\r
+          if (CompareMem (VariableName, AddedVariableName, NameSize) == 0) {\r
+            //\r
+            // If ADDED variable with the same name and vender GUID has been reinstalled,\r
+            // then discard this IN_DELETED copy.\r
+            //\r
+            FoundAdded = TRUE;\r
+            break;\r
+          }\r
+        }\r
+        AddedVariable = NextAddedVariable;\r
+      }\r
+      //\r
+      // Add IN_DELETE variables that have not been added to buffer\r
+      //\r
+      if (!FoundAdded) {\r
+        VariableSize = NextVariable - Variable;\r
+        CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize);\r
+        if (Variable != UpdatingVariable) {\r
+          //\r
+          // Make this IN_DELETE instance valid if:\r
+          // 1. No valid instance of this variable exists.\r
+          // 2. It is not the variable that is going to be updated.\r
+          //\r
+          ((VARIABLE_HEADER *) CurrPtr)->State = VAR_ADDED;\r
+        }\r
+        CurrPtr += VariableSize;\r
+        if ((!IsVolatile) && ((((VARIABLE_HEADER*)Variable)->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
+          Global->HwErrVariableTotalSize += VariableSize;\r
+        } else if ((!IsVolatile) && ((((VARIABLE_HEADER*)Variable)->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
+          Global->CommonVariableTotalSize += VariableSize;\r
+        }\r
+      }\r
+    }\r
+    Variable = NextVariable;\r
+  }\r
+\r
+  if (IsVolatile) {\r
+    //\r
+    // If volatile variable store, just copy valid buffer\r
+    //\r
+    SetMem ((UINT8 *) (UINTN) VariableBase, VariableStoreHeader.Size, 0xff);\r
+    CopyMem ((UINT8 *) (UINTN) VariableBase, ValidBuffer, (UINTN) (CurrPtr - (UINT8 *) ValidBuffer));\r
+    Status = EFI_SUCCESS;\r
+  } else {\r
+    //\r
+    // If non-volatile variable store, perform FTW here.\r
+    // Write ValidBuffer to destination specified by VariableBase.\r
+    //\r
+    Status = FtwVariableSpace (\r
+               VariableBase,\r
+               ValidBuffer,\r
+               (UINTN) (CurrPtr - (UINT8 *) ValidBuffer)\r
+               );\r
+  }\r
+  if (!EFI_ERROR (Status)) {\r
+    *LastVariableOffset = (UINTN) (CurrPtr - (UINT8 *) ValidBuffer);\r
+  } else {\r
+    *LastVariableOffset = 0;\r
+  }\r
+\r
+  FreePool (ValidBuffer);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Get index from supported language codes according to language string.\r
+\r
+  This code is used to get corresponding index in supported language codes. It can handle\r
+  RFC4646 and ISO639 language tags.\r
+  In ISO639 language tags, take 3-characters as a delimitation to find matched string and calculate the index.\r
+  In RFC4646 language tags, take semicolon as a delimitation to find matched string and calculate the index.\r
+\r
+  For example:\r
+    SupportedLang  = "engfraengfra"\r
+    Lang           = "eng"\r
+    Iso639Language = TRUE\r
+  The return value is "0".\r
+  Another example:\r
+    SupportedLang  = "en;fr;en-US;fr-FR"\r
+    Lang           = "fr-FR"\r
+    Iso639Language = FALSE\r
+  The return value is "3".\r
+\r
+  @param[in]  SupportedLang          Platform supported language codes.\r
+  @param[in]  Lang                   Configured language.\r
+  @param[in]  Iso639Language         A bool value to signify if the handler is operated on ISO639 or RFC4646.\r
+\r
+  @return                            The index of language in the language codes.\r
+\r
+**/\r
+UINTN\r
+GetIndexFromSupportedLangCodes(\r
+  IN  CHAR8            *SupportedLang,\r
+  IN  CHAR8            *Lang,\r
+  IN  BOOLEAN          Iso639Language\r
+  ) \r
+{\r
+  UINTN    Index;\r
+  UINTN    CompareLength;\r
+  UINTN    LanguageLength;\r
+\r
+  if (Iso639Language) {\r
+    CompareLength = ISO_639_2_ENTRY_SIZE;\r
+    for (Index = 0; Index < AsciiStrLen (SupportedLang); Index += CompareLength) {\r
+      if (AsciiStrnCmp (Lang, SupportedLang + Index, CompareLength) == 0) {\r
+        //\r
+        // Successfully find the index of Lang string in SupportedLang string.\r
+        //\r
+        Index = Index / CompareLength;\r
+        return Index;\r
+      }\r
+    }\r
+    ASSERT (FALSE);\r
+    return 0;\r
+  } else {\r
+    //\r
+    // Compare RFC4646 language code\r
+    //\r
+    Index = 0;\r
+    for (LanguageLength = 0; Lang[LanguageLength] != '\0'; LanguageLength++);\r
+\r
+    for (Index = 0; *SupportedLang != '\0'; Index++, SupportedLang += CompareLength) {\r
+      //\r
+      // Skip ';' characters in SupportedLang\r
+      //\r
+      for (; *SupportedLang != '\0' && *SupportedLang == ';'; SupportedLang++);\r
+      //\r
+      // Determine the length of the next language code in SupportedLang\r
+      //\r
+      for (CompareLength = 0; SupportedLang[CompareLength] != '\0' && SupportedLang[CompareLength] != ';'; CompareLength++);\r
+      \r
+      if ((CompareLength == LanguageLength) && \r
+          (AsciiStrnCmp (Lang, SupportedLang, CompareLength) == 0)) {\r
+        //\r
+        // Successfully find the index of Lang string in SupportedLang string.\r
+        //\r
+        return Index;\r
+      }\r
+    }\r
+    ASSERT (FALSE);\r
+    return 0;\r
+  }\r
+}\r
+\r
+/**\r
+  Get language string from supported language codes according to index.\r
+\r
+  This code is used to get corresponding language string in supported language codes. It can handle\r
+  RFC4646 and ISO639 language tags.\r
+  In ISO639 language tags, take 3-characters as a delimitation. Find language string according to the index.\r
+  In RFC4646 language tags, take semicolon as a delimitation. Find language string according to the index.\r
+\r
+  For example:\r
+    SupportedLang  = "engfraengfra"\r
+    Index          = "1"\r
+    Iso639Language = TRUE\r
+  The return value is "fra".\r
+  Another example:\r
+    SupportedLang  = "en;fr;en-US;fr-FR"\r
+    Index          = "1"\r
+    Iso639Language = FALSE\r
+  The return value is "fr".\r
+\r
+  @param[in]  SupportedLang   Platform supported language codes.\r
+  @param[in]  Index           the index in supported language codes.\r
+  @param[in]  Iso639Language  A bool value to signify if the handler is operated on ISO639 or RFC4646.\r
+  @param[in]  VirtualMode     Current calling mode for this function.\r
+  @param[in]  Global          Context of this Extended SAL Variable Services Class call.\r
+\r
+  @return                     The language string in the language codes.\r
+\r
+**/\r
+CHAR8 *\r
+GetLangFromSupportedLangCodes (\r
+  IN  CHAR8                 *SupportedLang,\r
+  IN  UINTN                 Index,\r
+  IN  BOOLEAN               Iso639Language,\r
+  IN  BOOLEAN               VirtualMode,\r
+  IN  ESAL_VARIABLE_GLOBAL  *Global\r
+  )\r
+{\r
+  UINTN    SubIndex;\r
+  UINTN    CompareLength;\r
+  CHAR8    *Supported;\r
+\r
+  SubIndex  = 0;\r
+  Supported = SupportedLang;\r
+  if (Iso639Language) {\r
+    //\r
+    // according to the index of Lang string in SupportedLang string to get the language.\r
+    // As this code will be invoked in RUNTIME, therefore there is not memory allocate/free operation.\r
+    // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.\r
+    //\r
+    CompareLength = ISO_639_2_ENTRY_SIZE;\r
+    Global->Lang[CompareLength] = '\0';\r
+    return CopyMem (Global->Lang, SupportedLang + Index * CompareLength, CompareLength);\r
+\r
+  } else {\r
+    while (TRUE) {\r
+      //\r
+      // take semicolon as delimitation, sequentially traverse supported language codes.\r
+      //\r
+      for (CompareLength = 0; *Supported != ';' && *Supported != '\0'; CompareLength++) {\r
+        Supported++;\r
+      }\r
+      if ((*Supported == '\0') && (SubIndex != Index)) {\r
+        //\r
+        // Have completed the traverse, but not find corrsponding string.\r
+        // This case is not allowed to happen.\r
+        //\r
+        ASSERT(FALSE);\r
+        return NULL;\r
+      }\r
+      if (SubIndex == Index) {\r
+        //\r
+        // according to the index of Lang string in SupportedLang string to get the language.\r
+        // As this code will be invoked in RUNTIME, therefore there is not memory allocate/free operation.\r
+        // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.\r
+        //\r
+        Global->PlatformLang[VirtualMode][CompareLength] = '\0';\r
+        return CopyMem (Global->PlatformLang[VirtualMode], Supported - CompareLength, CompareLength);\r
+      }\r
+      SubIndex++;\r
+\r
+      //\r
+      // Skip ';' characters in Supported\r
+      //\r
+      for (; *Supported != '\0' && *Supported == ';'; Supported++);\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+  Returns a pointer to an allocated buffer that contains the best matching language \r
+  from a set of supported languages.  \r
+  \r
+  This function supports both ISO 639-2 and RFC 4646 language codes, but language \r
+  code types may not be mixed in a single call to this function. This function\r
+  supports a variable argument list that allows the caller to pass in a prioritized\r
+  list of language codes to test against all the language codes in SupportedLanguages.\r
+\r
+  If SupportedLanguages is NULL, then ASSERT().\r
+\r
+  @param[in]  SupportedLanguages  A pointer to a Null-terminated ASCII string that\r
+                                  contains a set of language codes in the format \r
+                                  specified by Iso639Language.\r
+  @param[in]  Iso639Language      If TRUE, then all language codes are assumed to be\r
+                                  in ISO 639-2 format.  If FALSE, then all language\r
+                                  codes are assumed to be in RFC 4646 language format.\r
+  @param[in]  VirtualMode         Current calling mode for this function.\r
+  @param[in]  ...                 A variable argument list that contains pointers to \r
+                                  Null-terminated ASCII strings that contain one or more\r
+                                  language codes in the format specified by Iso639Language.\r
+                                  The first language code from each of these language\r
+                                  code lists is used to determine if it is an exact or\r
+                                  close match to any of the language codes in \r
+                                  SupportedLanguages.  Close matches only apply to RFC 4646\r
+                                  language codes, and the matching algorithm from RFC 4647\r
+                                  is used to determine if a close match is present.  If \r
+                                  an exact or close match is found, then the matching\r
+                                  language code from SupportedLanguages is returned.  If\r
+                                  no matches are found, then the next variable argument\r
+                                  parameter is evaluated.  The variable argument list \r
+                                  is terminated by a NULL.\r
+\r
+  @retval NULL   The best matching language could not be found in SupportedLanguages.\r
+  @retval NULL   There are not enough resources available to return the best matching \r
+                 language.\r
+  @retval Other  A pointer to a Null-terminated ASCII string that is the best matching \r
+                 language in SupportedLanguages.\r
+\r
+**/\r
+CHAR8 *\r
+VariableGetBestLanguage (\r
+  IN CONST CHAR8  *SupportedLanguages, \r
+  IN BOOLEAN      Iso639Language,\r
+  IN BOOLEAN      VirtualMode,\r
+  ...\r
+  )\r
+{\r
+  VA_LIST      Args;\r
+  CHAR8        *Language;\r
+  UINTN        CompareLength;\r
+  UINTN        LanguageLength;\r
+  CONST CHAR8  *Supported;\r
+  CHAR8        *Buffer;\r
+\r
+  ASSERT (SupportedLanguages != NULL);\r
+\r
+  VA_START (Args, VirtualMode);\r
+  while ((Language = VA_ARG (Args, CHAR8 *)) != NULL) {\r
+    //\r
+    // Default to ISO 639-2 mode\r
+    //\r
+    CompareLength  = 3;\r
+    LanguageLength = MIN (3, AsciiStrLen (Language));\r
+\r
+    //\r
+    // If in RFC 4646 mode, then determine the length of the first RFC 4646 language code in Language\r
+    //\r
+    if (!Iso639Language) {\r
+      for (LanguageLength = 0; Language[LanguageLength] != 0 && Language[LanguageLength] != ';'; LanguageLength++);\r
+    }\r
+\r
+    //\r
+    // Trim back the length of Language used until it is empty\r
+    //\r
+    while (LanguageLength > 0) {\r
+      //\r
+      // Loop through all language codes in SupportedLanguages\r
+      //\r
+      for (Supported = SupportedLanguages; *Supported != '\0'; Supported += CompareLength) {\r
+        //\r
+        // In RFC 4646 mode, then Loop through all language codes in SupportedLanguages\r
+        //\r
+        if (!Iso639Language) {\r
+          //\r
+          // Skip ';' characters in Supported\r
+          //\r
+          for (; *Supported != '\0' && *Supported == ';'; Supported++);\r
+          //\r
+          // Determine the length of the next language code in Supported\r
+          //\r
+          for (CompareLength = 0; Supported[CompareLength] != 0 && Supported[CompareLength] != ';'; CompareLength++);\r
+          //\r
+          // If Language is longer than the Supported, then skip to the next language\r
+          //\r
+          if (LanguageLength > CompareLength) {\r
+            continue;\r
+          }\r
+        }\r
+        //\r
+        // See if the first LanguageLength characters in Supported match Language\r
+        //\r
+        if (AsciiStrnCmp (Supported, Language, LanguageLength) == 0) {\r
+          VA_END (Args);\r
+\r
+          Buffer = Iso639Language ? mVariableModuleGlobal->Lang : mVariableModuleGlobal->PlatformLang[VirtualMode];\r
+          Buffer[CompareLength] = '\0';\r
+          return CopyMem (Buffer, Supported, CompareLength);\r
+        }\r
+      }\r
+\r
+      if (Iso639Language) {\r
+        //\r
+        // If ISO 639 mode, then each language can only be tested once\r
+        //\r
+        LanguageLength = 0;\r
+      } else {\r
+        //\r
+        // If RFC 4646 mode, then trim Language from the right to the next '-' character \r
+        //\r
+        for (LanguageLength--; LanguageLength > 0 && Language[LanguageLength] != '-'; LanguageLength--);\r
+      }\r
+    }\r
+  }\r
+  VA_END (Args);\r
+\r
+  //\r
+  // No matches were found \r
+  //\r
+  return NULL;\r
+}\r
+\r
+/**\r
+  Hook the operations in PlatformLangCodes, LangCodes, PlatformLang and Lang.\r
+\r
+  When setting Lang/LangCodes, simultaneously update PlatformLang/PlatformLangCodes.\r
+  According to UEFI spec, PlatformLangCodes/LangCodes are only set once in firmware initialization,\r
+  and are read-only. Therefore, in variable driver, only store the original value for other use.\r
+\r
+  @param[in] VariableName  Name of variable.\r
+  @param[in] Data          Variable data.\r
+  @param[in] DataSize      Size of data. 0 means delete.\r
+  @param[in] VirtualMode   Current calling mode for this function.\r
+  @param[in] Global        Context of this Extended SAL Variable Services Class call.\r
+\r
+**/\r
+VOID\r
+AutoUpdateLangVariable(\r
+  IN  CHAR16                *VariableName,\r
+  IN  VOID                  *Data,\r
+  IN  UINTN                 DataSize,\r
+  IN  BOOLEAN               VirtualMode,\r
+  IN  ESAL_VARIABLE_GLOBAL  *Global\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  CHAR8                   *BestPlatformLang;\r
+  CHAR8                   *BestLang;\r
+  UINTN                   Index;\r
+  UINT32                  Attributes;\r
+  VARIABLE_POINTER_TRACK  Variable;\r
+  BOOLEAN                 SetLanguageCodes;\r
+  CHAR16                  **PredefinedVariableName;\r
+  VARIABLE_GLOBAL         *VariableGlobal;\r
+  UINT32                  Instance;\r
+\r
+  //\r
+  // Don't do updates for delete operation\r
+  //\r
+  if (DataSize == 0) {\r
+    return;\r
+  }\r
+\r
+  SetLanguageCodes = FALSE;\r
+  VariableGlobal   = &Global->VariableGlobal[VirtualMode];\r
+  Instance         = Global->FvbInstance;\r
+\r
+\r
+  PredefinedVariableName = &Global->VariableName[VirtualMode][0];\r
+  if (StrCmp (VariableName, PredefinedVariableName[VAR_PLATFORM_LANG_CODES]) == 0) {\r
+    //\r
+    // PlatformLangCodes is a volatile variable, so it can not be updated at runtime.\r
+    //\r
+    if (EfiAtRuntime ()) {\r
+      return;\r
+    }\r
+\r
+    SetLanguageCodes = TRUE;\r
+\r
+    //\r
+    // According to UEFI spec, PlatformLangCodes is only set once in firmware initialization, and is read-only\r
+    // Therefore, in variable driver, only store the original value for other use.\r
+    //\r
+    if (Global->PlatformLangCodes[VirtualMode] != NULL) {\r
+      FreePool (Global->PlatformLangCodes[VirtualMode]);\r
+    }\r
+    Global->PlatformLangCodes[VirtualMode] = AllocateRuntimeCopyPool (DataSize, Data);\r
+    ASSERT (mVariableModuleGlobal->PlatformLangCodes[VirtualMode] != NULL);\r
+\r
+    //\r
+    // PlatformLang holds a single language from PlatformLangCodes, \r
+    // so the size of PlatformLangCodes is enough for the PlatformLang.\r
+    //\r
+    if (Global->PlatformLang[VirtualMode] != NULL) {\r
+      FreePool (Global->PlatformLang[VirtualMode]);\r
+    }\r
+    Global->PlatformLang[VirtualMode] = AllocateRuntimePool (DataSize);\r
+    ASSERT (Global->PlatformLang[VirtualMode] != NULL);\r
+\r
+  } else if (StrCmp (VariableName, PredefinedVariableName[VAR_LANG_CODES]) == 0) {\r
+    //\r
+    // LangCodes is a volatile variable, so it can not be updated at runtime.\r
+    //\r
+    if (EfiAtRuntime ()) {\r
+      return;\r
+    }\r
+\r
+    SetLanguageCodes = TRUE;\r
+\r
+    //\r
+    // According to UEFI spec, LangCodes is only set once in firmware initialization, and is read-only\r
+    // Therefore, in variable driver, only store the original value for other use.\r
+    //\r
+    if (Global->LangCodes[VirtualMode] != NULL) {\r
+      FreePool (Global->LangCodes[VirtualMode]);\r
+    }\r
+    Global->LangCodes[VirtualMode] = AllocateRuntimeCopyPool (DataSize, Data);\r
+    ASSERT (Global->LangCodes[VirtualMode] != NULL);\r
+  }\r
+\r
+  if (SetLanguageCodes \r
+      && (Global->PlatformLangCodes[VirtualMode] != NULL)\r
+      && (Global->LangCodes[VirtualMode] != NULL)) {\r
+    //\r
+    // Update Lang if PlatformLang is already set\r
+    // Update PlatformLang if Lang is already set\r
+    //\r
+    Status = FindVariable (PredefinedVariableName[VAR_PLATFORM_LANG], Global->GlobalVariableGuid[VirtualMode], &Variable, VariableGlobal, Instance);\r
+    if (!EFI_ERROR (Status)) {\r
+      //\r
+      // Update Lang\r
+      //\r
+      VariableName = PredefinedVariableName[VAR_PLATFORM_LANG];\r
+    } else {\r
+      Status = FindVariable (PredefinedVariableName[VAR_LANG], Global->GlobalVariableGuid[VirtualMode], &Variable, VariableGlobal, Instance);\r
+      if (!EFI_ERROR (Status)) {\r
+        //\r
+        // Update PlatformLang\r
+        //\r
+        VariableName = PredefinedVariableName[VAR_LANG];\r
+      } else {\r
+        //\r
+        // Neither PlatformLang nor Lang is set, directly return\r
+        //\r
+        return;\r
+      }\r
+    }\r
+    Data    = (VOID *) GetEndPointer (VariableGlobal->VolatileVariableBase, TRUE, VariableGlobal, Instance);\r
+    GetVariableDataPtr ((EFI_PHYSICAL_ADDRESS) Variable.CurrPtr, Variable.Volatile, VariableGlobal, Instance, (CHAR16 *) Data);\r
+\r
+    Status = AccessVariableStore (\r
+               FALSE,\r
+               VariableGlobal,\r
+               Variable.Volatile,\r
+               Instance,\r
+               (UINTN) &(((VARIABLE_HEADER *)Variable.CurrPtr)->DataSize),\r
+               sizeof (DataSize),\r
+               &DataSize\r
+               ); \r
+    ASSERT_EFI_ERROR (Status);\r
+  }\r
+\r
+  //\r
+  // According to UEFI spec, "Lang" and "PlatformLang" is NV|BS|RT attributions.\r
+  //\r
+  Attributes = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS;\r
+\r
+  if (StrCmp (VariableName, PredefinedVariableName[VAR_PLATFORM_LANG]) == 0) {\r
+    //\r
+    // Update Lang when PlatformLangCodes/LangCodes were set.\r
+    //\r
+    if ((Global->PlatformLangCodes[VirtualMode] != NULL) && (Global->LangCodes[VirtualMode] != NULL)) {\r
+      //\r
+      // When setting PlatformLang, firstly get most matched language string from supported language codes.\r
+      //\r
+      BestPlatformLang = VariableGetBestLanguage (Global->PlatformLangCodes[VirtualMode], FALSE, VirtualMode, Data, NULL);\r
+      if (BestPlatformLang != NULL) {\r
+        //\r
+        // Get the corresponding index in language codes.\r
+        //\r
+        Index = GetIndexFromSupportedLangCodes (Global->PlatformLangCodes[VirtualMode], BestPlatformLang, FALSE);\r
+\r
+        //\r
+        // Get the corresponding ISO639 language tag according to RFC4646 language tag.\r
+        //\r
+        BestLang = GetLangFromSupportedLangCodes (Global->LangCodes[VirtualMode], Index, TRUE, VirtualMode, Global);\r
+\r
+        //\r
+        // Successfully convert PlatformLang to Lang, and set the BestLang value into Lang variable simultaneously.\r
+        //\r
+        FindVariable (PredefinedVariableName[VAR_LANG], Global->GlobalVariableGuid[VirtualMode], &Variable, VariableGlobal, Instance);\r
+\r
+        Status = UpdateVariable (\r
+                   PredefinedVariableName[VAR_LANG],\r
+                   Global->GlobalVariableGuid[VirtualMode],\r
+                   BestLang,\r
+                   ISO_639_2_ENTRY_SIZE + 1,\r
+                   Attributes,\r
+                   0,\r
+                   0,\r
+                   VirtualMode,\r
+                   Global,\r
+                   &Variable\r
+                   );\r
+\r
+        DEBUG ((EFI_D_INFO, "Variable Driver Auto Update PlatformLang, PlatformLang:%a, Lang:%a\n", BestPlatformLang, BestLang));\r
+\r
+        ASSERT_EFI_ERROR (Status);\r
+      }\r
+    }\r
+\r
+  } else if (StrCmp (VariableName, PredefinedVariableName[VAR_LANG]) == 0) {\r
+    //\r
+    // Update PlatformLang when PlatformLangCodes/LangCodes were set.\r
+    //\r
+    if ((Global->PlatformLangCodes[VirtualMode] != NULL) && (Global->LangCodes[VirtualMode] != NULL)) {\r
+      //\r
+      // When setting Lang, firstly get most matched language string from supported language codes.\r
+      //\r
+      BestLang = VariableGetBestLanguage (Global->LangCodes[VirtualMode], TRUE, VirtualMode, Data, NULL);\r
+      if (BestLang != NULL) {\r
+        //\r
+        // Get the corresponding index in language codes.\r
+        //\r
+        Index = GetIndexFromSupportedLangCodes (Global->LangCodes[VirtualMode], BestLang, TRUE);\r
+\r
+        //\r
+        // Get the corresponding RFC4646 language tag according to ISO639 language tag.\r
+        //\r
+        BestPlatformLang = GetLangFromSupportedLangCodes (Global->PlatformLangCodes[VirtualMode], Index, FALSE, VirtualMode, Global);\r
+\r
+        //\r
+        // Successfully convert Lang to PlatformLang, and set the BestPlatformLang value into PlatformLang variable simultaneously.\r
+        //\r
+        FindVariable (PredefinedVariableName[VAR_PLATFORM_LANG], Global->GlobalVariableGuid[VirtualMode], &Variable, VariableGlobal, Instance);\r
+\r
+        Status = UpdateVariable (\r
+                   PredefinedVariableName[VAR_PLATFORM_LANG], \r
+                   Global->GlobalVariableGuid[VirtualMode], \r
+                   BestPlatformLang, \r
+                   AsciiStrSize (BestPlatformLang), \r
+                   Attributes, \r
+                   0,\r
+                   0,\r
+                   VirtualMode, \r
+                   Global, \r
+                   &Variable\r
+                   );\r
+\r
+        DEBUG ((EFI_D_INFO, "Variable Driver Auto Update Lang, Lang:%a, PlatformLang:%a\n", BestLang, BestPlatformLang));\r
+        ASSERT_EFI_ERROR (Status);\r
+      }\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+  Update the variable region with Variable information. These are the same \r
+  arguments as the EFI Variable services.\r
+\r
+  @param[in] VariableName       Name of variable.\r
+  @param[in] VendorGuid         Guid of variable.\r
+  @param[in] Data               Variable data.\r
+  @param[in] DataSize           Size of data. 0 means delete.\r
+  @param[in] Attributes         Attributes of the variable.\r
+  @param[in] KeyIndex           Index of associated public key.\r
+  @param[in] MonotonicCount     Value of associated monotonic count. \r
+  @param[in] VirtualMode        Current calling mode for this function.\r
+  @param[in] Global             Context of this Extended SAL Variable Services Class call.\r
+  @param[in] Variable           The variable information which is used to keep track of variable usage.\r
+\r
+  @retval EFI_SUCCESS           The update operation is success.\r
+  @retval EFI_OUT_OF_RESOURCES  Variable region is full, can not write other data into this region.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UpdateVariable (\r
+  IN      CHAR16                  *VariableName,\r
+  IN      EFI_GUID                *VendorGuid,\r
+  IN      VOID                    *Data,\r
+  IN      UINTN                   DataSize,\r
+  IN      UINT32                  Attributes OPTIONAL,  \r
+  IN      UINT32                  KeyIndex  OPTIONAL,\r
+  IN      UINT64                  MonotonicCount  OPTIONAL,\r
+  IN      BOOLEAN                 VirtualMode,\r
+  IN      ESAL_VARIABLE_GLOBAL    *Global,\r
+  IN      VARIABLE_POINTER_TRACK  *Variable\r
+  )\r
+{\r
+  EFI_STATUS                          Status;\r
+  VARIABLE_HEADER                     *NextVariable;\r
+  UINTN                               VarNameOffset;\r
+  UINTN                               VarDataOffset;\r
+  UINTN                               VarNameSize;\r
+  UINTN                               VarSize;\r
+  BOOLEAN                             Volatile;\r
+  UINT8                               State;\r
+  VARIABLE_HEADER                     VariableHeader;\r
+  VARIABLE_HEADER                     *NextVariableHeader;\r
+  BOOLEAN                             Valid;\r
+  BOOLEAN                             Reclaimed;\r
+  VARIABLE_STORE_HEADER               VariableStoreHeader;\r
+  UINTN                               ScratchSize;\r
+  VARIABLE_GLOBAL                     *VariableGlobal;\r
+  UINT32                              Instance;\r
+\r
+  VariableGlobal = &Global->VariableGlobal[VirtualMode];\r
+  Instance = Global->FvbInstance;\r
+\r
+  Reclaimed  = FALSE;\r
+\r
+  if (Variable->CurrPtr != 0) {\r
+\r
+    Valid = IsValidVariableHeader (Variable->CurrPtr, Variable->Volatile, VariableGlobal, Instance, &VariableHeader);\r
+    if (!Valid) {\r
+      Status = EFI_NOT_FOUND;\r
+      goto Done;\r
+    }\r
+\r
+    //\r
+    // Update/Delete existing variable\r
+    //\r
+    Volatile = Variable->Volatile;\r
+    \r
+    if (EfiAtRuntime ()) {        \r
+      //\r
+      // If EfiAtRuntime and the variable is Volatile and Runtime Access,  \r
+      // the volatile is ReadOnly, and SetVariable should be aborted and \r
+      // return EFI_WRITE_PROTECTED.\r
+      //\r
+      if (Variable->Volatile) {\r
+        Status = EFI_WRITE_PROTECTED;\r
+        goto Done;\r
+      }\r
+      //\r
+      // Only variable have NV attribute can be updated/deleted in Runtime\r
+      //\r
+      if ((VariableHeader.Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {\r
+        Status = EFI_INVALID_PARAMETER;\r
+        goto Done;      \r
+      }\r
+    }\r
+    //\r
+    // Setting a data variable with no access, or zero DataSize attributes\r
+    // specified causes it to be deleted.\r
+    //\r
+    if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) {    \r
+      State = VariableHeader.State;\r
+      State &= VAR_DELETED;\r
+\r
+      Status = AccessVariableStore (\r
+                 TRUE,\r
+                 VariableGlobal,\r
+                 Variable->Volatile,\r
+                 Instance,\r
+                 (UINTN) &(((VARIABLE_HEADER *)Variable->CurrPtr)->State),\r
+                 sizeof (UINT8),\r
+                 &State\r
+                 ); \r
+      if (!EFI_ERROR (Status)) {\r
+        UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, FALSE, TRUE, FALSE);\r
+        UpdateVariableCache (VariableName, VendorGuid, Attributes, DataSize, Data);\r
+      }\r
+      goto Done;     \r
+    }\r
+    //\r
+    // Logic comes here to update variable.\r
+    // If the variable is marked valid and the same data has been passed in\r
+    // then return to the caller immediately.\r
+    //\r
+    if (DataSizeOfVariable (&VariableHeader) == DataSize) {\r
+      NextVariable = (VARIABLE_HEADER *)GetEndPointer (VariableGlobal->VolatileVariableBase, TRUE, VariableGlobal, Instance);\r
+      GetVariableDataPtr (Variable->CurrPtr, Variable->Volatile, VariableGlobal, Instance, (CHAR16 *) NextVariable);\r
+      if  (CompareMem (Data, (VOID *) NextVariable, DataSize) == 0) {\r
+        UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, TRUE, FALSE, FALSE);\r
+        Status = EFI_SUCCESS;\r
+        goto Done;\r
+      }\r
+    }\r
+    if ((VariableHeader.State == VAR_ADDED) ||\r
+        (VariableHeader.State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION))) {\r
+      //\r
+      // If new data is different from the old one, mark the old one as VAR_IN_DELETED_TRANSITION.\r
+      // It will be deleted if new variable is successfully written.\r
+      //\r
+      State = VariableHeader.State;\r
+      State &= VAR_IN_DELETED_TRANSITION;\r
+\r
+      Status = AccessVariableStore (\r
+                 TRUE,\r
+                 VariableGlobal,\r
+                 Variable->Volatile,\r
+                 Instance,\r
+                 (UINTN) &(((VARIABLE_HEADER *)Variable->CurrPtr)->State),\r
+                 sizeof (UINT8),\r
+                 &State\r
+                 );      \r
+      if (EFI_ERROR (Status)) {\r
+        goto Done;  \r
+      }\r
+    }    \r
+  } else {\r
+    //\r
+    // Create a new variable\r
+    //  \r
+    \r
+    //\r
+    // Make sure we are trying to create a new variable.\r
+    // Setting a data variable with no access, or zero DataSize attributes means to delete it.    \r
+    //\r
+    if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) {\r
+      Status = EFI_NOT_FOUND;\r
+      goto Done;\r
+    }\r
+    \r
+    //\r
+    // Only variable have NV|RT attribute can be created in Runtime\r
+    //\r
+    if (EfiAtRuntime () &&\r
+        (((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) || ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0))) {\r
+      Status = EFI_INVALID_PARAMETER;\r
+      goto Done;\r
+    }         \r
+  }\r
+\r
+  //\r
+  // Function part - create a new variable and copy the data.\r
+  // Both update a variable and create a variable will come here.\r
+  //\r
+  // Tricky part: Use scratch data area at the end of volatile variable store\r
+  // as a temporary storage.\r
+  //\r
+  NextVariable = (VARIABLE_HEADER *)GetEndPointer (VariableGlobal->VolatileVariableBase, TRUE, VariableGlobal, Instance);\r
+  ScratchSize = MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize));\r
+  NextVariableHeader = (VARIABLE_HEADER *) NextVariable;\r
+\r
+  SetMem (NextVariableHeader, ScratchSize, 0xff);\r
+\r
+  NextVariableHeader->StartId         = VARIABLE_DATA;\r
+  NextVariableHeader->Attributes      = Attributes;\r
+  NextVariableHeader->PubKeyIndex     = KeyIndex;\r
+  NextVariableHeader->MonotonicCount  = MonotonicCount;\r
+  NextVariableHeader->Reserved        = 0;\r
+  VarNameOffset                       = sizeof (VARIABLE_HEADER);\r
+  VarNameSize                         = StrSize (VariableName);\r
+  CopyMem (\r
+    (UINT8 *) ((UINTN)NextVariable + VarNameOffset),\r
+    VariableName,\r
+    VarNameSize\r
+    );\r
+  VarDataOffset = VarNameOffset + VarNameSize + GET_PAD_SIZE (VarNameSize);\r
+  CopyMem (\r
+    (UINT8 *) ((UINTN)NextVariable + VarDataOffset),\r
+    Data,\r
+    DataSize\r
+    );\r
+  CopyMem (&NextVariableHeader->VendorGuid, VendorGuid, sizeof (EFI_GUID));\r
+  //\r
+  // There will be pad bytes after Data, the NextVariable->NameSize and\r
+  // NextVariable->DataSize should not include pad size so that variable\r
+  // service can get actual size in GetVariable.\r
+  //\r
+  NextVariableHeader->NameSize  = (UINT32)VarNameSize;\r
+  NextVariableHeader->DataSize  = (UINT32)DataSize;\r
+\r
+  //\r
+  // The actual size of the variable that stores in storage should\r
+  // include pad size.\r
+  //\r
+  VarSize = VarDataOffset + DataSize + GET_PAD_SIZE (DataSize);\r
+  if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {\r
+    //\r
+    // Create a nonvolatile variable\r
+    //\r
+    Volatile = FALSE;\r
+    \r
+    GetVarStoreHeader (VariableGlobal->NonVolatileVariableBase, FALSE, VariableGlobal, Instance, &VariableStoreHeader);\r
+    if ((((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) \r
+             && ((HEADER_ALIGN (VarSize) + Global->HwErrVariableTotalSize) > PcdGet32(PcdHwErrStorageSize)))\r
+             || (((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0) \r
+             && ((HEADER_ALIGN (VarSize) + Global->CommonVariableTotalSize) > VariableStoreHeader.Size - sizeof (VARIABLE_STORE_HEADER) - PcdGet32(PcdHwErrStorageSize)))) {\r
+      if (EfiAtRuntime ()) {\r
+        Status = EFI_OUT_OF_RESOURCES;\r
+        goto Done;\r
+      }\r
+      //\r
+      // Perform garbage collection & reclaim operation\r
+      //\r
+      Status = Reclaim (VariableGlobal->NonVolatileVariableBase, &(Global->NonVolatileLastVariableOffset), FALSE, VirtualMode, Global, Variable->CurrPtr);\r
+      if (EFI_ERROR (Status)) {\r
+        goto Done;\r
+      }\r
+\r
+      Reclaimed = TRUE;\r
+      //\r
+      // If still no enough space, return out of resources\r
+      //\r
+      if ((((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) \r
+               && ((HEADER_ALIGN (VarSize) + Global->HwErrVariableTotalSize) > PcdGet32(PcdHwErrStorageSize)))\r
+               || (((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0) \r
+               && ((HEADER_ALIGN (VarSize) + Global->CommonVariableTotalSize) > VariableStoreHeader.Size - sizeof (VARIABLE_STORE_HEADER) - PcdGet32(PcdHwErrStorageSize)))) {\r
+        Status = EFI_OUT_OF_RESOURCES;\r
+        goto Done;\r
+      }\r
+    }\r
+    //\r
+    // Four steps\r
+    // 1. Write variable header\r
+    // 2. Set variable state to header valid  \r
+    // 3. Write variable data\r
+    // 4. Set variable state to valid\r
+    //\r
+    //\r
+    // Step 1:\r
+    //\r
+    Status = AccessVariableStore (\r
+               TRUE,\r
+               VariableGlobal,\r
+               FALSE,\r
+               Instance,\r
+               VariableGlobal->NonVolatileVariableBase + Global->NonVolatileLastVariableOffset,\r
+               sizeof (VARIABLE_HEADER),\r
+               (UINT8 *) NextVariable\r
+               );\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      goto Done;\r
+    }\r
+\r
+    //\r
+    // Step 2:\r
+    //\r
+    NextVariableHeader->State = VAR_HEADER_VALID_ONLY;\r
+    Status = AccessVariableStore (\r
+               TRUE,\r
+               VariableGlobal,\r
+               FALSE,\r
+               Instance,\r
+               VariableGlobal->NonVolatileVariableBase + Global->NonVolatileLastVariableOffset,\r
+               sizeof (VARIABLE_HEADER),\r
+               (UINT8 *) NextVariable\r
+               );\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      goto Done;\r
+    }\r
+    //\r
+    // Step 3:\r
+    //\r
+    Status = AccessVariableStore (\r
+               TRUE,\r
+               VariableGlobal,\r
+               FALSE,\r
+               Instance,\r
+               VariableGlobal->NonVolatileVariableBase + Global->NonVolatileLastVariableOffset + sizeof (VARIABLE_HEADER),\r
+               (UINT32) VarSize - sizeof (VARIABLE_HEADER),\r
+               (UINT8 *) NextVariable + sizeof (VARIABLE_HEADER)\r
+               );\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      goto Done;\r
+    }\r
+    //\r
+    // Step 4:\r
+    //\r
+    NextVariableHeader->State = VAR_ADDED;\r
+    Status = AccessVariableStore (\r
+               TRUE,\r
+               VariableGlobal,\r
+               FALSE,\r
+               Instance,\r
+               VariableGlobal->NonVolatileVariableBase + Global->NonVolatileLastVariableOffset,\r
+               sizeof (VARIABLE_HEADER),\r
+               (UINT8 *) NextVariable\r
+               );\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      goto Done;\r
+    }\r
+\r
+    Global->NonVolatileLastVariableOffset += HEADER_ALIGN (VarSize);\r
+\r
+    if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) {\r
+      Global->HwErrVariableTotalSize += HEADER_ALIGN (VarSize);\r
+    } else {\r
+      Global->CommonVariableTotalSize += HEADER_ALIGN (VarSize);\r
+    }\r
+  } else {\r
+    //\r
+    // Create a volatile variable\r
+    //      \r
+    Volatile = TRUE;\r
+\r
+    if ((UINT32) (HEADER_ALIGN(VarSize) + Global->VolatileLastVariableOffset) >\r
+        ((VARIABLE_STORE_HEADER *) ((UINTN) (VariableGlobal->VolatileVariableBase)))->Size) {\r
+      //\r
+      // Perform garbage collection & reclaim operation\r
+      //\r
+      Status = Reclaim (VariableGlobal->VolatileVariableBase, &Global->VolatileLastVariableOffset, TRUE, VirtualMode, Global, Variable->CurrPtr);\r
+      if (EFI_ERROR (Status)) {\r
+        goto Done;\r
+      }\r
+      //\r
+      // If still no enough space, return out of resources\r
+      //\r
+      if ((UINT32) (HEADER_ALIGN (VarSize) + Global->VolatileLastVariableOffset) >\r
+            ((VARIABLE_STORE_HEADER *) ((UINTN) (VariableGlobal->VolatileVariableBase)))->Size\r
+            ) {\r
+        Status = EFI_OUT_OF_RESOURCES;\r
+        goto Done;\r
+      }\r
+      Reclaimed = TRUE;\r
+    }\r
+\r
+    NextVariableHeader->State = VAR_ADDED;\r
+    Status = AccessVariableStore (\r
+               TRUE,\r
+               VariableGlobal,\r
+               TRUE,\r
+               Instance,\r
+               VariableGlobal->VolatileVariableBase + Global->VolatileLastVariableOffset,\r
+               (UINT32) VarSize,\r
+               (UINT8 *) NextVariable\r
+               );\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      goto Done;\r
+    }\r
+\r
+    Global->VolatileLastVariableOffset += HEADER_ALIGN (VarSize);\r
+  }\r
+  //\r
+  // Mark the old variable as deleted\r
+  // If storage has just been reclaimed, the old variable marked as VAR_IN_DELETED_TRANSITION\r
+  // has already been eliminated, so no need to delete it.\r
+  //\r
+  if (!Reclaimed && !EFI_ERROR (Status) && Variable->CurrPtr != 0) {\r
+    State = ((VARIABLE_HEADER *)Variable->CurrPtr)->State;\r
+    State &= VAR_DELETED;\r
+\r
+    Status = AccessVariableStore (\r
+               TRUE,\r
+               VariableGlobal,\r
+               Variable->Volatile,\r
+               Instance,\r
+               (UINTN) &(((VARIABLE_HEADER *)Variable->CurrPtr)->State),\r
+               sizeof (UINT8),\r
+               &State\r
+               );\r
+  }\r
+\r
+  if (!EFI_ERROR (Status)) {\r
+    UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, TRUE, FALSE, FALSE);\r
+    UpdateVariableCache (VariableName, VendorGuid, Attributes, DataSize, Data);\r
+  }\r
+\r
+Done:\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Implements EsalGetVariable function of Extended SAL Variable Services Class.\r
+\r
+  This function implements EsalGetVariable function of Extended SAL Variable Services Class.\r
+  It is equivalent in functionality to the EFI Runtime Service GetVariable().\r
+  \r
+  @param[in]      VariableName    A Null-terminated Unicode string that is the name of\r
+                                  the vendor's variable.\r
+  @param[in]      VendorGuid      A unique identifier for the vendor.\r
+  @param[out]     Attributes      If not NULL, a pointer to the memory location to return the \r
+                                  attributes bitmask for the variable.\r
+  @param[in, out] DataSize        Size of Data found. If size is less than the\r
+                                  data, this value contains the required size.\r
+  @param[out]     Data            On input, the size in bytes of the return Data buffer.  \r
+                                  On output, the size of data returned in Data.\r
+  @param[in]      VirtualMode     Current calling mode for this function.\r
+  @param[in]      Global          Context of this Extended SAL Variable Services Class call.\r
+\r
+  @retval EFI_SUCCESS            The function completed successfully. \r
+  @retval EFI_NOT_FOUND          The variable was not found.\r
+  @retval EFI_BUFFER_TOO_SMALL   DataSize is too small for the result.  DataSize has \r
+                                 been updated with the size needed to complete the request.\r
+  @retval EFI_INVALID_PARAMETER  VariableName is NULL.\r
+  @retval EFI_INVALID_PARAMETER  VendorGuid is NULL.\r
+  @retval EFI_INVALID_PARAMETER  DataSize is NULL.\r
+  @retval EFI_INVALID_PARAMETER  DataSize is not too small and Data is NULL.\r
+  @retval EFI_DEVICE_ERROR       The variable could not be retrieved due to a hardware error.\r
+  @retval EFI_SECURITY_VIOLATION The variable could not be retrieved due to an authentication failure.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EsalGetVariable (\r
+  IN      CHAR16                *VariableName,\r
+  IN      EFI_GUID              *VendorGuid,\r
+  OUT     UINT32                *Attributes OPTIONAL,\r
+  IN OUT  UINTN                 *DataSize,\r
+  OUT     VOID                  *Data,\r
+  IN      BOOLEAN               VirtualMode,\r
+  IN      ESAL_VARIABLE_GLOBAL  *Global\r
+  )\r
+{\r
+  VARIABLE_POINTER_TRACK  Variable;\r
+  UINTN                   VarDataSize;\r
+  EFI_STATUS              Status;\r
+  VARIABLE_HEADER         VariableHeader;\r
+  BOOLEAN                 Valid;\r
+  VARIABLE_GLOBAL         *VariableGlobal;\r
+  UINT32                  Instance;\r
+\r
+  if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  VariableGlobal = &Global->VariableGlobal[VirtualMode];\r
+  Instance = Global->FvbInstance;\r
+\r
+  AcquireLockOnlyAtBootTime(&VariableGlobal->VariableServicesLock);\r
+\r
+  //\r
+  // Check if this variable exists in cache.\r
+  //\r
+  Status = FindVariableInCache (VariableName, VendorGuid, Attributes, DataSize, Data);\r
+  if ((Status == EFI_BUFFER_TOO_SMALL) || (Status == EFI_SUCCESS)){\r
+    //\r
+    // If variable exists in cache, just update statistical information for it and finish.\r
+    // Here UpdateVariableInfo() has already retrieved data & attributes for output.\r
+    //\r
+    UpdateVariableInfo (VariableName, VendorGuid, FALSE, TRUE, FALSE, FALSE, TRUE);\r
+    goto Done;\r
+  }\r
+  //\r
+  // If variable does not exist in cache, search for it in variable storage area.\r
+  //\r
+  Status = FindVariable (VariableName, VendorGuid, &Variable, VariableGlobal, Instance);\r
+  if (Variable.CurrPtr == 0x0 || EFI_ERROR (Status)) {\r
+    //\r
+    // If it cannot be found in variable storage area, goto Done.\r
+    //\r
+    goto Done;\r
+  }\r
+\r
+  Valid = IsValidVariableHeader (Variable.CurrPtr, Variable.Volatile, VariableGlobal, Instance, &VariableHeader);\r
+  if (!Valid) {\r
+    Status = EFI_NOT_FOUND;\r
+    goto Done;\r
+  }\r
+  //\r
+  // If variable exists, but not in cache, get its data and attributes, update\r
+  // statistical information, and update cache.\r
+  //\r
+  VarDataSize = DataSizeOfVariable (&VariableHeader);\r
+  ASSERT (VarDataSize != 0);\r
+\r
+  if (*DataSize >= VarDataSize) {\r
+    if (Data == NULL) {\r
+      Status = EFI_INVALID_PARAMETER;\r
+      goto Done;\r
+    }\r
+\r
+    GetVariableDataPtr (\r
+      Variable.CurrPtr,\r
+      Variable.Volatile,\r
+      VariableGlobal,\r
+      Instance,\r
+      Data\r
+      );\r
+    if (Attributes != NULL) {\r
+      *Attributes = VariableHeader.Attributes;\r
+    }\r
+\r
+    *DataSize = VarDataSize;\r
+    UpdateVariableInfo (VariableName, VendorGuid, Variable.Volatile, TRUE, FALSE, FALSE, FALSE);\r
+    UpdateVariableCache (VariableName, VendorGuid, VariableHeader.Attributes, VarDataSize, Data);\r
\r
+    Status = EFI_SUCCESS;\r
+    goto Done;\r
+  } else {\r
+    //\r
+    // If DataSize is too small for the result, return EFI_BUFFER_TOO_SMALL.\r
+    //\r
+    *DataSize = VarDataSize;\r
+    Status = EFI_BUFFER_TOO_SMALL;\r
+    goto Done;\r
+  }\r
+\r
+Done:\r
+  ReleaseLockOnlyAtBootTime (&VariableGlobal->VariableServicesLock);\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Implements EsalGetNextVariableName function of Extended SAL Variable Services Class.\r
+\r
+  This function implements EsalGetNextVariableName function of Extended SAL Variable Services Class.\r
+  It is equivalent in functionality to the EFI Runtime Service GetNextVariableName().\r
+  \r
+  @param[in, out] VariableNameSize Size of the variable\r
+  @param[in, out] VariableName     On input, supplies the last VariableName that was returned by GetNextVariableName().\r
+                                   On output, returns the Null-terminated Unicode string of the current variable.\r
+  @param[in, out] VendorGuid       On input, supplies the last VendorGuid that was returned by GetNextVariableName().\r
+                                   On output, returns the VendorGuid of the current variable.  \r
+  @param[in]      VirtualMode      Current calling mode for this function.\r
+  @param[in]      Global           Context of this Extended SAL Variable Services Class call.\r
+\r
+  @retval EFI_SUCCESS             The function completed successfully. \r
+  @retval EFI_NOT_FOUND           The next variable was not found.\r
+  @retval EFI_BUFFER_TOO_SMALL    VariableNameSize is too small for the result. \r
+                                  VariableNameSize has been updated with the size needed to complete the request.\r
+  @retval EFI_INVALID_PARAMETER   VariableNameSize is NULL.\r
+  @retval EFI_INVALID_PARAMETER   VariableName is NULL.\r
+  @retval EFI_INVALID_PARAMETER   VendorGuid is NULL.\r
+  @retval EFI_DEVICE_ERROR        The variable name could not be retrieved due to a hardware error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EsalGetNextVariableName (\r
+  IN OUT  UINTN                 *VariableNameSize,\r
+  IN OUT  CHAR16                *VariableName,\r
+  IN OUT  EFI_GUID              *VendorGuid,\r
+  IN      BOOLEAN               VirtualMode,\r
+  IN      ESAL_VARIABLE_GLOBAL  *Global\r
+  )\r
+{\r
+  VARIABLE_POINTER_TRACK  Variable;\r
+  UINTN                   VarNameSize;\r
+  EFI_STATUS              Status;\r
+  VARIABLE_HEADER         VariableHeader;\r
+  VARIABLE_GLOBAL         *VariableGlobal;\r
+  UINT32                  Instance;\r
+\r
+  if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  VariableGlobal = &Global->VariableGlobal[VirtualMode];\r
+  Instance = Global->FvbInstance;\r
+\r
+  AcquireLockOnlyAtBootTime(&VariableGlobal->VariableServicesLock);\r
+\r
+  Status = FindVariable (VariableName, VendorGuid, &Variable, VariableGlobal, Instance);\r
+  //\r
+  // If the variable does not exist, goto Done and return.\r
+  //\r
+  if (Variable.CurrPtr == 0x0 || EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+\r
+  if (VariableName[0] != 0) {\r
+    //\r
+    // If variable name is not NULL, get next variable\r
+    //\r
+    Variable.CurrPtr = GetNextVariablePtr (\r
+                         Variable.CurrPtr,\r
+                         Variable.Volatile,\r
+                         VariableGlobal,\r
+                         Instance\r
+                         );\r
+  }\r
+\r
+  while (TRUE) {\r
+    if (Variable.CurrPtr >= Variable.EndPtr || Variable.CurrPtr == 0x0) {\r
+      //\r
+      // If fail to find a variable in current area, reverse the volatile attribute of area to search.\r
+      //\r
+      Variable.Volatile = (BOOLEAN) (Variable.Volatile ^ ((BOOLEAN) 0x1));\r
+      //\r
+      // Here we depend on the searching sequence of FindVariable().\r
+      // It first searches volatile area, then NV area.\r
+      // So if the volatile attribute after switching is non-volatile, it means that we have finished searching volatile area,\r
+      // and EFI_NOT_FOUND is returnd.\r
+      // Otherwise, it means that we have finished searchig non-volatile area, and we will continue to search volatile area.\r
+      //\r
+      if (!Variable.Volatile) {\r
+        Variable.StartPtr = GetStartPointer (VariableGlobal->NonVolatileVariableBase);\r
+        Variable.EndPtr   = GetEndPointer (VariableGlobal->NonVolatileVariableBase, FALSE, VariableGlobal, Instance);\r
+      } else {\r
+        Status = EFI_NOT_FOUND;\r
+        goto Done;\r
+      }\r
+\r
+      Variable.CurrPtr = Variable.StartPtr;\r
+      if (!IsValidVariableHeader (Variable.CurrPtr, Variable.Volatile, VariableGlobal, Instance, NULL)) {\r
+        continue;\r
+      }\r
+    }\r
+    //\r
+    // Variable is found\r
+    //\r
+    if (IsValidVariableHeader (Variable.CurrPtr, Variable.Volatile, VariableGlobal, Instance, &VariableHeader)) {\r
+      if ((VariableHeader.State == VAR_ADDED) &&\r
+          (!(EfiAtRuntime () && ((VariableHeader.Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)))) {\r
+        VarNameSize = NameSizeOfVariable (&VariableHeader);\r
+        ASSERT (VarNameSize != 0);\r
+\r
+        if (VarNameSize <= *VariableNameSize) {\r
+          GetVariableNamePtr (\r
+            Variable.CurrPtr,\r
+            Variable.Volatile,\r
+            VariableGlobal,\r
+            Instance,\r
+            VariableName\r
+            );\r
+          CopyMem (\r
+            VendorGuid,\r
+            &VariableHeader.VendorGuid,\r
+            sizeof (EFI_GUID)\r
+            );\r
+          Status = EFI_SUCCESS;\r
+        } else {\r
+          Status = EFI_BUFFER_TOO_SMALL;\r
+        }\r
+\r
+        *VariableNameSize = VarNameSize;\r
+        goto Done;\r
+      }\r
+    }\r
+\r
+    Variable.CurrPtr = GetNextVariablePtr (\r
+                         Variable.CurrPtr,\r
+                         Variable.Volatile,\r
+                         VariableGlobal,\r
+                         Instance\r
+                         );\r
+  }\r
+\r
+Done:\r
+  ReleaseLockOnlyAtBootTime (&VariableGlobal->VariableServicesLock);\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Implements EsalSetVariable function of Extended SAL Variable Services Class.\r
+\r
+  This function implements EsalSetVariable function of Extended SAL Variable Services Class.\r
+  It is equivalent in functionality to the EFI Runtime Service SetVariable().\r
+  \r
+  @param[in]  VariableName       A Null-terminated Unicode string that is the name of the vendor's\r
+                                 variable.  Each VariableName is unique for each \r
+                                 VendorGuid.  VariableName must contain 1 or more \r
+                                 Unicode characters.  If VariableName is an empty Unicode \r
+                                 string, then EFI_INVALID_PARAMETER is returned.\r
+  @param[in]  VendorGuid         A unique identifier for the vendor.\r
+  @param[in]  Attributes         Attributes bitmask to set for the variable.\r
+  @param[in]  DataSize           The size in bytes of the Data buffer.  A size of zero causes the\r
+                                 variable to be deleted.\r
+  @param[in]  Data               The contents for the variable.\r
+  @param[in]  VirtualMode        Current calling mode for this function.\r
+  @param[in]  Global             Context of this Extended SAL Variable Services Class call.\r
+\r
+  @retval EFI_SUCCESS            The firmware has successfully stored the variable and its data as \r
+                                 defined by the Attributes.\r
+  @retval EFI_INVALID_PARAMETER  An invalid combination of attribute bits was supplied, or the \r
+                                 DataSize exceeds the maximum allowed.\r
+  @retval EFI_INVALID_PARAMETER  VariableName is an empty Unicode string.\r
+  @retval EFI_OUT_OF_RESOURCES   Not enough storage is available to hold the variable and its data.\r
+  @retval EFI_DEVICE_ERROR       The variable could not be saved due to a hardware failure.\r
+  @retval EFI_WRITE_PROTECTED    The variable in question is read-only.\r
+  @retval EFI_WRITE_PROTECTED    The variable in question cannot be deleted.\r
+  @retval EFI_SECURITY_VIOLATION The variable could not be retrieved due to an authentication failure.\r
+  @retval EFI_NOT_FOUND          The variable trying to be updated or deleted was not found.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EsalSetVariable (\r
+  IN CHAR16                  *VariableName,\r
+  IN EFI_GUID                *VendorGuid,\r
+  IN UINT32                  Attributes,\r
+  IN UINTN                   DataSize,\r
+  IN VOID                    *Data,\r
+  IN BOOLEAN                 VirtualMode,\r
+  IN ESAL_VARIABLE_GLOBAL    *Global\r
+  )\r
+{\r
+  VARIABLE_POINTER_TRACK  Variable;\r
+  EFI_STATUS              Status;\r
+  EFI_PHYSICAL_ADDRESS    NextVariable;\r
+  EFI_PHYSICAL_ADDRESS    Point;\r
+  VARIABLE_GLOBAL         *VariableGlobal;\r
+  UINT32                  Instance;\r
+  UINT32                  KeyIndex;\r
+  UINT64                  MonotonicCount;\r
+  UINTN                   PayloadSize;\r
+\r
+  //\r
+  // Check input parameters\r
+  //\r
+  if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }  \r
+\r
+  if (DataSize != 0 && Data == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // EFI_VARIABLE_RUNTIME_ACCESS bit cannot be set without EFI_VARIABLE_BOOTSERVICE_ACCESS bit.\r
+  //\r
+  if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) {\r
+    if (DataSize < AUTHINFO_SIZE) {\r
+      //\r
+      // Try to write Authencated Variable without AuthInfo\r
+      //\r
+      return EFI_SECURITY_VIOLATION;\r
+    } \r
+    PayloadSize = DataSize - AUTHINFO_SIZE; \r
+  } else {\r
+    PayloadSize = DataSize; \r
+  }\r
+\r
+  VariableGlobal = &Global->VariableGlobal[VirtualMode];\r
+  Instance = Global->FvbInstance;\r
+\r
+  if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
+    //\r
+    // For variable for hardware error record, the size of the VariableName, including the Unicode Null\r
+    // in bytes plus the DataSize is limited to maximum size of PcdGet32(PcdMaxHardwareErrorVariableSize) bytes.\r
+    //\r
+    if ((PayloadSize > PcdGet32(PcdMaxHardwareErrorVariableSize)) ||                                                       \r
+        (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + PayloadSize > PcdGet32(PcdMaxHardwareErrorVariableSize))) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+    //\r
+    // According to UEFI spec, HARDWARE_ERROR_RECORD variable name convention should be L"HwErrRecXXXX"\r
+    //\r
+    if (StrnCmp (VariableName, \\r
+                 Global->VariableName[VirtualMode][VAR_HW_ERR_REC], \\r
+                 StrLen(Global->VariableName[VirtualMode][VAR_HW_ERR_REC])) != 0) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+  } else {\r
+    //\r
+    // For variable not for hardware error record, the size of the VariableName, including the\r
+    // Unicode Null in bytes plus the DataSize is limited to maximum size of PcdGet32(PcdMaxVariableSize) bytes.\r
+    //\r
+    if ((PayloadSize > PcdGet32(PcdMaxVariableSize)) ||\r
+        (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + PayloadSize > PcdGet32(PcdMaxVariableSize))) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }  \r
+  }  \r
+\r
+  AcquireLockOnlyAtBootTime(&VariableGlobal->VariableServicesLock);\r
+\r
+  //\r
+  // Consider reentrant in MCA/INIT/NMI. It needs be reupdated;\r
+  //\r
+  if (InterlockedIncrement (&Global->ReentrantState) > 1) {\r
+    Point = VariableGlobal->NonVolatileVariableBase;;\r
+    //\r
+    // Parse non-volatile variable data and get last variable offset\r
+    //\r
+    NextVariable  = GetStartPointer (Point);\r
+    while (IsValidVariableHeader (NextVariable, FALSE, VariableGlobal, Instance, NULL)) {\r
+      NextVariable = GetNextVariablePtr (NextVariable, FALSE, VariableGlobal, Instance);\r
+    }\r
+    Global->NonVolatileLastVariableOffset = NextVariable - Point;\r
+  }\r
+\r
+  //\r
+  // Check whether the input variable exists\r
+  //\r
+\r
+  Status = FindVariable (VariableName, VendorGuid, &Variable, VariableGlobal, Instance);\r
+\r
+  //\r
+  // Hook the operation of setting PlatformLangCodes/PlatformLang and LangCodes/Lang\r
+  //\r
+  AutoUpdateLangVariable (VariableName, Data, PayloadSize, VirtualMode, Global);\r
+\r
+  //\r
+  // Process PK, KEK, Sigdb seperately\r
+  //\r
+  if (CompareGuid (VendorGuid, Global->GlobalVariableGuid[VirtualMode]) && (StrCmp (VariableName, Global->VariableName[VirtualMode][VAR_PLATFORM_KEY]) == 0)) {\r
+    Status = ProcessVarWithPk (VariableName, VendorGuid, Data, DataSize, VirtualMode, Global, &Variable, Attributes, TRUE);\r
+  } else if (CompareGuid (VendorGuid, Global->GlobalVariableGuid[VirtualMode]) && (StrCmp (VariableName, Global->VariableName[VirtualMode][VAR_KEY_EXCHANGE_KEY]) == 0)) {\r
+    Status = ProcessVarWithPk (VariableName, VendorGuid, Data, DataSize, VirtualMode, Global, &Variable, Attributes, FALSE);\r
+  } else if (CompareGuid (VendorGuid, Global->ImageSecurityDatabaseGuid[VirtualMode])) {\r
+    Status = ProcessVarWithKek (VariableName, VendorGuid, Data, DataSize, VirtualMode, Global, &Variable, Attributes);\r
+  } else {\r
+    Status = VerifyVariable (Data, DataSize, VirtualMode, Global, &Variable, Attributes, &KeyIndex, &MonotonicCount);\r
+    if (!EFI_ERROR(Status)) {\r
+      //\r
+      // Verification pass\r
+      //\r
+      if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
+        //\r
+        // Cut the certificate size before set\r
+        //\r
+        Status = UpdateVariable (\r
+                   VariableName, \r
+                   VendorGuid, \r
+                   (UINT8*)Data + AUTHINFO_SIZE, \r
+                   DataSize - AUTHINFO_SIZE, \r
+                   Attributes, \r
+                   KeyIndex, \r
+                   MonotonicCount, \r
+                   VirtualMode, \r
+                   Global, \r
+                   &Variable\r
+                   );\r
+      } else {\r
+        //\r
+        // Update variable as usual \r
+        //\r
+        Status = UpdateVariable (\r
+                   VariableName, \r
+                   VendorGuid, \r
+                   Data, \r
+                   DataSize, \r
+                   Attributes, \r
+                   0, \r
+                   0, \r
+                   VirtualMode, \r
+                   Global, \r
+                   &Variable\r
+                   );\r
+      }\r
+    }\r
+  }\r
+\r
+  InterlockedDecrement (&Global->ReentrantState);\r
+  ReleaseLockOnlyAtBootTime (&VariableGlobal->VariableServicesLock);\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Implements EsalQueryVariableInfo function of Extended SAL Variable Services Class.\r
+\r
+  This function implements EsalQueryVariableInfo function of Extended SAL Variable Services Class.\r
+  It is equivalent in functionality to the EFI Runtime Service QueryVariableInfo().\r
+\r
+  @param[in]  Attributes                   Attributes bitmask to specify the type of variables\r
+                                           on which to return information.\r
+  @param[out] MaximumVariableStorageSize   On output the maximum size of the storage space available for \r
+                                           the EFI variables associated with the attributes specified.  \r
+  @param[out] RemainingVariableStorageSize Returns the remaining size of the storage space available for EFI \r
+                                           variables associated with the attributes specified.\r
+  @param[out] MaximumVariableSize          Returns the maximum size of an individual EFI variable \r
+                                           associated with the attributes specified.\r
+  @param[in]  VirtualMode                  Current calling mode for this function\r
+  @param[in]  Global                       Context of this Extended SAL Variable Services Class call\r
+\r
+  @retval EFI_SUCCESS                      Valid answer returned.\r
+  @retval EFI_INVALID_PARAMETER            An invalid combination of attribute bits was supplied.\r
+  @retval EFI_UNSUPPORTED                  The attribute is not supported on this platform, and the \r
+                                           MaximumVariableStorageSize, RemainingVariableStorageSize, \r
+                                           MaximumVariableSize are undefined.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EsalQueryVariableInfo (\r
+  IN  UINT32                 Attributes,\r
+  OUT UINT64                 *MaximumVariableStorageSize,\r
+  OUT UINT64                 *RemainingVariableStorageSize,\r
+  OUT UINT64                 *MaximumVariableSize,\r
+  IN  BOOLEAN                VirtualMode,\r
+  IN  ESAL_VARIABLE_GLOBAL   *Global\r
+  )\r
+{\r
+  EFI_PHYSICAL_ADDRESS   Variable;\r
+  EFI_PHYSICAL_ADDRESS   NextVariable;\r
+  UINT64                 VariableSize;\r
+  EFI_PHYSICAL_ADDRESS   VariableStoreHeaderAddress;\r
+  BOOLEAN                Volatile;\r
+  VARIABLE_STORE_HEADER  VarStoreHeader;\r
+  VARIABLE_HEADER        VariableHeader;\r
+  UINT64                 CommonVariableTotalSize;\r
+  UINT64                 HwErrVariableTotalSize;\r
+  VARIABLE_GLOBAL        *VariableGlobal;\r
+  UINT32                 Instance;\r
+\r
+  CommonVariableTotalSize = 0;\r
+  HwErrVariableTotalSize = 0;\r
+\r
+  if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  \r
+  if((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == 0) {\r
+    //\r
+    // Make sure the Attributes combination is supported by the platform.\r
+    //\r
+    return EFI_UNSUPPORTED;  \r
+  } else if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {\r
+    //\r
+    // Make sure if runtime bit is set, boot service bit is set also.\r
+    //\r
+    return EFI_INVALID_PARAMETER;\r
+  } else if (EfiAtRuntime () && ((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)) {\r
+    //\r
+    // Make sure RT Attribute is set if we are in Runtime phase.\r
+    //\r
+    return EFI_INVALID_PARAMETER;\r
+  } else if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
+    //\r
+    // Make sure Hw Attribute is set with NV.\r
+    //\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  VariableGlobal = &Global->VariableGlobal[VirtualMode];\r
+  Instance = Global->FvbInstance;\r
+\r
+  AcquireLockOnlyAtBootTime(&VariableGlobal->VariableServicesLock);\r
+\r
+  if((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {\r
+    //\r
+    // Query is Volatile related.\r
+    //\r
+    Volatile = TRUE;\r
+    VariableStoreHeaderAddress = VariableGlobal->VolatileVariableBase;\r
+  } else {\r
+    //\r
+    // Query is Non-Volatile related.\r
+    //\r
+    Volatile = FALSE;\r
+    VariableStoreHeaderAddress = VariableGlobal->NonVolatileVariableBase;\r
+  }\r
+\r
+  //\r
+  // Now let's fill *MaximumVariableStorageSize *RemainingVariableStorageSize\r
+  // with the storage size (excluding the storage header size).\r
+  //\r
+  GetVarStoreHeader (VariableStoreHeaderAddress, Volatile, VariableGlobal, Instance, &VarStoreHeader);\r
+\r
+  *MaximumVariableStorageSize   = VarStoreHeader.Size - sizeof (VARIABLE_STORE_HEADER);\r
+\r
+  // Harware error record variable needs larger size.\r
+  //\r
+  if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
+    *MaximumVariableStorageSize = PcdGet32(PcdHwErrStorageSize);\r
+    *MaximumVariableSize = PcdGet32(PcdMaxHardwareErrorVariableSize) - sizeof (VARIABLE_HEADER);\r
+  } else {\r
+    if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {\r
+      ASSERT (PcdGet32(PcdHwErrStorageSize) < VarStoreHeader.Size);\r
+      *MaximumVariableStorageSize = VarStoreHeader.Size - sizeof (VARIABLE_STORE_HEADER) - PcdGet32(PcdHwErrStorageSize);\r
+    }\r
+\r
+    //\r
+    // Let *MaximumVariableSize be PcdGet32(PcdMaxVariableSize) with the exception of the variable header size.\r
+    //\r
+    *MaximumVariableSize = PcdGet32(PcdMaxVariableSize) - sizeof (VARIABLE_HEADER);\r
+  }\r
+\r
+  //\r
+  // Point to the starting address of the variables.\r
+  //\r
+  Variable = GetStartPointer (VariableStoreHeaderAddress);\r
+\r
+  //\r
+  // Now walk through the related variable store.\r
+  //\r
+  while (IsValidVariableHeader (Variable, Volatile, VariableGlobal, Instance, &VariableHeader) &&\r
+         (Variable < GetEndPointer (VariableStoreHeaderAddress, Volatile, VariableGlobal, Instance))) {\r
+    NextVariable = GetNextVariablePtr (Variable, Volatile, VariableGlobal, Instance);\r
+    VariableSize = NextVariable - Variable;\r
+\r
+    if (EfiAtRuntime ()) {\r
+      //\r
+      // we don't take the state of the variables in mind\r
+      // when calculating RemainingVariableStorageSize,\r
+      // since the space occupied by variables not marked with\r
+      // VAR_ADDED is not allowed to be reclaimed in Runtime.\r
+      //\r
+      if ((VariableHeader.Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
+        HwErrVariableTotalSize += VariableSize;\r
+      } else {\r
+        CommonVariableTotalSize += VariableSize;\r
+      }\r
+    } else {\r
+      //\r
+      // Only care about Variables with State VAR_ADDED,because\r
+      // the space not marked as VAR_ADDED is reclaimable now.\r
+      //\r
+      if (VariableHeader.State == VAR_ADDED) {\r
+        if ((VariableHeader.Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
+          HwErrVariableTotalSize += VariableSize;\r
+        } else {\r
+          CommonVariableTotalSize += VariableSize;\r
+        }\r
+      }\r
+    }\r
+\r
+    //\r
+    // Go to the next one\r
+    //\r
+    Variable = NextVariable;\r
+  }\r
+\r
+  if ((Attributes  & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD){\r
+    *RemainingVariableStorageSize = *MaximumVariableStorageSize - HwErrVariableTotalSize;\r
+  }else {\r
+    *RemainingVariableStorageSize = *MaximumVariableStorageSize - CommonVariableTotalSize;\r
+  }\r
+\r
+  if (*RemainingVariableStorageSize < sizeof (VARIABLE_HEADER)) {\r
+    *MaximumVariableSize = 0;\r
+  } else if ((*RemainingVariableStorageSize - sizeof (VARIABLE_HEADER)) < *MaximumVariableSize) {\r
+    *MaximumVariableSize = *RemainingVariableStorageSize - sizeof (VARIABLE_HEADER);\r
+  }\r
+\r
+  ReleaseLockOnlyAtBootTime (&VariableGlobal->VariableServicesLock);\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Notification function of EVT_GROUP_READY_TO_BOOT event group.\r
+\r
+  This is a notification function registered on EVT_GROUP_READY_TO_BOOT event group.\r
+  When the Boot Manager is about to load and execute a boot option, it reclaims variable\r
+  storage if free size is below the threshold.\r
+\r
+  @param[in]  Event        Event whose notification function is being invoked.\r
+  @param[in]  Context      Pointer to the notification function's context.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+ReclaimForOS(\r
+  IN EFI_EVENT  Event,\r
+  IN VOID       *Context\r
+  )\r
+{\r
+  UINT32                          VarSize;\r
+  EFI_STATUS                      Status;\r
+  UINTN                           CommonVariableSpace;\r
+  UINTN                           RemainingCommonVariableSpace;\r
+  UINTN                           RemainingHwErrVariableSpace;\r
+\r
+  VarSize = ((VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase))->Size;\r
+  Status  = EFI_SUCCESS; \r
+  //\r
+  //Allowable max size of common variable storage space\r
+  //\r
+  CommonVariableSpace = VarSize - sizeof (VARIABLE_STORE_HEADER) - PcdGet32(PcdHwErrStorageSize);\r
+\r
+  RemainingCommonVariableSpace = CommonVariableSpace - mVariableModuleGlobal->CommonVariableTotalSize;\r
\r
+  RemainingHwErrVariableSpace = PcdGet32 (PcdHwErrStorageSize) - mVariableModuleGlobal->HwErrVariableTotalSize;\r
+  //\r
+  // If the free area is below a threshold, then performs reclaim operation.\r
+  //\r
+  if ((RemainingCommonVariableSpace < PcdGet32 (PcdMaxVariableSize))\r
+    || ((PcdGet32 (PcdHwErrStorageSize) != 0) && \r
+       (RemainingHwErrVariableSpace < PcdGet32 (PcdMaxHardwareErrorVariableSize)))){\r
+    Status = Reclaim (\r
+               mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase,\r
+               &mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
+               FALSE,\r
+               Physical,\r
+               mVariableModuleGlobal,\r
+               0x0\r
+               );\r
+    ASSERT_EFI_ERROR (Status);\r
+  }\r
+}\r
+\r
+/**\r
+  Initializes variable store area for non-volatile and volatile variable.\r
+\r
+  This function allocates and initializes memory space for global context of ESAL\r
+  variable service and variable store area for non-volatile and volatile variable.\r
+\r
+  @param[in]  ImageHandle       The Image handle of this driver.\r
+  @param[in]  SystemTable       The pointer of EFI_SYSTEM_TABLE.\r
+\r
+  @retval EFI_SUCCESS           Function successfully executed.\r
+  @retval EFI_OUT_OF_RESOURCES  Fail to allocate enough memory resource.\r
+\r
+**/\r
+EFI_STATUS\r
+VariableCommonInitialize (\r
+  IN EFI_HANDLE         ImageHandle,\r
+  IN EFI_SYSTEM_TABLE   *SystemTable\r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  EFI_FIRMWARE_VOLUME_HEADER      *FwVolHeader;\r
+  EFI_PHYSICAL_ADDRESS            CurrPtr;\r
+  VARIABLE_STORE_HEADER           *VolatileVariableStore;\r
+  VARIABLE_STORE_HEADER           *VariableStoreHeader;\r
+  EFI_PHYSICAL_ADDRESS            Variable;\r
+  EFI_PHYSICAL_ADDRESS            NextVariable;\r
+  UINTN                           VariableSize;\r
+  UINT32                          Instance;\r
+  EFI_PHYSICAL_ADDRESS            FvVolHdr;\r
+  EFI_PHYSICAL_ADDRESS            TempVariableStoreHeader;\r
+  EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor;\r
+  UINT64                          BaseAddress;\r
+  UINT64                          Length;\r
+  UINTN                           Index;\r
+  UINT8                           Data;\r
+  EFI_PHYSICAL_ADDRESS            VariableStoreBase;\r
+  UINT64                          VariableStoreLength;\r
+  EFI_EVENT                       ReadyToBootEvent;\r
+  UINTN                           ScratchSize;\r
+\r
+  //\r
+  // Allocate memory for mVariableModuleGlobal\r
+  //\r
+  mVariableModuleGlobal = AllocateRuntimeZeroPool (sizeof (ESAL_VARIABLE_GLOBAL));\r
+  if (mVariableModuleGlobal == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  mVariableModuleGlobal->GlobalVariableGuid[Physical] = &gEfiGlobalVariableGuid;\r
+  CopyMem (\r
+    mVariableModuleGlobal->VariableName[Physical],\r
+    mVariableName,\r
+    sizeof (mVariableName)\r
+    );\r
+\r
+  EfiInitializeLock(&mVariableModuleGlobal->VariableGlobal[Physical].VariableServicesLock, TPL_NOTIFY);\r
+\r
+  //\r
+  // Note that in EdkII variable driver implementation, Hardware Error Record type variable\r
+  // is stored with common variable in the same NV region. So the platform integrator should\r
+  // ensure that the value of PcdHwErrStorageSize is less than or equal to the value of \r
+  // PcdFlashNvStorageVariableSize.\r
+  //\r
+  ASSERT (PcdGet32(PcdHwErrStorageSize) <= PcdGet32 (PcdFlashNvStorageVariableSize));\r
+\r
+  //\r
+  // Allocate memory for volatile variable store\r
+  //\r
+  ScratchSize = MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize));\r
+  VolatileVariableStore = AllocateRuntimePool (PcdGet32 (PcdVariableStoreSize) + ScratchSize);\r
+  if (VolatileVariableStore == NULL) {\r
+    FreePool (mVariableModuleGlobal);\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  SetMem (VolatileVariableStore, PcdGet32 (PcdVariableStoreSize) + ScratchSize, 0xff);\r
+\r
+  //\r
+  // Variable Specific Data\r
+  //\r
+  mVariableModuleGlobal->VariableGlobal[Physical].VolatileVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VolatileVariableStore;\r
+  mVariableModuleGlobal->VolatileLastVariableOffset = (UINTN) GetStartPointer ((EFI_PHYSICAL_ADDRESS) VolatileVariableStore) - (UINTN) VolatileVariableStore;\r
+\r
+  CopyGuid (&VolatileVariableStore->Signature, &gEfiAuthenticatedVariableGuid);\r
+  VolatileVariableStore->Size                       = PcdGet32 (PcdVariableStoreSize);\r
+  VolatileVariableStore->Format                     = VARIABLE_STORE_FORMATTED;\r
+  VolatileVariableStore->State                      = VARIABLE_STORE_HEALTHY;\r
+  VolatileVariableStore->Reserved                   = 0;\r
+  VolatileVariableStore->Reserved1                  = 0;\r
+\r
+  //\r
+  // Get non volatile varaible store\r
+  //\r
+  TempVariableStoreHeader = (UINT64) PcdGet32 (PcdFlashNvStorageVariableBase);\r
+  VariableStoreBase = TempVariableStoreHeader + \\r
+                              (((EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) (TempVariableStoreHeader)) -> HeaderLength);\r
+  VariableStoreLength = (UINT64) PcdGet32 (PcdFlashNvStorageVariableSize) - \\r
+                                (((EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) (TempVariableStoreHeader)) -> HeaderLength);\r
+  //\r
+  // Mark the variable storage region of the FLASH as RUNTIME\r
+  //\r
+  BaseAddress = VariableStoreBase & (~EFI_PAGE_MASK);\r
+  Length      = VariableStoreLength + (VariableStoreBase - BaseAddress);\r
+  Length      = (Length + EFI_PAGE_SIZE - 1) & (~EFI_PAGE_MASK);\r
+\r
+  Status      = gDS->GetMemorySpaceDescriptor (BaseAddress, &GcdDescriptor);\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+\r
+  Status = gDS->SetMemorySpaceAttributes (\r
+                  BaseAddress,\r
+                  Length,\r
+                  GcdDescriptor.Attributes | EFI_MEMORY_RUNTIME\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+  //\r
+  // Get address of non volatile variable store base.\r
+  //\r
+  mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase = VariableStoreBase;\r
+\r
+  //\r
+  // Check Integrity\r
+  //\r
+  //\r
+  // Find the Correct Instance of the FV Block Service.\r
+  //\r
+  Instance  = 0;\r
+  CurrPtr   = mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase;\r
+\r
+  do {\r
+    FvVolHdr = 0;\r
+    Status    = (EFI_STATUS) EsalCall (\r
+                               EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID_LO,\r
+                               EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID_HI,\r
+                               GetPhysicalAddressFunctionId, \r
+                               Instance, \r
+                               (UINT64) &FvVolHdr, \r
+                               0, \r
+                               0, \r
+                               0, \r
+                               0, \r
+                               0\r
+                               ).Status;\r
+    if (EFI_ERROR (Status)) {\r
+      break;\r
+    }\r
+    FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvVolHdr);\r
+    ASSERT (FwVolHeader != NULL);\r
+    if (CurrPtr >= (EFI_PHYSICAL_ADDRESS) FwVolHeader &&\r
+        CurrPtr <  ((EFI_PHYSICAL_ADDRESS) FwVolHeader + FwVolHeader->FvLength)) {\r
+      mVariableModuleGlobal->FvbInstance = Instance;\r
+      break;\r
+    }\r
+\r
+    Instance++;\r
+  } while (Status == EFI_SUCCESS);\r
+\r
+  VariableStoreHeader = (VARIABLE_STORE_HEADER *) CurrPtr;\r
+  if (GetVariableStoreStatus (VariableStoreHeader) == EfiValid) {\r
+    if (~VariableStoreHeader->Size == 0) {\r
+      Status = AccessVariableStore (\r
+                 TRUE,\r
+                 &mVariableModuleGlobal->VariableGlobal[Physical],\r
+                 FALSE,\r
+                 mVariableModuleGlobal->FvbInstance,\r
+                 (UINTN) &VariableStoreHeader->Size,\r
+                 sizeof (UINT32),\r
+                 (UINT8 *) &VariableStoreLength\r
+                 );\r
+      //\r
+      // As Variables are stored in NV storage, which are slow devices,such as flash.\r
+      // Variable operation may skip checking variable program result to improve performance,\r
+      // We can assume Variable program is OK through some check point.\r
+      // Variable Store Size Setting should be the first Variable write operation,\r
+      // We can assume all Read/Write is OK if we can set Variable store size successfully.\r
+      // If write fail, we will assert here.\r
+      //\r
+      ASSERT(VariableStoreHeader->Size == VariableStoreLength);\r
+\r
+      if (EFI_ERROR (Status)) {\r
+        goto Done;\r
+      }\r
+    }\r
+\r
+    mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase = (EFI_PHYSICAL_ADDRESS) ((UINTN) CurrPtr);\r
+    //\r
+    // Parse non-volatile variable data and get last variable offset.\r
+    //\r
+    Variable = GetStartPointer (CurrPtr);\r
+    Status   = EFI_SUCCESS;\r
+\r
+    while (IsValidVariableHeader (Variable, FALSE, &(mVariableModuleGlobal->VariableGlobal[Physical]), Instance, NULL)) {\r
+      NextVariable = GetNextVariablePtr (\r
+                       Variable,\r
+                       FALSE,\r
+                       &(mVariableModuleGlobal->VariableGlobal[Physical]),\r
+                       Instance\r
+                       );\r
+      VariableSize = NextVariable - Variable;\r
+      if ((((VARIABLE_HEADER *)Variable)->Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
+        mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize;\r
+      } else {\r
+        mVariableModuleGlobal->CommonVariableTotalSize += VariableSize;\r
+      }\r
+\r
+      Variable = NextVariable;\r
+    }\r
+\r
+    mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) Variable - (UINTN) CurrPtr;\r
+\r
+    //\r
+    // Check if the free area is really free.\r
+    //\r
+    for (Index = mVariableModuleGlobal->NonVolatileLastVariableOffset; Index < VariableStoreHeader->Size; Index++) {\r
+      Data = ((UINT8 *) (UINTN) mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase)[Index];\r
+      if (Data != 0xff) {\r
+        //\r
+        // There must be something wrong in variable store, do reclaim operation.\r
+        //\r
+        Status = Reclaim (\r
+                   mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase,\r
+                   &mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
+                   FALSE,\r
+                   Physical,\r
+                   mVariableModuleGlobal,\r
+                   0x0\r
+                   );\r
+        if (EFI_ERROR (Status)) {\r
+          goto Done;\r
+        }\r
+        break;\r
+      }\r
+    }\r
+\r
+    //\r
+    // Register the event handling function to reclaim variable for OS usage.\r
+    //\r
+    Status = EfiCreateEventReadyToBootEx (\r
+               TPL_NOTIFY, \r
+               ReclaimForOS, \r
+               NULL, \r
+               &ReadyToBootEvent\r
+               );\r
+  } else {\r
+    Status = EFI_VOLUME_CORRUPTED;\r
+    DEBUG((EFI_D_INFO, "Variable Store header is corrupted\n"));\r
+  }\r
+\r
+Done:\r
+  if (EFI_ERROR (Status)) {\r
+    FreePool (mVariableModuleGlobal);\r
+    FreePool (VolatileVariableStore);\r
+  }\r
+\r
+  return Status;\r
+}\r
diff --git a/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/Variable.h b/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/Variable.h
new file mode 100644 (file)
index 0000000..ecff20f
--- /dev/null
@@ -0,0 +1,496 @@
+/** @file\r
+  Internal header file for Extended SAL variable service module.\r
+\r
+Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _VARIABLE_H_\r
+#define _VARIABLE_H_\r
+\r
+#include <PiDxe.h>\r
+\r
+#include <Protocol/VariableWrite.h>\r
+#include <Protocol/FaultTolerantWrite.h>\r
+#include <Protocol/FirmwareVolumeBlock.h>\r
+#include <Protocol/Variable.h>\r
+#include <Protocol/ExtendedSalBootService.h>\r
+#include <Protocol/ExtendedSalServiceClasses.h>\r
+\r
+#include <Guid/GlobalVariable.h>\r
+#include <Guid/AuthenticatedVariableFormat.h>\r
+#include <Guid/ImageAuthentication.h>\r
+#include <Guid/EventGroup.h>\r
+\r
+#include <Library/PcdLib.h>\r
+#include <Library/UefiDriverEntryPoint.h>\r
+#include <Library/DxeServicesTableLib.h>\r
+#include <Library/UefiRuntimeLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/SynchronizationLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/ExtendedSalLib.h>\r
+#include <Library/BaseCryptLib.h>\r
+\r
+#define MAX_NAME_SIZE            0x100\r
+#define NUM_VAR_NAME             9  // Number of pre-defined variable name to be referenced\r
+#define VAR_PLATFORM_LANG_CODES  0  // Index of "PlatformLangCodes" variable\r
+#define VAR_LANG_CODES           1  // Index of "LangCodes" variable\r
+#define VAR_PLATFORM_LANG        2  // Index of "PlatformLang" variable\r
+#define VAR_LANG                 3  // Index of "Lang" variable\r
+#define VAR_HW_ERR_REC           4  // Index of "HwErrRecXXXX" variable\r
+#define VAR_AUTH_KEY_DB          5  // Index of "AuthVarKeyDatabase" variable\r
+#define VAR_SETUP_MODE           6  // Index of "SetupMode" variable\r
+#define VAR_PLATFORM_KEY         7  // Index of "PK" variable\r
+#define VAR_KEY_EXCHANGE_KEY     8  // Index of "KEK" variable\r
+\r
+///\r
+/// "AuthVarKeyDatabase" variable for the Public Key store.\r
+///\r
+#define AUTHVAR_KEYDB_NAME      L"AuthVarKeyDatabase"\r
+#define AUTHVAR_KEYDB_NAME_SIZE 38\r
+\r
+///\r
+/// The maximum size of the public key database, restricted by maximum individal EFI \r
+/// varible size, and excluding the variable header and name size.\r
+///\r
+#define MAX_KEYDB_SIZE  (FixedPcdGet32 (PcdMaxVariableSize) - sizeof (VARIABLE_HEADER) - AUTHVAR_KEYDB_NAME_SIZE)\r
+#define MAX_KEY_NUM     (MAX_KEYDB_SIZE / EFI_CERT_TYPE_RSA2048_SIZE)\r
+\r
+///\r
+/// The size of a 3 character ISO639 language code.\r
+///\r
+#define ISO_639_2_ENTRY_SIZE    3\r
+\r
+typedef enum {\r
+  Physical,\r
+  Virtual\r
+} VARIABLE_POINTER_TYPE;\r
+\r
+typedef struct {\r
+  EFI_PHYSICAL_ADDRESS CurrPtr;\r
+  EFI_PHYSICAL_ADDRESS EndPtr;\r
+  EFI_PHYSICAL_ADDRESS StartPtr;\r
+  BOOLEAN              Volatile;\r
+} VARIABLE_POINTER_TRACK;\r
+\r
+typedef struct {\r
+  EFI_PHYSICAL_ADDRESS  VolatileVariableBase;\r
+  EFI_PHYSICAL_ADDRESS  NonVolatileVariableBase;\r
+  EFI_LOCK              VariableServicesLock;\r
+} VARIABLE_GLOBAL;\r
+\r
+typedef struct {\r
+  VARIABLE_GLOBAL VariableGlobal[2];\r
+  CHAR16          *VariableName[2][NUM_VAR_NAME];\r
+  EFI_GUID        *GlobalVariableGuid[2];\r
+  UINTN           VolatileLastVariableOffset;\r
+  UINTN           NonVolatileLastVariableOffset;\r
+  UINTN           CommonVariableTotalSize;\r
+  UINTN           HwErrVariableTotalSize;\r
+  CHAR8           *PlatformLangCodes[2];\r
+  CHAR8           *LangCodes[2];\r
+  CHAR8           *PlatformLang[2];\r
+  CHAR8           Lang[ISO_639_2_ENTRY_SIZE + 1];\r
+  UINT32          FvbInstance;\r
+  UINT32          ReentrantState;\r
+  EFI_GUID        *AuthenticatedVariableGuid[2];\r
+  EFI_GUID        *CertRsa2048Sha256Guid[2];\r
+  EFI_GUID        *ImageSecurityDatabaseGuid[2];\r
+  VOID            *HashContext[2];             // Hash context pointer\r
+  UINT8           KeyList[MAX_KEYDB_SIZE];     // Cached Platform Key list\r
+  UINT8           PubKeyStore[MAX_KEYDB_SIZE]; // Cached Public Key list\r
+} ESAL_VARIABLE_GLOBAL;\r
+\r
+typedef struct {\r
+  EFI_GUID    *Guid;\r
+  CHAR16      *Name;\r
+  UINT32      Attributes;\r
+  UINTN       DataSize;\r
+  VOID        *Data;\r
+} VARIABLE_CACHE_ENTRY;\r
+\r
+\r
+extern ESAL_VARIABLE_GLOBAL  *mVariableModuleGlobal;\r
+\r
+//\r
+// Functions\r
+//\r
+\r
+/**\r
+  Initializes variable store area for non-volatile and volatile variable.\r
+\r
+  This function allocates and initializes memory space for global context of ESAL\r
+  variable service and variable store area for non-volatile and volatile variable.\r
+\r
+  @param[in]  ImageHandle       The Image handle of this driver.\r
+  @param[in]  SystemTable       The pointer of EFI_SYSTEM_TABLE.\r
+\r
+  @retval EFI_SUCCESS           Function successfully executed.\r
+  @retval EFI_OUT_OF_RESOURCES  Failed to allocate enough memory resource.\r
+\r
+**/\r
+EFI_STATUS\r
+VariableCommonInitialize (\r
+  IN EFI_HANDLE         ImageHandle,\r
+  IN EFI_SYSTEM_TABLE   *SystemTable\r
+  );\r
+\r
+/**\r
+  Entry point of Extended SAL Variable service module.\r
+\r
+  This function is the entry point of Extended SAL Variable service module.\r
+  It registers all functions of Extended SAL Variable class, initializes\r
+  variable store for non-volatile and volatile variables, and registers\r
+  notification function for EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.\r
+\r
+  @param[in]  ImageHandle   The Image handle of this driver.\r
+  @param[in]  SystemTable   The pointer of EFI_SYSTEM_TABLE.\r
+\r
+  @retval     EFI_SUCCESS   Extended SAL Variable Services Class successfully registered.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+VariableServiceInitialize (\r
+  IN EFI_HANDLE         ImageHandle,\r
+  IN EFI_SYSTEM_TABLE   *SystemTable\r
+  );\r
+\r
+/**\r
+  Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.\r
+\r
+  This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.\r
+  It convers pointer to new virtual address.\r
+\r
+  @param[in]  Event        The event whose notification function is being invoked.\r
+  @param[in]  Context      The pointer to the notification function's context.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+VariableClassAddressChangeEvent (\r
+  IN EFI_EVENT        Event,\r
+  IN VOID             *Context\r
+  );\r
+\r
+/**\r
+  Implements EsalGetVariable function of Extended SAL Variable Services Class.\r
+\r
+  This function implements EsalGetVariable function of Extended SAL Variable Services Class.\r
+  It is equivalent in functionality to the EFI Runtime Service GetVariable().\r
+  \r
+  @param[in]      VariableName    A Null-terminated Unicode string that is the name of\r
+                                  the vendor's variable.\r
+  @param[in]      VendorGuid      A unique identifier for the vendor.\r
+  @param[out]     Attributes      If not NULL, a pointer to the memory location to return the \r
+                                  attributes bitmask for the variable.\r
+  @param[in, out] DataSize        Size of Data found. If size is less than the\r
+                                  data, this value contains the required size.\r
+  @param[out]     Data            On input, the size in bytes of the return Data buffer.  \r
+                                  On output, the size of data returned in Data.\r
+  @param[in]      VirtualMode     Current calling mode for this function.\r
+  @param[in]      Global          Context of this Extended SAL Variable Services Class call.\r
+\r
+  @retval EFI_SUCCESS            The function completed successfully. \r
+  @retval EFI_NOT_FOUND          The variable was not found.\r
+  @retval EFI_BUFFER_TOO_SMALL   DataSize is too small for the result.  DataSize has \r
+                                 been updated with the size needed to complete the request.\r
+  @retval EFI_INVALID_PARAMETER  VariableName is NULL.\r
+  @retval EFI_INVALID_PARAMETER  VendorGuid is NULL.\r
+  @retval EFI_INVALID_PARAMETER  DataSize is NULL.\r
+  @retval EFI_INVALID_PARAMETER  DataSize is not too small and Data is NULL.\r
+  @retval EFI_DEVICE_ERROR       The variable could not be retrieved due to a hardware error.\r
+  @retval EFI_SECURITY_VIOLATION The variable could not be retrieved due to an authentication failure.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EsalGetVariable (\r
+  IN      CHAR16                *VariableName,\r
+  IN      EFI_GUID              *VendorGuid,\r
+  OUT     UINT32                *Attributes OPTIONAL,\r
+  IN OUT  UINTN                 *DataSize,\r
+  OUT     VOID                  *Data,\r
+  IN      BOOLEAN               VirtualMode,\r
+  IN      ESAL_VARIABLE_GLOBAL  *Global\r
+  );\r
+\r
+/**\r
+  Implements EsalGetNextVariableName function of Extended SAL Variable Services Class.\r
+\r
+  This function implements EsalGetNextVariableName function of Extended SAL Variable Services Class.\r
+  It is equivalent in functionality to the EFI Runtime Service GetNextVariableName().\r
+  \r
+  @param[in, out] VariableNameSize Size of the variable\r
+  @param[in, out] VariableName     On input, supplies the last VariableName that was returned by GetNextVariableName().\r
+                                   On output, returns the Null-terminated Unicode string of the current variable.\r
+  @param[in, out] VendorGuid       On input, supplies the last VendorGuid that was returned by GetNextVariableName().\r
+                                   On output, returns the VendorGuid of the current variable.  \r
+  @param[in]      VirtualMode      Current calling mode for this function.\r
+  @param[in]      Global           Context of this Extended SAL Variable Services Class call.\r
+\r
+  @retval EFI_SUCCESS             The function completed successfully. \r
+  @retval EFI_NOT_FOUND           The next variable was not found.\r
+  @retval EFI_BUFFER_TOO_SMALL    VariableNameSize is too small for the result. \r
+                                  VariableNameSize has been updated with the size needed to complete the request.\r
+  @retval EFI_INVALID_PARAMETER   VariableNameSize is NULL.\r
+  @retval EFI_INVALID_PARAMETER   VariableName is NULL.\r
+  @retval EFI_INVALID_PARAMETER   VendorGuid is NULL.\r
+  @retval EFI_DEVICE_ERROR        The variable name could not be retrieved due to a hardware error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EsalGetNextVariableName (\r
+  IN OUT  UINTN                 *VariableNameSize,\r
+  IN OUT  CHAR16                *VariableName,\r
+  IN OUT  EFI_GUID              *VendorGuid,\r
+  IN      BOOLEAN               VirtualMode,\r
+  IN      ESAL_VARIABLE_GLOBAL  *Global\r
+  );\r
+\r
+/**\r
+  Implements EsalSetVariable function of Extended SAL Variable Services Class.\r
+\r
+  This function implements EsalSetVariable function of Extended SAL Variable Services Class.\r
+  It is equivalent in functionality to the EFI Runtime Service SetVariable().\r
+  \r
+  @param[in]  VariableName       A Null-terminated Unicode string that is the name of the vendor's\r
+                                 variable.  Each VariableName is unique for each \r
+                                 VendorGuid.  VariableName must contain 1 or more \r
+                                 Unicode characters.  If VariableName is an empty Unicode \r
+                                 string, then EFI_INVALID_PARAMETER is returned.\r
+  @param[in]  VendorGuid         A unique identifier for the vendor.\r
+  @param[in]  Attributes         Attributes bitmask to set for the variable.\r
+  @param[in]  DataSize           The size in bytes of the Data buffer.  A size of zero causes the\r
+                                 variable to be deleted.\r
+  @param[in]  Data               The contents for the variable.\r
+  @param[in]  VirtualMode        Current calling mode for this function.\r
+  @param[in]  Global             Context of this Extended SAL Variable Services Class call.\r
+\r
+  @retval EFI_SUCCESS            The firmware has successfully stored the variable and its data as \r
+                                 defined by the Attributes.\r
+  @retval EFI_INVALID_PARAMETER  An invalid combination of attribute bits was supplied, or the \r
+                                 DataSize exceeds the maximum allowed.\r
+  @retval EFI_INVALID_PARAMETER  VariableName is an empty Unicode string.\r
+  @retval EFI_OUT_OF_RESOURCES   Not enough storage is available to hold the variable and its data.\r
+  @retval EFI_DEVICE_ERROR       The variable could not be saved due to a hardware failure.\r
+  @retval EFI_WRITE_PROTECTED    The variable in question is read-only.\r
+  @retval EFI_WRITE_PROTECTED    The variable in question cannot be deleted.\r
+  @retval EFI_SECURITY_VIOLATION The variable could not be retrieved due to an authentication failure.\r
+  @retval EFI_NOT_FOUND          The variable trying to be updated or deleted was not found.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EsalSetVariable (\r
+  IN CHAR16                  *VariableName,\r
+  IN EFI_GUID                *VendorGuid,\r
+  IN UINT32                  Attributes,\r
+  IN UINTN                   DataSize,\r
+  IN VOID                    *Data,\r
+  IN BOOLEAN                 VirtualMode,\r
+  IN ESAL_VARIABLE_GLOBAL    *Global\r
+  );\r
+\r
+/**\r
+  Implements EsalQueryVariableInfo function of Extended SAL Variable Services Class.\r
+\r
+  This function implements EsalQueryVariableInfo function of Extended SAL Variable Services Class.\r
+  It is equivalent in functionality to the EFI Runtime Service QueryVariableInfo().\r
+\r
+  @param[in]  Attributes                   Attributes bitmask to specify the type of variables\r
+                                           on which to return information.\r
+  @param[out] MaximumVariableStorageSize   On output the maximum size of the storage space available for \r
+                                           the EFI variables associated with the attributes specified.  \r
+  @param[out] RemainingVariableStorageSize Returns the remaining size of the storage space available for EFI \r
+                                           variables associated with the attributes specified.\r
+  @param[out] MaximumVariableSize          Returns the maximum size of an individual EFI variable \r
+                                           associated with the attributes specified.\r
+  @param[in]  VirtualMode                  Current calling mode for this function\r
+  @param[in]  Global                       Context of this Extended SAL Variable Services Class call\r
+\r
+  @retval EFI_SUCCESS                      Valid answer returned.\r
+  @retval EFI_INVALID_PARAMETER            An invalid combination of attribute bits was supplied.\r
+  @retval EFI_UNSUPPORTED                  The attribute is not supported on this platform, and the \r
+                                           MaximumVariableStorageSize, RemainingVariableStorageSize, \r
+                                           MaximumVariableSize are undefined.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EsalQueryVariableInfo (\r
+  IN  UINT32                 Attributes,\r
+  OUT UINT64                 *MaximumVariableStorageSize,\r
+  OUT UINT64                 *RemainingVariableStorageSize,\r
+  OUT UINT64                 *MaximumVariableSize,\r
+  IN  BOOLEAN                VirtualMode,\r
+  IN  ESAL_VARIABLE_GLOBAL   *Global\r
+  );\r
+\r
+/**\r
+  Writes a buffer to variable storage space.\r
+\r
+  This function writes a buffer to variable storage space into firmware\r
+  volume block device. The destination is specified by parameter\r
+  VariableBase. Fault Tolerant Write protocol is used for writing.\r
+\r
+  @param[in] VariableBase The base address of the variable to write.\r
+  @param[in] Buffer       Points to the data buffer.\r
+  @param[in] BufferSize   The number of bytes of the data Buffer.\r
+\r
+  @retval EFI_SUCCESS     The function completed successfully.\r
+  @retval EFI_NOT_FOUND   Fail to locate Fault Tolerant Write protocol.\r
+  @retval Other           The function could not complete successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+FtwVariableSpace (\r
+  IN EFI_PHYSICAL_ADDRESS   VariableBase,\r
+  IN UINT8                  *Buffer,\r
+  IN UINTN                  BufferSize\r
+  );\r
+\r
+/**\r
+  Finds variable in volatile and non-volatile storage areas.\r
+\r
+  This code finds variable in volatile and non-volatile storage areas.\r
+  If VariableName is an empty string, then we just return the first\r
+  qualified variable without comparing VariableName and VendorGuid.\r
+  Otherwise, VariableName and VendorGuid are compared.\r
+\r
+  @param[in]  VariableName            Name of the variable to be found.\r
+  @param[in]  VendorGuid              Vendor GUID to be found.\r
+  @param[out] PtrTrack                VARIABLE_POINTER_TRACK structure for output,\r
+                                      including the range searched and the target position.\r
+  @param[in]  Global                  Pointer to VARIABLE_GLOBAL structure, including\r
+                                      base of volatile variable storage area, base of\r
+                                      NV variable storage area, and a lock.\r
+  @param[in]  Instance                Instance of FV Block services.\r
+\r
+  @retval EFI_INVALID_PARAMETER       If VariableName is not an empty string, while\r
+                                      VendorGuid is NULL.\r
+  @retval EFI_SUCCESS                 Variable successfully found.\r
+  @retval EFI_INVALID_PARAMETER       Variable not found.\r
+\r
+**/\r
+EFI_STATUS\r
+FindVariable (\r
+  IN  CHAR16                  *VariableName,\r
+  IN  EFI_GUID                *VendorGuid,\r
+  OUT VARIABLE_POINTER_TRACK  *PtrTrack,\r
+  IN  VARIABLE_GLOBAL         *Global,\r
+  IN  UINTN                   Instance\r
+  );\r
+\r
+/**\r
+  Gets the pointer to variable data area.\r
+\r
+  This function gets the pointer to variable data area.\r
+  The variable is specified by its variable header.\r
+\r
+  @param[in]  VariableAddress    Start address of variable header.\r
+  @param[in]  Volatile           TRUE  - Variable is volatile.\r
+                                 FALSE - Variable is non-volatile.\r
+  @param[in]  Global             Pointer to VARAIBLE_GLOBAL structure.\r
+  @param[in]  Instance           Instance of FV Block services.\r
+  @param[out] VariableData       Buffer to hold variable data for output.\r
+\r
+**/\r
+VOID\r
+GetVariableDataPtr (\r
+  IN  EFI_PHYSICAL_ADDRESS   VariableAddress,\r
+  IN  BOOLEAN                Volatile,\r
+  IN  VARIABLE_GLOBAL        *Global,\r
+  IN  UINTN                  Instance,\r
+  OUT CHAR16                 *VariableData\r
+  );\r
+\r
+/**\r
+  Gets the size of variable data area.\r
+\r
+  This function gets the size of variable data area.\r
+  The variable is specified by its variable header.\r
+  If variable header contains raw data, just return 0.\r
+\r
+  @param[in]  Variable  Pointer to the variable header.\r
+\r
+  @return               Size of variable data area in bytes.\r
+\r
+**/\r
+UINTN\r
+DataSizeOfVariable (\r
+  IN  VARIABLE_HEADER   *Variable\r
+  );\r
+\r
+/**\r
+  Update the variable region with Variable information. These are the same \r
+  arguments as the EFI Variable services.\r
+\r
+  @param[in] VariableName       Name of variable.\r
+  @param[in] VendorGuid         Guid of variable.\r
+  @param[in] Data               Variable data.\r
+  @param[in] DataSize           Size of data. 0 means delete.\r
+  @param[in] Attributes         Attributes of the variable.\r
+  @param[in] KeyIndex           Index of associated public key.\r
+  @param[in] MonotonicCount     Value of associated monotonic count. \r
+  @param[in] VirtualMode        Current calling mode for this function.\r
+  @param[in] Global             Context of this Extended SAL Variable Services Class call.\r
+  @param[in] Variable           The variable information which is used to keep track of variable usage.\r
+\r
+  @retval EFI_SUCCESS           The update operation is success.\r
+  @retval EFI_OUT_OF_RESOURCES  Variable region is full, can not write other data into this region.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UpdateVariable (\r
+  IN      CHAR16                  *VariableName,\r
+  IN      EFI_GUID                *VendorGuid,\r
+  IN      VOID                    *Data,\r
+  IN      UINTN                   DataSize,\r
+  IN      UINT32                  Attributes OPTIONAL,  \r
+  IN      UINT32                  KeyIndex  OPTIONAL,\r
+  IN      UINT64                  MonotonicCount  OPTIONAL,\r
+  IN      BOOLEAN                 VirtualMode,\r
+  IN      ESAL_VARIABLE_GLOBAL    *Global,\r
+  IN      VARIABLE_POINTER_TRACK  *Variable\r
+  );\r
+\r
+/**\r
+  Checks variable header.\r
+\r
+  This function checks if variable header is valid or not.\r
+\r
+  @param[in]  VariableAddress    Start address of variable header.\r
+  @param[in]  Volatile           TRUE  - Variable is volatile.\r
+                                 FALSE - Variable is non-volatile.\r
+  @param[in]  Global             Pointer to VARAIBLE_GLOBAL structure.\r
+  @param[in]  Instance           Instance of FV Block services.\r
+  @param[out] VariableHeader     Pointer to VARIABLE_HEADER for output.\r
+\r
+  @retval TRUE                   Variable header is valid.\r
+  @retval FALSE                  Variable header is not valid.\r
+\r
+**/\r
+BOOLEAN\r
+IsValidVariableHeader (\r
+  IN  EFI_PHYSICAL_ADDRESS   VariableAddress,\r
+  IN  BOOLEAN                Volatile,\r
+  IN  VARIABLE_GLOBAL        *Global,\r
+  IN  UINTN                  Instance,\r
+  OUT VARIABLE_HEADER        *VariableHeader  OPTIONAL\r
+  );\r
+\r
+#endif\r
diff --git a/SecurityPkg/VariableAuthenticated/Pei/Variable.c b/SecurityPkg/VariableAuthenticated/Pei/Variable.c
new file mode 100644 (file)
index 0000000..1fd051b
--- /dev/null
@@ -0,0 +1,671 @@
+/** @file\r
+  Implement ReadOnly Variable Services required by PEIM and install PEI\r
+  ReadOnly Varaiable2 PPI. These services operates the non-volatile \r
+  storage space.\r
+\r
+Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+\r
+#include "Variable.h"\r
+\r
+//\r
+// Module globals\r
+//\r
+EFI_PEI_READ_ONLY_VARIABLE2_PPI mVariablePpi = {\r
+  PeiGetVariable,\r
+  PeiGetNextVariableName\r
+};\r
+\r
+EFI_PEI_PPI_DESCRIPTOR     mPpiListVariable = {\r
+  (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
+  &gEfiPeiReadOnlyVariable2PpiGuid,\r
+  &mVariablePpi\r
+};\r
+\r
+\r
+/**\r
+  Provide the functionality of the variable services.\r
+  \r
+  @param  FileHandle   Handle of the file being invoked. \r
+                       Type EFI_PEI_FILE_HANDLE is defined in FfsFindNextFile().\r
+  @param  PeiServices  General purpose services available to every PEIM.\r
+\r
+  @retval EFI_SUCCESS  If the interface could be successfully installed\r
+  @retval Others       Returned from PeiServicesInstallPpi()\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PeimInitializeVariableServices (\r
+  IN       EFI_PEI_FILE_HANDLE       FileHandle,\r
+  IN CONST EFI_PEI_SERVICES          **PeiServices\r
+  )\r
+{\r
+  EFI_BOOT_MODE BootMode;\r
+  EFI_STATUS    Status;\r
+\r
+  //\r
+  // Check if this is recovery boot path. If no, publish the variable access capability\r
+  // to other modules. If yes, the content of variable area is not reliable. Therefore,\r
+  // in this case we should not provide variable service to other pei modules. \r
+  // \r
+  Status = (*PeiServices)->GetBootMode (PeiServices, &BootMode);\r
+  ASSERT_EFI_ERROR (Status);\r
+  \r
+  if (BootMode == BOOT_IN_RECOVERY_MODE) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  return PeiServicesInstallPpi (&mPpiListVariable);\r
+\r
+}\r
+\r
+/**\r
+\r
+  Gets the pointer to the first variable header in given variable store area.\r
+\r
+  @param VarStoreHeader  Pointer to the Variable Store Header.\r
+\r
+  @return Pointer to the first variable header\r
+\r
+**/\r
+VARIABLE_HEADER *\r
+GetStartPointer (\r
+  IN VARIABLE_STORE_HEADER       *VarStoreHeader\r
+  )\r
+{\r
+  //\r
+  // The end of variable store\r
+  //\r
+  return (VARIABLE_HEADER *) HEADER_ALIGN (VarStoreHeader + 1);\r
+}\r
+\r
+\r
+/**\r
+  This code gets the pointer to the last variable memory pointer byte.\r
+\r
+  @param  VarStoreHeader  Pointer to the Variable Store Header.\r
+\r
+  @return VARIABLE_HEADER* pointer to last unavailable Variable Header.\r
+\r
+**/\r
+VARIABLE_HEADER *\r
+GetEndPointer (\r
+  IN VARIABLE_STORE_HEADER       *VarStoreHeader\r
+  )\r
+{\r
+  //\r
+  // The end of variable store\r
+  //\r
+  return (VARIABLE_HEADER *) HEADER_ALIGN ((UINTN) VarStoreHeader + VarStoreHeader->Size);\r
+}\r
+\r
+\r
+/**\r
+  This code checks if variable header is valid or not.\r
+\r
+  @param  Variable  Pointer to the Variable Header.\r
+\r
+  @retval TRUE      Variable header is valid.\r
+  @retval FALSE     Variable header is not valid.\r
+\r
+**/\r
+BOOLEAN\r
+IsValidVariableHeader (\r
+  IN  VARIABLE_HEADER   *Variable\r
+  )\r
+{\r
+  if (Variable == NULL || Variable->StartId != VARIABLE_DATA ) {\r
+    return FALSE;\r
+  }\r
+\r
+  return TRUE;\r
+}\r
+\r
+\r
+/**\r
+  This code gets the size of name of variable.\r
+\r
+  @param  Variable  Pointer to the Variable Header.\r
+\r
+  @return Size of variable in bytes in type UINTN.\r
+\r
+**/\r
+UINTN\r
+NameSizeOfVariable (\r
+  IN  VARIABLE_HEADER   *Variable\r
+  )\r
+{\r
+  if (Variable->State    == (UINT8) (-1) ||\r
+      Variable->DataSize == (UINT32) (-1) ||\r
+      Variable->NameSize == (UINT32) (-1) ||\r
+      Variable->Attributes == (UINT32) (-1)) {\r
+    return 0;\r
+  }\r
+  return (UINTN) Variable->NameSize;\r
+}\r
+\r
+\r
+/**\r
+  This code gets the size of data of variable.\r
+\r
+  @param  Variable  Pointer to the Variable Header.\r
+\r
+  @return Size of variable in bytes in type UINTN.\r
+\r
+**/\r
+UINTN\r
+DataSizeOfVariable (\r
+  IN  VARIABLE_HEADER   *Variable\r
+  )\r
+{\r
+  if (Variable->State    == (UINT8)  (-1) ||\r
+      Variable->DataSize == (UINT32) (-1) ||\r
+      Variable->NameSize == (UINT32) (-1) ||\r
+      Variable->Attributes == (UINT32) (-1)) {\r
+    return 0;\r
+  }\r
+  return (UINTN) Variable->DataSize;\r
+}\r
+\r
+/**\r
+  This code gets the pointer to the variable name.\r
+\r
+  @param   Variable  Pointer to the Variable Header.\r
+\r
+  @return  A CHAR16* pointer to Variable Name.\r
+\r
+**/\r
+CHAR16 *\r
+GetVariableNamePtr (\r
+  IN  VARIABLE_HEADER   *Variable\r
+  )\r
+{\r
+\r
+  return (CHAR16 *) (Variable + 1);\r
+}\r
+\r
+\r
+/**\r
+  This code gets the pointer to the variable data.\r
+\r
+  @param   Variable  Pointer to the Variable Header.\r
+\r
+  @return  A UINT8* pointer to Variable Data.\r
+\r
+**/\r
+UINT8 *\r
+GetVariableDataPtr (\r
+  IN  VARIABLE_HEADER   *Variable\r
+  )\r
+{\r
+  UINTN Value;\r
+  \r
+  //\r
+  // Be careful about pad size for alignment\r
+  //\r
+  Value =  (UINTN) GetVariableNamePtr (Variable);\r
+  Value += NameSizeOfVariable (Variable);\r
+  Value += GET_PAD_SIZE (NameSizeOfVariable (Variable));\r
+\r
+  return (UINT8 *) Value;\r
+}\r
+\r
+\r
+/**\r
+  This code gets the pointer to the next variable header.\r
+\r
+  @param  Variable  Pointer to the Variable Header.\r
+\r
+  @return  A VARIABLE_HEADER* pointer to next variable header.\r
+\r
+**/\r
+VARIABLE_HEADER *\r
+GetNextVariablePtr (\r
+  IN  VARIABLE_HEADER   *Variable\r
+  )\r
+{\r
+  UINTN Value;\r
+\r
+  if (!IsValidVariableHeader (Variable)) {\r
+    return NULL;\r
+  }\r
+\r
+  Value =  (UINTN) GetVariableDataPtr (Variable);\r
+  Value += DataSizeOfVariable (Variable);\r
+  Value += GET_PAD_SIZE (DataSizeOfVariable (Variable));\r
+\r
+  //\r
+  // Be careful about pad size for alignment\r
+  //\r
+  return (VARIABLE_HEADER *) HEADER_ALIGN (Value);\r
+}\r
+\r
+/**\r
+  This code gets the pointer to the variable name.\r
+\r
+  @param  VarStoreHeader  Pointer to the Variable Store Header.\r
+\r
+  @retval  EfiRaw      Variable store is raw\r
+  @retval  EfiValid    Variable store is valid\r
+  @retval  EfiInvalid  Variable store is invalid\r
+\r
+**/\r
+VARIABLE_STORE_STATUS\r
+GetVariableStoreStatus (\r
+  IN VARIABLE_STORE_HEADER *VarStoreHeader\r
+  )\r
+{\r
+       \r
+  if (CompareGuid (&VarStoreHeader->Signature, &gEfiAuthenticatedVariableGuid) &&\r
+      VarStoreHeader->Format == VARIABLE_STORE_FORMATTED &&\r
+      VarStoreHeader->State == VARIABLE_STORE_HEALTHY\r
+      ) {\r
+\r
+    return EfiValid;\r
+  }\r
+\r
+  if (((UINT32 *)(&VarStoreHeader->Signature))[0] == 0xffffffff &&\r
+      ((UINT32 *)(&VarStoreHeader->Signature))[1] == 0xffffffff &&\r
+      ((UINT32 *)(&VarStoreHeader->Signature))[2] == 0xffffffff &&\r
+      ((UINT32 *)(&VarStoreHeader->Signature))[3] == 0xffffffff &&\r
+      VarStoreHeader->Size == 0xffffffff &&\r
+      VarStoreHeader->Format == 0xff &&\r
+      VarStoreHeader->State == 0xff\r
+      ) {\r
+\r
+    return EfiRaw;\r
+  } else {\r
+    return EfiInvalid;\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  This function compares a variable with variable entries in database.\r
+\r
+  @param  Variable      Pointer to the variable in our database\r
+  @param  VariableName  Name of the variable to compare to 'Variable'\r
+  @param  VendorGuid    GUID of the variable to compare to 'Variable'\r
+  @param  PtrTrack      Variable Track Pointer structure that contains Variable Information.\r
+\r
+  @retval EFI_SUCCESS    Found match variable\r
+  @retval EFI_NOT_FOUND  Variable not found\r
+\r
+**/\r
+EFI_STATUS\r
+CompareWithValidVariable (\r
+  IN  VARIABLE_HEADER               *Variable,\r
+  IN  CONST CHAR16                  *VariableName,\r
+  IN  CONST EFI_GUID                *VendorGuid,\r
+  OUT VARIABLE_POINTER_TRACK        *PtrTrack\r
+  )\r
+{\r
+  VOID  *Point;\r
+\r
+  if (VariableName[0] == 0) {\r
+    PtrTrack->CurrPtr = Variable;\r
+    return EFI_SUCCESS;\r
+  } else {\r
+    //\r
+    // Don't use CompareGuid function here for performance reasons.\r
+    // Instead we compare the GUID a UINT32 at a time and branch\r
+    // on the first failed comparison.\r
+    //\r
+    if ((((INT32 *) VendorGuid)[0] == ((INT32 *) &Variable->VendorGuid)[0]) &&\r
+        (((INT32 *) VendorGuid)[1] == ((INT32 *) &Variable->VendorGuid)[1]) &&\r
+        (((INT32 *) VendorGuid)[2] == ((INT32 *) &Variable->VendorGuid)[2]) &&\r
+        (((INT32 *) VendorGuid)[3] == ((INT32 *) &Variable->VendorGuid)[3])\r
+        ) {\r
+      ASSERT (NameSizeOfVariable (Variable) != 0);\r
+      Point = (VOID *) GetVariableNamePtr (Variable);\r
+      if (CompareMem (VariableName, Point, NameSizeOfVariable (Variable)) == 0) {\r
+        PtrTrack->CurrPtr = Variable;\r
+        return EFI_SUCCESS;\r
+      }\r
+    }\r
+  }\r
+\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+\r
+/**\r
+  This code finds variable in storage blocks (Non-Volatile).\r
+\r
+  @param  PeiServices   General purpose services available to every PEIM.\r
+  @param  VariableName  Name of the variable to be found\r
+  @param  VendorGuid    Vendor GUID to be found.\r
+  @param  PtrTrack      Variable Track Pointer structure that contains Variable Information.\r
+\r
+  @retval  EFI_SUCCESS            Variable found successfully\r
+  @retval  EFI_NOT_FOUND          Variable not found\r
+  @retval  EFI_INVALID_PARAMETER  Invalid variable name\r
+\r
+**/\r
+EFI_STATUS\r
+FindVariable (\r
+  IN CONST EFI_PEI_SERVICES   **PeiServices,\r
+  IN CONST  CHAR16            *VariableName,\r
+  IN CONST  EFI_GUID          *VendorGuid,\r
+  OUT VARIABLE_POINTER_TRACK  *PtrTrack\r
+  )\r
+{\r
+  EFI_HOB_GUID_TYPE       *GuidHob;\r
+  VARIABLE_STORE_HEADER   *VariableStoreHeader;\r
+  VARIABLE_HEADER         *Variable;\r
+  VARIABLE_HEADER         *LastVariable;\r
+  VARIABLE_HEADER         *MaxIndex;\r
+  VARIABLE_INDEX_TABLE    *IndexTable;\r
+  UINT32                  Count;\r
+  UINT32                  Offset;\r
+  UINT8                   *VariableBase;\r
+  BOOLEAN                 StopRecord;\r
+\r
+  if (VariableName[0] != 0 && VendorGuid == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  //\r
+  // No Variable Address equals zero, so 0 as initial value is safe.\r
+  //\r
+  MaxIndex = 0;\r
+  StopRecord = FALSE;\r
+\r
+  GuidHob = GetFirstGuidHob (&gEfiVariableIndexTableGuid);\r
+  if (GuidHob == NULL) {\r
+    //\r
+    // If it's the first time to access variable region in flash, create a guid hob to record\r
+    // VAR_ADDED type variable info.\r
+    // Note that as the resource of PEI phase is limited, only store the number of \r
+    // VARIABLE_INDEX_TABLE_VOLUME of VAR_ADDED type variables to reduce access time.\r
+    //\r
+    IndexTable = BuildGuidHob (&gEfiVariableIndexTableGuid, sizeof (VARIABLE_INDEX_TABLE));\r
+    IndexTable->Length      = 0;\r
+    IndexTable->StartPtr    = NULL;\r
+    IndexTable->EndPtr      = NULL;\r
+    IndexTable->GoneThrough = 0;\r
+  } else {\r
+    IndexTable = GET_GUID_HOB_DATA (GuidHob);\r
+    for (Offset = 0, Count = 0; Count < IndexTable->Length; Count++) {\r
+      //\r
+      // traverse the variable info list to look for varible.\r
+      // The IndexTable->Index[Count] records the distance of two neighbouring VAR_ADDED type variables.\r
+      //\r
+      ASSERT (Count < VARIABLE_INDEX_TABLE_VOLUME);\r
+      Offset   += IndexTable->Index[Count];\r
+      MaxIndex  = (VARIABLE_HEADER *)((CHAR8 *)(IndexTable->StartPtr) + Offset);\r
+      if (CompareWithValidVariable (MaxIndex, VariableName, VendorGuid, PtrTrack) == EFI_SUCCESS) {\r
+        PtrTrack->StartPtr  = IndexTable->StartPtr;\r
+        PtrTrack->EndPtr    = IndexTable->EndPtr;\r
+\r
+        return EFI_SUCCESS;\r
+      }\r
+    }\r
+\r
+    if (IndexTable->GoneThrough != 0) {\r
+      return EFI_NOT_FOUND;\r
+    }\r
+  }\r
+  //\r
+  // If not found in HOB, then let's start from the MaxIndex we've found.\r
+  //\r
+  if (MaxIndex != NULL) {\r
+    Variable     = GetNextVariablePtr (MaxIndex);\r
+    LastVariable = MaxIndex;\r
+  } else {\r
+    if ((IndexTable->StartPtr != NULL) || (IndexTable->EndPtr != NULL)) {\r
+      Variable = IndexTable->StartPtr;\r
+    } else {\r
+      VariableBase = (UINT8 *) (UINTN) PcdGet64 (PcdFlashNvStorageVariableBase64);\r
+      if (VariableBase == NULL) {\r
+        VariableBase = (UINT8 *) (UINTN) PcdGet32 (PcdFlashNvStorageVariableBase);\r
+      }\r
+      \r
+      VariableStoreHeader = (VARIABLE_STORE_HEADER *) (VariableBase + \\r
+                            ((EFI_FIRMWARE_VOLUME_HEADER *) (VariableBase)) -> HeaderLength);\r
+\r
+      if (GetVariableStoreStatus (VariableStoreHeader) != EfiValid) {\r
+        return EFI_UNSUPPORTED;\r
+      }\r
+\r
+      if (~VariableStoreHeader->Size == 0) {\r
+        return EFI_NOT_FOUND;\r
+      }\r
+      //\r
+      // Find the variable by walk through non-volatile variable store\r
+      //\r
+      IndexTable->StartPtr  = GetStartPointer (VariableStoreHeader);\r
+      IndexTable->EndPtr    = GetEndPointer (VariableStoreHeader);\r
+\r
+      //\r
+      // Start Pointers for the variable.\r
+      // Actual Data Pointer where data can be written.\r
+      //\r
+      Variable = IndexTable->StartPtr;\r
+    }\r
+\r
+    LastVariable = IndexTable->StartPtr;\r
+  }\r
+  //\r
+  // Find the variable by walk through non-volatile variable store\r
+  //\r
+  PtrTrack->StartPtr  = IndexTable->StartPtr;\r
+  PtrTrack->EndPtr    = IndexTable->EndPtr;\r
+\r
+  while ((Variable < IndexTable->EndPtr) && IsValidVariableHeader (Variable)) {\r
+    if (Variable->State == VAR_ADDED) {\r
+      //\r
+      // Record Variable in VariableIndex HOB\r
+      //\r
+      if (IndexTable->Length < VARIABLE_INDEX_TABLE_VOLUME && !StopRecord) {\r
+        Offset = (UINT32)((UINTN)Variable - (UINTN)LastVariable);\r
+        //\r
+        // The distance of two neighbouring VAR_ADDED variable is larger than 2^16, \r
+        // which is beyond the allowable scope(UINT16) of record. In such case, need not to\r
+        // record the subsequent VAR_ADDED type variables again.\r
+        //\r
+        if ((Offset & 0xFFFF0000UL) != 0) {\r
+          StopRecord = TRUE;\r
+        }\r
+\r
+        if (!StopRecord) {\r
+          IndexTable->Index[IndexTable->Length++] = (UINT16) Offset;\r
+        }\r
+        LastVariable = Variable;\r
+      }\r
+\r
+      if (CompareWithValidVariable (Variable, VariableName, VendorGuid, PtrTrack) == EFI_SUCCESS) {\r
+        return EFI_SUCCESS;\r
+      }\r
+    }\r
+\r
+    Variable = GetNextVariablePtr (Variable);\r
+  }\r
+  //\r
+  // If gone through the VariableStore, that means we never find in Firmware any more.\r
+  //\r
+  if ((IndexTable->Length < VARIABLE_INDEX_TABLE_VOLUME) && (!StopRecord)) {\r
+    IndexTable->GoneThrough = 1;\r
+  }\r
+\r
+  PtrTrack->CurrPtr = NULL;\r
+\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+/**\r
+  This service retrieves a variable's value using its name and GUID.\r
+\r
+  Read the specified variable from the UEFI variable store. If the Data \r
+  buffer is too small to hold the contents of the variable, the error\r
+  EFI_BUFFER_TOO_SMALL is returned and DataSize is set to the required buffer\r
+  size to obtain the data.\r
+\r
+  @param  This                  A pointer to this instance of the EFI_PEI_READ_ONLY_VARIABLE2_PPI.\r
+  @param  VariableName          A pointer to a null-terminated string that is the variable's name.\r
+  @param  VariableGuid          A pointer to an EFI_GUID that is the variable's GUID. The combination of\r
+                                VariableGuid and VariableName must be unique.\r
+  @param  Attributes            If non-NULL, on return, points to the variable's attributes.\r
+  @param  DataSize              On entry, points to the size in bytes of the Data buffer.\r
+                                On return, points to the size of the data returned in Data.\r
+  @param  Data                  Points to the buffer which will hold the returned variable value.\r
+\r
+  @retval EFI_SUCCESS           The variable was read successfully.\r
+  @retval EFI_NOT_FOUND         The variable could not be found.\r
+  @retval EFI_BUFFER_TOO_SMALL  The DataSize is too small for the resulting data. \r
+                                DataSize is updated with the size required for \r
+                                the specified variable.\r
+  @retval EFI_INVALID_PARAMETER VariableName, VariableGuid, DataSize or Data is NULL.\r
+  @retval EFI_DEVICE_ERROR      The variable could not be retrieved because of a device error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PeiGetVariable (\r
+  IN CONST  EFI_PEI_READ_ONLY_VARIABLE2_PPI *This,\r
+  IN CONST  CHAR16                          *VariableName,\r
+  IN CONST  EFI_GUID                        *VariableGuid,\r
+  OUT       UINT32                          *Attributes,\r
+  IN OUT    UINTN                           *DataSize,\r
+  OUT       VOID                            *Data\r
+  )\r
+{\r
+  VARIABLE_POINTER_TRACK  Variable;\r
+  UINTN                   VarDataSize;\r
+  EFI_STATUS              Status;\r
+  CONST EFI_PEI_SERVICES  **PeiServices;\r
+\r
+  PeiServices = GetPeiServicesTablePointer ();\r
+  if (VariableName == NULL || VariableGuid == NULL || DataSize == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  //\r
+  // Find existing variable\r
+  //\r
+  Status = FindVariable (PeiServices, VariableName, VariableGuid, &Variable);\r
+  if (Variable.CurrPtr == NULL || Status != EFI_SUCCESS) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Get data size\r
+  //\r
+  VarDataSize = DataSizeOfVariable (Variable.CurrPtr);\r
+  if (*DataSize >= VarDataSize) {\r
+    if (Data == NULL) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    CopyMem (Data, GetVariableDataPtr (Variable.CurrPtr), VarDataSize);\r
+\r
+    if (Attributes != NULL) {\r
+      *Attributes = Variable.CurrPtr->Attributes;\r
+    }\r
+\r
+    *DataSize = VarDataSize;\r
+    return EFI_SUCCESS;\r
+  } else {\r
+    *DataSize = VarDataSize;\r
+    return EFI_BUFFER_TOO_SMALL;\r
+  }\r
+}\r
+\r
+/**\r
+  Return the next variable name and GUID.\r
+\r
+  This function is called multiple times to retrieve the VariableName \r
+  and VariableGuid of all variables currently available in the system. \r
+  On each call, the previous results are passed into the interface, \r
+  and, on return, the interface returns the data for the next \r
+  interface. When the entire variable list has been returned, \r
+  EFI_NOT_FOUND is returned.\r
+\r
+  @param  This              A pointer to this instance of the EFI_PEI_READ_ONLY_VARIABLE2_PPI.\r
+\r
+  @param  VariableNameSize  On entry, points to the size of the buffer pointed to by VariableName.\r
+                            On return, the size of the variable name buffer.\r
+  @param  VariableName      On entry, a pointer to a null-terminated string that is the variable's name.\r
+                            On return, points to the next variable's null-terminated name string.\r
+  @param  VariableGuid      On entry, a pointer to an EFI_GUID that is the variable's GUID. \r
+                            On return, a pointer to the next variable's GUID.\r
+\r
+  @retval EFI_SUCCESS           The variable was read successfully.\r
+  @retval EFI_NOT_FOUND         The variable could not be found.\r
+  @retval EFI_BUFFER_TOO_SMALL  The VariableNameSize is too small for the resulting\r
+                                data. VariableNameSize is updated with the size\r
+                                required for the specified variable.\r
+  @retval EFI_INVALID_PARAMETER VariableName, VariableGuid or\r
+                                VariableNameSize is NULL.\r
+  @retval EFI_DEVICE_ERROR      The variable could not be retrieved because of a device error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PeiGetNextVariableName (\r
+  IN CONST  EFI_PEI_READ_ONLY_VARIABLE2_PPI *This,\r
+  IN OUT UINTN                              *VariableNameSize,\r
+  IN OUT CHAR16                             *VariableName,\r
+  IN OUT EFI_GUID                           *VariableGuid\r
+  )\r
+{\r
+  VARIABLE_POINTER_TRACK  Variable;\r
+  UINTN                   VarNameSize;\r
+  EFI_STATUS              Status;\r
+  CONST EFI_PEI_SERVICES  **PeiServices;\r
+\r
+  PeiServices = GetPeiServicesTablePointer ();\r
+  if (VariableName == NULL || VariableGuid == NULL || VariableNameSize == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Status = FindVariable (PeiServices, VariableName, VariableGuid, &Variable);\r
+  if (Variable.CurrPtr == NULL || Status != EFI_SUCCESS) {\r
+    return Status;\r
+  }\r
+\r
+  if (VariableName[0] != 0) {\r
+    //\r
+    // If variable name is not NULL, get next variable\r
+    //\r
+    Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);\r
+  }\r
+\r
+  while (!(Variable.CurrPtr >= Variable.EndPtr || Variable.CurrPtr == NULL)) {\r
+    if (IsValidVariableHeader (Variable.CurrPtr)) {\r
+      if (Variable.CurrPtr->State == VAR_ADDED) {\r
+        ASSERT (NameSizeOfVariable (Variable.CurrPtr) != 0);\r
+\r
+        VarNameSize = (UINTN) NameSizeOfVariable (Variable.CurrPtr);\r
+        if (VarNameSize <= *VariableNameSize) {\r
+          CopyMem (VariableName, GetVariableNamePtr (Variable.CurrPtr), VarNameSize);\r
+\r
+          CopyMem (VariableGuid, &Variable.CurrPtr->VendorGuid, sizeof (EFI_GUID));\r
+\r
+          Status = EFI_SUCCESS;\r
+        } else {\r
+          Status = EFI_BUFFER_TOO_SMALL;\r
+        }\r
+\r
+        *VariableNameSize = VarNameSize;\r
+        return Status;\r
+        //\r
+        // Variable is found\r
+        //\r
+      } else {\r
+        Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);\r
+      }\r
+    } else {\r
+      break;\r
+    }\r
+  }\r
+\r
+  return EFI_NOT_FOUND;\r
+}\r
diff --git a/SecurityPkg/VariableAuthenticated/Pei/Variable.h b/SecurityPkg/VariableAuthenticated/Pei/Variable.h
new file mode 100644 (file)
index 0000000..af22687
--- /dev/null
@@ -0,0 +1,128 @@
+/** @file\r
+  The internal header file includes the common header files, defines\r
+  internal structure and functions used by PeiVariable module.\r
+\r
+Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _PEI_VARIABLE_H_\r
+#define _PEI_VARIABLE_H_\r
+\r
+#include <PiPei.h>\r
+#include <Ppi/ReadOnlyVariable2.h>\r
+\r
+#include <Library/DebugLib.h>\r
+#include <Library/PeimEntryPoint.h>\r
+#include <Library/HobLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/PeiServicesTablePointerLib.h>\r
+#include <Library/PeiServicesLib.h>\r
+\r
+#include <Guid/AuthenticatedVariableFormat.h>\r
+#include <Guid/VariableIndexTable.h>\r
+//\r
+// Functions\r
+//\r
+/**\r
+  Provide the functionality of the variable services.\r
+  \r
+  @param  FileHandle  Handle of the file being invoked. \r
+                      Type EFI_PEI_FILE_HANDLE is defined in FfsFindNextFile().\r
+  @param  PeiServices  General purpose services available to every PEIM.\r
+\r
+  @retval EFI_SUCCESS  If the interface could be successfully installed\r
+  @retval Others       Returned from PeiServicesInstallPpi()\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PeimInitializeVariableServices (\r
+  IN       EFI_PEI_FILE_HANDLE       FileHandle,\r
+  IN CONST EFI_PEI_SERVICES          **PeiServices\r
+  );\r
+\r
+/**\r
+  This service retrieves a variable's value using its name and GUID.\r
+\r
+  Read the specified variable from the UEFI variable store. If the Data \r
+  buffer is too small to hold the contents of the variable, the error\r
+  EFI_BUFFER_TOO_SMALL is returned and DataSize is set to the required buffer\r
+  size to obtain the data.\r
+\r
+  @param  This                  A pointer to this instance of the EFI_PEI_READ_ONLY_VARIABLE2_PPI.\r
+  @param  VariableName          A pointer to a null-terminated string that is the variable's name.\r
+  @param  VariableGuid          A pointer to an EFI_GUID that is the variable's GUID. The combination of\r
+                                VariableGuid and VariableName must be unique.\r
+  @param  Attributes            If non-NULL, on return, points to the variable's attributes.\r
+  @param  DataSize              On entry, points to the size in bytes of the Data buffer.\r
+                                On return, points to the size of the data returned in Data.\r
+  @param  Data                  Points to the buffer which will hold the returned variable value.\r
+\r
+  @retval EFI_SUCCESS           The variable was read successfully.\r
+  @retval EFI_NOT_FOUND         The variable could not be found.\r
+  @retval EFI_BUFFER_TOO_SMALL  The DataSize is too small for the resulting data. \r
+                                DataSize is updated with the size required for \r
+                                the specified variable.\r
+  @retval EFI_INVALID_PARAMETER VariableName, VariableGuid, DataSize or Data is NULL.\r
+  @retval EFI_DEVICE_ERROR      The variable could not be retrieved because of a device error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PeiGetVariable (\r
+  IN CONST  EFI_PEI_READ_ONLY_VARIABLE2_PPI *This,\r
+  IN CONST  CHAR16                          *VariableName,\r
+  IN CONST  EFI_GUID                        *VariableGuid,\r
+  OUT       UINT32                          *Attributes,\r
+  IN OUT    UINTN                           *DataSize,\r
+  OUT       VOID                            *Data\r
+  );\r
+\r
+/**\r
+  Return the next variable name and GUID.\r
+\r
+  This function is called multiple times to retrieve the VariableName \r
+  and VariableGuid of all variables currently available in the system. \r
+  On each call, the previous results are passed into the interface, \r
+  and, on return, the interface returns the data for the next \r
+  interface. When the entire variable list has been returned, \r
+  EFI_NOT_FOUND is returned.\r
+\r
+  @param  This              A pointer to this instance of the EFI_PEI_READ_ONLY_VARIABLE2_PPI.\r
+\r
+  @param  VariableNameSize  On entry, points to the size of the buffer pointed to by VariableName.\r
+  @param  VariableName      On entry, a pointer to a null-terminated string that is the variable's name.\r
+                            On return, points to the next variable's null-terminated name string.\r
+\r
+  @param  VariableGuid      On entry, a pointer to an UEFI _GUID that is the variable's GUID. \r
+                            On return, a pointer to the next variable's GUID.\r
+\r
+  @retval EFI_SUCCESS           The variable was read successfully.\r
+  @retval EFI_NOT_FOUND         The variable could not be found.\r
+  @retval EFI_BUFFER_TOO_SMALL  The VariableNameSize is too small for the resulting\r
+                                data. VariableNameSize is updated with the size\r
+                                required for the specified variable.\r
+  @retval EFI_INVALID_PARAMETER VariableName, VariableGuid or\r
+                                VariableNameSize is NULL.\r
+  @retval EFI_DEVICE_ERROR      The variable could not be retrieved because of a device error.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PeiGetNextVariableName (\r
+  IN CONST  EFI_PEI_READ_ONLY_VARIABLE2_PPI *This,\r
+  IN OUT UINTN                              *VariableNameSize,\r
+  IN OUT CHAR16                             *VariableName,\r
+  IN OUT EFI_GUID                           *VariableGuid\r
+  );\r
+\r
+#endif\r
diff --git a/SecurityPkg/VariableAuthenticated/Pei/VariablePei.inf b/SecurityPkg/VariableAuthenticated/Pei/VariablePei.inf
new file mode 100644 (file)
index 0000000..7863293
--- /dev/null
@@ -0,0 +1,64 @@
+## @file\r
+#  The component description for PEI variable driver. \r
+#\r
+# Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = PeiVariable\r
+  FILE_GUID                      = B1F7AF2F-2807-478c-A893-2BF4DDD1F62B\r
+  MODULE_TYPE                    = PEIM\r
+  VERSION_STRING                 = 1.0\r
+  ENTRY_POINT                    = PeimInitializeVariableServices\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC\r
+#\r
+\r
+[Sources]\r
+  Variable.c\r
+  Variable.h\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+  SecurityPkg/SecurityPkg.dec\r
+\r
+[LibraryClasses]\r
+  BaseMemoryLib\r
+  PcdLib\r
+  HobLib\r
+  PeimEntryPoint\r
+  DebugLib\r
+  PeiServicesTablePointerLib\r
+  PeiServicesLib\r
+\r
+[Guids]\r
+  gEfiAuthenticatedVariableGuid\r
+  gEfiVariableIndexTableGuid\r
+\r
+[Ppis]\r
+  gEfiPeiReadOnlyVariable2PpiGuid                ## SOMETIMES_PRODUCES (Not for boot mode RECOVERY)\r
+\r
+[Pcd]\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase  ## CONSUMES\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64  ## CONSUMES\r
+\r
+[Depex]\r
+  TRUE\r
+\r
+#\r
+#  [BootMode]\r
+#    RECOVERY          ## CONSUMES\r
+#\r
+\r
diff --git a/SecurityPkg/VariableAuthenticated/RuntimeDxe/AuthService.c b/SecurityPkg/VariableAuthenticated/RuntimeDxe/AuthService.c
new file mode 100644 (file)
index 0000000..cf94182
--- /dev/null
@@ -0,0 +1,1205 @@
+/** @file\r
+  Implement authentication services for the authenticated variable\r
+  service in UEFI2.2.\r
+\r
+Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "Variable.h"\r
+#include "AuthService.h"\r
+\r
+///\r
+/// Global database array for scratch\r
+/// \r
+UINT8    mPubKeyStore[MAX_KEYDB_SIZE];\r
+UINT32   mPubKeyNumber;\r
+UINT32   mPlatformMode;\r
+EFI_GUID mSignatureSupport[SIGSUPPORT_NUM] = {EFI_CERT_RSA2048_SHA256_GUID, EFI_CERT_RSA2048_SHA1_GUID};\r
+//\r
+// Public Exponent of RSA Key.\r
+//\r
+CONST UINT8 mRsaE[] = { 0x01, 0x00, 0x01 };\r
+//\r
+// Hash context pointer\r
+//\r
+VOID  *mHashCtx = NULL;\r
+\r
+\r
+//\r
+// Pointer to runtime buffer. \r
+// For "Append" operation to an existing variable, a read/modify/write operation \r
+// is supported by firmware internally. Reserve runtime buffer to cache previous \r
+// variable data in runtime phase because memory allocation is forbidden in virtual mode.\r
+//\r
+VOID  *mStorageArea = NULL;\r
+\r
+/**\r
+  Update platform mode.\r
+\r
+  @param[in]      Mode                    SETUP_MODE or USER_MODE.\r
+\r
+  @return EFI_INVALID_PARAMETER           Invalid parameter.\r
+  @return EFI_SUCCESS                     Update platform mode successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+UpdatePlatformMode (\r
+  IN  UINT32                    Mode\r
+  );\r
+\r
+/**\r
+  Initializes for authenticated varibale service.\r
+\r
+  @retval EFI_SUCCESS           Function successfully executed.\r
+  @retval EFI_OUT_OF_RESOURCES  Fail to allocate enough memory resources.\r
+\r
+**/\r
+EFI_STATUS\r
+AutenticatedVariableServiceInitialize (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  VARIABLE_POINTER_TRACK  Variable;\r
+  UINT8                   VarValue;\r
+  UINT32                  VarAttr;\r
+  UINT8                   *Data;\r
+  UINTN                   DataSize;\r
+  UINTN                   CtxSize;\r
+  //\r
+  // Initialize hash context.\r
+  //\r
+  CtxSize   = Sha256GetContextSize ();\r
+  mHashCtx  = AllocateRuntimePool (CtxSize);\r
+  if (mHashCtx == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  //\r
+  // Reserved runtime buffer for "Append" operation in virtual mode.\r
+  //\r
+  mStorageArea  = AllocateRuntimePool (PcdGet32 (PcdMaxAppendVariableSize));\r
+  if (mStorageArea == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  //\r
+  // Check "AuthVarKeyDatabase" variable's existence. \r
+  // If it doesn't exist, create a new one with initial value of 0 and EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set. \r
+  //\r
+  Status = FindVariable (\r
+             AUTHVAR_KEYDB_NAME, \r
+             &gEfiAuthenticatedVariableGuid, \r
+             &Variable, \r
+             &mVariableModuleGlobal->VariableGlobal\r
+             );\r
+\r
+  if (Variable.CurrPtr == NULL) {\r
+    VarAttr       = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;\r
+    VarValue      = 0;\r
+    mPubKeyNumber = 0;\r
+    Status        = UpdateVariable (\r
+                      AUTHVAR_KEYDB_NAME,\r
+                      &gEfiAuthenticatedVariableGuid,\r
+                      &VarValue,\r
+                      sizeof(UINT8),\r
+                      VarAttr,\r
+                      0,\r
+                      0,\r
+                      &Variable,\r
+                      NULL\r
+                      );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  } else {\r
+    //\r
+    // Load database in global variable for cache.\r
+    //\r
+    DataSize  = DataSizeOfVariable (Variable.CurrPtr);\r
+    Data      = GetVariableDataPtr (Variable.CurrPtr);\r
+    ASSERT ((DataSize != 0) && (Data != NULL));\r
+    CopyMem (mPubKeyStore, (UINT8 *) Data, DataSize);\r
+    mPubKeyNumber = (UINT32) (DataSize / EFI_CERT_TYPE_RSA2048_SIZE);\r
+  }\r
+  //\r
+  // Check "SetupMode" variable's existence. \r
+  // If it doesn't exist, check PK database's existence to determine the value.\r
+  // Then create a new one with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set. \r
+  //\r
+  Status = FindVariable (\r
+             EFI_SETUP_MODE_NAME, \r
+             &gEfiGlobalVariableGuid, \r
+             &Variable, \r
+             &mVariableModuleGlobal->VariableGlobal\r
+             );\r
+\r
+  if (Variable.CurrPtr == NULL) {\r
+    Status = FindVariable (\r
+               EFI_PLATFORM_KEY_NAME, \r
+               &gEfiGlobalVariableGuid, \r
+               &Variable, \r
+               &mVariableModuleGlobal->VariableGlobal\r
+               );\r
+    if (Variable.CurrPtr == NULL) {\r
+      mPlatformMode = SETUP_MODE;\r
+    } else {\r
+      mPlatformMode = USER_MODE;\r
+    }\r
+\r
+    VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;\r
+    Status  = UpdateVariable (\r
+                EFI_SETUP_MODE_NAME,\r
+                &gEfiGlobalVariableGuid,\r
+                &mPlatformMode,\r
+                sizeof(UINT8),\r
+                VarAttr,\r
+                0,\r
+                0,\r
+                &Variable,\r
+                NULL\r
+                );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  } else {\r
+    mPlatformMode = *(GetVariableDataPtr (Variable.CurrPtr));\r
+  }\r
+  //\r
+  // Check "SignatureSupport" variable's existence. \r
+  // If it doesn't exist, then create a new one with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set. \r
+  //\r
+  Status = FindVariable (\r
+             EFI_SIGNATURE_SUPPORT_NAME, \r
+             &gEfiGlobalVariableGuid, \r
+             &Variable, \r
+             &mVariableModuleGlobal->VariableGlobal\r
+             );\r
+\r
+  if (Variable.CurrPtr == NULL) {\r
+    VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;\r
+    Status  = UpdateVariable (\r
+                EFI_SIGNATURE_SUPPORT_NAME,\r
+                &gEfiGlobalVariableGuid,\r
+                mSignatureSupport,\r
+                SIGSUPPORT_NUM * sizeof(EFI_GUID),\r
+                VarAttr,\r
+                0,\r
+                0,\r
+                &Variable,\r
+                NULL\r
+                );\r
+  }\r
+  \r
+  //\r
+  // Detect whether a secure platform-specific method to clear PK(Platform Key)\r
+  // is configured by platform owner. This method is provided for users force to clear PK \r
+  // in case incorrect enrollment mis-haps.\r
+  //\r
+  if (ForceClearPK ()) {\r
+    //\r
+    // 1. Check whether PK is existing, and clear PK if existing\r
+    //\r
+    FindVariable (\r
+      EFI_PLATFORM_KEY_NAME, \r
+      &gEfiGlobalVariableGuid, \r
+      &Variable, \r
+      &mVariableModuleGlobal->VariableGlobal\r
+      );\r
+    if (Variable.CurrPtr != NULL) {\r
+      VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;\r
+      Status  = UpdateVariable (\r
+                  EFI_PLATFORM_KEY_NAME,\r
+                  &gEfiGlobalVariableGuid,\r
+                  NULL,\r
+                  0,\r
+                  VarAttr,\r
+                  0,\r
+                  0,\r
+                  &Variable,\r
+                  NULL\r
+                  );\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+    }\r
+\r
+    //\r
+    // 2. Update "SetupMode" variable to SETUP_MODE\r
+    //\r
+    UpdatePlatformMode (SETUP_MODE);\r
+  }\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Add public key in store and return its index.\r
+\r
+  @param[in]  PubKey                  Input pointer to Public Key data\r
+\r
+  @return                             Index of new added item\r
+\r
+**/\r
+UINT32\r
+AddPubKeyInStore (\r
+  IN  UINT8               *PubKey\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  BOOLEAN                 IsFound;\r
+  UINT32                  Index;\r
+  VARIABLE_POINTER_TRACK  Variable;\r
+  UINT8                   *Ptr;\r
+\r
+  if (PubKey == NULL) {\r
+    return 0;\r
+  }\r
+\r
+  Status = FindVariable (\r
+             AUTHVAR_KEYDB_NAME,\r
+             &gEfiAuthenticatedVariableGuid,\r
+             &Variable,\r
+             &mVariableModuleGlobal->VariableGlobal\r
+             );\r
+  ASSERT_EFI_ERROR (Status);\r
+  //\r
+  // Check whether the public key entry does exist.\r
+  //\r
+  IsFound = FALSE;\r
+  for (Ptr = mPubKeyStore, Index = 1; Index <= mPubKeyNumber; Index++) {\r
+    if (CompareMem (Ptr, PubKey, EFI_CERT_TYPE_RSA2048_SIZE) == 0) {\r
+      IsFound = TRUE;\r
+      break;\r
+    }\r
+    Ptr += EFI_CERT_TYPE_RSA2048_SIZE;\r
+  }\r
+\r
+  if (!IsFound) {\r
+    //\r
+    // Add public key in database.\r
+    //\r
+    if (mPubKeyNumber == MAX_KEY_NUM) {\r
+      //\r
+      // Notes: Database is full, need enhancement here, currently just return 0.\r
+      //\r
+      return 0;\r
+    }\r
+\r
+    CopyMem (mPubKeyStore + mPubKeyNumber * EFI_CERT_TYPE_RSA2048_SIZE, PubKey, EFI_CERT_TYPE_RSA2048_SIZE);\r
+    Index = ++mPubKeyNumber;\r
+    //\r
+    // Update public key database variable.\r
+    //\r
+    Status = UpdateVariable (\r
+               AUTHVAR_KEYDB_NAME,\r
+               &gEfiAuthenticatedVariableGuid,\r
+               mPubKeyStore,\r
+               mPubKeyNumber * EFI_CERT_TYPE_RSA2048_SIZE,\r
+               EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS,\r
+               0,\r
+               0,\r
+               &Variable,\r
+               NULL\r
+               );\r
+    ASSERT_EFI_ERROR (Status);\r
+  }\r
+\r
+  return Index;\r
+}\r
+\r
+/**\r
+  Verify data payload with AuthInfo in EFI_CERT_TYPE_RSA2048_SHA256 type.\r
+  Follow the steps in UEFI2.2.\r
+\r
+  @param[in]      Data                    Pointer to data with AuthInfo.\r
+  @param[in]      DataSize                Size of Data.\r
+  @param[in]      PubKey                  Public key used for verification.\r
+\r
+  @return EFI_INVALID_PARAMETER       Invalid parameter.\r
+  @retval EFI_SECURITY_VIOLATION      If authentication failed.\r
+  @return EFI_SUCCESS                 Authentication successful.\r
+\r
+**/\r
+EFI_STATUS\r
+VerifyCounterBasedPayload (\r
+  IN     UINT8          *Data,\r
+  IN     UINTN          DataSize,\r
+  IN     UINT8          *PubKey\r
+  )\r
+{\r
+  BOOLEAN                         Status;\r
+  EFI_VARIABLE_AUTHENTICATION     *CertData;\r
+  EFI_CERT_BLOCK_RSA_2048_SHA256  *CertBlock;\r
+  UINT8                           Digest[SHA256_DIGEST_SIZE];\r
+  VOID                            *Rsa;\r
+\r
+  Rsa         = NULL;\r
+  CertData    = NULL;\r
+  CertBlock   = NULL;\r
+\r
+  if (Data == NULL || PubKey == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  CertData  = (EFI_VARIABLE_AUTHENTICATION *) Data;\r
+  CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);\r
+\r
+  //\r
+  // wCertificateType should be WIN_CERT_TYPE_EFI_GUID.\r
+  // Cert type should be EFI_CERT_TYPE_RSA2048_SHA256.\r
+  //\r
+  if ((CertData->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) ||\r
+      !CompareGuid (&CertData->AuthInfo.CertType, &gEfiCertRsa2048Sha256Guid)\r
+        ) {\r
+    //\r
+    // Invalid AuthInfo type, return EFI_SECURITY_VIOLATION.\r
+    //\r
+    return EFI_SECURITY_VIOLATION;\r
+  }\r
+  //\r
+  // Hash data payload with SHA256.\r
+  //\r
+  ZeroMem (Digest, SHA256_DIGEST_SIZE);\r
+  Status  = Sha256Init (mHashCtx);\r
+  if (!Status) {\r
+    goto Done;\r
+  }\r
+  Status  = Sha256Update (mHashCtx, Data + AUTHINFO_SIZE, (UINTN) (DataSize - AUTHINFO_SIZE));\r
+  if (!Status) {\r
+    goto Done;\r
+  }\r
+  //\r
+  // Hash Monotonic Count.\r
+  //\r
+  Status  = Sha256Update (mHashCtx, &CertData->MonotonicCount, sizeof (UINT64));\r
+  if (!Status) {\r
+    goto Done;\r
+  }\r
+  Status  = Sha256Final (mHashCtx, Digest);\r
+  if (!Status) {\r
+    goto Done;\r
+  }\r
+  //\r
+  // Generate & Initialize RSA Context.\r
+  //\r
+  Rsa = RsaNew ();\r
+  ASSERT (Rsa != NULL);\r
+  // \r
+  // Set RSA Key Components.\r
+  // NOTE: Only N and E are needed to be set as RSA public key for signature verification.\r
+  //\r
+  Status = RsaSetKey (Rsa, RsaKeyN, PubKey, EFI_CERT_TYPE_RSA2048_SIZE);\r
+  if (!Status) {\r
+    goto Done;\r
+  }\r
+  Status = RsaSetKey (Rsa, RsaKeyE, mRsaE, sizeof (mRsaE));\r
+  if (!Status) {\r
+    goto Done;\r
+  }\r
+  //\r
+  // Verify the signature.\r
+  //\r
+  Status = RsaPkcs1Verify (\r
+             Rsa, \r
+             Digest, \r
+             SHA256_DIGEST_SIZE, \r
+             CertBlock->Signature, \r
+             EFI_CERT_TYPE_RSA2048_SHA256_SIZE\r
+             );\r
+\r
+Done:\r
+  if (Rsa != NULL) {\r
+    RsaFree (Rsa);\r
+  }\r
+  if (Status) {\r
+    return EFI_SUCCESS;\r
+  } else {\r
+    return EFI_SECURITY_VIOLATION;\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Update platform mode.\r
+\r
+  @param[in]      Mode                    SETUP_MODE or USER_MODE.\r
+\r
+  @return EFI_INVALID_PARAMETER           Invalid parameter.\r
+  @return EFI_SUCCESS                     Update platform mode successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+UpdatePlatformMode (\r
+  IN  UINT32                    Mode\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  VARIABLE_POINTER_TRACK  Variable;\r
+  UINT32                  VarAttr;\r
+  UINT8                   SecureBootMode;\r
+\r
+  Status = FindVariable (\r
+             EFI_SETUP_MODE_NAME, \r
+             &gEfiGlobalVariableGuid, \r
+             &Variable, \r
+             &mVariableModuleGlobal->VariableGlobal\r
+             );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  mPlatformMode  = Mode;\r
+  VarAttr        = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;\r
+  Status         = UpdateVariable (\r
+                     EFI_SETUP_MODE_NAME,\r
+                     &gEfiGlobalVariableGuid,\r
+                     &mPlatformMode,\r
+                     sizeof(UINT8),\r
+                     VarAttr,\r
+                     0,\r
+                     0,\r
+                     &Variable,\r
+                     NULL\r
+                     );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Check "SecureBoot" variable's existence.\r
+  // If it doesn't exist, firmware has no capability to perform driver signing verification,\r
+  // then set "SecureBoot" to 0.\r
+  //\r
+  Status = FindVariable (\r
+             EFI_SECURE_BOOT_MODE_NAME, \r
+             &gEfiGlobalVariableGuid, \r
+             &Variable, \r
+             &mVariableModuleGlobal->VariableGlobal\r
+             );\r
+  //\r
+  // If "SecureBoot" variable exists, then check "SetupMode" variable update.\r
+  // If "SetupMode" variable is USER_MODE, "SecureBoot" variable is set to 1.\r
+  // If "SetupMode" variable is SETUP_MODE, "SecureBoot" variable is set to 0.\r
+  //\r
+  if (Variable.CurrPtr == NULL) {\r
+    SecureBootMode = SECURE_BOOT_MODE_DISABLE;\r
+  } else {\r
+    if (mPlatformMode == USER_MODE) {\r
+      SecureBootMode = SECURE_BOOT_MODE_ENABLE;\r
+    } else if (mPlatformMode == SETUP_MODE) {\r
+      SecureBootMode = SECURE_BOOT_MODE_DISABLE;\r
+    } else {\r
+      return EFI_NOT_FOUND;\r
+    }\r
+  }\r
+\r
+  VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;\r
+  return    UpdateVariable (\r
+              EFI_SECURE_BOOT_MODE_NAME,\r
+              &gEfiGlobalVariableGuid,\r
+              &SecureBootMode,\r
+              sizeof(UINT8),\r
+              VarAttr,\r
+              0,\r
+              0,\r
+              &Variable,\r
+              NULL\r
+              );\r
+}\r
+\r
+/**\r
+  Process variable with platform key for verification.\r
+\r
+  @param[in]  VariableName                Name of Variable to be found.\r
+  @param[in]  VendorGuid                  Variable vendor GUID.\r
+  @param[in]  Data                        Data pointer.\r
+  @param[in]  DataSize                    Size of Data found. If size is less than the\r
+                                          data, this value contains the required size.\r
+  @param[in]  Variable                    The variable information which is used to keep track of variable usage.\r
+  @param[in]  Attributes                  Attribute value of the variable\r
+  @param[in]  IsPk                        Indicate whether it is to process pk.\r
+\r
+  @return EFI_INVALID_PARAMETER           Invalid parameter.\r
+  @return EFI_SECURITY_VIOLATION          The variable does NOT pass the validation. \r
+                                          check carried out by the firmware. \r
+  @return EFI_SUCCESS                     Variable passed validation successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+ProcessVarWithPk (\r
+  IN  CHAR16                    *VariableName,\r
+  IN  EFI_GUID                  *VendorGuid,\r
+  IN  VOID                      *Data,\r
+  IN  UINTN                     DataSize,\r
+  IN  VARIABLE_POINTER_TRACK    *Variable,\r
+  IN  UINT32                    Attributes OPTIONAL,\r
+  IN  BOOLEAN                   IsPk\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  VARIABLE_POINTER_TRACK      PkVariable;\r
+  EFI_SIGNATURE_LIST          *OldPkList;\r
+  EFI_SIGNATURE_DATA          *OldPkData;\r
+  EFI_VARIABLE_AUTHENTICATION *CertData;\r
+  BOOLEAN                     TimeBase;\r
+  BOOLEAN                     Del;\r
+\r
+  if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {\r
+    //\r
+    // PK and KEK should set EFI_VARIABLE_NON_VOLATILE attribute.\r
+    //\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (mPlatformMode == USER_MODE) {\r
+\r
+    if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
+      //\r
+      // EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute means time-based X509 Cert PK.\r
+      //\r
+      TimeBase = TRUE;\r
+    } else if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
+      //\r
+      // EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute means counter-based RSA-2048 Cert PK.\r
+      //\r
+      TimeBase = FALSE;\r
+    } else {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    if (TimeBase) {\r
+      //\r
+      // Verify against X509 Cert PK.\r
+      //\r
+      Del    = FALSE;\r
+      Status = VerifyTimeBasedPayload (VariableName, VendorGuid, Data, DataSize, Variable, Attributes, TRUE, &Del);\r
+      if (!EFI_ERROR (Status)) {\r
+        //\r
+        // If delete PK in user mode, need change to setup mode.\r
+        //\r
+        if (Del && IsPk) {\r
+          Status = UpdatePlatformMode (SETUP_MODE);\r
+        }\r
+      }\r
+      return Status;\r
+    } else {\r
+      //\r
+      // Verify against RSA2048 Cert PK.\r
+      //\r
+      CertData = (EFI_VARIABLE_AUTHENTICATION *) Data;\r
+      if ((Variable->CurrPtr != NULL) && (CertData->MonotonicCount <= Variable->CurrPtr->MonotonicCount)) {\r
+        //\r
+        // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.\r
+        //\r
+        return EFI_SECURITY_VIOLATION;\r
+      }\r
+      //\r
+      // Get platform key from variable.\r
+      //\r
+      Status = FindVariable (\r
+                 EFI_PLATFORM_KEY_NAME, \r
+                 &gEfiGlobalVariableGuid, \r
+                 &PkVariable, \r
+                 &mVariableModuleGlobal->VariableGlobal\r
+                 );\r
+      ASSERT_EFI_ERROR (Status);\r
+  \r
+      OldPkList = (EFI_SIGNATURE_LIST *) GetVariableDataPtr (PkVariable.CurrPtr);\r
+      OldPkData = (EFI_SIGNATURE_DATA *) ((UINT8 *) OldPkList + sizeof (EFI_SIGNATURE_LIST) + OldPkList->SignatureHeaderSize);\r
+      Status    = VerifyCounterBasedPayload (Data, DataSize, OldPkData->SignatureData);\r
+      if (!EFI_ERROR (Status)) {\r
+        Status = UpdateVariable (\r
+                   VariableName, \r
+                   VendorGuid, \r
+                   (UINT8*)Data + AUTHINFO_SIZE, \r
+                   DataSize - AUTHINFO_SIZE, \r
+                   Attributes, \r
+                   0, \r
+                   CertData->MonotonicCount, \r
+                   Variable,\r
+                   NULL\r
+                   );\r
+  \r
+        if (!EFI_ERROR (Status)) {\r
+          //\r
+          // If delete PK in user mode, need change to setup mode.\r
+          //\r
+          if ((DataSize == AUTHINFO_SIZE) && IsPk) {\r
+            Status = UpdatePlatformMode (SETUP_MODE);\r
+          }\r
+        }\r
+      }\r
+    }\r
+  } else {\r
+    Status = UpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes, 0, 0, Variable, NULL);\r
+    //\r
+    // If enroll PK in setup mode, need change to user mode.\r
+    //\r
+    if ((DataSize != 0) && IsPk) {\r
+      Status = UpdatePlatformMode (USER_MODE);\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Process variable with key exchange key for verification.\r
+\r
+  @param[in]  VariableName                Name of Variable to be found.\r
+  @param[in]  VendorGuid                  Variable vendor GUID.\r
+  @param[in]  Data                        Data pointer.\r
+  @param[in]  DataSize                    Size of Data found. If size is less than the\r
+                                          data, this value contains the required size.\r
+  @param[in]  Variable                    The variable information which is used to keep track of variable usage.\r
+  @param[in]  Attributes                  Attribute value of the variable.\r
+\r
+  @return EFI_INVALID_PARAMETER           Invalid parameter.\r
+  @return EFI_SECURITY_VIOLATION          The variable does NOT pass the validation \r
+                                          check carried out by the firmware. \r
+  @return EFI_SUCCESS                     Variable pass validation successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+ProcessVarWithKek (\r
+  IN  CHAR16                               *VariableName,\r
+  IN  EFI_GUID                             *VendorGuid,\r
+  IN  VOID                                 *Data,\r
+  IN  UINTN                                DataSize,\r
+  IN  VARIABLE_POINTER_TRACK               *Variable,\r
+  IN  UINT32                               Attributes OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  VARIABLE_POINTER_TRACK          KekVariable;\r
+  EFI_SIGNATURE_LIST              *KekList;\r
+  EFI_SIGNATURE_DATA              *KekItem;\r
+  UINT32                          KekCount;\r
+  EFI_VARIABLE_AUTHENTICATION     *CertData;\r
+  EFI_CERT_BLOCK_RSA_2048_SHA256  *CertBlock;\r
+  BOOLEAN                         IsFound;\r
+  UINT32                          Index;\r
+  UINT32                          KekDataSize;\r
+\r
+  if (mPlatformMode == USER_MODE) {\r
+    if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == 0) {\r
+      //\r
+      // In user mode, should set EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute.\r
+      //\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    CertData  = (EFI_VARIABLE_AUTHENTICATION *) Data;\r
+    CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);\r
+    if ((Variable->CurrPtr != NULL) && (CertData->MonotonicCount <= Variable->CurrPtr->MonotonicCount)) {\r
+      //\r
+      // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.\r
+      //\r
+      return EFI_SECURITY_VIOLATION;\r
+    }\r
+    //\r
+    // Get KEK database from variable.\r
+    //\r
+    Status = FindVariable (\r
+               EFI_KEY_EXCHANGE_KEY_NAME, \r
+               &gEfiGlobalVariableGuid, \r
+               &KekVariable, \r
+               &mVariableModuleGlobal->VariableGlobal\r
+               );\r
+    ASSERT_EFI_ERROR (Status);\r
+\r
+    KekDataSize = KekVariable.CurrPtr->DataSize;\r
+    KekList     = (EFI_SIGNATURE_LIST *) GetVariableDataPtr (KekVariable.CurrPtr);\r
+\r
+    //\r
+    // Enumerate all Kek items in this list to verify the variable certificate data.\r
+    // If anyone is authenticated successfully, it means the variable is correct!\r
+    //\r
+    IsFound   = FALSE;\r
+    while ((KekDataSize > 0) && (KekDataSize >= KekList->SignatureListSize)) {\r
+      if (CompareGuid (&KekList->SignatureType, &gEfiCertRsa2048Guid)) {\r
+        KekItem   = (EFI_SIGNATURE_DATA *) ((UINT8 *) KekList + sizeof (EFI_SIGNATURE_LIST) + KekList->SignatureHeaderSize);\r
+        KekCount  = (KekList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - KekList->SignatureHeaderSize) / KekList->SignatureSize;\r
+        for (Index = 0; Index < KekCount; Index++) {\r
+          if (CompareMem (KekItem->SignatureData, CertBlock->PublicKey, EFI_CERT_TYPE_RSA2048_SIZE) == 0) {\r
+            IsFound = TRUE;\r
+            break;\r
+          }\r
+          KekItem = (EFI_SIGNATURE_DATA *) ((UINT8 *) KekItem + KekList->SignatureSize);\r
+        }\r
+      }\r
+      KekDataSize -= KekList->SignatureListSize;\r
+      KekList = (EFI_SIGNATURE_LIST *) ((UINT8 *) KekList + KekList->SignatureListSize);\r
+    }\r
+    \r
+    if (!IsFound) {\r
+      return EFI_SECURITY_VIOLATION;\r
+    }\r
+\r
+    Status = VerifyCounterBasedPayload (Data, DataSize, CertBlock->PublicKey);\r
+    if (!EFI_ERROR (Status)) {\r
+      Status = UpdateVariable (\r
+                 VariableName, \r
+                 VendorGuid, \r
+                 (UINT8*)Data + AUTHINFO_SIZE, \r
+                 DataSize - AUTHINFO_SIZE, \r
+                 Attributes, \r
+                 0, \r
+                 CertData->MonotonicCount, \r
+                 Variable,\r
+                 NULL\r
+                 );\r
+    }\r
+  } else {\r
+    //\r
+    // If in setup mode, no authentication needed.\r
+    //\r
+    Status = UpdateVariable (\r
+               VariableName, \r
+               VendorGuid, \r
+               Data, \r
+               DataSize, \r
+               Attributes, \r
+               0, \r
+               0, \r
+               Variable,\r
+               NULL\r
+               );\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Process variable with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS/EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set\r
+\r
+  @param[in]  VariableName                Name of Variable to be found.\r
+  @param[in]  VendorGuid                  Variable vendor GUID.\r
+\r
+  @param[in]  Data                        Data pointer.\r
+  @param[in]  DataSize                    Size of Data found. If size is less than the\r
+                                          data, this value contains the required size.\r
+  @param[in]  Variable                    The variable information which is used to keep track of variable usage.\r
+  @param[in]  Attributes                  Attribute value of the variable.\r
+\r
+  @return EFI_INVALID_PARAMETER           Invalid parameter.\r
+  @return EFI_WRITE_PROTECTED             Variable is write-protected and needs authentication with\r
+                                          EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.\r
+  @return EFI_SECURITY_VIOLATION          The variable is with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS\r
+                                          set, but the AuthInfo does NOT pass the validation \r
+                                          check carried out by the firmware. \r
+  @return EFI_SUCCESS                     Variable is not write-protected or pass validation successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+ProcessVariable (\r
+  IN     CHAR16                             *VariableName,\r
+  IN     EFI_GUID                           *VendorGuid,\r
+  IN     VOID                               *Data,\r
+  IN     UINTN                              DataSize,\r
+  IN     VARIABLE_POINTER_TRACK             *Variable,\r
+  IN     UINT32                             Attributes\r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  BOOLEAN                         IsDeletion;\r
+  BOOLEAN                         IsFirstTime;\r
+  UINT8                           *PubKey;\r
+  EFI_VARIABLE_AUTHENTICATION     *CertData;\r
+  EFI_CERT_BLOCK_RSA_2048_SHA256  *CertBlock;\r
+  UINT32                          KeyIndex;\r
+  UINT64                          MonotonicCount;\r
+\r
+  KeyIndex    = 0;  \r
+  CertData    = NULL;\r
+  CertBlock   = NULL;\r
+  PubKey      = NULL;\r
+  IsDeletion  = FALSE;\r
+\r
+  //\r
+  // Process Time-based Authenticated variable.\r
+  //\r
+  if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
+    return VerifyTimeBasedPayload (VariableName, VendorGuid, Data, DataSize, Variable, Attributes, FALSE, NULL);\r
+  }\r
+  \r
+  //\r
+  // Determine if first time SetVariable with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS.\r
+  //\r
+  if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
+    //\r
+    // Determine current operation type.\r
+    //\r
+    if (DataSize == AUTHINFO_SIZE) {\r
+      IsDeletion = TRUE;\r
+    }\r
+    //\r
+    // Determine whether this is the first time with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.\r
+    //\r
+    if (Variable->CurrPtr == NULL) {\r
+      IsFirstTime = TRUE;\r
+    } else if ((Variable->CurrPtr->Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == 0) {\r
+      IsFirstTime = TRUE;\r
+    } else {\r
+      KeyIndex   = Variable->CurrPtr->PubKeyIndex;\r
+      IsFirstTime = FALSE;\r
+    }\r
+  } else if ((Variable->CurrPtr != NULL) &&\r
+           (Variable->CurrPtr->Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0\r
+          ) {\r
+    //\r
+    // If the variable is already write-protected, it always needs authentication before update.\r
+    //\r
+    return EFI_WRITE_PROTECTED;\r
+  } else {\r
+    //\r
+    // If without EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, set and attributes collision.\r
+    // That means it is not authenticated variable, just update variable as usual.\r
+    //\r
+    Status = UpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes, 0, 0, Variable, NULL);\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Get PubKey and check Monotonic Count value corresponding to the variable.\r
+  //\r
+  CertData  = (EFI_VARIABLE_AUTHENTICATION *) Data;\r
+  CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);\r
+  PubKey    = CertBlock->PublicKey;\r
+\r
+  //\r
+  // Update Monotonic Count value.\r
+  //\r
+  MonotonicCount = CertData->MonotonicCount;\r
+\r
+  if (!IsFirstTime) {\r
+    //\r
+    // Check input PubKey.\r
+    //\r
+    if (CompareMem (PubKey, mPubKeyStore + (KeyIndex - 1) * EFI_CERT_TYPE_RSA2048_SIZE, EFI_CERT_TYPE_RSA2048_SIZE) != 0) {\r
+      return EFI_SECURITY_VIOLATION;\r
+    }\r
+    //\r
+    // Compare the current monotonic count and ensure that it is greater than the last SetVariable\r
+    // operation with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute set.\r
+    //\r
+    if (CertData->MonotonicCount <= Variable->CurrPtr->MonotonicCount) {\r
+      //\r
+      // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.\r
+      //\r
+      return EFI_SECURITY_VIOLATION;\r
+    }\r
+  } \r
+  //\r
+  // Verify the certificate in Data payload.\r
+  //\r
+  Status = VerifyCounterBasedPayload (Data, DataSize, PubKey);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  \r
+  //\r
+  // Now, the signature has been verified!\r
+  //\r
+  if (IsFirstTime && !IsDeletion) {\r
+    //\r
+    // Update public key database variable if need.\r
+    //\r
+    KeyIndex = AddPubKeyInStore (PubKey);\r
+  }\r
+\r
+  //\r
+  // Verification pass.\r
+  //\r
+  return UpdateVariable (VariableName, VendorGuid, (UINT8*)Data + AUTHINFO_SIZE, DataSize - AUTHINFO_SIZE, Attributes, KeyIndex, MonotonicCount, Variable, NULL);\r
+}\r
+\r
+/**\r
+  Compare two EFI_TIME data.\r
+\r
+\r
+  @param FirstTime           A pointer to the first EFI_TIME data.\r
+  @param SecondTime          A pointer to the second EFI_TIME data.\r
+\r
+  @retval  TRUE              The FirstTime is not later than the SecondTime.\r
+  @retval  FALSE             The FirstTime is later than the SecondTime.\r
+\r
+**/\r
+BOOLEAN\r
+CompareTimeStamp (\r
+  IN EFI_TIME               *FirstTime,\r
+  IN EFI_TIME               *SecondTime\r
+  )\r
+{\r
+  if (FirstTime->Year != SecondTime->Year) {\r
+    return (BOOLEAN) (FirstTime->Year < SecondTime->Year);\r
+  } else if (FirstTime->Month != SecondTime->Month) {\r
+    return (BOOLEAN) (FirstTime->Month < SecondTime->Month);\r
+  } else if (FirstTime->Day != SecondTime->Day) {\r
+    return (BOOLEAN) (FirstTime->Day < SecondTime->Day);\r
+  } else if (FirstTime->Hour != SecondTime->Hour) {\r
+    return (BOOLEAN) (FirstTime->Hour < SecondTime->Hour);\r
+  } else if (FirstTime->Minute != SecondTime->Minute) {\r
+    return (BOOLEAN) (FirstTime->Minute < FirstTime->Minute);\r
+  } \r
+\r
+  return (BOOLEAN) (FirstTime->Second <= SecondTime->Second);\r
+}\r
+\r
+/**\r
+  Process variable with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set\r
+\r
+  @param[in]  VariableName                Name of Variable to be found.\r
+  @param[in]  VendorGuid                  Variable vendor GUID.\r
+  @param[in]  Data                        Data pointer.\r
+  @param[in]  DataSize                    Size of Data found. If size is less than the\r
+                                          data, this value contains the required size.\r
+  @param[in]  Variable                    The variable information which is used to keep track of variable usage.\r
+  @param[in]  Attributes                  Attribute value of the variable.\r
+  @param[in]  Pk                          Verify against PK or KEK database.\r
+  @param[out] VarDel                      Delete the variable or not.\r
+\r
+  @retval EFI_INVALID_PARAMETER           Invalid parameter.\r
+  @retval EFI_SECURITY_VIOLATION          The variable does NOT pass the validation \r
+                                          check carried out by the firmware. \r
+  @retval EFI_OUT_OF_RESOURCES            Failed to process variable due to lack\r
+                                          of resources.\r
+  @retval EFI_SUCCESS                     Variable pass validation successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+VerifyTimeBasedPayload (\r
+  IN     CHAR16                             *VariableName,\r
+  IN     EFI_GUID                           *VendorGuid,\r
+  IN     VOID                               *Data,\r
+  IN     UINTN                              DataSize,\r
+  IN     VARIABLE_POINTER_TRACK             *Variable,\r
+  IN     UINT32                             Attributes,\r
+  IN     BOOLEAN                            Pk,\r
+  OUT    BOOLEAN                            *VarDel\r
+  )\r
+{\r
+  UINT8                            *RootCert;\r
+  UINT8                            *SigData;\r
+  UINT8                            *PayLoadPtr;\r
+  UINTN                            RootCertSize;\r
+  UINTN                            Index;\r
+  UINTN                            CertCount;  \r
+  UINTN                            PayLoadSize;  \r
+  UINT32                           Attr;\r
+  UINT32                           SigDataSize;\r
+  UINT32                           KekDataSize;\r
+  BOOLEAN                          Result;\r
+  BOOLEAN                          VerifyStatus;\r
+  EFI_STATUS                       Status;\r
+  EFI_SIGNATURE_LIST               *CertList;\r
+  EFI_SIGNATURE_DATA               *Cert;\r
+  VARIABLE_POINTER_TRACK           KekVariable;\r
+  EFI_VARIABLE_AUTHENTICATION_2    *CertData;\r
+  UINT8                            *NewData;\r
+  UINTN                            NewDataSize;\r
+  VARIABLE_POINTER_TRACK           PkVariable;\r
+\r
+\r
+  Result                 = FALSE;\r
+  VerifyStatus           = FALSE;\r
+  CertData               = NULL;\r
+  NewData                = NULL;\r
+  Attr                   = Attributes;\r
+\r
+  //\r
+  // When the attribute EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS is \r
+  // set, then the Data buffer shall begin with an instance of a complete (and serialized)\r
+  // EFI_VARIABLE_AUTHENTICATION_2 descriptor. The descriptor shall be followed by the new \r
+  // variable value and DataSize shall reflect the combined size of the descriptor and the new \r
+  // variable value. The authentication descriptor is not part of the variable data and is not \r
+  // returned by subsequent calls to GetVariable().\r
+  //\r
+  CertData = (EFI_VARIABLE_AUTHENTICATION_2 *) Data;\r
+  \r
+  if ((Variable->CurrPtr != NULL) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0)) {\r
+    if (CompareTimeStamp (&CertData->TimeStamp, &Variable->CurrPtr->TimeStamp)) {\r
+      //\r
+      // TimeStamp check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.\r
+      //\r
+      return EFI_SECURITY_VIOLATION;\r
+    }\r
+  }\r
+\r
+  //\r
+  // wCertificateType should be WIN_CERT_TYPE_EFI_GUID.\r
+  // Cert type should be EFI_CERT_TYPE_PKCS7_GUID.\r
+  //\r
+  if ((CertData->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) ||\r
+      !CompareGuid (&CertData->AuthInfo.CertType, &gEfiCertPkcs7Guid)\r
+        ) {\r
+    //\r
+    // Invalid AuthInfo type, return EFI_SECURITY_VIOLATION.\r
+    //\r
+    return EFI_SECURITY_VIOLATION;\r
+  }\r
+\r
+  //\r
+  // Find out Pkcs7 SignedData which follows the EFI_VARIABLE_AUTHENTICATION_2 descriptor.\r
+  // AuthInfo.Hdr.dwLength is the length of the entire certificate, including the length of the header.\r
+  //\r
+  SigData = (UINT8*) ((UINTN)Data + (UINTN)(((EFI_VARIABLE_AUTHENTICATION_2 *) 0)->AuthInfo.CertData));\r
+  SigDataSize = CertData->AuthInfo.Hdr.dwLength - (UINT32)(UINTN)(((WIN_CERTIFICATE_UEFI_GUID *) 0)->CertData);\r
+  \r
+  //\r
+  // Find out the new data payload which follows Pkcs7 SignedData directly.\r
+  //\r
+  PayLoadPtr = (UINT8*) ((UINTN) SigData + (UINTN) SigDataSize);\r
+  PayLoadSize = DataSize - (UINTN)(((EFI_VARIABLE_AUTHENTICATION_2 *) 0)->AuthInfo.CertData) - (UINTN) SigDataSize;\r
+\r
+\r
+  //\r
+  // Construct a buffer to fill with (VariableName, VendorGuid, Attributes, TimeStamp, Data).\r
+  //\r
+  NewDataSize = PayLoadSize + sizeof (EFI_TIME) + sizeof (UINT32) +\r
+                sizeof (EFI_GUID) + StrSize (VariableName);\r
+  NewData     = (UINT8 *) AllocateZeroPool (NewDataSize);\r
+\r
+  if (NewData == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  CopyMem (NewData, VariableName, StrSize (VariableName));\r
+\r
+  CopyMem (NewData + StrSize (VariableName), VendorGuid, sizeof (EFI_GUID));\r
+\r
+  CopyMem (\r
+    NewData + StrSize (VariableName) + sizeof (EFI_GUID),\r
+    &Attr,\r
+    sizeof (UINT32)\r
+    );\r
+\r
+  CopyMem (\r
+    NewData + StrSize (VariableName) + sizeof (EFI_GUID) + sizeof (UINT32),\r
+    &CertData->TimeStamp,\r
+    sizeof (EFI_TIME)\r
+    );\r
+\r
+  CopyMem (NewData + (NewDataSize - PayLoadSize), PayLoadPtr, PayLoadSize);\r
+\r
+\r
+  if (Pk) {\r
+    //\r
+    // Get platform key from variable.\r
+    //\r
+    Status = FindVariable (\r
+               EFI_PLATFORM_KEY_NAME, \r
+               &gEfiGlobalVariableGuid, \r
+               &PkVariable, \r
+               &mVariableModuleGlobal->VariableGlobal\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    CertList = (EFI_SIGNATURE_LIST *) GetVariableDataPtr (PkVariable.CurrPtr);\r
+    Cert     = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\r
+    RootCert      = Cert->SignatureData;\r
+    RootCertSize  = CertList->SignatureSize;\r
+\r
+\r
+    //\r
+    // Verify Pkcs7 SignedData via Pkcs7Verify library.\r
+    //\r
+    VerifyStatus = Pkcs7Verify (\r
+                     SigData,\r
+                     SigDataSize,\r
+                     RootCert,\r
+                     RootCertSize,\r
+                     NewData,\r
+                     NewDataSize\r
+                     );\r
+\r
+  } else {\r
+  \r
+    //\r
+    // Get KEK database from variable.\r
+    //\r
+    Status = FindVariable (\r
+               EFI_KEY_EXCHANGE_KEY_NAME, \r
+               &gEfiGlobalVariableGuid, \r
+               &KekVariable, \r
+               &mVariableModuleGlobal->VariableGlobal\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    //\r
+    // Ready to verify Pkcs7 SignedData. Go through KEK Signature Database to find out X.509 CertList.\r
+    // \r
+    KekDataSize      = KekVariable.CurrPtr->DataSize;\r
+    CertList         = (EFI_SIGNATURE_LIST *) GetVariableDataPtr (KekVariable.CurrPtr);\r
+    while ((KekDataSize > 0) && (KekDataSize >= CertList->SignatureListSize)) {\r
+      if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {\r
+        Cert       = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\r
+        CertCount  = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;\r
+        for (Index = 0; Index < CertCount; Index++) {\r
+          //\r
+          // Iterate each Signature Data Node within this CertList for a verify\r
+          //\r
+          RootCert      = Cert->SignatureData;\r
+          RootCertSize  = CertList->SignatureSize;\r
+       \r
+          //\r
+          // Verify Pkcs7 SignedData via Pkcs7Verify library.\r
+          //\r
+          VerifyStatus = Pkcs7Verify (\r
+                           SigData,\r
+                           SigDataSize,\r
+                           RootCert,\r
+                           RootCertSize,\r
+                           NewData,\r
+                           NewDataSize\r
+                           );\r
+          if (VerifyStatus) {\r
+            goto Exit;\r
+          }\r
+          Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);\r
+        }\r
+      }\r
+      KekDataSize -= CertList->SignatureListSize;\r
+      CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);\r
+    }\r
+  }\r
+\r
+Exit:\r
+\r
+  FreePool (NewData);\r
+\r
+  if (!VerifyStatus) {\r
+    return EFI_SECURITY_VIOLATION;\r
+  }\r
+\r
+  if ((PayLoadSize == 0) && (VarDel != NULL)) {\r
+    *VarDel = TRUE;\r
+  }\r
+  \r
+  //\r
+  // Final step: Update/Append Variable if it pass Pkcs7Verify\r
+  //\r
+  return   UpdateVariable (\r
+             VariableName, \r
+             VendorGuid, \r
+             PayLoadPtr, \r
+             PayLoadSize, \r
+             Attributes, \r
+             0, \r
+             0, \r
+             Variable,\r
+             &CertData->TimeStamp\r
+             );\r
+}\r
diff --git a/SecurityPkg/VariableAuthenticated/RuntimeDxe/AuthService.h b/SecurityPkg/VariableAuthenticated/RuntimeDxe/AuthService.h
new file mode 100644 (file)
index 0000000..6b0db74
--- /dev/null
@@ -0,0 +1,209 @@
+/** @file\r
+  The internal header file includes the common header files, defines\r
+  internal structure and functions used by AuthService module.\r
+\r
+Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _AUTHSERVICE_H_\r
+#define _AUTHSERVICE_H_\r
+\r
+#define EFI_CERT_TYPE_RSA2048_SHA256_SIZE 256\r
+#define EFI_CERT_TYPE_RSA2048_SIZE        256\r
+\r
+///\r
+/// Size of AuthInfo prior to the data payload\r
+///\r
+#define AUTHINFO_SIZE (((UINTN)(((EFI_VARIABLE_AUTHENTICATION *) 0)->AuthInfo.CertData)) + sizeof (EFI_CERT_BLOCK_RSA_2048_SHA256))\r
+\r
+///\r
+/// "AuthVarKeyDatabase" variable for the Public Key store.\r
+///\r
+#define AUTHVAR_KEYDB_NAME      L"AuthVarKeyDatabase"\r
+#define AUTHVAR_KEYDB_NAME_SIZE 38\r
+\r
+///\r
+/// Max size of public key database, restricted by max individal EFI varible size, exclude variable header and name size.\r
+///\r
+#define MAX_KEYDB_SIZE  (FixedPcdGet32 (PcdMaxVariableSize) - sizeof (VARIABLE_HEADER) - AUTHVAR_KEYDB_NAME_SIZE)\r
+#define MAX_KEY_NUM     (MAX_KEYDB_SIZE / EFI_CERT_TYPE_RSA2048_SIZE)\r
+\r
+///\r
+/// Item number of support signature types.\r
+///\r
+#define SIGSUPPORT_NUM 2\r
+\r
+\r
+/**\r
+  Process variable with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS/EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set.\r
+\r
+  @param[in]  VariableName                Name of Variable to be found.\r
+  @param[in]  VendorGuid                  Variable vendor GUID.\r
+\r
+  @param[in]  Data                        Data pointer.\r
+  @param[in]  DataSize                    Size of Data found. If size is less than the\r
+                                          data, this value contains the required size.\r
+  @param[in]  Variable                    The variable information which is used to keep track of variable usage.\r
+  @param[in]  Attributes                  Attribute value of the variable.\r
+\r
+  @return EFI_INVALID_PARAMETER           Invalid parameter\r
+  @return EFI_WRITE_PROTECTED             Variable is write-protected and needs authentication with\r
+                                          EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.\r
+  @return EFI_SECURITY_VIOLATION          The variable is with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS\r
+                                          set, but the AuthInfo does NOT pass the validation \r
+                                          check carried out by the firmware. \r
+  @return EFI_SUCCESS                     Variable is not write-protected, or passed validation successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+ProcessVariable (\r
+  IN     CHAR16                             *VariableName,\r
+  IN     EFI_GUID                           *VendorGuid,\r
+  IN     VOID                               *Data,\r
+  IN     UINTN                              DataSize,\r
+  IN     VARIABLE_POINTER_TRACK             *Variable,\r
+  IN     UINT32                             Attributes\r
+  );\r
+\r
+/**\r
+  Initializes for authenticated varibale service.\r
+\r
+  @retval EFI_SUCCESS           Function successfully executed.\r
+  @retval EFI_OUT_OF_RESOURCES  Fail to allocate enough memory resource.\r
+\r
+**/\r
+EFI_STATUS\r
+AutenticatedVariableServiceInitialize (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Initializes for cryptlib service before use, include register algrithm and allocate scratch.\r
+\r
+**/\r
+VOID\r
+CryptLibraryInitialize (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Process variable with platform key for verification.\r
+\r
+  @param[in]  VariableName                Name of Variable to be found.\r
+  @param[in]  VendorGuid                  Variable vendor GUID.\r
+  @param[in]  Data                        Data pointer.\r
+  @param[in]  DataSize                    Size of Data found. If size is less than the\r
+                                          data, this value contains the required size.\r
+  @param[in]  Variable                    The variable information which is used to keep track of variable usage.\r
+  @param[in]  Attributes                  Attribute value of the variable.\r
+  @param[in]  IsPk                        Indicate whether it is to process pk.\r
+\r
+  @return EFI_INVALID_PARAMETER           Invalid parameter\r
+  @return EFI_SECURITY_VIOLATION          The variable does NOT pass the validation \r
+                                          check carried out by the firmware. \r
+  @return EFI_SUCCESS                     Variable passed validation successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+ProcessVarWithPk (\r
+  IN  CHAR16                    *VariableName,\r
+  IN  EFI_GUID                  *VendorGuid,\r
+  IN  VOID                      *Data,\r
+  IN  UINTN                     DataSize,\r
+  IN  VARIABLE_POINTER_TRACK    *Variable,\r
+  IN  UINT32                    Attributes OPTIONAL,\r
+  IN  BOOLEAN                   IsPk\r
+  );\r
+\r
+/**\r
+  Process variable with key exchange key for verification.\r
+\r
+  @param[in]  VariableName                Name of Variable to be found.\r
+  @param[in]  VendorGuid                  Variable vendor GUID.\r
+  @param[in]  Data                        Data pointer.\r
+  @param[in]  DataSize                    Size of Data found. If size is less than the\r
+                                          data, this value contains the required size.\r
+  @param[in]  Variable                    The variable information that is used to keep track of variable usage.\r
+  @param[in]  Attributes                  Attribute value of the variable.\r
+\r
+  @return EFI_INVALID_PARAMETER           Invalid parameter.\r
+  @return EFI_SECURITY_VIOLATION          The variable does NOT pass the validation \r
+                                          check carried out by the firmware. \r
+  @return EFI_SUCCESS                     Variable passed validation successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+ProcessVarWithKek (\r
+  IN  CHAR16                    *VariableName,\r
+  IN  EFI_GUID                  *VendorGuid,\r
+  IN  VOID                      *Data,\r
+  IN  UINTN                     DataSize,\r
+  IN  VARIABLE_POINTER_TRACK    *Variable,\r
+  IN  UINT32                    Attributes OPTIONAL\r
+  );\r
+\r
+/**\r
+  Compare two EFI_TIME data.\r
+\r
+\r
+  @param FirstTime           A pointer to the first EFI_TIME data.\r
+  @param SecondTime          A pointer to the second EFI_TIME data.\r
+\r
+  @retval  TRUE              The FirstTime is not later than the SecondTime.\r
+  @retval  FALSE             The FirstTime is later than the SecondTime.\r
+\r
+**/\r
+BOOLEAN\r
+CompareTimeStamp (\r
+  IN EFI_TIME               *FirstTime,\r
+  IN EFI_TIME               *SecondTime\r
+  );\r
+\r
+\r
+/**\r
+  Process variable with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set\r
+\r
+  @param[in]  VariableName                Name of Variable to be found.\r
+  @param[in]  VendorGuid                  Variable vendor GUID.\r
+  @param[in]  Data                        Data pointer.\r
+  @param[in]  DataSize                    Size of Data found. If size is less than the\r
+                                          data, this value contains the required size.\r
+  @param[in]  Variable                    The variable information which is used to keep track of variable usage.\r
+  @param[in]  Attributes                  Attribute value of the variable.\r
+  @param[in]  Pk                          Verify against PK or KEK database.\r
+  @param[out] VarDel                      Delete the variable or not.\r
+\r
+  @retval EFI_INVALID_PARAMETER           Invalid parameter.\r
+  @retval EFI_SECURITY_VIOLATION          The variable does NOT pass the validation \r
+                                          check carried out by the firmware. \r
+  @retval EFI_OUT_OF_RESOURCES            Failed to process variable due to lack\r
+                                          of resources.\r
+  @retval EFI_SUCCESS                     Variable pass validation successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+VerifyTimeBasedPayload (\r
+  IN     CHAR16                             *VariableName,\r
+  IN     EFI_GUID                           *VendorGuid,\r
+  IN     VOID                               *Data,\r
+  IN     UINTN                              DataSize,\r
+  IN     VARIABLE_POINTER_TRACK             *Variable,\r
+  IN     UINT32                             Attributes,\r
+  IN     BOOLEAN                            Pk,\r
+  OUT    BOOLEAN                            *VarDel\r
+  );\r
+\r
+extern UINT8  mPubKeyStore[MAX_KEYDB_SIZE];\r
+extern UINT32 mPubKeyNumber;\r
+extern VOID   *mHashCtx;\r
+extern VOID   *mStorageArea;\r
+  \r
+#endif\r
diff --git a/SecurityPkg/VariableAuthenticated/RuntimeDxe/Reclaim.c b/SecurityPkg/VariableAuthenticated/RuntimeDxe/Reclaim.c
new file mode 100644 (file)
index 0000000..4f7a41c
--- /dev/null
@@ -0,0 +1,172 @@
+/** @file\r
+  Handles non-volatile variable store garbage collection, using FTW\r
+  (Fault Tolerant Write) protocol.\r
+\r
+Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "Variable.h"\r
+\r
+/**\r
+  Gets LBA of block and offset by given address.\r
+\r
+  This function gets the Logical Block Address (LBA) of a firmware\r
+  volume block containing the given address, and the offset of the\r
+  address on the block.\r
+\r
+  @param  Address        Address which should be contained\r
+                         by returned FVB handle.\r
+  @param  Lba            Pointer to LBA for output.\r
+  @param  Offset         Pointer to offset for output.\r
+\r
+  @retval EFI_SUCCESS    LBA and offset successfully returned.\r
+  @retval EFI_NOT_FOUND  Fail to find FVB handle by address.\r
+  @retval EFI_ABORTED    Fail to find valid LBA and offset.\r
+\r
+**/\r
+EFI_STATUS\r
+GetLbaAndOffsetByAddress (\r
+  IN  EFI_PHYSICAL_ADDRESS   Address,\r
+  OUT EFI_LBA                *Lba,\r
+  OUT UINTN                  *Offset\r
+  )\r
+{\r
+  EFI_STATUS                          Status;\r
+  EFI_PHYSICAL_ADDRESS                FvbBaseAddress;\r
+  EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *Fvb;\r
+  EFI_FIRMWARE_VOLUME_HEADER          *FwVolHeader;\r
+  EFI_FV_BLOCK_MAP_ENTRY              *FvbMapEntry;\r
+  UINT32                              LbaIndex;\r
+\r
+  *Lba    = (EFI_LBA) (-1);\r
+  *Offset = 0;\r
+  \r
+  //\r
+  // Get the proper FVB protocol.\r
+  //\r
+  Status = GetFvbInfoByAddress (Address, NULL, &Fvb);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Get the Base Address of FV.\r
+  //\r
+  Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress);\r
+\r
+  //\r
+  // Get the (LBA, Offset) of Address.\r
+  //\r
+  if ((FwVolHeader->FvLength) > (FwVolHeader->HeaderLength)) {\r
+    //\r
+    // BUGBUG: Assume one FV has one type of BlockLength.\r
+    //\r
+    FvbMapEntry = &FwVolHeader->BlockMap[0];\r
+    for (LbaIndex = 1; LbaIndex <= FvbMapEntry->NumBlocks; LbaIndex += 1) {\r
+      if (Address < (FvbBaseAddress + FvbMapEntry->Length * LbaIndex)) {\r
+        //\r
+        // Found the (Lba, Offset).\r
+        //\r
+        *Lba    = LbaIndex - 1;\r
+        *Offset = (UINTN) (Address - (FvbBaseAddress + FvbMapEntry->Length * (LbaIndex - 1)));\r
+        return EFI_SUCCESS;\r
+     }\r
+    }\r
+  }\r
+\r
+  return EFI_ABORTED;\r
+}\r
+\r
+/**\r
+  Writes a buffer to variable storage space, in the working block.\r
+\r
+  This function writes a buffer to variable storage space into a firmware\r
+  volume block device. The destination is specified by parameter\r
+  VariableBase. Fault Tolerant Write protocol is used for writing.\r
+\r
+  @param  VariableBase   Base address of variable to write\r
+  @param  Buffer         Point to the data buffer.\r
+  @param  BufferSize     The number of bytes of the data Buffer.\r
+\r
+  @retval EFI_SUCCESS    The function completed successfully.\r
+  @retval EFI_NOT_FOUND  Fail to locate Fault Tolerant Write protocol.\r
+  @retval EFI_ABORTED    The function could not complete successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+FtwVariableSpace (\r
+  IN EFI_PHYSICAL_ADDRESS   VariableBase,\r
+  IN UINT8                  *Buffer,\r
+  IN UINTN                  BufferSize\r
+  )\r
+{\r
+  EFI_STATUS                         Status;\r
+  EFI_HANDLE                         FvbHandle;\r
+  EFI_LBA                            VarLba;\r
+  UINTN                              VarOffset;\r
+  UINT8                              *FtwBuffer;\r
+  UINTN                              FtwBufferSize;\r
+  EFI_FAULT_TOLERANT_WRITE_PROTOCOL  *FtwProtocol;\r
+\r
+  //\r
+  // Locate fault tolerant write protocol.\r
+  //\r
+  Status = GetFtwProtocol((VOID **) &FtwProtocol);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+  //\r
+  // Locate Fvb handle by address.\r
+  //\r
+  Status = GetFvbInfoByAddress (VariableBase, &FvbHandle, NULL);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Get LBA and Offset by address.\r
+  //\r
+  Status = GetLbaAndOffsetByAddress (VariableBase, &VarLba, &VarOffset);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_ABORTED;\r
+  }\r
+  //\r
+  // Prepare for the variable data.\r
+  //\r
+  FtwBufferSize = ((VARIABLE_STORE_HEADER *) ((UINTN) VariableBase))->Size;\r
+  FtwBuffer     = AllocatePool (FtwBufferSize);\r
+  if (FtwBuffer == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  SetMem (FtwBuffer, FtwBufferSize, (UINT8) 0xff);\r
+  CopyMem (FtwBuffer, Buffer, BufferSize);\r
+\r
+  //\r
+  // FTW write record.\r
+  //\r
+  Status = FtwProtocol->Write (\r
+                          FtwProtocol,\r
+                          VarLba,         // LBA\r
+                          VarOffset,      // Offset\r
+                          FtwBufferSize,  // NumBytes\r
+                          NULL,           // PrivateData NULL\r
+                          FvbHandle,      // Fvb Handle\r
+                          FtwBuffer       // write buffer\r
+                          );\r
+\r
+  FreePool (FtwBuffer);\r
+  return Status;\r
+}\r
diff --git a/SecurityPkg/VariableAuthenticated/RuntimeDxe/Variable.c b/SecurityPkg/VariableAuthenticated/RuntimeDxe/Variable.c
new file mode 100644 (file)
index 0000000..136bafe
--- /dev/null
@@ -0,0 +1,2618 @@
+/** @file\r
+  The common variable operation routines shared by DXE_RINTIME variable \r
+  module and DXE_SMM variable module.\r
+\r
+Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "Variable.h"\r
+#include "AuthService.h"\r
+\r
+VARIABLE_MODULE_GLOBAL  *mVariableModuleGlobal;\r
+\r
+///\r
+/// Define a memory cache that improves the search performance for a variable.\r
+///\r
+VARIABLE_STORE_HEADER  *mNvVariableCache = NULL;\r
+\r
+///\r
+/// The memory entry used for variable statistics data.\r
+///\r
+VARIABLE_INFO_ENTRY    *gVariableInfo    = NULL;\r
+\r
+\r
+/**\r
+  Routine used to track statistical information about variable usage. \r
+  The data is stored in the EFI system table so it can be accessed later.\r
+  VariableInfo.efi can dump out the table. Only Boot Services variable \r
+  accesses are tracked by this code. The PcdVariableCollectStatistics\r
+  build flag controls if this feature is enabled. \r
+\r
+  A read that hits in the cache will have Read and Cache true for \r
+  the transaction. Data is allocated by this routine, but never\r
+  freed.\r
+\r
+  @param[in] VariableName   Name of the Variable to track.\r
+  @param[in] VendorGuid     Guid of the Variable to track.\r
+  @param[in] Volatile       TRUE if volatile FALSE if non-volatile.\r
+  @param[in] Read           TRUE if GetVariable() was called.\r
+  @param[in] Write          TRUE if SetVariable() was called.\r
+  @param[in] Delete         TRUE if deleted via SetVariable().\r
+  @param[in] Cache          TRUE for a cache hit.\r
+\r
+**/\r
+VOID\r
+UpdateVariableInfo (\r
+  IN  CHAR16                  *VariableName,\r
+  IN  EFI_GUID                *VendorGuid,\r
+  IN  BOOLEAN                 Volatile,\r
+  IN  BOOLEAN                 Read,\r
+  IN  BOOLEAN                 Write,\r
+  IN  BOOLEAN                 Delete,\r
+  IN  BOOLEAN                 Cache\r
+  )\r
+{\r
+  VARIABLE_INFO_ENTRY   *Entry;\r
+\r
+  if (FeaturePcdGet (PcdVariableCollectStatistics)) {\r
+\r
+    if (AtRuntime ()) {\r
+      // Don't collect statistics at runtime.\r
+      return;\r
+    }\r
+\r
+    if (gVariableInfo == NULL) {\r
+      //\r
+      // On the first call allocate a entry and place a pointer to it in\r
+      // the EFI System Table.\r
+      //\r
+      gVariableInfo = AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY));\r
+      ASSERT (gVariableInfo != NULL);\r
+\r
+      CopyGuid (&gVariableInfo->VendorGuid, VendorGuid);\r
+      gVariableInfo->Name = AllocatePool (StrSize (VariableName));\r
+      ASSERT (gVariableInfo->Name != NULL);\r
+      StrCpy (gVariableInfo->Name, VariableName);\r
+      gVariableInfo->Volatile = Volatile;\r
+    }\r
+\r
+    \r
+    for (Entry = gVariableInfo; Entry != NULL; Entry = Entry->Next) {\r
+      if (CompareGuid (VendorGuid, &Entry->VendorGuid)) {\r
+        if (StrCmp (VariableName, Entry->Name) == 0) {\r
+          if (Read) {\r
+            Entry->ReadCount++;\r
+          }\r
+          if (Write) {\r
+            Entry->WriteCount++;\r
+          }\r
+          if (Delete) {\r
+            Entry->DeleteCount++;\r
+          }\r
+          if (Cache) {\r
+            Entry->CacheCount++;\r
+          }\r
+\r
+          return;\r
+        }\r
+      }\r
+\r
+      if (Entry->Next == NULL) {\r
+        //\r
+        // If the entry is not in the table add it.\r
+        // Next iteration of the loop will fill in the data.\r
+        //\r
+        Entry->Next = AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY));\r
+        ASSERT (Entry->Next != NULL);\r
+\r
+        CopyGuid (&Entry->Next->VendorGuid, VendorGuid);\r
+        Entry->Next->Name = AllocatePool (StrSize (VariableName));\r
+        ASSERT (Entry->Next->Name != NULL);\r
+        StrCpy (Entry->Next->Name, VariableName);\r
+        Entry->Next->Volatile = Volatile;\r
+      }\r
+\r
+    }\r
+  }\r
+}\r
+\r
+\r
+/**\r
+\r
+  This code checks if variable header is valid or not.\r
+\r
+  @param Variable        Pointer to the Variable Header.\r
+\r
+  @retval TRUE           Variable header is valid.\r
+  @retval FALSE          Variable header is not valid.\r
+\r
+**/\r
+BOOLEAN\r
+IsValidVariableHeader (\r
+  IN  VARIABLE_HEADER   *Variable\r
+  )\r
+{\r
+  if (Variable == NULL || Variable->StartId != VARIABLE_DATA) {\r
+    return FALSE;\r
+  }\r
+\r
+  return TRUE;\r
+}\r
+\r
+\r
+/**\r
+\r
+  This function writes data to the FWH at the correct LBA even if the LBAs\r
+  are fragmented.\r
+\r
+  @param Global                  Pointer to VARAIBLE_GLOBAL structure.\r
+  @param Volatile                Point out the Variable is Volatile or Non-Volatile.\r
+  @param SetByIndex              TRUE if target pointer is given as index.\r
+                                 FALSE if target pointer is absolute.\r
+  @param Fvb                     Pointer to the writable FVB protocol.\r
+  @param DataPtrIndex            Pointer to the Data from the end of VARIABLE_STORE_HEADER\r
+                                 structure.\r
+  @param DataSize                Size of data to be written.\r
+  @param Buffer                  Pointer to the buffer from which data is written.\r
+\r
+  @retval EFI_INVALID_PARAMETER  Parameters not valid.\r
+  @retval EFI_SUCCESS            Variable store successfully updated.\r
+\r
+**/\r
+EFI_STATUS\r
+UpdateVariableStore (\r
+  IN  VARIABLE_GLOBAL                     *Global,\r
+  IN  BOOLEAN                             Volatile,\r
+  IN  BOOLEAN                             SetByIndex,\r
+  IN  EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *Fvb,\r
+  IN  UINTN                               DataPtrIndex,\r
+  IN  UINT32                              DataSize,\r
+  IN  UINT8                               *Buffer\r
+  )\r
+{\r
+  EFI_FV_BLOCK_MAP_ENTRY      *PtrBlockMapEntry;\r
+  UINTN                       BlockIndex2;\r
+  UINTN                       LinearOffset;\r
+  UINTN                       CurrWriteSize;\r
+  UINTN                       CurrWritePtr;\r
+  UINT8                       *CurrBuffer;\r
+  EFI_LBA                     LbaNumber;\r
+  UINTN                       Size;\r
+  EFI_FIRMWARE_VOLUME_HEADER  *FwVolHeader;\r
+  VARIABLE_STORE_HEADER       *VolatileBase;\r
+  EFI_PHYSICAL_ADDRESS        FvVolHdr;\r
+  EFI_PHYSICAL_ADDRESS        DataPtr;\r
+  EFI_STATUS                  Status;\r
+\r
+  FwVolHeader = NULL;\r
+  DataPtr     = DataPtrIndex;\r
+\r
+  //\r
+  // Check if the Data is Volatile.\r
+  //\r
+  if (!Volatile) {\r
+    ASSERT (Fvb != NULL);\r
+    Status = Fvb->GetPhysicalAddress(Fvb, &FvVolHdr);\r
+    ASSERT_EFI_ERROR (Status);\r
+\r
+    FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvVolHdr);\r
+    //\r
+    // Data Pointer should point to the actual Address where data is to be\r
+    // written.\r
+    //\r
+    if (SetByIndex) {\r
+      DataPtr += mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;\r
+    }\r
+\r
+    if ((DataPtr + DataSize) >= ((EFI_PHYSICAL_ADDRESS) (UINTN) ((UINT8 *) FwVolHeader + FwVolHeader->FvLength))) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+  } else {\r
+    //\r
+    // Data Pointer should point to the actual Address where data is to be\r
+    // written.\r
+    //\r
+    VolatileBase = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);\r
+    if (SetByIndex) {\r
+      DataPtr += mVariableModuleGlobal->VariableGlobal.VolatileVariableBase;\r
+    }\r
+\r
+    if ((DataPtr + DataSize) >= ((UINTN) ((UINT8 *) VolatileBase + VolatileBase->Size))) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+    \r
+    //\r
+    // If Volatile Variable just do a simple mem copy.\r
+    //    \r
+    CopyMem ((UINT8 *)(UINTN)DataPtr, Buffer, DataSize);\r
+    return EFI_SUCCESS;\r
+  }\r
+  \r
+  //\r
+  // If we are here we are dealing with Non-Volatile Variables.\r
+  //\r
+  LinearOffset  = (UINTN) FwVolHeader;\r
+  CurrWritePtr  = (UINTN) DataPtr;\r
+  CurrWriteSize = DataSize;\r
+  CurrBuffer    = Buffer;\r
+  LbaNumber     = 0;\r
+\r
+  if (CurrWritePtr < LinearOffset) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  for (PtrBlockMapEntry = FwVolHeader->BlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) {\r
+    for (BlockIndex2 = 0; BlockIndex2 < PtrBlockMapEntry->NumBlocks; BlockIndex2++) {\r
+      //\r
+      // Check to see if the Variable Writes are spanning through multiple\r
+      // blocks.\r
+      //\r
+      if ((CurrWritePtr >= LinearOffset) && (CurrWritePtr < LinearOffset + PtrBlockMapEntry->Length)) {\r
+        if ((CurrWritePtr + CurrWriteSize) <= (LinearOffset + PtrBlockMapEntry->Length)) {\r
+          Status = Fvb->Write (\r
+                    Fvb,\r
+                    LbaNumber,\r
+                    (UINTN) (CurrWritePtr - LinearOffset),\r
+                    &CurrWriteSize,\r
+                    CurrBuffer\r
+                    );\r
+          return Status;\r
+        } else {\r
+          Size = (UINT32) (LinearOffset + PtrBlockMapEntry->Length - CurrWritePtr);\r
+          Status = Fvb->Write (\r
+                    Fvb,\r
+                    LbaNumber,\r
+                    (UINTN) (CurrWritePtr - LinearOffset),\r
+                    &Size,\r
+                    CurrBuffer\r
+                    );\r
+          if (EFI_ERROR (Status)) {\r
+            return Status;\r
+          }\r
+\r
+          CurrWritePtr  = LinearOffset + PtrBlockMapEntry->Length;\r
+          CurrBuffer    = CurrBuffer + Size;\r
+          CurrWriteSize = CurrWriteSize - Size;\r
+        }\r
+      }\r
+\r
+      LinearOffset += PtrBlockMapEntry->Length;\r
+      LbaNumber++;\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+\r
+  This code gets the current status of Variable Store.\r
+\r
+  @param VarStoreHeader  Pointer to the Variable Store Header.\r
+\r
+  @retval EfiRaw         Variable store status is raw.\r
+  @retval EfiValid       Variable store status is valid.\r
+  @retval EfiInvalid     Variable store status is invalid.\r
+\r
+**/\r
+VARIABLE_STORE_STATUS\r
+GetVariableStoreStatus (\r
+  IN VARIABLE_STORE_HEADER *VarStoreHeader\r
+  )\r
+{\r
+  if (CompareGuid (&VarStoreHeader->Signature, &gEfiAuthenticatedVariableGuid) &&\r
+      VarStoreHeader->Format == VARIABLE_STORE_FORMATTED &&\r
+      VarStoreHeader->State == VARIABLE_STORE_HEALTHY\r
+      ) {\r
+\r
+    return EfiValid;\r
+  } else if (((UINT32 *)(&VarStoreHeader->Signature))[0] == 0xffffffff &&\r
+             ((UINT32 *)(&VarStoreHeader->Signature))[1] == 0xffffffff &&\r
+             ((UINT32 *)(&VarStoreHeader->Signature))[2] == 0xffffffff &&\r
+             ((UINT32 *)(&VarStoreHeader->Signature))[3] == 0xffffffff &&\r
+             VarStoreHeader->Size == 0xffffffff &&\r
+             VarStoreHeader->Format == 0xff &&\r
+             VarStoreHeader->State == 0xff\r
+          ) {\r
+\r
+    return EfiRaw;\r
+  } else {\r
+    return EfiInvalid;\r
+  }\r
+}\r
+\r
+\r
+/**\r
+\r
+  This code gets the size of name of variable.\r
+\r
+  @param Variable        Pointer to the Variable Header.\r
+\r
+  @return UINTN          Size of variable in bytes.\r
+\r
+**/\r
+UINTN\r
+NameSizeOfVariable (\r
+  IN  VARIABLE_HEADER   *Variable\r
+  )\r
+{\r
+  if (Variable->State    == (UINT8) (-1) ||\r
+      Variable->DataSize == (UINT32) (-1) ||\r
+      Variable->NameSize == (UINT32) (-1) ||\r
+      Variable->Attributes == (UINT32) (-1)) {\r
+    return 0;\r
+  }\r
+  return (UINTN) Variable->NameSize;\r
+}\r
+\r
+/**\r
+\r
+  This code gets the size of variable data.\r
+\r
+  @param Variable        Pointer to the Variable Header.\r
+\r
+  @return Size of variable in bytes.\r
+\r
+**/\r
+UINTN\r
+DataSizeOfVariable (\r
+  IN  VARIABLE_HEADER   *Variable\r
+  )\r
+{\r
+  if (Variable->State    == (UINT8)  (-1) ||\r
+      Variable->DataSize == (UINT32) (-1) ||\r
+      Variable->NameSize == (UINT32) (-1) ||\r
+      Variable->Attributes == (UINT32) (-1)) {\r
+    return 0;\r
+  }\r
+  return (UINTN) Variable->DataSize;\r
+}\r
+\r
+/**\r
+\r
+  This code gets the pointer to the variable name.\r
+\r
+  @param Variable        Pointer to the Variable Header.\r
+\r
+  @return Pointer to Variable Name which is Unicode encoding.\r
+\r
+**/\r
+CHAR16 *\r
+GetVariableNamePtr (\r
+  IN  VARIABLE_HEADER   *Variable\r
+  )\r
+{\r
+\r
+  return (CHAR16 *) (Variable + 1);\r
+}\r
+\r
+/**\r
+\r
+  This code gets the pointer to the variable data.\r
+\r
+  @param Variable        Pointer to the Variable Header.\r
+\r
+  @return Pointer to Variable Data.\r
+\r
+**/\r
+UINT8 *\r
+GetVariableDataPtr (\r
+  IN  VARIABLE_HEADER   *Variable\r
+  )\r
+{\r
+  UINTN Value;\r
+  \r
+  //\r
+  // Be careful about pad size for alignment.\r
+  //\r
+  Value =  (UINTN) GetVariableNamePtr (Variable);\r
+  Value += NameSizeOfVariable (Variable);\r
+  Value += GET_PAD_SIZE (NameSizeOfVariable (Variable));\r
+\r
+  return (UINT8 *) Value;\r
+}\r
+\r
+\r
+/**\r
+\r
+  This code gets the pointer to the next variable header.\r
+\r
+  @param Variable        Pointer to the Variable Header.\r
+\r
+  @return Pointer to next variable header.\r
+\r
+**/\r
+VARIABLE_HEADER *\r
+GetNextVariablePtr (\r
+  IN  VARIABLE_HEADER   *Variable\r
+  )\r
+{\r
+  UINTN Value;\r
+\r
+  if (!IsValidVariableHeader (Variable)) {\r
+    return NULL;\r
+  }\r
+\r
+  Value =  (UINTN) GetVariableDataPtr (Variable);\r
+  Value += DataSizeOfVariable (Variable);\r
+  Value += GET_PAD_SIZE (DataSizeOfVariable (Variable));\r
+\r
+  //\r
+  // Be careful about pad size for alignment.\r
+  //\r
+  return (VARIABLE_HEADER *) HEADER_ALIGN (Value);\r
+}\r
+\r
+/**\r
+\r
+  Gets the pointer to the first variable header in given variable store area.\r
+\r
+  @param VarStoreHeader  Pointer to the Variable Store Header.\r
+\r
+  @return Pointer to the first variable header.\r
+\r
+**/\r
+VARIABLE_HEADER *\r
+GetStartPointer (\r
+  IN VARIABLE_STORE_HEADER       *VarStoreHeader\r
+  )\r
+{\r
+  //\r
+  // The end of variable store.\r
+  //\r
+  return (VARIABLE_HEADER *) HEADER_ALIGN (VarStoreHeader + 1);\r
+}\r
+\r
+/**\r
+\r
+  Gets the pointer to the end of the variable storage area.\r
+\r
+  This function gets pointer to the end of the variable storage\r
+  area, according to the input variable store header.\r
+\r
+  @param VarStoreHeader  Pointer to the Variable Store Header.\r
+\r
+  @return Pointer to the end of the variable storage area. \r
+\r
+**/\r
+VARIABLE_HEADER *\r
+GetEndPointer (\r
+  IN VARIABLE_STORE_HEADER       *VarStoreHeader\r
+  )\r
+{\r
+  //\r
+  // The end of variable store\r
+  //\r
+  return (VARIABLE_HEADER *) HEADER_ALIGN ((UINTN) VarStoreHeader + VarStoreHeader->Size);\r
+}\r
+\r
+\r
+/**\r
+\r
+  Variable store garbage collection and reclaim operation.\r
+\r
+  @param VariableBase            Base address of variable store.\r
+  @param LastVariableOffset      Offset of last variable.\r
+  @param IsVolatile              The variable store is volatile or not;\r
+                                 if it is non-volatile, need FTW.\r
+  @param UpdatingVariable        Pointer to updating variable.\r
+\r
+  @return EFI_OUT_OF_RESOURCES\r
+  @return EFI_SUCCESS\r
+  @return Others\r
+\r
+**/\r
+EFI_STATUS\r
+Reclaim (\r
+  IN  EFI_PHYSICAL_ADDRESS  VariableBase,\r
+  OUT UINTN                 *LastVariableOffset,\r
+  IN  BOOLEAN               IsVolatile,\r
+  IN  VARIABLE_HEADER       *UpdatingVariable\r
+  )\r
+{\r
+  VARIABLE_HEADER       *Variable;\r
+  VARIABLE_HEADER       *AddedVariable;\r
+  VARIABLE_HEADER       *NextVariable;\r
+  VARIABLE_HEADER       *NextAddedVariable;\r
+  VARIABLE_STORE_HEADER *VariableStoreHeader;\r
+  UINT8                 *ValidBuffer;\r
+  UINTN                 MaximumBufferSize;\r
+  UINTN                 VariableSize;\r
+  UINTN                 VariableNameSize;\r
+  UINTN                 UpdatingVariableNameSize;\r
+  UINTN                 NameSize;\r
+  UINT8                 *CurrPtr;\r
+  VOID                  *Point0;\r
+  VOID                  *Point1;\r
+  BOOLEAN               FoundAdded;\r
+  EFI_STATUS            Status;\r
+  CHAR16                *VariableNamePtr;\r
+  CHAR16                *UpdatingVariableNamePtr;\r
+\r
+  VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) VariableBase);\r
+  //\r
+  // Recalculate the total size of Common/HwErr type variables in non-volatile area.\r
+  //\r
+  if (!IsVolatile) {\r
+    mVariableModuleGlobal->CommonVariableTotalSize = 0;\r
+    mVariableModuleGlobal->HwErrVariableTotalSize  = 0;\r
+  }\r
+\r
+  //\r
+  // Start Pointers for the variable.\r
+  //\r
+  Variable          = GetStartPointer (VariableStoreHeader);\r
+  MaximumBufferSize = sizeof (VARIABLE_STORE_HEADER);\r
+\r
+  while (IsValidVariableHeader (Variable)) {\r
+    NextVariable = GetNextVariablePtr (Variable);\r
+    if (Variable->State == VAR_ADDED || \r
+        Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)\r
+       ) {\r
+      VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r
+      MaximumBufferSize += VariableSize;\r
+    }\r
+\r
+    Variable = NextVariable;\r
+  }\r
+\r
+  //\r
+  // Reserve the 1 Bytes with Oxff to identify the \r
+  // end of the variable buffer. \r
+  // \r
+  MaximumBufferSize += 1;\r
+  ValidBuffer = AllocatePool (MaximumBufferSize);\r
+  if (ValidBuffer == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  SetMem (ValidBuffer, MaximumBufferSize, 0xff);\r
+\r
+  //\r
+  // Copy variable store header.\r
+  //\r
+  CopyMem (ValidBuffer, VariableStoreHeader, sizeof (VARIABLE_STORE_HEADER));\r
+  CurrPtr = (UINT8 *) GetStartPointer ((VARIABLE_STORE_HEADER *) ValidBuffer);\r
+\r
+  //\r
+  // Reinstall all ADDED variables as long as they are not identical to Updating Variable.\r
+  // \r
+  Variable = GetStartPointer (VariableStoreHeader);\r
+  while (IsValidVariableHeader (Variable)) {\r
+    NextVariable = GetNextVariablePtr (Variable);\r
+    if (Variable->State == VAR_ADDED) {\r
+      if (UpdatingVariable != NULL) {\r
+        if (UpdatingVariable == Variable) {\r
+          Variable = NextVariable;\r
+          continue;\r
+        }\r
+\r
+        VariableNameSize         = NameSizeOfVariable(Variable);\r
+        UpdatingVariableNameSize = NameSizeOfVariable(UpdatingVariable);\r
+\r
+        VariableNamePtr         = GetVariableNamePtr (Variable);\r
+        UpdatingVariableNamePtr = GetVariableNamePtr (UpdatingVariable);\r
+        if (CompareGuid (&Variable->VendorGuid, &UpdatingVariable->VendorGuid)    &&\r
+            VariableNameSize == UpdatingVariableNameSize &&\r
+            CompareMem (VariableNamePtr, UpdatingVariableNamePtr, VariableNameSize) == 0 ) {\r
+          Variable = NextVariable;\r
+          continue;\r
+        }\r
+      }\r
+      VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r
+      CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize);\r
+      CurrPtr += VariableSize;\r
+      if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
+        mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize;\r
+      } else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
+        mVariableModuleGlobal->CommonVariableTotalSize += VariableSize;\r
+      }\r
+    }\r
+    Variable = NextVariable;\r
+  }\r
+\r
+  //\r
+  // Reinstall the variable being updated if it is not NULL.\r
+  //\r
+  if (UpdatingVariable != NULL) {\r
+    VariableSize = (UINTN)(GetNextVariablePtr (UpdatingVariable)) - (UINTN)UpdatingVariable;\r
+    CopyMem (CurrPtr, (UINT8 *) UpdatingVariable, VariableSize);\r
+    CurrPtr += VariableSize;\r
+    if ((!IsVolatile) && ((UpdatingVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
+        mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize;\r
+    } else if ((!IsVolatile) && ((UpdatingVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
+        mVariableModuleGlobal->CommonVariableTotalSize += VariableSize;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Reinstall all in delete transition variables.\r
+  // \r
+  Variable      = GetStartPointer (VariableStoreHeader);\r
+  while (IsValidVariableHeader (Variable)) {\r
+    NextVariable = GetNextVariablePtr (Variable);\r
+    if (Variable != UpdatingVariable && Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
+\r
+      //\r
+      // Buffer has cached all ADDED variable. \r
+      // Per IN_DELETED variable, we have to guarantee that\r
+      // no ADDED one in previous buffer. \r
+      // \r
+     \r
+      FoundAdded = FALSE;\r
+      AddedVariable = GetStartPointer ((VARIABLE_STORE_HEADER *) ValidBuffer);\r
+      while (IsValidVariableHeader (AddedVariable)) {\r
+        NextAddedVariable = GetNextVariablePtr (AddedVariable);\r
+        NameSize = NameSizeOfVariable (AddedVariable);\r
+        if (CompareGuid (&AddedVariable->VendorGuid, &Variable->VendorGuid) &&\r
+            NameSize == NameSizeOfVariable (Variable)\r
+           ) {\r
+          Point0 = (VOID *) GetVariableNamePtr (AddedVariable);\r
+          Point1 = (VOID *) GetVariableNamePtr (Variable);\r
+          if (CompareMem (Point0, Point1, NameSizeOfVariable (AddedVariable)) == 0) {\r
+            FoundAdded = TRUE;\r
+            break;\r
+          }\r
+        }\r
+        AddedVariable = NextAddedVariable;\r
+      }\r
+      if (!FoundAdded) {\r
+        //\r
+        // Promote VAR_IN_DELETED_TRANSITION to VAR_ADDED.\r
+        //\r
+        VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r
+        CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize);\r
+        ((VARIABLE_HEADER *) CurrPtr)->State = VAR_ADDED;\r
+        CurrPtr += VariableSize;\r
+        if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
+          mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize;\r
+        } else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
+          mVariableModuleGlobal->CommonVariableTotalSize += VariableSize;\r
+        }\r
+      }\r
+    }\r
+\r
+    Variable = NextVariable;\r
+  }\r
+\r
+  if (IsVolatile) {\r
+    //\r
+    // If volatile variable store, just copy valid buffer.\r
+    //\r
+    SetMem ((UINT8 *) (UINTN) VariableBase, VariableStoreHeader->Size, 0xff);\r
+    CopyMem ((UINT8 *) (UINTN) VariableBase, ValidBuffer, (UINTN) (CurrPtr - (UINT8 *) ValidBuffer));\r
+    Status  = EFI_SUCCESS;\r
+  } else {\r
+    //\r
+    // If non-volatile variable store, perform FTW here.\r
+    //\r
+    Status = FtwVariableSpace (\r
+              VariableBase,\r
+              ValidBuffer,\r
+              (UINTN) (CurrPtr - (UINT8 *) ValidBuffer)\r
+              );\r
+    CopyMem (mNvVariableCache, (CHAR8 *)(UINTN)VariableBase, VariableStoreHeader->Size);\r
+  }\r
+  if (!EFI_ERROR (Status)) {\r
+    *LastVariableOffset = (UINTN) (CurrPtr - (UINT8 *) ValidBuffer);\r
+  } else {\r
+    *LastVariableOffset = 0;\r
+  }\r
+\r
+  FreePool (ValidBuffer);\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Finds variable in storage blocks of volatile and non-volatile storage areas.\r
+\r
+  This code finds variable in storage blocks of volatile and non-volatile storage areas.\r
+  If VariableName is an empty string, then we just return the first\r
+  qualified variable without comparing VariableName and VendorGuid.\r
+  Otherwise, VariableName and VendorGuid are compared.\r
+\r
+  @param  VariableName                Name of the variable to be found.\r
+  @param  VendorGuid                  Vendor GUID to be found.\r
+  @param  PtrTrack                    VARIABLE_POINTER_TRACK structure for output,\r
+                                      including the range searched and the target position.\r
+  @param  Global                      Pointer to VARIABLE_GLOBAL structure, including\r
+                                      base of volatile variable storage area, base of\r
+                                      NV variable storage area, and a lock.\r
+\r
+  @retval EFI_INVALID_PARAMETER       If VariableName is not an empty string, while\r
+                                      VendorGuid is NULL.\r
+  @retval EFI_SUCCESS                 Variable successfully found.\r
+  @retval EFI_NOT_FOUND               Variable not found\r
+\r
+**/\r
+EFI_STATUS\r
+FindVariable (\r
+  IN  CHAR16                  *VariableName,\r
+  IN  EFI_GUID                *VendorGuid,\r
+  OUT VARIABLE_POINTER_TRACK  *PtrTrack,\r
+  IN  VARIABLE_GLOBAL         *Global\r
+  )\r
+{\r
+  VARIABLE_HEADER         *Variable[2];\r
+  VARIABLE_HEADER         *InDeletedVariable;\r
+  VARIABLE_STORE_HEADER   *VariableStoreHeader[2];\r
+  UINTN                   InDeletedStorageIndex;\r
+  UINTN                   Index;\r
+  VOID                    *Point;\r
+\r
+  //\r
+  // 0: Volatile, 1: Non-Volatile.\r
+  // The index and attributes mapping must be kept in this order as RuntimeServiceGetNextVariableName\r
+  // make use of this mapping to implement search algorithm.\r
+  //\r
+  VariableStoreHeader[0]  = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);\r
+  VariableStoreHeader[1]  = mNvVariableCache;\r
+\r
+  //\r
+  // Start Pointers for the variable.\r
+  // Actual Data Pointer where data can be written.\r
+  //\r
+  Variable[0] = GetStartPointer (VariableStoreHeader[0]);\r
+  Variable[1] = GetStartPointer (VariableStoreHeader[1]);\r
+\r
+  if (VariableName[0] != 0 && VendorGuid == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // Find the variable by walk through volatile and then non-volatile variable store.\r
+  //\r
+  InDeletedVariable     = NULL;\r
+  InDeletedStorageIndex = 0;\r
+  for (Index = 0; Index < 2; Index++) {\r
+    while ((Variable[Index] < GetEndPointer (VariableStoreHeader[Index])) && IsValidVariableHeader (Variable[Index])) {\r
+      if (Variable[Index]->State == VAR_ADDED || \r
+          Variable[Index]->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)\r
+         ) {\r
+        if (!AtRuntime () || ((Variable[Index]->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) != 0)) {\r
+          if (VariableName[0] == 0) {\r
+            if (Variable[Index]->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
+              InDeletedVariable     = Variable[Index];\r
+              InDeletedStorageIndex = Index;\r
+            } else {\r
+              PtrTrack->StartPtr  = GetStartPointer (VariableStoreHeader[Index]);\r
+              PtrTrack->EndPtr    = GetEndPointer (VariableStoreHeader[Index]);\r
+              PtrTrack->CurrPtr   = Variable[Index];\r
+              PtrTrack->Volatile  = (BOOLEAN)(Index == 0);\r
+\r
+              return EFI_SUCCESS;\r
+            }\r
+          } else {\r
+            if (CompareGuid (VendorGuid, &Variable[Index]->VendorGuid)) {\r
+              Point = (VOID *) GetVariableNamePtr (Variable[Index]);\r
+\r
+              ASSERT (NameSizeOfVariable (Variable[Index]) != 0);\r
+              if (CompareMem (VariableName, Point, NameSizeOfVariable (Variable[Index])) == 0) {\r
+                if (Variable[Index]->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
+                  InDeletedVariable     = Variable[Index];\r
+                  InDeletedStorageIndex = Index;\r
+                } else {\r
+                  PtrTrack->StartPtr  = GetStartPointer (VariableStoreHeader[Index]);\r
+                  PtrTrack->EndPtr    = GetEndPointer (VariableStoreHeader[Index]);\r
+                  PtrTrack->CurrPtr   = Variable[Index];\r
+                  PtrTrack->Volatile  = (BOOLEAN)(Index == 0);\r
+\r
+                  return EFI_SUCCESS;\r
+                }\r
+              }\r
+            }\r
+          }\r
+        }\r
+      }\r
+\r
+      Variable[Index] = GetNextVariablePtr (Variable[Index]);\r
+    }\r
+    if (InDeletedVariable != NULL) {\r
+      PtrTrack->StartPtr  = GetStartPointer (VariableStoreHeader[InDeletedStorageIndex]);\r
+      PtrTrack->EndPtr    = GetEndPointer (VariableStoreHeader[InDeletedStorageIndex]);\r
+      PtrTrack->CurrPtr   = InDeletedVariable;\r
+      PtrTrack->Volatile  = (BOOLEAN)(InDeletedStorageIndex == 0);\r
+      return EFI_SUCCESS;\r
+    }\r
+  }\r
+  PtrTrack->CurrPtr = NULL;\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+/**\r
+  Get index from supported language codes according to language string.\r
+\r
+  This code is used to get corresponding index in supported language codes. It can handle\r
+  RFC4646 and ISO639 language tags.\r
+  In ISO639 language tags, take 3-characters as a delimitation to find matched string and calculate the index.\r
+  In RFC4646 language tags, take semicolon as a delimitation to find matched string and calculate the index.\r
+\r
+  For example:\r
+    SupportedLang  = "engfraengfra"\r
+    Lang           = "eng"\r
+    Iso639Language = TRUE\r
+  The return value is "0".\r
+  Another example:\r
+    SupportedLang  = "en;fr;en-US;fr-FR"\r
+    Lang           = "fr-FR"\r
+    Iso639Language = FALSE\r
+  The return value is "3".\r
+\r
+  @param  SupportedLang               Platform supported language codes.\r
+  @param  Lang                        Configured language.\r
+  @param  Iso639Language              A bool value to signify if the handler is operated on ISO639 or RFC4646.\r
+\r
+  @retval The index of language in the language codes.\r
+\r
+**/\r
+UINTN\r
+GetIndexFromSupportedLangCodes(\r
+  IN  CHAR8            *SupportedLang,\r
+  IN  CHAR8            *Lang,\r
+  IN  BOOLEAN          Iso639Language\r
+  ) \r
+{\r
+  UINTN    Index;\r
+  UINTN    CompareLength;\r
+  UINTN    LanguageLength;\r
+\r
+  if (Iso639Language) {\r
+    CompareLength = ISO_639_2_ENTRY_SIZE;\r
+    for (Index = 0; Index < AsciiStrLen (SupportedLang); Index += CompareLength) {\r
+      if (AsciiStrnCmp (Lang, SupportedLang + Index, CompareLength) == 0) {\r
+        //\r
+        // Successfully find the index of Lang string in SupportedLang string.\r
+        //\r
+        Index = Index / CompareLength;\r
+        return Index;\r
+      }\r
+    }\r
+    ASSERT (FALSE);\r
+    return 0;\r
+  } else {\r
+    //\r
+    // Compare RFC4646 language code\r
+    //\r
+    Index = 0;\r
+    for (LanguageLength = 0; Lang[LanguageLength] != '\0'; LanguageLength++);\r
+\r
+    for (Index = 0; *SupportedLang != '\0'; Index++, SupportedLang += CompareLength) {\r
+      //\r
+      // Skip ';' characters in SupportedLang\r
+      //\r
+      for (; *SupportedLang != '\0' && *SupportedLang == ';'; SupportedLang++);\r
+      //\r
+      // Determine the length of the next language code in SupportedLang\r
+      //\r
+      for (CompareLength = 0; SupportedLang[CompareLength] != '\0' && SupportedLang[CompareLength] != ';'; CompareLength++);\r
+      \r
+      if ((CompareLength == LanguageLength) && \r
+          (AsciiStrnCmp (Lang, SupportedLang, CompareLength) == 0)) {\r
+        //\r
+        // Successfully find the index of Lang string in SupportedLang string.\r
+        //\r
+        return Index;\r
+      }\r
+    }\r
+    ASSERT (FALSE);\r
+    return 0;\r
+  }\r
+}\r
+\r
+/**\r
+  Get language string from supported language codes according to index.\r
+\r
+  This code is used to get corresponding language strings in supported language codes. It can handle\r
+  RFC4646 and ISO639 language tags.\r
+  In ISO639 language tags, take 3-characters as a delimitation. Find language string according to the index.\r
+  In RFC4646 language tags, take semicolon as a delimitation. Find language string according to the index.\r
+\r
+  For example:\r
+    SupportedLang  = "engfraengfra"\r
+    Index          = "1"\r
+    Iso639Language = TRUE\r
+  The return value is "fra".\r
+  Another example:\r
+    SupportedLang  = "en;fr;en-US;fr-FR"\r
+    Index          = "1"\r
+    Iso639Language = FALSE\r
+  The return value is "fr".\r
+\r
+  @param  SupportedLang               Platform supported language codes.\r
+  @param  Index                       The index in supported language codes.\r
+  @param  Iso639Language              A bool value to signify if the handler is operated on ISO639 or RFC4646.\r
+\r
+  @retval The language string in the language codes.\r
+\r
+**/\r
+CHAR8 *\r
+GetLangFromSupportedLangCodes (\r
+  IN  CHAR8            *SupportedLang,\r
+  IN  UINTN            Index,\r
+  IN  BOOLEAN          Iso639Language\r
+)\r
+{\r
+  UINTN    SubIndex;\r
+  UINTN    CompareLength;\r
+  CHAR8    *Supported;\r
+\r
+  SubIndex  = 0;\r
+  Supported = SupportedLang;\r
+  if (Iso639Language) {\r
+    //\r
+    // According to the index of Lang string in SupportedLang string to get the language.\r
+    // This code will be invoked in RUNTIME, therefore there is not a memory allocate/free operation.\r
+    // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.\r
+    //\r
+    CompareLength = ISO_639_2_ENTRY_SIZE;\r
+    mVariableModuleGlobal->Lang[CompareLength] = '\0';\r
+    return CopyMem (mVariableModuleGlobal->Lang, SupportedLang + Index * CompareLength, CompareLength);\r
+      \r
+  } else {\r
+    while (TRUE) {\r
+      //\r
+      // Take semicolon as delimitation, sequentially traverse supported language codes.\r
+      //\r
+      for (CompareLength = 0; *Supported != ';' && *Supported != '\0'; CompareLength++) {\r
+        Supported++;\r
+      }\r
+      if ((*Supported == '\0') && (SubIndex != Index)) {\r
+        //\r
+        // Have completed the traverse, but not find corrsponding string.\r
+        // This case is not allowed to happen.\r
+        //\r
+        ASSERT(FALSE);\r
+        return NULL;\r
+      }\r
+      if (SubIndex == Index) {\r
+        //\r
+        // According to the index of Lang string in SupportedLang string to get the language.\r
+        // As this code will be invoked in RUNTIME, therefore there is not memory allocate/free operation.\r
+        // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.\r
+        //\r
+        mVariableModuleGlobal->PlatformLang[CompareLength] = '\0';\r
+        return CopyMem (mVariableModuleGlobal->PlatformLang, Supported - CompareLength, CompareLength);\r
+      }\r
+      SubIndex++;\r
+\r
+      //\r
+      // Skip ';' characters in Supported\r
+      //\r
+      for (; *Supported != '\0' && *Supported == ';'; Supported++);\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+  Returns a pointer to an allocated buffer that contains the best matching language \r
+  from a set of supported languages.  \r
+  \r
+  This function supports both ISO 639-2 and RFC 4646 language codes, but language \r
+  code types may not be mixed in a single call to this function. This function\r
+  supports a variable argument list that allows the caller to pass in a prioritized\r
+  list of language codes to test against all the language codes in SupportedLanguages.\r
+\r
+  If SupportedLanguages is NULL, then ASSERT().\r
+\r
+  @param[in]  SupportedLanguages  A pointer to a Null-terminated ASCII string that\r
+                                  contains a set of language codes in the format \r
+                                  specified by Iso639Language.\r
+  @param[in]  Iso639Language      If TRUE, then all language codes are assumed to be\r
+                                  in ISO 639-2 format.  If FALSE, then all language\r
+                                  codes are assumed to be in RFC 4646 language format\r
+  @param[in]  ...                 A variable argument list that contains pointers to \r
+                                  Null-terminated ASCII strings that contain one or more\r
+                                  language codes in the format specified by Iso639Language.\r
+                                  The first language code from each of these language\r
+                                  code lists is used to determine if it is an exact or\r
+                                  close match to any of the language codes in \r
+                                  SupportedLanguages.  Close matches only apply to RFC 4646\r
+                                  language codes, and the matching algorithm from RFC 4647\r
+                                  is used to determine if a close match is present.  If \r
+                                  an exact or close match is found, then the matching\r
+                                  language code from SupportedLanguages is returned.  If\r
+                                  no matches are found, then the next variable argument\r
+                                  parameter is evaluated.  The variable argument list \r
+                                  is terminated by a NULL.\r
+\r
+  @retval NULL   The best matching language could not be found in SupportedLanguages.\r
+  @retval NULL   There are not enough resources available to return the best matching \r
+                 language.\r
+  @retval Other  A pointer to a Null-terminated ASCII string that is the best matching \r
+                 language in SupportedLanguages.\r
+\r
+**/\r
+CHAR8 *\r
+EFIAPI\r
+VariableGetBestLanguage (\r
+  IN CONST CHAR8  *SupportedLanguages, \r
+  IN BOOLEAN      Iso639Language,\r
+  ...\r
+  )\r
+{\r
+  VA_LIST      Args;\r
+  CHAR8        *Language;\r
+  UINTN        CompareLength;\r
+  UINTN        LanguageLength;\r
+  CONST CHAR8  *Supported;\r
+  CHAR8        *Buffer;\r
+\r
+  ASSERT (SupportedLanguages != NULL);\r
+\r
+  VA_START (Args, Iso639Language);\r
+  while ((Language = VA_ARG (Args, CHAR8 *)) != NULL) {\r
+    //\r
+    // Default to ISO 639-2 mode\r
+    //\r
+    CompareLength  = 3;\r
+    LanguageLength = MIN (3, AsciiStrLen (Language));\r
+\r
+    //\r
+    // If in RFC 4646 mode, then determine the length of the first RFC 4646 language code in Language\r
+    //\r
+    if (!Iso639Language) {\r
+      for (LanguageLength = 0; Language[LanguageLength] != 0 && Language[LanguageLength] != ';'; LanguageLength++);\r
+    }\r
+\r
+    //\r
+    // Trim back the length of Language used until it is empty\r
+    //\r
+    while (LanguageLength > 0) {\r
+      //\r
+      // Loop through all language codes in SupportedLanguages\r
+      //\r
+      for (Supported = SupportedLanguages; *Supported != '\0'; Supported += CompareLength) {\r
+        //\r
+        // In RFC 4646 mode, then Loop through all language codes in SupportedLanguages\r
+        //\r
+        if (!Iso639Language) {\r
+          //\r
+          // Skip ';' characters in Supported\r
+          //\r
+          for (; *Supported != '\0' && *Supported == ';'; Supported++);\r
+          //\r
+          // Determine the length of the next language code in Supported\r
+          //\r
+          for (CompareLength = 0; Supported[CompareLength] != 0 && Supported[CompareLength] != ';'; CompareLength++);\r
+          //\r
+          // If Language is longer than the Supported, then skip to the next language\r
+          //\r
+          if (LanguageLength > CompareLength) {\r
+            continue;\r
+          }\r
+        }\r
+        //\r
+        // See if the first LanguageLength characters in Supported match Language\r
+        //\r
+        if (AsciiStrnCmp (Supported, Language, LanguageLength) == 0) {\r
+          VA_END (Args);\r
+\r
+          Buffer = Iso639Language ? mVariableModuleGlobal->Lang : mVariableModuleGlobal->PlatformLang;\r
+          Buffer[CompareLength] = '\0';\r
+          return CopyMem (Buffer, Supported, CompareLength);\r
+        }\r
+      }\r
+\r
+      if (Iso639Language) {\r
+        //\r
+        // If ISO 639 mode, then each language can only be tested once\r
+        //\r
+        LanguageLength = 0;\r
+      } else {\r
+        //\r
+        // If RFC 4646 mode, then trim Language from the right to the next '-' character \r
+        //\r
+        for (LanguageLength--; LanguageLength > 0 && Language[LanguageLength] != '-'; LanguageLength--);\r
+      }\r
+    }\r
+  }\r
+  VA_END (Args);\r
+\r
+  //\r
+  // No matches were found \r
+  //\r
+  return NULL;\r
+}\r
+\r
+/**\r
+  Hook the operations in PlatformLangCodes, LangCodes, PlatformLang and Lang.\r
+\r
+  When setting Lang/LangCodes, simultaneously update PlatformLang/PlatformLangCodes.\r
+\r
+  According to UEFI spec, PlatformLangCodes/LangCodes are only set once in firmware initialization,\r
+  and are read-only. Therefore, in variable driver, only store the original value for other use.\r
+\r
+  @param[in] VariableName       Name of variable.\r
+\r
+  @param[in] Data               Variable data.\r
+\r
+  @param[in] DataSize           Size of data. 0 means delete.\r
+\r
+**/\r
+VOID\r
+AutoUpdateLangVariable(\r
+  IN  CHAR16             *VariableName,\r
+  IN  VOID               *Data,\r
+  IN  UINTN              DataSize\r
+  )\r
+{\r
+  EFI_STATUS             Status;\r
+  CHAR8                  *BestPlatformLang;\r
+  CHAR8                  *BestLang;\r
+  UINTN                  Index;\r
+  UINT32                 Attributes;\r
+  VARIABLE_POINTER_TRACK Variable;\r
+  BOOLEAN                SetLanguageCodes;\r
+\r
+  //\r
+  // Don't do updates for delete operation\r
+  //\r
+  if (DataSize == 0) {\r
+    return;\r
+  }\r
+\r
+  SetLanguageCodes = FALSE;\r
+\r
+  if (StrCmp (VariableName, L"PlatformLangCodes") == 0) {\r
+    //\r
+    // PlatformLangCodes is a volatile variable, so it can not be updated at runtime.\r
+    //\r
+    if (AtRuntime ()) {\r
+      return;\r
+    }\r
+\r
+    SetLanguageCodes = TRUE;\r
+\r
+    //\r
+    // According to UEFI spec, PlatformLangCodes is only set once in firmware initialization, and is read-only\r
+    // Therefore, in variable driver, only store the original value for other use.\r
+    //\r
+    if (mVariableModuleGlobal->PlatformLangCodes != NULL) {\r
+      FreePool (mVariableModuleGlobal->PlatformLangCodes);\r
+    }\r
+    mVariableModuleGlobal->PlatformLangCodes = AllocateRuntimeCopyPool (DataSize, Data);\r
+    ASSERT (mVariableModuleGlobal->PlatformLangCodes != NULL);\r
+\r
+    //\r
+    // PlatformLang holds a single language from PlatformLangCodes, \r
+    // so the size of PlatformLangCodes is enough for the PlatformLang.\r
+    //\r
+    if (mVariableModuleGlobal->PlatformLang != NULL) {\r
+      FreePool (mVariableModuleGlobal->PlatformLang);\r
+    }\r
+    mVariableModuleGlobal->PlatformLang = AllocateRuntimePool (DataSize);\r
+    ASSERT (mVariableModuleGlobal->PlatformLang != NULL);\r
+\r
+  } else if (StrCmp (VariableName, L"LangCodes") == 0) {\r
+    //\r
+    // LangCodes is a volatile variable, so it can not be updated at runtime.\r
+    //\r
+    if (AtRuntime ()) {\r
+      return;\r
+    }\r
+\r
+    SetLanguageCodes = TRUE;\r
+\r
+    //\r
+    // According to UEFI spec, LangCodes is only set once in firmware initialization, and is read-only\r
+    // Therefore, in variable driver, only store the original value for other use.\r
+    //\r
+    if (mVariableModuleGlobal->LangCodes != NULL) {\r
+      FreePool (mVariableModuleGlobal->LangCodes);\r
+    }\r
+    mVariableModuleGlobal->LangCodes = AllocateRuntimeCopyPool (DataSize, Data);\r
+    ASSERT (mVariableModuleGlobal->LangCodes != NULL);\r
+  }\r
+\r
+  if (SetLanguageCodes \r
+      && (mVariableModuleGlobal->PlatformLangCodes != NULL)\r
+      && (mVariableModuleGlobal->LangCodes != NULL)) {\r
+    //\r
+    // Update Lang if PlatformLang is already set\r
+    // Update PlatformLang if Lang is already set\r
+    //\r
+    Status = FindVariable (L"PlatformLang", &gEfiGlobalVariableGuid, &Variable, (VARIABLE_GLOBAL *) mVariableModuleGlobal);\r
+    if (!EFI_ERROR (Status)) {\r
+      //\r
+      // Update Lang\r
+      //\r
+      VariableName = L"PlatformLang";\r
+      Data         = GetVariableDataPtr (Variable.CurrPtr);\r
+      DataSize     = Variable.CurrPtr->DataSize;\r
+    } else {\r
+      Status = FindVariable (L"Lang", &gEfiGlobalVariableGuid, &Variable, (VARIABLE_GLOBAL *) mVariableModuleGlobal);\r
+      if (!EFI_ERROR (Status)) {\r
+        //\r
+        // Update PlatformLang\r
+        //\r
+        VariableName = L"Lang";\r
+        Data         = GetVariableDataPtr (Variable.CurrPtr);\r
+        DataSize     = Variable.CurrPtr->DataSize;\r
+      } else {\r
+        //\r
+        // Neither PlatformLang nor Lang is set, directly return\r
+        //\r
+        return;\r
+      }\r
+    }\r
+  }\r
+  \r
+  //\r
+  // According to UEFI spec, "Lang" and "PlatformLang" is NV|BS|RT attributions.\r
+  //\r
+  Attributes = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS;\r
+\r
+  if (StrCmp (VariableName, L"PlatformLang") == 0) {\r
+    //\r
+    // Update Lang when PlatformLangCodes/LangCodes were set.\r
+    //\r
+    if ((mVariableModuleGlobal->PlatformLangCodes != NULL) && (mVariableModuleGlobal->LangCodes != NULL)) {\r
+      //\r
+      // When setting PlatformLang, firstly get most matched language string from supported language codes.\r
+      //\r
+      BestPlatformLang = VariableGetBestLanguage (mVariableModuleGlobal->PlatformLangCodes, FALSE, Data, NULL);\r
+      if (BestPlatformLang != NULL) {\r
+        //\r
+        // Get the corresponding index in language codes.\r
+        //\r
+        Index = GetIndexFromSupportedLangCodes (mVariableModuleGlobal->PlatformLangCodes, BestPlatformLang, FALSE);\r
+\r
+        //\r
+        // Get the corresponding ISO639 language tag according to RFC4646 language tag.\r
+        //\r
+        BestLang = GetLangFromSupportedLangCodes (mVariableModuleGlobal->LangCodes, Index, TRUE);\r
+\r
+        //\r
+        // Successfully convert PlatformLang to Lang, and set the BestLang value into Lang variable simultaneously.\r
+        //\r
+        FindVariable (L"Lang", &gEfiGlobalVariableGuid, &Variable, (VARIABLE_GLOBAL *)mVariableModuleGlobal);\r
+\r
+        Status = UpdateVariable (L"Lang", &gEfiGlobalVariableGuid, BestLang,\r
+                                 ISO_639_2_ENTRY_SIZE + 1, Attributes, 0, 0, &Variable, NULL);\r
+\r
+        DEBUG ((EFI_D_INFO, "Variable Driver Auto Update PlatformLang, PlatformLang:%a, Lang:%a\n", BestPlatformLang, BestLang));\r
+\r
+        ASSERT_EFI_ERROR(Status);\r
+      }\r
+    }\r
+\r
+  } else if (StrCmp (VariableName, L"Lang") == 0) {\r
+    //\r
+    // Update PlatformLang when PlatformLangCodes/LangCodes were set.\r
+    //\r
+    if ((mVariableModuleGlobal->PlatformLangCodes != NULL) && (mVariableModuleGlobal->LangCodes != NULL)) {\r
+      //\r
+      // When setting Lang, firstly get most matched language string from supported language codes.\r
+      //\r
+      BestLang = VariableGetBestLanguage (mVariableModuleGlobal->LangCodes, TRUE, Data, NULL);\r
+      if (BestLang != NULL) {\r
+        //\r
+        // Get the corresponding index in language codes.\r
+        //\r
+        Index = GetIndexFromSupportedLangCodes (mVariableModuleGlobal->LangCodes, BestLang, TRUE);\r
+\r
+        //\r
+        // Get the corresponding RFC4646 language tag according to ISO639 language tag.\r
+        //\r
+        BestPlatformLang = GetLangFromSupportedLangCodes (mVariableModuleGlobal->PlatformLangCodes, Index, FALSE);\r
+\r
+        //\r
+        // Successfully convert Lang to PlatformLang, and set the BestPlatformLang value into PlatformLang variable simultaneously.\r
+        //\r
+        FindVariable (L"PlatformLang", &gEfiGlobalVariableGuid, &Variable, (VARIABLE_GLOBAL *)mVariableModuleGlobal);\r
+\r
+        Status = UpdateVariable (L"PlatformLang", &gEfiGlobalVariableGuid, BestPlatformLang, \r
+                                 AsciiStrSize (BestPlatformLang), Attributes, 0, 0, &Variable, NULL);\r
+\r
+        DEBUG ((EFI_D_INFO, "Variable Driver Auto Update Lang, Lang:%a, PlatformLang:%a\n", BestLang, BestPlatformLang));\r
+        ASSERT_EFI_ERROR (Status);\r
+      }\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+  Update the variable region with Variable information. If EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS is set,\r
+  index of associated public key is needed.\r
+\r
+  @param[in] VariableName       Name of variable.\r
+  @param[in] VendorGuid         Guid of variable.\r
+  @param[in] Data               Variable data.\r
+  @param[in] DataSize           Size of data. 0 means delete.\r
+  @param[in] Attributes         Attributes of the variable.\r
+  @param[in] KeyIndex           Index of associated public key.\r
+  @param[in] MonotonicCount     Value of associated monotonic count.\r
+  @param[in] CacheVariable      The variable information which is used to keep track of variable usage.\r
+  @param[in] TimeStamp          Value of associated TimeStamp.\r
+  \r
+  @retval EFI_SUCCESS           The update operation is success.\r
+  @retval EFI_OUT_OF_RESOURCES  Variable region is full, can not write other data into this region.\r
+\r
+**/\r
+EFI_STATUS\r
+UpdateVariable (\r
+  IN      CHAR16                      *VariableName,\r
+  IN      EFI_GUID                    *VendorGuid,\r
+  IN      VOID                        *Data,\r
+  IN      UINTN                       DataSize,\r
+  IN      UINT32                      Attributes      OPTIONAL,\r
+  IN      UINT32                      KeyIndex        OPTIONAL,\r
+  IN      UINT64                      MonotonicCount  OPTIONAL,\r
+  IN      VARIABLE_POINTER_TRACK      *CacheVariable,\r
+  IN      EFI_TIME                    *TimeStamp      OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS                          Status;\r
+  VARIABLE_HEADER                     *NextVariable;\r
+  UINTN                               ScratchSize;\r
+  UINTN                               ScratchDataSize;\r
+  UINTN                               NonVolatileVarableStoreSize;\r
+  UINTN                               VarNameOffset;\r
+  UINTN                               VarDataOffset;\r
+  UINTN                               VarNameSize;\r
+  UINTN                               VarSize;\r
+  BOOLEAN                             Volatile;\r
+  EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *Fvb;\r
+  UINT8                               State;\r
+  BOOLEAN                             Reclaimed;\r
+  VARIABLE_POINTER_TRACK              *Variable;\r
+  VARIABLE_POINTER_TRACK              NvVariable;\r
+  VARIABLE_STORE_HEADER               *VariableStoreHeader;\r
+  UINTN                               CacheOffset;\r
+  UINTN                               BufSize;\r
+  UINTN                               DataOffset;\r
+  UINTN                               RevBufSize;\r
+\r
+  if (mVariableModuleGlobal->FvbInstance == NULL) {\r
+    //\r
+    // The FVB protocol is not installed, so the EFI_VARIABLE_WRITE_ARCH_PROTOCOL is not installed.\r
+    //\r
+    if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {\r
+      //\r
+      // Trying to update NV variable prior to the installation of EFI_VARIABLE_WRITE_ARCH_PROTOCOL\r
+      //\r
+      return EFI_NOT_AVAILABLE_YET;\r
+    } else if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
+      //\r
+      // Trying to update volatile authenticated variable prior to the installation of EFI_VARIABLE_WRITE_ARCH_PROTOCOL\r
+      // The authenticated variable perhaps is not initialized, just return here.\r
+      //\r
+      return EFI_NOT_AVAILABLE_YET;\r
+    }\r
+  }\r
+\r
+  if ((CacheVariable->CurrPtr == NULL) || CacheVariable->Volatile) {\r
+    Variable = CacheVariable;\r
+  } else {\r
+    //\r
+    // Update/Delete existing NV variable.\r
+    // CacheVariable points to the variable in the memory copy of Flash area\r
+    // Now let Variable points to the same variable in Flash area.\r
+    //\r
+    VariableStoreHeader  = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase);\r
+    Variable = &NvVariable;    \r
+    Variable->StartPtr = GetStartPointer (VariableStoreHeader);\r
+    Variable->EndPtr   = GetEndPointer (VariableStoreHeader);\r
+    Variable->CurrPtr  = (VARIABLE_HEADER *)((UINTN)Variable->StartPtr + ((UINTN)CacheVariable->CurrPtr - (UINTN)CacheVariable->StartPtr));\r
+    Variable->Volatile = FALSE;\r
+  } \r
+\r
+  Fvb       = mVariableModuleGlobal->FvbInstance;\r
+  Reclaimed = FALSE;\r
+\r
+  //\r
+  // Tricky part: Use scratch data area at the end of volatile variable store\r
+  // as a temporary storage.\r
+  //\r
+  NextVariable = GetEndPointer ((VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase));\r
+  ScratchSize = MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize));\r
+  ScratchDataSize = ScratchSize - sizeof (VARIABLE_HEADER) - StrSize (VariableName) - GET_PAD_SIZE (StrSize (VariableName));\r
+\r
+  if (Variable->CurrPtr != NULL) {\r
+    //\r
+    // Update/Delete existing variable.\r
+    //\r
+    if (AtRuntime ()) {        \r
+      //\r
+      // If AtRuntime and the variable is Volatile and Runtime Access,  \r
+      // the volatile is ReadOnly, and SetVariable should be aborted and \r
+      // return EFI_WRITE_PROTECTED.\r
+      //\r
+      if (Variable->Volatile) {\r
+        Status = EFI_WRITE_PROTECTED;\r
+        goto Done;\r
+      }\r
+      //\r
+      // Only variable that have NV attributes can be updated/deleted in Runtime.\r
+      //\r
+      if ((Variable->CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {\r
+        Status = EFI_INVALID_PARAMETER;\r
+        goto Done;      \r
+      }\r
+    }\r
+\r
+    //\r
+    // Setting a data variable with no access, or zero DataSize attributes\r
+    // causes it to be deleted.\r
+    // When the EFI_VARIABLE_APPEND_WRITE attribute is set, DataSize of zero will \r
+    // not delete the variable.    \r
+    //\r
+    if ((((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) && (DataSize == 0))|| ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0)) {    \r
+      State = Variable->CurrPtr->State;\r
+      State &= VAR_DELETED;\r
+\r
+      Status = UpdateVariableStore (\r
+                 &mVariableModuleGlobal->VariableGlobal,\r
+                 Variable->Volatile,\r
+                 FALSE,\r
+                 Fvb,\r
+                 (UINTN) &Variable->CurrPtr->State,\r
+                 sizeof (UINT8),\r
+                 &State\r
+                 ); \r
+      if (!EFI_ERROR (Status)) {\r
+        UpdateVariableInfo (VariableName, VendorGuid, Variable->Volatile, FALSE, FALSE, TRUE, FALSE);\r
+        if (!Variable->Volatile) {\r
+          CacheVariable->CurrPtr->State = State;\r
+        }\r
+      }\r
+      goto Done;     \r
+    }\r
+    //\r
+    // If the variable is marked valid, and the same data has been passed in,\r
+    // then return to the caller immediately.\r
+    //\r
+    if (DataSizeOfVariable (Variable->CurrPtr) == DataSize &&\r
+        (CompareMem (Data, GetVariableDataPtr (Variable->CurrPtr), DataSize) == 0)  &&\r
+        ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0)) {\r
+      \r
+      UpdateVariableInfo (VariableName, VendorGuid, Variable->Volatile, FALSE, TRUE, FALSE, FALSE);\r
+      Status = EFI_SUCCESS;\r
+      goto Done;\r
+    } else if ((Variable->CurrPtr->State == VAR_ADDED) ||\r
+               (Variable->CurrPtr->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION))) {\r
+\r
+      //\r
+      // EFI_VARIABLE_APPEND_WRITE attribute only effects for existing variable\r
+      //\r
+      if ((Attributes & EFI_VARIABLE_APPEND_WRITE) != 0) {\r
+    \r
+        BufSize = Variable->CurrPtr->DataSize +  DataSize;\r
+        RevBufSize = MIN (PcdGet32 (PcdMaxAppendVariableSize), ScratchDataSize);\r
+    \r
+        if (BufSize > RevBufSize) {\r
+          //\r
+          // If variable size (previous + current) is bigger than reserved buffer in runtime,\r
+          // return EFI_OUT_OF_RESOURCES.\r
+          //\r
+          return EFI_OUT_OF_RESOURCES;\r
+        }\r
+       \r
+        SetMem (mStorageArea, PcdGet32 (PcdMaxAppendVariableSize), 0xff);\r
+        //\r
+        // Cache the previous variable data into StorageArea.\r
+        //\r
+        DataOffset = sizeof (VARIABLE_HEADER) + Variable->CurrPtr->NameSize + GET_PAD_SIZE (Variable->CurrPtr->NameSize);\r
+        CopyMem (mStorageArea, (UINT8*)((UINTN)Variable->CurrPtr + DataOffset), Variable->CurrPtr->DataSize);\r
+        \r
+        //\r
+        // Append the new data to the end of previous data.\r
+        // \r
+        CopyMem ((UINT8*)((UINTN)mStorageArea + Variable->CurrPtr->DataSize), Data, DataSize);\r
+    \r
+        //\r
+        // Override Data and DataSize which are used for combined data area including previous and new data.\r
+        //\r
+        Data     = mStorageArea;\r
+        DataSize = BufSize;\r
+      }\r
+\r
+      //\r
+      // Mark the old variable as in delete transition.\r
+      //\r
+      State = Variable->CurrPtr->State;\r
+      State &= VAR_IN_DELETED_TRANSITION;\r
+\r
+      Status = UpdateVariableStore (\r
+                 &mVariableModuleGlobal->VariableGlobal,\r
+                 Variable->Volatile,\r
+                 FALSE,\r
+                 Fvb,\r
+                 (UINTN) &Variable->CurrPtr->State,\r
+                 sizeof (UINT8),\r
+                 &State\r
+                 );      \r
+      if (EFI_ERROR (Status)) {\r
+        goto Done;  \r
+      } \r
+      if (!Variable->Volatile) {\r
+        CacheVariable->CurrPtr->State = State;\r
+      }\r
+    }    \r
+  } else {\r
+    //\r
+    // Not found existing variable. Create a new variable.\r
+    //  \r
+\r
+    //\r
+    // EFI_VARIABLE_APPEND_WRITE attribute only set for existing variable\r
+    //\r
+    if ((Attributes & EFI_VARIABLE_APPEND_WRITE) != 0) {\r
+      Status = EFI_INVALID_PARAMETER;\r
+      goto Done;\r
+    }\r
+    \r
+    //\r
+    // Make sure we are trying to create a new variable.\r
+    // Setting a data variable with zero DataSize or no access attributes means to delete it.    \r
+    //\r
+    if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) {\r
+      Status = EFI_NOT_FOUND;\r
+      goto Done;\r
+    }\r
+        \r
+    //\r
+    // Only variable have NV|RT attribute can be created in Runtime.\r
+    //\r
+    if (AtRuntime () &&\r
+        (((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) || ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0))) {\r
+      Status = EFI_INVALID_PARAMETER;\r
+      goto Done;\r
+    }         \r
+  }\r
+\r
+  //\r
+  // Function part - create a new variable and copy the data.\r
+  // Both update a variable and create a variable will come here.\r
+\r
+  SetMem (NextVariable, ScratchSize, 0xff);\r
+\r
+  NextVariable->StartId     = VARIABLE_DATA;\r
+  //\r
+  // NextVariable->State = VAR_ADDED;\r
+  //\r
+  NextVariable->Reserved        = 0;\r
+  NextVariable->PubKeyIndex     = KeyIndex;\r
+  NextVariable->MonotonicCount  = MonotonicCount;\r
+  SetMem (&NextVariable->TimeStamp, sizeof (EFI_TIME), 0);\r
+\r
+  if (((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) && \r
+      ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0)) {\r
+    CopyMem (&NextVariable->TimeStamp, TimeStamp, sizeof (EFI_TIME));\r
+  } else if (\r
+      ((Attributes & EFI_VARIABLE_APPEND_WRITE) != 0) && \r
+      ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0)) {\r
+      //\r
+      // In the case when the EFI_VARIABLE_APPEND_WRITE attribute is set, only\r
+      // when the new TimeStamp value is later than the current timestamp associated\r
+      // with the variable, we need associate the new timestamp with the updated value.\r
+      //\r
+      if (CompareTimeStamp (&Variable->CurrPtr->TimeStamp, TimeStamp)) {\r
+        CopyMem (&NextVariable->TimeStamp, TimeStamp, sizeof (EFI_TIME));\r
+      }\r
+  }\r
+\r
+  //\r
+  // The EFI_VARIABLE_APPEND_WRITE attribute will never be set in the returned \r
+  // Attributes bitmask parameter of a GetVariable() call.\r
+  //\r
+  NextVariable->Attributes  = Attributes & (~EFI_VARIABLE_APPEND_WRITE);\r
+  \r
+  VarNameOffset                 = sizeof (VARIABLE_HEADER);\r
+  VarNameSize                   = StrSize (VariableName);\r
+  CopyMem (\r
+    (UINT8 *) ((UINTN) NextVariable + VarNameOffset),\r
+    VariableName,\r
+    VarNameSize\r
+    );\r
+  VarDataOffset = VarNameOffset + VarNameSize + GET_PAD_SIZE (VarNameSize);\r
+  CopyMem (\r
+    (UINT8 *) ((UINTN) NextVariable + VarDataOffset),\r
+    Data,\r
+    DataSize\r
+    );\r
+  CopyMem (&NextVariable->VendorGuid, VendorGuid, sizeof (EFI_GUID));\r
+  //\r
+  // There will be pad bytes after Data, the NextVariable->NameSize and\r
+  // NextVariable->DataSize should not include pad size so that variable\r
+  // service can get actual size in GetVariable.\r
+  //\r
+  NextVariable->NameSize  = (UINT32)VarNameSize;\r
+  NextVariable->DataSize  = (UINT32)DataSize;\r
+\r
+  //\r
+  // The actual size of the variable that stores in storage should\r
+  // include pad size.\r
+  //\r
+  VarSize = VarDataOffset + DataSize + GET_PAD_SIZE (DataSize);\r
+  if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {\r
+    //\r
+    // Create a nonvolatile variable.\r
+    //\r
+    Volatile = FALSE;\r
+    NonVolatileVarableStoreSize = ((VARIABLE_STORE_HEADER *)(UINTN)(mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase))->Size;\r
+    if ((((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) \r
+      && ((VarSize + mVariableModuleGlobal->HwErrVariableTotalSize) > PcdGet32 (PcdHwErrStorageSize)))\r
+      || (((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0) \r
+      && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > NonVolatileVarableStoreSize - sizeof (VARIABLE_STORE_HEADER) - PcdGet32 (PcdHwErrStorageSize)))) {\r
+      if (AtRuntime ()) {\r
+        Status = EFI_OUT_OF_RESOURCES;\r
+        goto Done;\r
+      }\r
+      //\r
+      // Perform garbage collection & reclaim operation.\r
+      //\r
+      Status = Reclaim (mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase, \r
+                        &mVariableModuleGlobal->NonVolatileLastVariableOffset, FALSE, Variable->CurrPtr);\r
+      if (EFI_ERROR (Status)) {\r
+        goto Done;\r
+      }\r
+      //\r
+      // If still no enough space, return out of resources.\r
+      //\r
+      if ((((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) \r
+        && ((VarSize + mVariableModuleGlobal->HwErrVariableTotalSize) > PcdGet32 (PcdHwErrStorageSize)))\r
+        || (((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0) \r
+        && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > NonVolatileVarableStoreSize - sizeof (VARIABLE_STORE_HEADER) - PcdGet32 (PcdHwErrStorageSize)))) {\r
+        Status = EFI_OUT_OF_RESOURCES;\r
+        goto Done;\r
+      }\r
+      Reclaimed = TRUE;\r
+    }\r
+    //\r
+    // Four steps\r
+    // 1. Write variable header\r
+    // 2. Set variable state to header valid  \r
+    // 3. Write variable data\r
+    // 4. Set variable state to valid\r
+    //\r
+    //\r
+    // Step 1:\r
+    //\r
+    CacheOffset = mVariableModuleGlobal->NonVolatileLastVariableOffset;\r
+    Status = UpdateVariableStore (\r
+               &mVariableModuleGlobal->VariableGlobal,\r
+               FALSE,\r
+               TRUE,\r
+               Fvb,\r
+               mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
+               sizeof (VARIABLE_HEADER),\r
+               (UINT8 *) NextVariable\r
+               );\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      goto Done;\r
+    }\r
+\r
+    //\r
+    // Step 2:\r
+    //\r
+    NextVariable->State = VAR_HEADER_VALID_ONLY;\r
+    Status = UpdateVariableStore (\r
+               &mVariableModuleGlobal->VariableGlobal,\r
+               FALSE,\r
+               TRUE,\r
+               Fvb,\r
+               mVariableModuleGlobal->NonVolatileLastVariableOffset + OFFSET_OF (VARIABLE_HEADER, State),\r
+               sizeof (UINT8),\r
+               &NextVariable->State\r
+               );\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      goto Done;\r
+    }\r
+    //\r
+    // Step 3:\r
+    //\r
+    Status = UpdateVariableStore (\r
+               &mVariableModuleGlobal->VariableGlobal,\r
+               FALSE,\r
+               TRUE,\r
+               Fvb,\r
+               mVariableModuleGlobal->NonVolatileLastVariableOffset + sizeof (VARIABLE_HEADER),\r
+               (UINT32) VarSize - sizeof (VARIABLE_HEADER),\r
+               (UINT8 *) NextVariable + sizeof (VARIABLE_HEADER)\r
+               );\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      goto Done;\r
+    }\r
+    //\r
+    // Step 4:\r
+    //\r
+    NextVariable->State = VAR_ADDED;\r
+    Status = UpdateVariableStore (\r
+               &mVariableModuleGlobal->VariableGlobal,\r
+               FALSE,\r
+               TRUE,\r
+               Fvb,\r
+               mVariableModuleGlobal->NonVolatileLastVariableOffset + OFFSET_OF (VARIABLE_HEADER, State),\r
+               sizeof (UINT8),\r
+               &NextVariable->State\r
+               );\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      goto Done;\r
+    }\r
+\r
+    mVariableModuleGlobal->NonVolatileLastVariableOffset += HEADER_ALIGN (VarSize);\r
+\r
+    if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) {\r
+      mVariableModuleGlobal->HwErrVariableTotalSize += HEADER_ALIGN (VarSize);\r
+    } else {\r
+      mVariableModuleGlobal->CommonVariableTotalSize += HEADER_ALIGN (VarSize);\r
+    }\r
+    //\r
+    // update the memory copy of Flash region.\r
+    //\r
+    CopyMem ((UINT8 *)mNvVariableCache + CacheOffset, (UINT8 *)NextVariable, VarSize);\r
+  } else {\r
+    //\r
+    // Create a volatile variable.\r
+    //      \r
+    Volatile = TRUE;\r
+\r
+    if ((UINT32) (VarSize + mVariableModuleGlobal->VolatileLastVariableOffset) >\r
+        ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase)))->Size) {\r
+      //\r
+      // Perform garbage collection & reclaim operation.\r
+      //\r
+      Status = Reclaim (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase, \r
+                          &mVariableModuleGlobal->VolatileLastVariableOffset, TRUE, Variable->CurrPtr);\r
+      if (EFI_ERROR (Status)) {\r
+        goto Done;\r
+      }\r
+      //\r
+      // If still no enough space, return out of resources.\r
+      //\r
+      if ((UINT32) (VarSize + mVariableModuleGlobal->VolatileLastVariableOffset) >\r
+            ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase)))->Size\r
+            ) {\r
+        Status = EFI_OUT_OF_RESOURCES;\r
+        goto Done;\r
+      }\r
+      Reclaimed = TRUE;\r
+    }\r
+\r
+    NextVariable->State = VAR_ADDED;\r
+    Status = UpdateVariableStore (\r
+               &mVariableModuleGlobal->VariableGlobal,\r
+               TRUE,\r
+               TRUE,\r
+               Fvb,\r
+               mVariableModuleGlobal->VolatileLastVariableOffset,\r
+               (UINT32) VarSize,\r
+               (UINT8 *) NextVariable\r
+               );\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      goto Done;\r
+    }\r
+\r
+    mVariableModuleGlobal->VolatileLastVariableOffset += HEADER_ALIGN (VarSize);\r
+  }\r
+\r
+  //\r
+  // Mark the old variable as deleted.\r
+  //\r
+  if (!Reclaimed && !EFI_ERROR (Status) && Variable->CurrPtr != NULL) {\r
+    State = Variable->CurrPtr->State;\r
+    State &= VAR_DELETED;\r
+\r
+    Status = UpdateVariableStore (\r
+             &mVariableModuleGlobal->VariableGlobal,\r
+             Variable->Volatile,\r
+             FALSE,\r
+             Fvb,\r
+             (UINTN) &Variable->CurrPtr->State,\r
+             sizeof (UINT8),\r
+             &State\r
+             );\r
+    if (!EFI_ERROR (Status) && !Variable->Volatile) {         \r
+      CacheVariable->CurrPtr->State = State;\r
+    }\r
+  }\r
+\r
+  if (!EFI_ERROR (Status)) {\r
+    UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, TRUE, FALSE, FALSE);\r
+  }\r
+\r
+Done:\r
+  return Status;\r
+}\r
+\r
+/**\r
+\r
+  This code finds variable in storage blocks (Volatile or Non-Volatile).\r
+\r
+  @param VariableName               Name of Variable to be found.\r
+  @param VendorGuid                 Variable vendor GUID.\r
+  @param Attributes                 Attribute value of the variable found.\r
+  @param DataSize                   Size of Data found. If size is less than the\r
+                                    data, this value contains the required size.\r
+  @param Data                       Data pointer.\r
+                      \r
+  @return EFI_INVALID_PARAMETER     Invalid parameter.\r
+  @return EFI_SUCCESS               Find the specified variable.\r
+  @return EFI_NOT_FOUND             Not found.\r
+  @return EFI_BUFFER_TO_SMALL       DataSize is too small for the result.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+VariableServiceGetVariable (\r
+  IN      CHAR16            *VariableName,\r
+  IN      EFI_GUID          *VendorGuid,\r
+  OUT     UINT32            *Attributes OPTIONAL,\r
+  IN OUT  UINTN             *DataSize,\r
+  OUT     VOID              *Data\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  VARIABLE_POINTER_TRACK  Variable;\r
+  UINTN                   VarDataSize;\r
+\r
+  if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
+  \r
+  Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal);\r
+  if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+\r
+  //\r
+  // Get data size\r
+  //\r
+  VarDataSize = DataSizeOfVariable (Variable.CurrPtr);\r
+  ASSERT (VarDataSize != 0);\r
+\r
+  if (*DataSize >= VarDataSize) {\r
+    if (Data == NULL) {\r
+      Status = EFI_INVALID_PARAMETER;\r
+      goto Done;\r
+    }\r
+\r
+    CopyMem (Data, GetVariableDataPtr (Variable.CurrPtr), VarDataSize);\r
+    if (Attributes != NULL) {\r
+      *Attributes = Variable.CurrPtr->Attributes;\r
+    }\r
+\r
+    *DataSize = VarDataSize;\r
+    UpdateVariableInfo (VariableName, VendorGuid, Variable.Volatile, TRUE, FALSE, FALSE, FALSE);\r
\r
+    Status = EFI_SUCCESS;\r
+    goto Done;\r
+  } else {\r
+    *DataSize = VarDataSize;\r
+    Status = EFI_BUFFER_TOO_SMALL;\r
+    goto Done;\r
+  }\r
+\r
+Done:\r
+  ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
+  return Status;\r
+}\r
+\r
+\r
+\r
+/**\r
+\r
+  This code Finds the Next available variable.\r
+\r
+  @param VariableNameSize           Size of the variable name.\r
+  @param VariableName               Pointer to variable name.\r
+  @param VendorGuid                 Variable Vendor Guid.\r
+\r
+  @return EFI_INVALID_PARAMETER     Invalid parameter.\r
+  @return EFI_SUCCESS               Find the specified variable.\r
+  @return EFI_NOT_FOUND             Not found.\r
+  @return EFI_BUFFER_TO_SMALL       DataSize is too small for the result.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+VariableServiceGetNextVariableName (\r
+  IN OUT  UINTN             *VariableNameSize,\r
+  IN OUT  CHAR16            *VariableName,\r
+  IN OUT  EFI_GUID          *VendorGuid\r
+  )\r
+{\r
+  VARIABLE_POINTER_TRACK  Variable;\r
+  UINTN                   VarNameSize;\r
+  EFI_STATUS              Status;\r
+\r
+  if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
+\r
+  Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal);\r
+  if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {\r
+    goto Done;\r
+  }\r
+\r
+  if (VariableName[0] != 0) {\r
+    //\r
+    // If variable name is not NULL, get next variable.\r
+    //\r
+    Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);\r
+  }\r
+\r
+  while (TRUE) {\r
+    //\r
+    // If both volatile and non-volatile variable store are parsed,\r
+    // return not found.\r
+    //\r
+    if (Variable.CurrPtr >= Variable.EndPtr || Variable.CurrPtr == NULL) {\r
+      Variable.Volatile = (BOOLEAN) (Variable.Volatile ^ ((BOOLEAN) 0x1));\r
+      if (!Variable.Volatile) {\r
+        Variable.StartPtr = GetStartPointer ((VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase);\r
+        Variable.EndPtr   = GetEndPointer ((VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase));\r
+      } else {\r
+        Status = EFI_NOT_FOUND;\r
+        goto Done;\r
+      }\r
+\r
+      Variable.CurrPtr = Variable.StartPtr;\r
+      if (!IsValidVariableHeader (Variable.CurrPtr)) {\r
+        continue;\r
+      }\r
+    }\r
+    //\r
+    // Variable is found\r
+    //\r
+    if (IsValidVariableHeader (Variable.CurrPtr) && Variable.CurrPtr->State == VAR_ADDED) {\r
+      if ((AtRuntime () && ((Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)) == 0) {\r
+        VarNameSize = NameSizeOfVariable (Variable.CurrPtr);\r
+        ASSERT (VarNameSize != 0);\r
+\r
+        if (VarNameSize <= *VariableNameSize) {\r
+          CopyMem (\r
+            VariableName,\r
+            GetVariableNamePtr (Variable.CurrPtr),\r
+            VarNameSize\r
+            );\r
+          CopyMem (\r
+            VendorGuid,\r
+            &Variable.CurrPtr->VendorGuid,\r
+            sizeof (EFI_GUID)\r
+            );\r
+          Status = EFI_SUCCESS;\r
+        } else {\r
+          Status = EFI_BUFFER_TOO_SMALL;\r
+        }\r
+\r
+        *VariableNameSize = VarNameSize;\r
+        goto Done;\r
+      }\r
+    }\r
+\r
+    Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);\r
+  }\r
+\r
+Done:\r
+  ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
+  return Status;\r
+}\r
+\r
+/**\r
+\r
+  This code sets variable in storage blocks (Volatile or Non-Volatile).\r
+\r
+  @param VariableName                     Name of Variable to be found.\r
+  @param VendorGuid                       Variable vendor GUID.\r
+  @param Attributes                       Attribute value of the variable found\r
+  @param DataSize                         Size of Data found. If size is less than the\r
+                                          data, this value contains the required size.\r
+  @param Data                             Data pointer.\r
+\r
+  @return EFI_INVALID_PARAMETER           Invalid parameter.\r
+  @return EFI_SUCCESS                     Set successfully.\r
+  @return EFI_OUT_OF_RESOURCES            Resource not enough to set variable.\r
+  @return EFI_NOT_FOUND                   Not found.\r
+  @return EFI_WRITE_PROTECTED             Variable is read-only.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+VariableServiceSetVariable (\r
+  IN CHAR16                  *VariableName,\r
+  IN EFI_GUID                *VendorGuid,\r
+  IN UINT32                  Attributes,\r
+  IN UINTN                   DataSize,\r
+  IN VOID                    *Data\r
+  )\r
+{\r
+  VARIABLE_POINTER_TRACK              Variable;\r
+  EFI_STATUS                          Status;\r
+  VARIABLE_HEADER                     *NextVariable;\r
+  EFI_PHYSICAL_ADDRESS                Point;\r
+  UINTN                               PayloadSize;\r
+\r
+  //\r
+  // Check input parameters.\r
+  //\r
+  if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  } \r
+\r
+  if (DataSize != 0 && Data == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  //  Make sure if runtime bit is set, boot service bit is set also.\r
+  //\r
+  if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS and EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute \r
+  // cannot be set both.\r
+  //\r
+  if (((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS)             \\r
+     && ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }  \r
+\r
+  if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) {\r
+    if (DataSize < AUTHINFO_SIZE) {\r
+      //\r
+      // Try to write Authencated Variable without AuthInfo.\r
+      //\r
+      return EFI_SECURITY_VIOLATION;\r
+    } \r
+    PayloadSize = DataSize - AUTHINFO_SIZE; \r
+  } else {\r
+    PayloadSize = DataSize; \r
+  }\r
+  //\r
+  //  The size of the VariableName, including the Unicode Null in bytes plus\r
+  //  the DataSize is limited to maximum size of PcdGet32 (PcdMaxHardwareErrorVariableSize)\r
+  //  bytes for HwErrRec, and PcdGet32 (PcdMaxVariableSize) bytes for the others.\r
+  //\r
+  if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
+    if ((PayloadSize > PcdGet32 (PcdMaxHardwareErrorVariableSize)) ||\r
+        (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + PayloadSize > PcdGet32 (PcdMaxHardwareErrorVariableSize))) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+    //\r
+    // According to UEFI spec, HARDWARE_ERROR_RECORD variable name convention should be L"HwErrRecXXXX".\r
+    //\r
+    if (StrnCmp(VariableName, L"HwErrRec", StrLen(L"HwErrRec")) != 0) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+  } else {\r
+    //\r
+    //  The size of the VariableName, including the Unicode Null in bytes plus\r
+    //  the DataSize is limited to maximum size of PcdGet32 (PcdMaxVariableSize) bytes.\r
+    //\r
+    if ((PayloadSize > PcdGet32 (PcdMaxVariableSize)) ||\r
+        (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + PayloadSize > PcdGet32 (PcdMaxVariableSize))) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }  \r
+  }  \r
+\r
+  AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
+\r
+  //\r
+  // Consider reentrant in MCA/INIT/NMI. It needs be reupdated.\r
+  //\r
+  if (1 < InterlockedIncrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState)) {\r
+    Point = mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;\r
+    //\r
+    // Parse non-volatile variable data and get last variable offset.\r
+    //\r
+    NextVariable  = GetStartPointer ((VARIABLE_STORE_HEADER *) (UINTN) Point);\r
+    while ((NextVariable < GetEndPointer ((VARIABLE_STORE_HEADER *) (UINTN) Point)) \r
+        && IsValidVariableHeader (NextVariable)) {\r
+      NextVariable = GetNextVariablePtr (NextVariable);\r
+    }\r
+    mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) Point;\r
+  }\r
+\r
+  //\r
+  // Check whether the input variable is already existed.\r
+  //\r
+  FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal);\r
+\r
+  //\r
+  // Hook the operation of setting PlatformLangCodes/PlatformLang and LangCodes/Lang.\r
+  //\r
+  AutoUpdateLangVariable (VariableName, Data, DataSize);\r
+  //\r
+  // Process PK, KEK, Sigdb seperately.\r
+  //\r
+  if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_PLATFORM_KEY_NAME) == 0)){\r
+    Status = ProcessVarWithPk (VariableName, VendorGuid, Data, DataSize, &Variable, Attributes, TRUE);\r
+  } else if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_KEY_EXCHANGE_KEY_NAME) == 0)) {\r
+    Status = ProcessVarWithPk (VariableName, VendorGuid, Data, DataSize, &Variable, Attributes, FALSE);\r
+  } else if (CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid) && ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == 0)) {\r
+    Status = ProcessVarWithKek (VariableName, VendorGuid, Data, DataSize, &Variable, Attributes);\r
+  } else {\r
+    Status = ProcessVariable (VariableName, VendorGuid, Data, DataSize, &Variable, Attributes);\r
+  }\r
+\r
+  InterlockedDecrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState);\r
+  ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+\r
+  This code returns information about the EFI variables.\r
+\r
+  @param Attributes                     Attributes bitmask to specify the type of variables\r
+                                        on which to return information.\r
+  @param MaximumVariableStorageSize     Pointer to the maximum size of the storage space available\r
+                                        for the EFI variables associated with the attributes specified.\r
+  @param RemainingVariableStorageSize   Pointer to the remaining size of the storage space available\r
+                                        for EFI variables associated with the attributes specified.\r
+  @param MaximumVariableSize            Pointer to the maximum size of an individual EFI variables\r
+                                        associated with the attributes specified.\r
+\r
+  @return EFI_INVALID_PARAMETER         An invalid combination of attribute bits was supplied.\r
+  @return EFI_SUCCESS                   Query successfully.\r
+  @return EFI_UNSUPPORTED               The attribute is not supported on this platform.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+VariableServiceQueryVariableInfo (\r
+  IN  UINT32                 Attributes,\r
+  OUT UINT64                 *MaximumVariableStorageSize,\r
+  OUT UINT64                 *RemainingVariableStorageSize,\r
+  OUT UINT64                 *MaximumVariableSize\r
+  )\r
+{\r
+  VARIABLE_HEADER        *Variable;\r
+  VARIABLE_HEADER        *NextVariable;\r
+  UINT64                 VariableSize;\r
+  VARIABLE_STORE_HEADER  *VariableStoreHeader;\r
+  UINT64                 CommonVariableTotalSize;\r
+  UINT64                 HwErrVariableTotalSize;\r
+\r
+  CommonVariableTotalSize = 0;\r
+  HwErrVariableTotalSize = 0;\r
+\r
+  if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == 0) {\r
+    //\r
+    // Make sure the Attributes combination is supported by the platform.\r
+    //\r
+    return EFI_UNSUPPORTED;  \r
+  } else if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {\r
+    //\r
+    // Make sure if runtime bit is set, boot service bit is set also.\r
+    //\r
+    return EFI_INVALID_PARAMETER;\r
+  } else if (AtRuntime () && ((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)) {\r
+    //\r
+    // Make sure RT Attribute is set if we are in Runtime phase.\r
+    //\r
+    return EFI_INVALID_PARAMETER;\r
+  } else if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
+    //\r
+    // Make sure Hw Attribute is set with NV.\r
+    //\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
+\r
+  if((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {\r
+    //\r
+    // Query is Volatile related.\r
+    //\r
+    VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);\r
+  } else {\r
+    //\r
+    // Query is Non-Volatile related.\r
+    //\r
+    VariableStoreHeader = mNvVariableCache;\r
+  }\r
+\r
+  //\r
+  // Now let's fill *MaximumVariableStorageSize *RemainingVariableStorageSize\r
+  // with the storage size (excluding the storage header size).\r
+  //\r
+  *MaximumVariableStorageSize   = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER);\r
+\r
+  //\r
+  // Harware error record variable needs larger size.\r
+  //\r
+  if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
+    *MaximumVariableStorageSize = PcdGet32 (PcdHwErrStorageSize);\r
+    *MaximumVariableSize = PcdGet32 (PcdMaxHardwareErrorVariableSize) - sizeof (VARIABLE_HEADER);\r
+  } else {\r
+    if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {\r
+      ASSERT (PcdGet32 (PcdHwErrStorageSize) < VariableStoreHeader->Size);\r
+      *MaximumVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER) - PcdGet32 (PcdHwErrStorageSize);\r
+    }\r
+\r
+    //\r
+    // Let *MaximumVariableSize be PcdGet32 (PcdMaxVariableSize) with the exception of the variable header size.\r
+    //\r
+    *MaximumVariableSize = PcdGet32 (PcdMaxVariableSize) - sizeof (VARIABLE_HEADER);\r
+  }\r
+\r
+  //\r
+  // Point to the starting address of the variables.\r
+  //\r
+  Variable = GetStartPointer (VariableStoreHeader);\r
+\r
+  //\r
+  // Now walk through the related variable store.\r
+  //\r
+  while ((Variable < GetEndPointer (VariableStoreHeader)) && IsValidVariableHeader (Variable)) {\r
+    NextVariable = GetNextVariablePtr (Variable);\r
+    VariableSize = (UINT64) (UINTN) NextVariable - (UINT64) (UINTN) Variable;\r
+\r
+    if (AtRuntime ()) {\r
+      //\r
+      // We don't take the state of the variables in mind\r
+      // when calculating RemainingVariableStorageSize,\r
+      // since the space occupied by variables not marked with\r
+      // VAR_ADDED is not allowed to be reclaimed in Runtime.\r
+      //\r
+      if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
+        HwErrVariableTotalSize += VariableSize;\r
+      } else {\r
+        CommonVariableTotalSize += VariableSize;\r
+      }\r
+    } else {\r
+      //\r
+      // Only care about Variables with State VAR_ADDED, because\r
+      // the space not marked as VAR_ADDED is reclaimable now.\r
+      //\r
+      if (Variable->State == VAR_ADDED) {\r
+        if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
+          HwErrVariableTotalSize += VariableSize;\r
+        } else {\r
+          CommonVariableTotalSize += VariableSize;\r
+        }\r
+      }\r
+    }\r
+\r
+    //\r
+    // Go to the next one.\r
+    //\r
+    Variable = NextVariable;\r
+  }\r
+\r
+  if ((Attributes  & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD){\r
+    *RemainingVariableStorageSize = *MaximumVariableStorageSize - HwErrVariableTotalSize;\r
+  }else {\r
+    *RemainingVariableStorageSize = *MaximumVariableStorageSize - CommonVariableTotalSize;\r
+  }\r
+\r
+  if (*RemainingVariableStorageSize < sizeof (VARIABLE_HEADER)) {\r
+    *MaximumVariableSize = 0;\r
+  } else if ((*RemainingVariableStorageSize - sizeof (VARIABLE_HEADER)) < *MaximumVariableSize) {\r
+    *MaximumVariableSize = *RemainingVariableStorageSize - sizeof (VARIABLE_HEADER);\r
+  }\r
+\r
+  ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  This function reclaims variable storage if free size is below the threshold.\r
+  \r
+**/\r
+VOID\r
+ReclaimForOS(\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS                     Status;\r
+  UINTN                          CommonVariableSpace;\r
+  UINTN                          RemainingCommonVariableSpace;\r
+  UINTN                          RemainingHwErrVariableSpace;\r
+\r
+  Status  = EFI_SUCCESS; \r
+\r
+  CommonVariableSpace = ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase)))->Size - sizeof (VARIABLE_STORE_HEADER) - PcdGet32(PcdHwErrStorageSize); //Allowable max size of common variable storage space\r
+\r
+  RemainingCommonVariableSpace = CommonVariableSpace - mVariableModuleGlobal->CommonVariableTotalSize;\r
+\r
+  RemainingHwErrVariableSpace = PcdGet32 (PcdHwErrStorageSize) - mVariableModuleGlobal->HwErrVariableTotalSize;\r
+  //\r
+  // Check if the free area is blow a threshold.\r
+  //\r
+  if ((RemainingCommonVariableSpace < PcdGet32 (PcdMaxVariableSize))\r
+    || ((PcdGet32 (PcdHwErrStorageSize) != 0) && \r
+       (RemainingHwErrVariableSpace < PcdGet32 (PcdMaxHardwareErrorVariableSize)))){\r
+    Status = Reclaim (\r
+            mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,\r
+            &mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
+            FALSE,\r
+            NULL\r
+            );\r
+    ASSERT_EFI_ERROR (Status);\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Initializes variable write service after FVB was ready.\r
+\r
+  @retval EFI_SUCCESS          Function successfully executed.\r
+  @retval Others               Fail to initialize the variable service.\r
+\r
+**/\r
+EFI_STATUS\r
+VariableWriteServiceInitialize (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  VARIABLE_STORE_HEADER           *VariableStoreHeader;\r
+  UINTN                           Index;\r
+  UINT8                           Data;\r
+  EFI_PHYSICAL_ADDRESS            VariableStoreBase;\r
+  UINT64                          VariableStoreLength;\r
+\r
+  VariableStoreBase   = mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;\r
+  VariableStoreHeader = (VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase;\r
+  VariableStoreLength = VariableStoreHeader->Size;\r
+  \r
+  //\r
+  // Check if the free area is really free.\r
+  //\r
+  for (Index = mVariableModuleGlobal->NonVolatileLastVariableOffset; Index < VariableStoreLength; Index++) {\r
+    Data = ((UINT8 *) mNvVariableCache)[Index];\r
+    if (Data != 0xff) {\r
+      //\r
+      // There must be something wrong in variable store, do reclaim operation.\r
+      //\r
+      Status = Reclaim (\r
+                 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,\r
+                 &mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
+                 FALSE,\r
+                 NULL\r
+                 );\r
+      if (EFI_ERROR (Status)) {\r
+        return Status;\r
+      }\r
+      break;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Authenticated variable initialize.\r
+  //\r
+  Status = AutenticatedVariableServiceInitialize ();\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Initializes variable store area for non-volatile and volatile variable.\r
+\r
+  @retval EFI_SUCCESS           Function successfully executed.\r
+  @retval EFI_OUT_OF_RESOURCES  Fail to allocate enough memory resource.\r
+\r
+**/\r
+EFI_STATUS\r
+VariableCommonInitialize (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  VARIABLE_STORE_HEADER           *VolatileVariableStore;\r
+  VARIABLE_STORE_HEADER           *VariableStoreHeader;\r
+  VARIABLE_HEADER                 *NextVariable;\r
+  EFI_PHYSICAL_ADDRESS            TempVariableStoreHeader;\r
+  EFI_PHYSICAL_ADDRESS            VariableStoreBase;\r
+  UINT64                          VariableStoreLength;\r
+  UINTN                           ScratchSize;\r
+  UINTN                           VariableSize;\r
+\r
+  //\r
+  // Allocate runtime memory for variable driver global structure.\r
+  //\r
+  mVariableModuleGlobal = AllocateRuntimeZeroPool (sizeof (VARIABLE_MODULE_GLOBAL));\r
+  if (mVariableModuleGlobal == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  InitializeLock (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock, TPL_NOTIFY);\r
+\r
+  //\r
+  // Note that in EdkII variable driver implementation, Hardware Error Record type variable\r
+  // is stored with common variable in the same NV region. So the platform integrator should\r
+  // ensure that the value of PcdHwErrStorageSize is less than or equal to the value of \r
+  // PcdFlashNvStorageVariableSize.\r
+  //\r
+  ASSERT (PcdGet32 (PcdHwErrStorageSize) <= PcdGet32 (PcdFlashNvStorageVariableSize));\r
+\r
+  //\r
+  // Allocate memory for volatile variable store, note that there is a scratch space to store scratch data.\r
+  //\r
+  ScratchSize = MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize));\r
+  VolatileVariableStore = AllocateRuntimePool (PcdGet32 (PcdVariableStoreSize) + ScratchSize);\r
+  if (VolatileVariableStore == NULL) {\r
+    FreePool (mVariableModuleGlobal);\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  SetMem (VolatileVariableStore, PcdGet32 (PcdVariableStoreSize) + ScratchSize, 0xff);\r
+\r
+  //\r
+  // Initialize Variable Specific Data.\r
+  //\r
+  mVariableModuleGlobal->VariableGlobal.VolatileVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VolatileVariableStore;\r
+  mVariableModuleGlobal->VolatileLastVariableOffset = (UINTN) GetStartPointer (VolatileVariableStore) - (UINTN) VolatileVariableStore;\r
+  mVariableModuleGlobal->FvbInstance = NULL;\r
+\r
+  CopyGuid (&VolatileVariableStore->Signature, &gEfiAuthenticatedVariableGuid);\r
+  VolatileVariableStore->Size        = PcdGet32 (PcdVariableStoreSize);\r
+  VolatileVariableStore->Format      = VARIABLE_STORE_FORMATTED;\r
+  VolatileVariableStore->State       = VARIABLE_STORE_HEALTHY;\r
+  VolatileVariableStore->Reserved    = 0;\r
+  VolatileVariableStore->Reserved1   = 0;\r
+\r
+  //\r
+  // Get non-volatile varaible store.\r
+  //\r
+\r
+  TempVariableStoreHeader = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageVariableBase64);\r
+  if (TempVariableStoreHeader == 0) {\r
+    TempVariableStoreHeader = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase);\r
+  }\r
+  VariableStoreBase       = TempVariableStoreHeader + \\r
+                              (((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader)) -> HeaderLength);\r
+  VariableStoreLength     = (UINT64) PcdGet32 (PcdFlashNvStorageVariableSize) - \\r
+                              (((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader)) -> HeaderLength);\r
+\r
+  mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase;\r
+  VariableStoreHeader = (VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase;\r
+  if (GetVariableStoreStatus (VariableStoreHeader) != EfiValid) {\r
+    Status = EFI_VOLUME_CORRUPTED;\r
+    DEBUG((EFI_D_INFO, "Variable Store header is corrupted\n"));\r
+    goto Done;\r
+  }  \r
+  ASSERT(VariableStoreHeader->Size == VariableStoreLength);\r
+    \r
+  //\r
+  // Parse non-volatile variable data and get last variable offset.\r
+  //\r
+  NextVariable  = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase);\r
+  while (IsValidVariableHeader (NextVariable)) {\r
+    VariableSize = NextVariable->NameSize + NextVariable->DataSize + sizeof (VARIABLE_HEADER);\r
+    if ((NextVariable->Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
+      mVariableModuleGlobal->HwErrVariableTotalSize += HEADER_ALIGN (VariableSize);\r
+    } else {\r
+      mVariableModuleGlobal->CommonVariableTotalSize += HEADER_ALIGN (VariableSize);\r
+    }\r
+\r
+    NextVariable = GetNextVariablePtr (NextVariable);\r
+  }\r
+\r
+  mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) VariableStoreBase;\r
+    \r
+  //\r
+  // Allocate runtime memory used for a memory copy of the FLASH region.\r
+  // Keep the memory and the FLASH in sync as updates occur\r
+  //\r
+  mNvVariableCache = AllocateRuntimeZeroPool ((UINTN)VariableStoreLength);\r
+  if (mNvVariableCache == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto Done;\r
+  }\r
+  CopyMem (mNvVariableCache, (CHAR8 *)(UINTN)VariableStoreBase, (UINTN)VariableStoreLength);\r
+  Status = EFI_SUCCESS;\r
+\r
+Done:\r
+  if (EFI_ERROR (Status)) {\r
+    FreePool (mVariableModuleGlobal);\r
+    FreePool (VolatileVariableStore);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Get the proper fvb handle and/or fvb protocol by the given Flash address.\r
+\r
+  @param[in]  Address       The Flash address.\r
+  @param[out] FvbHandle     In output, if it is not NULL, it points to the proper FVB handle.\r
+  @param[out] FvbProtocol   In output, if it is not NULL, it points to the proper FVB protocol.\r
+\r
+**/\r
+EFI_STATUS\r
+GetFvbInfoByAddress (\r
+  IN  EFI_PHYSICAL_ADDRESS                Address,\r
+  OUT EFI_HANDLE                          *FvbHandle OPTIONAL,\r
+  OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  **FvbProtocol OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS                              Status;\r
+  EFI_HANDLE                              *HandleBuffer;\r
+  UINTN                                   HandleCount;\r
+  UINTN                                   Index;\r
+  EFI_PHYSICAL_ADDRESS                    FvbBaseAddress;\r
+  EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL      *Fvb;\r
+  EFI_FIRMWARE_VOLUME_HEADER              *FwVolHeader;\r
+  EFI_FVB_ATTRIBUTES_2                    Attributes;\r
\r
+  //\r
+  // Get all FVB handles.\r
+  //\r
+  Status = GetFvbCountAndBuffer (&HandleCount, &HandleBuffer);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  //\r
+  // Get the FVB to access variable store.\r
+  //\r
+  Fvb = NULL;\r
+  for (Index = 0; Index < HandleCount; Index += 1, Status = EFI_NOT_FOUND, Fvb = NULL) {\r
+    Status = GetFvbByHandle (HandleBuffer[Index], &Fvb);\r
+    if (EFI_ERROR (Status)) {\r
+      Status = EFI_NOT_FOUND;\r
+      break;\r
+    }\r
+\r
+    //\r
+    // Ensure this FVB protocol supported Write operation.\r
+    //\r
+    Status = Fvb->GetAttributes (Fvb, &Attributes);\r
+    if (EFI_ERROR (Status) || ((Attributes & EFI_FVB2_WRITE_STATUS) == 0)) {\r
+      continue;     \r
+    }\r
+    \r
+    //\r
+    // Compare the address and select the right one.\r
+    //\r
+    Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress);\r
+    if (EFI_ERROR (Status)) {\r
+      continue;\r
+    }\r
+\r
+    FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress);\r
+    if ((Address >= FvbBaseAddress) && (Address < (FvbBaseAddress + FwVolHeader->FvLength))) {\r
+      if (FvbHandle != NULL) {\r
+        *FvbHandle  = HandleBuffer[Index];\r
+      }\r
+      if (FvbProtocol != NULL) {\r
+        *FvbProtocol = Fvb;\r
+      }\r
+      Status = EFI_SUCCESS;\r
+      break;\r
+    }\r
+  }\r
+  FreePool (HandleBuffer);\r
+\r
+  if (Fvb == NULL) {\r
+    Status = EFI_NOT_FOUND;\r
+  }\r
+  \r
+  return Status;  \r
+}\r
+\r
diff --git a/SecurityPkg/VariableAuthenticated/RuntimeDxe/Variable.h b/SecurityPkg/VariableAuthenticated/RuntimeDxe/Variable.h
new file mode 100644 (file)
index 0000000..6865f0d
--- /dev/null
@@ -0,0 +1,491 @@
+/** @file\r
+  The internal header file includes the common header files, defines\r
+  internal structure and functions used by Variable modules.\r
+\r
+Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _VARIABLE_H_\r
+#define _VARIABLE_H_\r
+\r
+#include <PiDxe.h>\r
+#include <Protocol/VariableWrite.h>\r
+#include <Protocol/FaultTolerantWrite.h>\r
+#include <Protocol/FirmwareVolumeBlock.h>\r
+#include <Protocol/Variable.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/UefiDriverEntryPoint.h>\r
+#include <Library/DxeServicesTableLib.h>\r
+#include <Library/UefiRuntimeLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/SynchronizationLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/BaseCryptLib.h>\r
+#include <Library/PlatformSecureLib.h>\r
+#include <Guid/GlobalVariable.h>\r
+#include <Guid/EventGroup.h>\r
+#include <Guid/AuthenticatedVariableFormat.h>\r
+#include <Guid/ImageAuthentication.h>\r
+\r
+#define VARIABLE_RECLAIM_THRESHOLD (1024)\r
+\r
+///\r
+/// The size of a 3 character ISO639 language code.\r
+///\r
+#define ISO_639_2_ENTRY_SIZE    3\r
+\r
+typedef struct {\r
+  VARIABLE_HEADER *CurrPtr;\r
+  VARIABLE_HEADER *EndPtr;\r
+  VARIABLE_HEADER *StartPtr;\r
+  BOOLEAN         Volatile;\r
+} VARIABLE_POINTER_TRACK;\r
+\r
+typedef struct {\r
+  EFI_PHYSICAL_ADDRESS  VolatileVariableBase;\r
+  EFI_PHYSICAL_ADDRESS  NonVolatileVariableBase;\r
+  EFI_LOCK              VariableServicesLock;\r
+  UINT32                ReentrantState;\r
+} VARIABLE_GLOBAL;\r
+\r
+typedef struct {\r
+  VARIABLE_GLOBAL VariableGlobal;\r
+  UINTN           VolatileLastVariableOffset;\r
+  UINTN           NonVolatileLastVariableOffset;\r
+  UINTN           CommonVariableTotalSize;\r
+  UINTN           HwErrVariableTotalSize;\r
+  CHAR8           *PlatformLangCodes;\r
+  CHAR8           *LangCodes;\r
+  CHAR8           *PlatformLang;\r
+  CHAR8           Lang[ISO_639_2_ENTRY_SIZE + 1];\r
+  EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbInstance;\r
+} VARIABLE_MODULE_GLOBAL;\r
+\r
+typedef struct {\r
+  EFI_GUID    *Guid;\r
+  CHAR16      *Name;\r
+  UINT32      Attributes;\r
+  UINTN       DataSize;\r
+  VOID        *Data;\r
+} VARIABLE_CACHE_ENTRY;\r
+\r
+/**\r
+  Writes a buffer to variable storage space, in the working block.\r
+\r
+  This function writes a buffer to variable storage space into a firmware\r
+  volume block device. The destination is specified by the parameter\r
+  VariableBase. Fault Tolerant Write protocol is used for writing.\r
+\r
+  @param  VariableBase   Base address of the variable to write.\r
+  @param  Buffer         Point to the data buffer.\r
+  @param  BufferSize     The number of bytes of the data Buffer.\r
+\r
+  @retval EFI_SUCCESS    The function completed successfully.\r
+  @retval EFI_NOT_FOUND  Fail to locate Fault Tolerant Write protocol.\r
+  @retval EFI_ABORTED    The function could not complete successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+FtwVariableSpace (\r
+  IN EFI_PHYSICAL_ADDRESS   VariableBase,\r
+  IN UINT8                  *Buffer,\r
+  IN UINTN                  BufferSize\r
+  );\r
+\r
+/**\r
+  Finds variable in storage blocks of volatile and non-volatile storage areas.\r
+\r
+  This code finds variable in storage blocks of volatile and non-volatile storage areas.\r
+  If VariableName is an empty string, then we just return the first\r
+  qualified variable without comparing VariableName and VendorGuid.\r
+  Otherwise, VariableName and VendorGuid are compared.\r
+\r
+  @param  VariableName                Name of the variable to be found.\r
+  @param  VendorGuid                  Vendor GUID to be found.\r
+  @param  PtrTrack                    VARIABLE_POINTER_TRACK structure for output,\r
+                                      including the range searched and the target position.\r
+  @param  Global                      Pointer to VARIABLE_GLOBAL structure, including\r
+                                      base of volatile variable storage area, base of\r
+                                      NV variable storage area, and a lock.\r
+\r
+  @retval EFI_INVALID_PARAMETER       If VariableName is not an empty string, while\r
+                                      VendorGuid is NULL.\r
+  @retval EFI_SUCCESS                 Variable successfully found.\r
+  @retval EFI_INVALID_PARAMETER       Variable not found.\r
+\r
+**/\r
+EFI_STATUS\r
+FindVariable (\r
+  IN  CHAR16                  *VariableName,\r
+  IN  EFI_GUID                *VendorGuid,\r
+  OUT VARIABLE_POINTER_TRACK  *PtrTrack,\r
+  IN  VARIABLE_GLOBAL         *Global\r
+  );\r
+\r
+/**\r
+\r
+  This code gets the pointer to the variable data.\r
+\r
+  @param Variable        Pointer to the Variable Header.\r
+\r
+  @return Pointer to Variable Data.\r
+\r
+**/\r
+UINT8 *\r
+GetVariableDataPtr (\r
+  IN  VARIABLE_HEADER   *Variable\r
+  );\r
+\r
+/**\r
+\r
+  This code gets the size of variable data.\r
+\r
+  @param Variable        Pointer to the Variable Header.\r
+\r
+  @return Size of variable in bytes.\r
+\r
+**/\r
+UINTN\r
+DataSizeOfVariable (\r
+  IN  VARIABLE_HEADER   *Variable\r
+  );\r
+\r
+/**\r
+  Update the variable region with Variable information. If EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS is set,\r
+  index of associated public key is needed.\r
+\r
+  @param[in] VariableName       Name of variable.\r
+  @param[in] VendorGuid         Guid of variable.\r
+  @param[in] Data               Variable data.\r
+  @param[in] DataSize           Size of data. 0 means delete.\r
+  @param[in] Attributes         Attributes of the variable.\r
+  @param[in] KeyIndex           Index of associated public key.\r
+  @param[in] MonotonicCount     Value of associated monotonic count.\r
+  @param[in] Variable           The variable information that is used to keep track of variable usage.\r
+\r
+  @param[in] TimeStamp          Value of associated TimeStamp.\r
+\r
+  @retval EFI_SUCCESS           The update operation is success.\r
+  @retval EFI_OUT_OF_RESOURCES  Variable region is full, cannot write other data into this region.\r
+\r
+**/\r
+EFI_STATUS\r
+UpdateVariable (\r
+  IN      CHAR16          *VariableName,\r
+  IN      EFI_GUID        *VendorGuid,\r
+  IN      VOID            *Data,\r
+  IN      UINTN           DataSize,\r
+  IN      UINT32          Attributes OPTIONAL,\r
+  IN      UINT32          KeyIndex  OPTIONAL,\r
+  IN      UINT64          MonotonicCount  OPTIONAL,\r
+  IN      VARIABLE_POINTER_TRACK *Variable,\r
+  IN      EFI_TIME        *TimeStamp  OPTIONAL  \r
+  );\r
+\r
+\r
+/**\r
+  Return TRUE if ExitBootServices () has been called.\r
+  \r
+  @retval TRUE If ExitBootServices () has been called.\r
+**/\r
+BOOLEAN\r
+AtRuntime (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Initializes a basic mutual exclusion lock.\r
+\r
+  This function initializes a basic mutual exclusion lock to the released state \r
+  and returns the lock.  Each lock provides mutual exclusion access at its task \r
+  priority level.  Since there is no preemption or multiprocessor support in EFI,\r
+  acquiring the lock only consists of raising to the locks TPL.\r
+  If Lock is NULL, then ASSERT().\r
+  If Priority is not a valid TPL value, then ASSERT().\r
+\r
+  @param  Lock       A pointer to the lock data structure to initialize.\r
+  @param  Priority   EFI TPL is associated with the lock.\r
+\r
+  @return The lock.\r
+\r
+**/\r
+EFI_LOCK *\r
+InitializeLock (\r
+  IN OUT EFI_LOCK  *Lock,\r
+  IN EFI_TPL        Priority\r
+  );\r
+\r
+  \r
+/**\r
+  Acquires lock only at boot time. Simply returns at runtime.\r
+\r
+  This is a temperary function that will be removed when\r
+  EfiAcquireLock() in UefiLib can handle the call in UEFI\r
+  Runtimer driver in RT phase.\r
+  It calls EfiAcquireLock() at boot time, and simply returns\r
+  at runtime.\r
+\r
+  @param  Lock         A pointer to the lock to acquire.\r
+\r
+**/\r
+VOID\r
+AcquireLockOnlyAtBootTime (\r
+  IN EFI_LOCK  *Lock\r
+  );\r
+\r
+\r
+/**\r
+  Releases lock only at boot time. Simply returns at runtime.\r
+\r
+  This is a temperary function which will be removed when\r
+  EfiReleaseLock() in UefiLib can handle the call in UEFI\r
+  Runtimer driver in RT phase.\r
+  It calls EfiReleaseLock() at boot time and simply returns\r
+  at runtime.\r
+\r
+  @param  Lock         A pointer to the lock to release.\r
+\r
+**/\r
+VOID\r
+ReleaseLockOnlyAtBootTime (\r
+  IN EFI_LOCK  *Lock\r
+  );  \r
+\r
+/**\r
+  Retrive the FVB protocol interface by HANDLE.\r
+\r
+  @param[in]  FvBlockHandle     The handle of FVB protocol that provides services for\r
+                                reading, writing, and erasing the target block.\r
+  @param[out] FvBlock           The interface of FVB protocol\r
+\r
+  @retval EFI_SUCCESS           The interface information for the specified protocol was returned.\r
+  @retval EFI_UNSUPPORTED       The device does not support the FVB protocol.\r
+  @retval EFI_INVALID_PARAMETER FvBlockHandle is not a valid EFI_HANDLE or FvBlock is NULL.\r
+  \r
+**/\r
+EFI_STATUS\r
+GetFvbByHandle (\r
+  IN  EFI_HANDLE                          FvBlockHandle,\r
+  OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  **FvBlock\r
+  );\r
+\r
+\r
+/**\r
+  Retrive the Swap Address Range protocol interface.\r
+\r
+  @param[out] SarProtocol       The interface of SAR protocol\r
+\r
+  @retval EFI_SUCCESS           The SAR protocol instance was found and returned in SarProtocol.\r
+  @retval EFI_NOT_FOUND         The SAR protocol instance was not found.\r
+  @retval EFI_INVALID_PARAMETER SarProtocol is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+GetSarProtocol (\r
+  OUT VOID                                **SarProtocol\r
+  );\r
+\r
+/**\r
+  Function returns an array of handles that support the FVB protocol\r
+  in a buffer allocated from pool. \r
+\r
+  @param[out]  NumberHandles    The number of handles returned in Buffer.\r
+  @param[out]  Buffer           A pointer to the buffer to return the requested\r
+                                array of  handles that support FVB protocol.\r
+\r
+  @retval EFI_SUCCESS           The array of handles was returned in Buffer, and the number of\r
+                                handles in Buffer was returned in NumberHandles.\r
+  @retval EFI_NOT_FOUND         No FVB handle was found.\r
+  @retval EFI_OUT_OF_RESOURCES  There is not enough pool memory to store the matching results.\r
+  @retval EFI_INVALID_PARAMETER NumberHandles is NULL or Buffer is NULL.\r
+  \r
+**/\r
+EFI_STATUS\r
+GetFvbCountAndBuffer (\r
+  OUT UINTN                               *NumberHandles,\r
+  OUT EFI_HANDLE                          **Buffer\r
+  );\r
+\r
+/**\r
+  Initializes variable store area for non-volatile and volatile variable.\r
+\r
+  @retval EFI_SUCCESS           Function successfully executed.\r
+  @retval EFI_OUT_OF_RESOURCES  Fail to allocate enough memory resource.\r
+\r
+**/\r
+EFI_STATUS\r
+VariableCommonInitialize (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  This function reclaims variable storage if free size is below the threshold.\r
+  \r
+**/\r
+VOID\r
+ReclaimForOS(\r
+  VOID\r
+  );  \r
+\r
+\r
+/**\r
+  Initializes variable write service after FVB was ready.\r
+\r
+  @retval EFI_SUCCESS          Function successfully executed.\r
+  @retval Others               Fail to initialize the variable service.\r
+\r
+**/\r
+EFI_STATUS\r
+VariableWriteServiceInitialize (\r
+  VOID\r
+  );\r
+  \r
+/**\r
+  Retrive the SMM Fault Tolerent Write protocol interface.\r
+\r
+  @param[out] FtwProtocol       The interface of SMM Ftw protocol\r
+\r
+  @retval EFI_SUCCESS           The SMM SAR protocol instance was found and returned in SarProtocol.\r
+  @retval EFI_NOT_FOUND         The SMM SAR protocol instance was not found.\r
+  @retval EFI_INVALID_PARAMETER SarProtocol is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+GetFtwProtocol (\r
+  OUT VOID                                **FtwProtocol\r
+  );\r
+\r
+/**\r
+  Get the proper fvb handle and/or fvb protocol by the given Flash address.\r
+\r
+  @param[in] Address        The Flash address.\r
+  @param[out] FvbHandle     In output, if it is not NULL, it points to the proper FVB handle.\r
+  @param[out] FvbProtocol   In output, if it is not NULL, it points to the proper FVB protocol.\r
+\r
+**/\r
+EFI_STATUS\r
+GetFvbInfoByAddress (\r
+  IN  EFI_PHYSICAL_ADDRESS                Address,\r
+  OUT EFI_HANDLE                          *FvbHandle OPTIONAL,\r
+  OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  **FvbProtocol OPTIONAL\r
+  );\r
+\r
+/**\r
+\r
+  This code finds variable in storage blocks (Volatile or Non-Volatile).\r
+\r
+  @param VariableName               Name of Variable to be found.\r
+  @param VendorGuid                 Variable vendor GUID.\r
+  @param Attributes                 Attribute value of the variable found.\r
+  @param DataSize                   Size of Data found. If size is less than the\r
+                                    data, this value contains the required size.\r
+  @param Data                       Data pointer.\r
+                      \r
+  @return EFI_INVALID_PARAMETER     Invalid parameter.\r
+  @return EFI_SUCCESS               Find the specified variable.\r
+  @return EFI_NOT_FOUND             Not found.\r
+  @return EFI_BUFFER_TO_SMALL       DataSize is too small for the result.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+VariableServiceGetVariable (\r
+  IN      CHAR16            *VariableName,\r
+  IN      EFI_GUID          *VendorGuid,\r
+  OUT     UINT32            *Attributes OPTIONAL,\r
+  IN OUT  UINTN             *DataSize,\r
+  OUT     VOID              *Data\r
+  );\r
+\r
+/**\r
+\r
+  This code Finds the Next available variable.\r
+\r
+  @param VariableNameSize           Size of the variable name.\r
+  @param VariableName               Pointer to variable name.\r
+  @param VendorGuid                 Variable Vendor Guid.\r
+\r
+  @return EFI_INVALID_PARAMETER     Invalid parameter.\r
+  @return EFI_SUCCESS               Find the specified variable.\r
+  @return EFI_NOT_FOUND             Not found.\r
+  @return EFI_BUFFER_TO_SMALL       DataSize is too small for the result.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+VariableServiceGetNextVariableName (\r
+  IN OUT  UINTN             *VariableNameSize,\r
+  IN OUT  CHAR16            *VariableName,\r
+  IN OUT  EFI_GUID          *VendorGuid\r
+  );\r
+\r
+/**\r
+\r
+  This code sets variable in storage blocks (Volatile or Non-Volatile).\r
+\r
+  @param VariableName                     Name of Variable to be found.\r
+  @param VendorGuid                       Variable vendor GUID.\r
+  @param Attributes                       Attribute value of the variable found\r
+  @param DataSize                         Size of Data found. If size is less than the\r
+                                          data, this value contains the required size.\r
+  @param Data                             Data pointer.\r
+\r
+  @return EFI_INVALID_PARAMETER           Invalid parameter.\r
+  @return EFI_SUCCESS                     Set successfully.\r
+  @return EFI_OUT_OF_RESOURCES            Resource not enough to set variable.\r
+  @return EFI_NOT_FOUND                   Not found.\r
+  @return EFI_WRITE_PROTECTED             Variable is read-only.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+VariableServiceSetVariable (\r
+  IN CHAR16                  *VariableName,\r
+  IN EFI_GUID                *VendorGuid,\r
+  IN UINT32                  Attributes,\r
+  IN UINTN                   DataSize,\r
+  IN VOID                    *Data\r
+  );\r
+\r
+/**\r
+\r
+  This code returns information about the EFI variables.\r
+\r
+  @param Attributes                     Attributes bitmask to specify the type of variables\r
+                                        on which to return information.\r
+  @param MaximumVariableStorageSize     Pointer to the maximum size of the storage space available\r
+                                        for the EFI variables associated with the attributes specified.\r
+  @param RemainingVariableStorageSize   Pointer to the remaining size of the storage space available\r
+                                        for EFI variables associated with the attributes specified.\r
+  @param MaximumVariableSize            Pointer to the maximum size of an individual EFI variables\r
+                                        associated with the attributes specified.\r
+\r
+  @return EFI_INVALID_PARAMETER         An invalid combination of attribute bits was supplied.\r
+  @return EFI_SUCCESS                   Query successfully.\r
+  @return EFI_UNSUPPORTED               The attribute is not supported on this platform.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+VariableServiceQueryVariableInfo (\r
+  IN  UINT32                 Attributes,\r
+  OUT UINT64                 *MaximumVariableStorageSize,\r
+  OUT UINT64                 *RemainingVariableStorageSize,\r
+  OUT UINT64                 *MaximumVariableSize\r
+  );  \r
+  \r
+extern VARIABLE_MODULE_GLOBAL  *mVariableModuleGlobal;\r
+\r
+#endif\r
diff --git a/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableDxe.c b/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableDxe.c
new file mode 100644 (file)
index 0000000..7b88f15
--- /dev/null
@@ -0,0 +1,433 @@
+/** @file\r
+  Implement all four UEFI Runtime Variable services for the nonvolatile\r
+  and volatile storage space and install variable architecture protocol.\r
+\r
+Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "Variable.h"\r
+#include "AuthService.h"\r
+\r
+extern VARIABLE_STORE_HEADER        *mNvVariableCache;\r
+extern VARIABLE_INFO_ENTRY          *gVariableInfo;\r
+EFI_HANDLE                          mHandle                    = NULL;\r
+EFI_EVENT                           mVirtualAddressChangeEvent = NULL;\r
+EFI_EVENT                           mFtwRegistration           = NULL;\r
+\r
+/**\r
+  Return TRUE if ExitBootServices () has been called.\r
+  \r
+  @retval TRUE If ExitBootServices () has been called.\r
+**/\r
+BOOLEAN\r
+AtRuntime (\r
+  VOID\r
+  )\r
+{\r
+  return EfiAtRuntime ();\r
+}\r
+\r
+\r
+/**\r
+  Initializes a basic mutual exclusion lock.\r
+\r
+  This function initializes a basic mutual exclusion lock to the released state \r
+  and returns the lock.  Each lock provides mutual exclusion access at its task \r
+  priority level.  Since there is no preemption or multiprocessor support in EFI,\r
+  acquiring the lock only consists of raising to the locks TPL.\r
+  If Lock is NULL, then ASSERT().\r
+  If Priority is not a valid TPL value, then ASSERT().\r
+\r
+  @param  Lock       A pointer to the lock data structure to initialize.\r
+  @param  Priority   EFI TPL is associated with the lock.\r
+\r
+  @return The lock.\r
+\r
+**/\r
+EFI_LOCK *\r
+InitializeLock (\r
+  IN OUT EFI_LOCK                         *Lock,\r
+  IN     EFI_TPL                          Priority\r
+  )\r
+{\r
+  return EfiInitializeLock (Lock, Priority);\r
+}\r
+\r
+\r
+/**\r
+  Acquires lock only at boot time. Simply returns at runtime.\r
+\r
+  This is a temperary function that will be removed when\r
+  EfiAcquireLock() in UefiLib can handle the call in UEFI\r
+  Runtimer driver in RT phase.\r
+  It calls EfiAcquireLock() at boot time, and simply returns\r
+  at runtime.\r
+\r
+  @param  Lock         A pointer to the lock to acquire.\r
+\r
+**/\r
+VOID\r
+AcquireLockOnlyAtBootTime (\r
+  IN EFI_LOCK                             *Lock\r
+  )\r
+{\r
+  if (!AtRuntime ()) {\r
+    EfiAcquireLock (Lock);\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Releases lock only at boot time. Simply returns at runtime.\r
+\r
+  This is a temperary function which will be removed when\r
+  EfiReleaseLock() in UefiLib can handle the call in UEFI\r
+  Runtimer driver in RT phase.\r
+  It calls EfiReleaseLock() at boot time and simply returns\r
+  at runtime.\r
+\r
+  @param  Lock         A pointer to the lock to release.\r
+\r
+**/\r
+VOID\r
+ReleaseLockOnlyAtBootTime (\r
+  IN EFI_LOCK                             *Lock\r
+  )\r
+{\r
+  if (!AtRuntime ()) {\r
+    EfiReleaseLock (Lock);\r
+  }\r
+}\r
+\r
+/**\r
+  Retrive the Fault Tolerent Write protocol interface.\r
+\r
+  @param[out] FtwProtocol       The interface of Ftw protocol\r
+\r
+  @retval EFI_SUCCESS           The FTW protocol instance was found and returned in FtwProtocol.\r
+  @retval EFI_NOT_FOUND         The FTW protocol instance was not found.\r
+  @retval EFI_INVALID_PARAMETER SarProtocol is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+GetFtwProtocol (\r
+  OUT VOID                                **FtwProtocol\r
+  )\r
+{\r
+  EFI_STATUS                              Status;\r
+\r
+  //\r
+  // Locate Fault Tolerent Write protocol\r
+  //\r
+  Status = gBS->LocateProtocol (\r
+                  &gEfiFaultTolerantWriteProtocolGuid,\r
+                  NULL,\r
+                  FtwProtocol\r
+                  );                    \r
+  return Status;\r
+}\r
+\r
+/**\r
+  Retrive the FVB protocol interface by HANDLE.\r
+\r
+  @param[in]  FvBlockHandle     The handle of FVB protocol that provides services for\r
+                                reading, writing, and erasing the target block.\r
+  @param[out] FvBlock           The interface of FVB protocol\r
+\r
+  @retval EFI_SUCCESS           The interface information for the specified protocol was returned.\r
+  @retval EFI_UNSUPPORTED       The device does not support the FVB protocol.\r
+  @retval EFI_INVALID_PARAMETER FvBlockHandle is not a valid EFI_HANDLE or FvBlock is NULL.\r
+  \r
+**/\r
+EFI_STATUS\r
+GetFvbByHandle (\r
+  IN  EFI_HANDLE                          FvBlockHandle,\r
+  OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  **FvBlock\r
+  )\r
+{\r
+  //\r
+  // To get the FVB protocol interface on the handle\r
+  //\r
+  return gBS->HandleProtocol (\r
+                FvBlockHandle,\r
+                &gEfiFirmwareVolumeBlockProtocolGuid,\r
+                (VOID **) FvBlock\r
+                );\r
+}\r
+\r
+\r
+/**\r
+  Function returns an array of handles that support the FVB protocol\r
+  in a buffer allocated from pool. \r
+\r
+  @param[out]  NumberHandles    The number of handles returned in Buffer.\r
+  @param[out]  Buffer           A pointer to the buffer to return the requested\r
+                                array of  handles that support FVB protocol.\r
+\r
+  @retval EFI_SUCCESS           The array of handles was returned in Buffer, and the number of\r
+                                handles in Buffer was returned in NumberHandles.\r
+  @retval EFI_NOT_FOUND         No FVB handle was found.\r
+  @retval EFI_OUT_OF_RESOURCES  There is not enough pool memory to store the matching results.\r
+  @retval EFI_INVALID_PARAMETER NumberHandles is NULL or Buffer is NULL.\r
+  \r
+**/\r
+EFI_STATUS\r
+GetFvbCountAndBuffer (\r
+  OUT UINTN                               *NumberHandles,\r
+  OUT EFI_HANDLE                          **Buffer\r
+  )\r
+{\r
+  EFI_STATUS                              Status;\r
+\r
+  //\r
+  // Locate all handles of Fvb protocol\r
+  //\r
+  Status = gBS->LocateHandleBuffer (\r
+                  ByProtocol,\r
+                  &gEfiFirmwareVolumeBlockProtocolGuid,\r
+                  NULL,\r
+                  NumberHandles,\r
+                  Buffer\r
+                  );\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.\r
+\r
+  This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.\r
+  It convers pointer to new virtual address.\r
+\r
+  @param  Event        Event whose notification function is being invoked.\r
+  @param  Context      Pointer to the notification function's context.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+VariableClassAddressChangeEvent (\r
+  IN EFI_EVENT                            Event,\r
+  IN VOID                                 *Context\r
+  )\r
+{\r
+  EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetBlockSize);\r
+  EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetPhysicalAddress);\r
+  EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetAttributes);\r
+  EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->SetAttributes);\r
+  EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->Read);\r
+  EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->Write);\r
+  EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->EraseBlocks);\r
+  EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance);\r
+  EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->PlatformLangCodes);\r
+  EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->LangCodes);\r
+  EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->PlatformLang);\r
+  EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase);\r
+  EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);\r
+  EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal);\r
+  EfiConvertPointer (0x0, (VOID **) &mHashCtx);\r
+  EfiConvertPointer (0x0, (VOID **) &mStorageArea);  \r
+  EfiConvertPointer (0x0, (VOID **) &mNvVariableCache);  \r
+}\r
+\r
+\r
+/**\r
+  Notification function of EVT_GROUP_READY_TO_BOOT event group.\r
+\r
+  This is a notification function registered on EVT_GROUP_READY_TO_BOOT event group.\r
+  When the Boot Manager is about to load and execute a boot option, it reclaims variable\r
+  storage if free size is below the threshold.\r
+\r
+  @param  Event        Event whose notification function is being invoked.\r
+  @param  Context      Pointer to the notification function's context.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+OnReadyToBoot (\r
+  EFI_EVENT                               Event,\r
+  VOID                                    *Context\r
+  )\r
+{\r
+  ReclaimForOS ();\r
+  if (FeaturePcdGet (PcdVariableCollectStatistics)) {\r
+    gBS->InstallConfigurationTable (&gEfiAuthenticatedVariableGuid, gVariableInfo);\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Fault Tolerant Write protocol notification event handler.\r
+\r
+  Non-Volatile variable write may needs FTW protocol to reclaim when \r
+  writting variable.\r
+\r
+  @param[in] Event    Event whose notification function is being invoked.\r
+  @param[in] Context  Pointer to the notification function's context.\r
+  \r
+**/\r
+VOID\r
+EFIAPI\r
+FtwNotificationEvent (\r
+  IN  EFI_EVENT                           Event,\r
+  IN  VOID                                *Context\r
+  )\r
+{\r
+  EFI_STATUS                              Status;\r
+  EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL      *FvbProtocol;\r
+  EFI_FAULT_TOLERANT_WRITE_PROTOCOL       *FtwProtocol;\r
+  EFI_PHYSICAL_ADDRESS                    NvStorageVariableBase;\r
+  EFI_GCD_MEMORY_SPACE_DESCRIPTOR         GcdDescriptor;\r
+  EFI_PHYSICAL_ADDRESS                    BaseAddress;\r
+  UINT64                                  Length;\r
+  EFI_PHYSICAL_ADDRESS                    VariableStoreBase;\r
+  UINT64                                  VariableStoreLength;\r
+\r
+  //\r
+  // Ensure FTW protocol is installed.\r
+  //\r
+  Status = GetFtwProtocol ((VOID**) &FtwProtocol);\r
+  if (EFI_ERROR (Status)) {\r
+    return ;\r
+  }\r
+  \r
+  //\r
+  // Find the proper FVB protocol for variable.\r
+  //\r
+  NvStorageVariableBase = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageVariableBase64);\r
+  if (NvStorageVariableBase == 0) {\r
+    NvStorageVariableBase = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase);\r
+  }\r
+  Status = GetFvbInfoByAddress (NvStorageVariableBase, NULL, &FvbProtocol);\r
+  if (EFI_ERROR (Status)) {\r
+    return ;\r
+  }\r
+  mVariableModuleGlobal->FvbInstance = FvbProtocol;\r
+\r
+  //\r
+  // Mark the variable storage region of the FLASH as RUNTIME.\r
+  //\r
+  VariableStoreBase   = mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;\r
+  VariableStoreLength = ((VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase)->Size;\r
+  BaseAddress = VariableStoreBase & (~EFI_PAGE_MASK);\r
+  Length      = VariableStoreLength + (VariableStoreBase - BaseAddress);\r
+  Length      = (Length + EFI_PAGE_SIZE - 1) & (~EFI_PAGE_MASK);\r
+\r
+  Status      = gDS->GetMemorySpaceDescriptor (BaseAddress, &GcdDescriptor);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_WARN, "Variable driver failed to add EFI_MEMORY_RUNTIME attribute to Flash.\n"));\r
+  } else {\r
+    Status = gDS->SetMemorySpaceAttributes (\r
+                    BaseAddress,\r
+                    Length,\r
+                    GcdDescriptor.Attributes | EFI_MEMORY_RUNTIME\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((DEBUG_WARN, "Variable driver failed to add EFI_MEMORY_RUNTIME attribute to Flash.\n"));\r
+    }\r
+  }\r
+  \r
+  Status = VariableWriteServiceInitialize ();\r
+  ASSERT_EFI_ERROR (Status);\r
\r
+  //\r
+  // Install the Variable Write Architectural protocol.\r
+  //\r
+  Status = gBS->InstallProtocolInterface (\r
+                  &mHandle,\r
+                  &gEfiVariableWriteArchProtocolGuid, \r
+                  EFI_NATIVE_INTERFACE,\r
+                  NULL\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+  \r
+  //\r
+  // Close the notify event to avoid install gEfiVariableWriteArchProtocolGuid again.\r
+  //\r
+  gBS->CloseEvent (Event);\r
+\r
+}\r
+\r
+\r
+/**\r
+  Variable Driver main entry point. The Variable driver places the 4 EFI\r
+  runtime services in the EFI System Table and installs arch protocols \r
+  for variable read and write services being available. It also registers\r
+  a notification function for an EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.\r
+\r
+  @param[in] ImageHandle    The firmware allocated handle for the EFI image.  \r
+  @param[in] SystemTable    A pointer to the EFI System Table.\r
+  \r
+  @retval EFI_SUCCESS       Variable service successfully initialized.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+VariableServiceInitialize (\r
+  IN EFI_HANDLE                         ImageHandle,\r
+  IN EFI_SYSTEM_TABLE                   *SystemTable\r
+  )\r
+{\r
+  EFI_STATUS                            Status;\r
+  EFI_EVENT                             ReadyToBootEvent;    \r
+\r
+  Status = VariableCommonInitialize ();\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  SystemTable->RuntimeServices->GetVariable         = VariableServiceGetVariable;\r
+  SystemTable->RuntimeServices->GetNextVariableName = VariableServiceGetNextVariableName;\r
+  SystemTable->RuntimeServices->SetVariable         = VariableServiceSetVariable;\r
+  SystemTable->RuntimeServices->QueryVariableInfo   = VariableServiceQueryVariableInfo;\r
+    \r
+  //\r
+  // Now install the Variable Runtime Architectural protocol on a new handle.\r
+  //\r
+  Status = gBS->InstallProtocolInterface (\r
+                  &mHandle,\r
+                  &gEfiVariableArchProtocolGuid, \r
+                  EFI_NATIVE_INTERFACE,\r
+                  NULL\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // Register FtwNotificationEvent () notify function.\r
+  // \r
+  EfiCreateProtocolNotifyEvent (\r
+    &gEfiFaultTolerantWriteProtocolGuid,\r
+    TPL_CALLBACK,\r
+    FtwNotificationEvent,\r
+    (VOID *)SystemTable,\r
+    &mFtwRegistration\r
+    );\r
+\r
+  Status = gBS->CreateEventEx (\r
+                  EVT_NOTIFY_SIGNAL,\r
+                  TPL_NOTIFY,\r
+                  VariableClassAddressChangeEvent,\r
+                  NULL,\r
+                  &gEfiEventVirtualAddressChangeGuid,\r
+                  &mVirtualAddressChangeEvent\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // Register the event handling function to reclaim variable for OS usage.\r
+  //\r
+  Status = EfiCreateEventReadyToBootEx (\r
+             TPL_NOTIFY, \r
+             OnReadyToBoot, \r
+             NULL, \r
+             &ReadyToBootEvent\r
+             );\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
diff --git a/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableRuntimeDxe.inf b/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableRuntimeDxe.inf
new file mode 100644 (file)
index 0000000..7858084
--- /dev/null
@@ -0,0 +1,98 @@
+## @file\r
+#  Component description file for Authenticated Variable module.\r
+#\r
+# Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = VariableRuntimeDxe\r
+  FILE_GUID                      = 2226F30F-3D5B-402d-9936-A97184EB4516\r
+  MODULE_TYPE                    = DXE_RUNTIME_DRIVER\r
+  VERSION_STRING                 = 1.0\r
+  ENTRY_POINT                    = VariableServiceInitialize\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64 EBC\r
+#\r
+#  VIRTUAL_ADDRESS_MAP_CALLBACK  =  VariableClassAddressChangeEvent\r
+#\r
+\r
+[Sources]\r
+  Reclaim.c\r
+  Variable.c\r
+  VariableDxe.c\r
+  Variable.h\r
+  AuthService.c\r
+  AuthService.h\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+  CryptoPkg/CryptoPkg.dec\r
+  SecurityPkg/SecurityPkg.dec\r
+\r
+[LibraryClasses]\r
+  MemoryAllocationLib\r
+  BaseLib\r
+  SynchronizationLib\r
+  UefiLib\r
+  UefiBootServicesTableLib\r
+  BaseMemoryLib\r
+  DebugLib\r
+  UefiRuntimeLib\r
+  DxeServicesTableLib\r
+  UefiDriverEntryPoint\r
+  PcdLib\r
+  BaseCryptLib\r
+  PlatformSecureLib  \r
+\r
+[Protocols]\r
+  gEfiFirmwareVolumeBlockProtocolGuid           ## SOMETIMES_CONSUMES\r
+  gEfiVariableWriteArchProtocolGuid             ## ALWAYS_PRODUCES\r
+  gEfiVariableArchProtocolGuid                  ## ALWAYS_PRODUCES\r
+  gEfiFaultTolerantWriteProtocolGuid            ## SOMETIMES_CONSUMES\r
+\r
+[Guids]\r
+  gEfiAuthenticatedVariableGuid                 ## PRODUCES ## Configuration Table Guid \r
+  gEfiGlobalVariableGuid                        ## PRODUCES ## Variable Guid\r
+  gEfiEventVirtualAddressChangeGuid             ## PRODUCES ## Event\r
+  gEfiCertRsa2048Sha256Guid\r
+  gEfiImageSecurityDatabaseGuid\r
+  gEfiCertX509Guid\r
+  gEfiCertPkcs7Guid\r
+  gEfiCertRsa2048Guid  \r
+\r
+[Pcd]\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxHardwareErrorVariableSize\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdHwErrStorageSize\r
+  gEfiSecurityPkgTokenSpaceGuid.PcdMaxAppendVariableSize\r
+  \r
+[FeaturePcd]\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdVariableCollectStatistics  ## SOMETIME_CONSUMES (statistic the information of variable.)\r
+\r
+[Depex]\r
+  gEfiFirmwareVolumeBlockProtocolGuid AND gEfiFaultTolerantWriteProtocolGuid\r
+\r
+# [Event]\r
+#   ##\r
+#   # Event will be signaled for VIRTUAL_ADDRESS_CHANGE event.\r
+#   #\r
+#   EVENT_TYPE_NOTIFY_SIGNAL                    ## PRODUCES\r
+#\r
+#\r
+    \r
diff --git a/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmm.c b/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmm.c
new file mode 100644 (file)
index 0000000..52d9aa0
--- /dev/null
@@ -0,0 +1,587 @@
+/** @file\r
+  The sample implementation for SMM variable protocol. And this driver \r
+  implements an SMI handler to communicate with the DXE runtime driver \r
+  to provide variable services.\r
+\r
+Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include <Protocol/SmmVariable.h>\r
+#include <Protocol/SmmFirmwareVolumeBlock.h>\r
+#include <Protocol/SmmFaultTolerantWrite.h>\r
+#include <Library/SmmServicesTableLib.h>\r
+\r
+#include <Guid/AuthenticatedVariableFormat.h>\r
+#include <Guid/SmmVariableCommon.h>\r
+#include "Variable.h"\r
+\r
+extern VARIABLE_INFO_ENTRY                           *gVariableInfo;\r
+EFI_HANDLE                                           mSmmVariableHandle      = NULL;\r
+EFI_HANDLE                                           mVariableHandle         = NULL;\r
+BOOLEAN                                              mAtRuntime              = FALSE;\r
+EFI_GUID                                             mZeroGuid               = {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}};\r
+  \r
+EFI_SMM_VARIABLE_PROTOCOL      gSmmVariable = {\r
+  VariableServiceGetVariable,\r
+  VariableServiceGetNextVariableName,\r
+  VariableServiceSetVariable,\r
+  VariableServiceQueryVariableInfo\r
+};\r
+\r
+\r
+/**\r
+  Return TRUE if ExitBootServices () has been called.\r
+  \r
+  @retval TRUE If ExitBootServices () has been called.\r
+**/\r
+BOOLEAN\r
+AtRuntime (\r
+  VOID\r
+  )\r
+{\r
+  return mAtRuntime;\r
+}\r
+\r
+/**\r
+  Initializes a basic mutual exclusion lock.\r
+\r
+  This function initializes a basic mutual exclusion lock to the released state \r
+  and returns the lock.  Each lock provides mutual exclusion access at its task \r
+  priority level.  Since there is no preemption or multiprocessor support in EFI,\r
+  acquiring the lock only consists of raising to the locks TPL.\r
+  If Lock is NULL, then ASSERT().\r
+  If Priority is not a valid TPL value, then ASSERT().\r
+\r
+  @param  Lock       A pointer to the lock data structure to initialize.\r
+  @param  Priority   EFI TPL is associated with the lock.\r
+\r
+  @return The lock.\r
+\r
+**/\r
+EFI_LOCK *\r
+InitializeLock (\r
+  IN OUT EFI_LOCK                         *Lock,\r
+  IN EFI_TPL                              Priority\r
+  )\r
+{\r
+  return Lock;\r
+}\r
+\r
+/**\r
+  Acquires lock only at boot time. Simply returns at runtime.\r
+\r
+  This is a temperary function that will be removed when\r
+  EfiAcquireLock() in UefiLib can handle the call in UEFI\r
+  Runtimer driver in RT phase.\r
+  It calls EfiAcquireLock() at boot time, and simply returns\r
+  at runtime.\r
+\r
+  @param  Lock         A pointer to the lock to acquire.\r
+\r
+**/\r
+VOID\r
+AcquireLockOnlyAtBootTime (\r
+  IN EFI_LOCK                             *Lock\r
+  )\r
+{\r
+\r
+}\r
+\r
+\r
+/**\r
+  Releases lock only at boot time. Simply returns at runtime.\r
+\r
+  This is a temperary function which will be removed when\r
+  EfiReleaseLock() in UefiLib can handle the call in UEFI\r
+  Runtimer driver in RT phase.\r
+  It calls EfiReleaseLock() at boot time and simply returns\r
+  at runtime.\r
+\r
+  @param  Lock         A pointer to the lock to release.\r
+\r
+**/\r
+VOID\r
+ReleaseLockOnlyAtBootTime (\r
+  IN EFI_LOCK                             *Lock\r
+  )\r
+{\r
+\r
+}\r
+\r
+/**\r
+  Retrive the SMM Fault Tolerent Write protocol interface.\r
+\r
+  @param[out] FtwProtocol       The interface of SMM Ftw protocol\r
+\r
+  @retval EFI_SUCCESS           The SMM FTW protocol instance was found and returned in FtwProtocol.\r
+  @retval EFI_NOT_FOUND         The SMM FTW protocol instance was not found.\r
+  @retval EFI_INVALID_PARAMETER SarProtocol is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+GetFtwProtocol (\r
+  OUT VOID                                **FtwProtocol\r
+  )\r
+{\r
+  EFI_STATUS                              Status;\r
+\r
+  //\r
+  // Locate Smm Fault Tolerent Write protocol\r
+  //\r
+  Status = gSmst->SmmLocateProtocol (\r
+                    &gEfiSmmFaultTolerantWriteProtocolGuid, \r
+                    NULL, \r
+                    FtwProtocol\r
+                    );\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Retrive the SMM FVB protocol interface by HANDLE.\r
+\r
+  @param[in]  FvBlockHandle     The handle of SMM FVB protocol that provides services for\r
+                                reading, writing, and erasing the target block.\r
+  @param[out] FvBlock           The interface of SMM FVB protocol\r
+\r
+  @retval EFI_SUCCESS           The interface information for the specified protocol was returned.\r
+  @retval EFI_UNSUPPORTED       The device does not support the SMM FVB protocol.\r
+  @retval EFI_INVALID_PARAMETER FvBlockHandle is not a valid EFI_HANDLE or FvBlock is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+GetFvbByHandle (\r
+  IN  EFI_HANDLE                          FvBlockHandle,\r
+  OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  **FvBlock\r
+  )\r
+{\r
+  //\r
+  // To get the SMM FVB protocol interface on the handle\r
+  //\r
+  return gSmst->SmmHandleProtocol (\r
+                  FvBlockHandle,\r
+                  &gEfiSmmFirmwareVolumeBlockProtocolGuid,\r
+                  (VOID **) FvBlock\r
+                  );\r
+}\r
+\r
+\r
+/**\r
+  Function returns an array of handles that support the SMM FVB protocol\r
+  in a buffer allocated from pool. \r
+\r
+  @param[out]  NumberHandles    The number of handles returned in Buffer.\r
+  @param[out]  Buffer           A pointer to the buffer to return the requested\r
+                                array of  handles that support SMM FVB protocol.\r
+\r
+  @retval EFI_SUCCESS           The array of handles was returned in Buffer, and the number of\r
+                                handles in Buffer was returned in NumberHandles.\r
+  @retval EFI_NOT_FOUND         No SMM FVB handle was found.\r
+  @retval EFI_OUT_OF_RESOURCES  There is not enough pool memory to store the matching results.\r
+  @retval EFI_INVALID_PARAMETER NumberHandles is NULL or Buffer is NULL.\r
+\r
+**/\r
+EFI_STATUS\r
+GetFvbCountAndBuffer (\r
+  OUT UINTN                               *NumberHandles,\r
+  OUT EFI_HANDLE                          **Buffer\r
+  )\r
+{\r
+  EFI_STATUS                              Status;\r
+  UINTN                                   BufferSize;\r
+\r
+  if ((NumberHandles == NULL) || (Buffer == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  BufferSize     = 0;\r
+  *NumberHandles = 0;\r
+  *Buffer        = NULL;\r
+  Status = gSmst->SmmLocateHandle (\r
+                    ByProtocol,\r
+                    &gEfiSmmFirmwareVolumeBlockProtocolGuid,\r
+                    NULL,\r
+                    &BufferSize,\r
+                    *Buffer\r
+                    );\r
+  if (EFI_ERROR(Status) && Status != EFI_BUFFER_TOO_SMALL) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  *Buffer = AllocatePool (BufferSize);\r
+  if (*Buffer == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Status = gSmst->SmmLocateHandle (\r
+                    ByProtocol,\r
+                    &gEfiSmmFirmwareVolumeBlockProtocolGuid,\r
+                    NULL,\r
+                    &BufferSize,\r
+                    *Buffer\r
+                    );\r
+\r
+  *NumberHandles = BufferSize / sizeof(EFI_HANDLE);\r
+  if (EFI_ERROR(Status)) {\r
+    *NumberHandles = 0;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Get the variable statistics information from the information buffer pointed by gVariableInfo.\r
+\r
+  @param[in, out]  InfoEntry   A pointer to the buffer of variable information entry.\r
+                               On input, point to the variable information returned last time. if \r
+                               InfoEntry->VendorGuid is zero, return the first information.\r
+                               On output, point to the next variable information.\r
+  @param[in, out]  InfoSize    On input, the size of the variable information buffer.\r
+                               On output, the returned variable information size.\r
+\r
+  @retval EFI_SUCCESS          The variable information is found and returned successfully.\r
+  @retval EFI_UNSUPPORTED      No variable inoformation exists in variable driver. The \r
+                               PcdVariableCollectStatistics should be set TRUE to support it.\r
+  @retval EFI_BUFFER_TOO_SMALL The buffer is too small to hold the next variable information.\r
+\r
+**/\r
+EFI_STATUS\r
+SmmVariableGetStatistics (\r
+  IN OUT VARIABLE_INFO_ENTRY                           *InfoEntry,\r
+  IN OUT UINTN                                         *InfoSize\r
+  )\r
+{\r
+  VARIABLE_INFO_ENTRY                                  *VariableInfo;\r
+  UINTN                                                NameLength;\r
+  UINTN                                                StatisticsInfoSize;\r
+  CHAR16                                               *InfoName;\r
\r
+  ASSERT (InfoEntry != NULL);\r
+  VariableInfo = gVariableInfo; \r
+  if (VariableInfo == NULL) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  StatisticsInfoSize = sizeof (VARIABLE_INFO_ENTRY) + StrSize (VariableInfo->Name);\r
+  if (*InfoSize < sizeof (VARIABLE_INFO_ENTRY)) {\r
+    *InfoSize = StatisticsInfoSize;\r
+    return EFI_BUFFER_TOO_SMALL;\r
+  }\r
+  InfoName = (CHAR16 *)(InfoEntry + 1);\r
+\r
+  if (CompareGuid (&InfoEntry->VendorGuid, &mZeroGuid)) {\r
+    //\r
+    // Return the first variable info\r
+    //\r
+    CopyMem (InfoEntry, VariableInfo, sizeof (VARIABLE_INFO_ENTRY));\r
+    CopyMem (InfoName, VariableInfo->Name, StrSize (VariableInfo->Name));\r
+    *InfoSize = StatisticsInfoSize;\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // Get the next variable info\r
+  //\r
+  while (VariableInfo != NULL) {\r
+    if (CompareGuid (&VariableInfo->VendorGuid, &InfoEntry->VendorGuid)) {\r
+      NameLength = StrSize (VariableInfo->Name);\r
+      if (NameLength == StrSize (InfoName)) {\r
+        if (CompareMem (VariableInfo->Name, InfoName, NameLength) == 0) {\r
+          //\r
+          // Find the match one\r
+          //\r
+          VariableInfo = VariableInfo->Next;\r
+          break;\r
+        }\r
+      }\r
+    }\r
+    VariableInfo = VariableInfo->Next;\r
+  };\r
+    \r
+  if (VariableInfo == NULL) {\r
+    *InfoSize = 0;\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // Output the new variable info\r
+  //\r
+  StatisticsInfoSize = sizeof (VARIABLE_INFO_ENTRY) + StrSize (VariableInfo->Name);\r
+  if (*InfoSize < StatisticsInfoSize) {\r
+    *InfoSize = StatisticsInfoSize;\r
+    return EFI_BUFFER_TOO_SMALL;\r
+  }\r
+\r
+  CopyMem (InfoEntry, VariableInfo, sizeof (VARIABLE_INFO_ENTRY));\r
+  CopyMem (InfoName, VariableInfo->Name, StrSize (VariableInfo->Name));\r
+  *InfoSize = StatisticsInfoSize;\r
+  \r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Communication service SMI Handler entry.\r
+\r
+  This SMI handler provides services for the variable wrapper driver.\r
+\r
+  @param[in]     DispatchHandle  The unique handle assigned to this handler by SmiHandlerRegister().\r
+  @param[in]     RegisterContext Points to an optional handler context which was specified when the\r
+                                 handler was registered.\r
+  @param[in, out] CommBuffer     A pointer to a collection of data in memory that will\r
+                                 be conveyed from a non-SMM environment into an SMM environment.\r
+  @param[in, out] CommBufferSize The size of the CommBuffer.\r
+\r
+  @retval EFI_SUCCESS                         The interrupt was handled and quiesced. No other handlers \r
+                                              should still be called.\r
+  @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED  The interrupt has been quiesced but other handlers should \r
+                                              still be called.\r
+  @retval EFI_WARN_INTERRUPT_SOURCE_PENDING   The interrupt is still pending and other handlers should still \r
+                                              be called.\r
+  @retval EFI_INTERRUPT_PENDING               The interrupt could not be quiesced.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmVariableHandler (\r
+  IN     EFI_HANDLE                                DispatchHandle,\r
+  IN     CONST VOID                                *RegisterContext,\r
+  IN OUT VOID                                      *CommBuffer,\r
+  IN OUT UINTN                                     *CommBufferSize\r
+  )\r
+{\r
+  EFI_STATUS                                       Status;\r
+  SMM_VARIABLE_COMMUNICATE_HEADER                  *SmmVariableFunctionHeader;\r
+  SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE         *SmmVariableHeader;\r
+  SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME  *GetNextVariableName;\r
+  SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO     *QueryVariableInfo;\r
+  VARIABLE_INFO_ENTRY                              *VariableInfo;\r
+  UINTN                                            InfoSize;\r
+\r
+  ASSERT (CommBuffer != NULL);\r
+\r
+  SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *)CommBuffer;\r
+  switch (SmmVariableFunctionHeader->Function) {\r
+    case SMM_VARIABLE_FUNCTION_GET_VARIABLE:\r
+      SmmVariableHeader = (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *) SmmVariableFunctionHeader->Data;     \r
+      Status = VariableServiceGetVariable (\r
+                 SmmVariableHeader->Name,\r
+                 &SmmVariableHeader->Guid,\r
+                 &SmmVariableHeader->Attributes,\r
+                 &SmmVariableHeader->DataSize,\r
+                 (UINT8 *)SmmVariableHeader->Name + SmmVariableHeader->NameSize\r
+                 );\r
+      break;\r
+      \r
+    case SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME:\r
+      GetNextVariableName = (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *) SmmVariableFunctionHeader->Data;\r
+      Status = VariableServiceGetNextVariableName (\r
+                 &GetNextVariableName->NameSize,\r
+                 GetNextVariableName->Name,\r
+                 &GetNextVariableName->Guid\r
+                 );\r
+      break;\r
+      \r
+    case SMM_VARIABLE_FUNCTION_SET_VARIABLE:\r
+      SmmVariableHeader = (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *) SmmVariableFunctionHeader->Data;\r
+      Status = VariableServiceSetVariable (\r
+                 SmmVariableHeader->Name,\r
+                 &SmmVariableHeader->Guid,\r
+                 SmmVariableHeader->Attributes,\r
+                 SmmVariableHeader->DataSize,\r
+                 (UINT8 *)SmmVariableHeader->Name + SmmVariableHeader->NameSize\r
+                 );\r
+      break;\r
+      \r
+    case SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO:\r
+      QueryVariableInfo = (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO *) SmmVariableFunctionHeader->Data;\r
+      Status = VariableServiceQueryVariableInfo (\r
+                 QueryVariableInfo->Attributes,\r
+                 &QueryVariableInfo->MaximumVariableStorageSize,\r
+                 &QueryVariableInfo->RemainingVariableStorageSize,\r
+                 &QueryVariableInfo->MaximumVariableSize\r
+                 );\r
+      break;\r
+\r
+    case SMM_VARIABLE_FUNCTION_READY_TO_BOOT:\r
+      ReclaimForOS ();\r
+      Status = EFI_SUCCESS;\r
+      break;\r
+  \r
+    case SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE:\r
+      mAtRuntime = TRUE;\r
+      Status = EFI_SUCCESS;\r
+      break;\r
+\r
+    case SMM_VARIABLE_FUNCTION_GET_STATISTICS:\r
+      VariableInfo = (VARIABLE_INFO_ENTRY *) SmmVariableFunctionHeader->Data;\r
+      InfoSize = *CommBufferSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_HEADER, Data);\r
+      Status = SmmVariableGetStatistics (VariableInfo, &InfoSize);\r
+      *CommBufferSize = InfoSize + OFFSET_OF (SMM_VARIABLE_COMMUNICATE_HEADER, Data);\r
+      break;\r
+\r
+    default:\r
+      ASSERT (FALSE);\r
+      Status = EFI_UNSUPPORTED;\r
+  }\r
+\r
+  SmmVariableFunctionHeader->ReturnStatus = Status;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  SMM Fault Tolerant Write protocol notification event handler.\r
+\r
+  Non-Volatile variable write may needs FTW protocol to reclaim when \r
+  writting variable.\r
+  \r
+  @param  Protocol   Points to the protocol's unique identifier\r
+  @param  Interface  Points to the interface instance\r
+  @param  Handle     The handle on which the interface was installed\r
+\r
+  @retval EFI_SUCCESS   SmmEventCallback runs successfully\r
+  @retval EFI_NOT_FOUND The Fvb protocol for variable is not found.\r
+  \r
+ **/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmFtwNotificationEvent (\r
+  IN CONST EFI_GUID                       *Protocol,\r
+  IN VOID                                 *Interface,\r
+  IN EFI_HANDLE                           Handle\r
+  )\r
+{\r
+  EFI_STATUS                              Status;\r
+  EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *FvbProtocol;\r
+  EFI_SMM_FAULT_TOLERANT_WRITE_PROTOCOL   *FtwProtocol;\r
+  EFI_PHYSICAL_ADDRESS                    NvStorageVariableBase;\r
+  \r
+  if (mVariableModuleGlobal->FvbInstance != NULL) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // Ensure SMM FTW protocol is installed.\r
+  //\r
+  Status = GetFtwProtocol ((VOID **)&FtwProtocol);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Find the proper FVB protocol for variable.\r
+  //\r
+  NvStorageVariableBase = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageVariableBase64);\r
+  if (NvStorageVariableBase == 0) {\r
+    NvStorageVariableBase = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase);\r
+  }\r
+  Status = GetFvbInfoByAddress (NvStorageVariableBase, NULL, &FvbProtocol);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  mVariableModuleGlobal->FvbInstance = FvbProtocol;\r
+  \r
+  Status = VariableWriteServiceInitialize ();\r
+  ASSERT_EFI_ERROR (Status);\r
\r
+  //\r
+  // Notify the variable wrapper driver the variable write service is ready\r
+  //\r
+  Status = gBS->InstallProtocolInterface (\r
+                  &mSmmVariableHandle,\r
+                  &gSmmVariableWriteGuid,\r
+                  EFI_NATIVE_INTERFACE,\r
+                  NULL\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+  \r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Variable Driver main entry point. The Variable driver places the 4 EFI\r
+  runtime services in the EFI System Table and installs arch protocols \r
+  for variable read and write services being available. It also registers\r
+  a notification function for an EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.\r
+\r
+  @param[in] ImageHandle    The firmware allocated handle for the EFI image.  \r
+  @param[in] SystemTable    A pointer to the EFI System Table.\r
+  \r
+  @retval EFI_SUCCESS       Variable service successfully initialized.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+VariableServiceInitialize (\r
+  IN EFI_HANDLE                           ImageHandle,\r
+  IN EFI_SYSTEM_TABLE                     *SystemTable\r
+  )\r
+{\r
+  EFI_STATUS                              Status;\r
+  EFI_HANDLE                              VariableHandle;\r
+  VOID                                    *SmmFtwRegistration;\r
+  \r
+  //\r
+  // Variable initialize.\r
+  //\r
+  Status = VariableCommonInitialize ();\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // Install the Smm Variable Protocol on a new handle.\r
+  //\r
+  VariableHandle = NULL;\r
+  Status = gSmst->SmmInstallProtocolInterface (\r
+                    &VariableHandle,\r
+                    &gEfiSmmVariableProtocolGuid,\r
+                    EFI_NATIVE_INTERFACE,\r
+                    &gSmmVariable\r
+                    );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  ///\r
+  /// Register SMM variable SMI handler\r
+  ///\r
+  VariableHandle = NULL;\r
+  Status = gSmst->SmiHandlerRegister (SmmVariableHandler, &gEfiSmmVariableProtocolGuid, &VariableHandle);\r
+  ASSERT_EFI_ERROR (Status);\r
+  \r
+  //\r
+  // Notify the variable wrapper driver the variable service is ready\r
+  //\r
+  Status = SystemTable->BootServices->InstallProtocolInterface (\r
+                                        &mVariableHandle,\r
+                                        &gEfiSmmVariableProtocolGuid,\r
+                                        EFI_NATIVE_INTERFACE,\r
+                                        &gSmmVariable\r
+                                        );\r
+  ASSERT_EFI_ERROR (Status);\r
\r
+  //\r
+  // Register FtwNotificationEvent () notify function.\r
+  // \r
+  Status = gSmst->SmmRegisterProtocolNotify (\r
+                    &gEfiSmmFaultTolerantWriteProtocolGuid,\r
+                    SmmFtwNotificationEvent,\r
+                    &SmmFtwRegistration\r
+                    );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  SmmFtwNotificationEvent (NULL, NULL, NULL);\r
+  \r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
diff --git a/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmm.inf b/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmm.inf
new file mode 100644 (file)
index 0000000..63c34e4
--- /dev/null
@@ -0,0 +1,96 @@
+## @file\r
+#  Component description file for SMM Authenticated Variable module.\r
+#\r
+#  This module installs SMM variable protocol into SMM protocol database,\r
+#  which can be used by SMM driver, and installs SMM variable protocol \r
+#  into BS protocol database, which can be used to notify the SMM Runtime\r
+#  Dxe driver that the SMM variable service is ready.\r
+#  This module should be used with SMM Runtime DXE module together. The \r
+#  SMM Runtime DXE module would install variable arch protocol and variable \r
+#  write arch protocol based on SMM variable module.\r
+#\r
+# Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.<BR>\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = VariableSmm\r
+  FILE_GUID                      = D34BDC5E-968A-40f5-A48C-E594F45AE211\r
+  MODULE_TYPE                    = DXE_SMM_DRIVER\r
+  VERSION_STRING                 = 1.0\r
+  PI_SPECIFICATION_VERSION       = 0x0001000A\r
+  ENTRY_POINT                    = VariableServiceInitialize\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64\r
+#\r
+\r
+\r
+[Sources]\r
+  Reclaim.c\r
+  Variable.c\r
+  VariableSmm.c\r
+  AuthService.c\r
+  Variable.h\r
+  AuthService.h\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+  CryptoPkg/CryptoPkg.dec\r
+  SecurityPkg/SecurityPkg.dec\r
+\r
+[LibraryClasses]\r
+  UefiDriverEntryPoint\r
+  MemoryAllocationLib\r
+  BaseLib\r
+  SynchronizationLib\r
+  UefiLib\r
+  SmmServicesTableLib\r
+  BaseMemoryLib\r
+  DebugLib\r
+  DxeServicesTableLib\r
+  BaseCryptLib\r
+  PlatformSecureLib  \r
+\r
+[Protocols]\r
+  gEfiSmmFirmwareVolumeBlockProtocolGuid        ## SOMETIMES_CONSUMES\r
+  gEfiSmmVariableProtocolGuid                   ## ALWAYS_PRODUCES\r
+  gEfiSmmFaultTolerantWriteProtocolGuid         ## SOMETIMES_CONSUMES\r
+\r
+[Guids]\r
+  gEfiAuthenticatedVariableGuid                 ## PRODUCES ## Configuration Table Guid \r
+  gEfiGlobalVariableGuid                        ## PRODUCES ## Variable Guid\r
+  gSmmVariableWriteGuid                         ## PRODUCES ## SMM Variable Write Guid \r
+  gEfiCertRsa2048Sha256Guid\r
+  gEfiImageSecurityDatabaseGuid\r
+  gEfiCertX509Guid\r
+  gEfiCertPkcs7Guid\r
+  gEfiCertRsa2048Guid  \r
+\r
+[Pcd]\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxHardwareErrorVariableSize\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdHwErrStorageSize\r
+  gEfiSecurityPkgTokenSpaceGuid.PcdMaxAppendVariableSize  \r
+  \r
+[FeaturePcd]\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdVariableCollectStatistics  ## SOMETIME_CONSUMES (statistic the information of variable.)\r
+\r
+[Depex]\r
+  TRUE \r
+\r
+    \r
diff --git a/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmmRuntimeDxe.c b/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmmRuntimeDxe.c
new file mode 100644 (file)
index 0000000..212dd51
--- /dev/null
@@ -0,0 +1,651 @@
+/** @file\r
+  Implement all four UEFI Runtime Variable services for the nonvolatile\r
+  and volatile storage space and install variable architecture protocol\r
+  based on SMM variable module.\r
+\r
+Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials \r
+are licensed and made available under the terms and conditions of the BSD License \r
+which accompanies this distribution.  The full text of the license may be found at \r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include <PiDxe.h>\r
+#include <Protocol/VariableWrite.h>\r
+#include <Protocol/Variable.h>\r
+#include <Protocol/SmmCommunication.h>\r
+#include <Protocol/SmmVariable.h>\r
+\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiRuntimeServicesTableLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/UefiDriverEntryPoint.h>\r
+#include <Library/UefiRuntimeLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/BaseLib.h>\r
+\r
+#include <Guid/EventGroup.h>\r
+#include <Guid/AuthenticatedVariableFormat.h>\r
+#include <Guid/SmmVariableCommon.h>\r
+\r
+EFI_HANDLE                       mHandle                    = NULL; \r
+EFI_SMM_VARIABLE_PROTOCOL       *mSmmVariable               = NULL;\r
+EFI_EVENT                        mVirtualAddressChangeEvent = NULL;\r
+EFI_SMM_COMMUNICATION_PROTOCOL  *mSmmCommunication          = NULL;\r
+UINT8                           *mVariableBuffer            = NULL;\r
+UINT8                           *mVariableBufferPhysical    = NULL;\r
+UINTN                            mVariableBufferSize;\r
+\r
+\r
+/**\r
+  Initialize the communicate buffer using DataSize and Function.\r
+\r
+  The communicate size is: SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE +\r
+  DataSize.\r
+\r
+  @param[out]      DataPtr          Points to the data in the communicate buffer.\r
+  @param[in]       DataSize         The data size to send to SMM.\r
+  @param[in]       Function         The function number to initialize the communicate header.\r
+                      \r
+  @retval EFI_INVALID_PARAMETER     The data size is too big.\r
+  @retval EFI_SUCCESS               Find the specified variable.\r
+\r
+**/\r
+EFI_STATUS\r
+InitCommunicateBuffer (\r
+  OUT     VOID                              **DataPtr OPTIONAL,\r
+  IN      UINTN                             DataSize,\r
+  IN      UINTN                             Function\r
+  )\r
+{\r
+  EFI_SMM_COMMUNICATE_HEADER                *SmmCommunicateHeader;  \r
+  SMM_VARIABLE_COMMUNICATE_HEADER           *SmmVariableFunctionHeader; \r
+\r
\r
+  if (DataSize + SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE > mVariableBufferSize) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) mVariableBuffer;\r
+  CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmVariableProtocolGuid);\r
+  SmmCommunicateHeader->MessageLength = DataSize + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;\r
+   \r
+  SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) SmmCommunicateHeader->Data;\r
+  SmmVariableFunctionHeader->Function = Function;\r
+  if (DataPtr != NULL) {\r
+    *DataPtr = SmmVariableFunctionHeader->Data;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Send the data in communicate buffer to SMM.\r
+\r
+  @param[in]   DataSize               This size of the function header and the data.\r
+\r
+  @retval      EFI_SUCCESS            Success is returned from the functin in SMM.\r
+  @retval      Others                 Failure is returned from the function in SMM. \r
+  \r
+**/\r
+EFI_STATUS\r
+SendCommunicateBuffer (\r
+  IN      UINTN                             DataSize\r
+  )\r
+{\r
+  EFI_STATUS                                Status;\r
+  UINTN                                     CommSize;\r
+  EFI_SMM_COMMUNICATE_HEADER                *SmmCommunicateHeader;  \r
+  SMM_VARIABLE_COMMUNICATE_HEADER           *SmmVariableFunctionHeader;\r
+  \r
+  CommSize = DataSize + SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;\r
+  Status = mSmmCommunication->Communicate (mSmmCommunication, mVariableBufferPhysical, &CommSize);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  SmmCommunicateHeader      = (EFI_SMM_COMMUNICATE_HEADER *) mVariableBuffer;\r
+  SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *)SmmCommunicateHeader->Data;\r
+  return  SmmVariableFunctionHeader->ReturnStatus;\r
+}\r
+\r
+\r
+/**\r
+  This code finds variable in storage blocks (Volatile or Non-Volatile).\r
+\r
+  @param[in]      VariableName       Name of Variable to be found.\r
+  @param[in]      VendorGuid         Variable vendor GUID.\r
+  @param[out]     Attributes         Attribute value of the variable found.\r
+  @param[in, out] DataSize           Size of Data found. If size is less than the\r
+                                     data, this value contains the required size.\r
+  @param[out]     Data               Data pointer.\r
+                      \r
+  @retval EFI_INVALID_PARAMETER      Invalid parameter.\r
+  @retval EFI_SUCCESS                Find the specified variable.\r
+  @retval EFI_NOT_FOUND              Not found.\r
+  @retval EFI_BUFFER_TO_SMALL        DataSize is too small for the result.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+RuntimeServiceGetVariable (\r
+  IN      CHAR16                            *VariableName,\r
+  IN      EFI_GUID                          *VendorGuid,\r
+  OUT     UINT32                            *Attributes OPTIONAL,\r
+  IN OUT  UINTN                             *DataSize,\r
+  OUT     VOID                              *Data\r
+  )\r
+{\r
+  EFI_STATUS                                Status;\r
+  UINTN                                     PayloadSize;\r
+  SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE  *SmmVariableHeader;\r
+\r
+  if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((*DataSize != 0) && (Data == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  \r
+  //\r
+  // Init the communicate buffer. The buffer data size is:\r
+  // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.\r
+  //\r
+  PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + StrSize (VariableName);\r
+  Status = InitCommunicateBuffer ((VOID **)&SmmVariableHeader, PayloadSize, SMM_VARIABLE_FUNCTION_GET_VARIABLE);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  ASSERT (SmmVariableHeader != NULL);\r
+\r
+  CopyGuid (&SmmVariableHeader->Guid, VendorGuid);\r
+  SmmVariableHeader->DataSize   = *DataSize;\r
+  SmmVariableHeader->NameSize   = StrSize (VariableName);\r
+  if (Attributes == NULL) {\r
+    SmmVariableHeader->Attributes = 0;\r
+  } else {\r
+    SmmVariableHeader->Attributes = *Attributes;\r
+  }\r
+  CopyMem (SmmVariableHeader->Name, VariableName, SmmVariableHeader->NameSize);\r
+\r
+  //\r
+  // Send data to SMM.\r
+  //\r
+  Status = SendCommunicateBuffer (PayloadSize);\r
+\r
+  //\r
+  // Get data from SMM.\r
+  //\r
+  *DataSize = SmmVariableHeader->DataSize;\r
+  if (Attributes != NULL) {\r
+    *Attributes = SmmVariableHeader->Attributes;\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  CopyMem (Data, (UINT8 *)SmmVariableHeader->Name + SmmVariableHeader->NameSize, SmmVariableHeader->DataSize);\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  This code Finds the Next available variable.\r
+\r
+  @param[in, out] VariableNameSize   Size of the variable name.\r
+  @param[in, out] VariableName       Pointer to variable name.\r
+  @param[in, out] VendorGuid         Variable Vendor Guid.\r
+\r
+  @retval EFI_INVALID_PARAMETER      Invalid parameter.\r
+  @retval EFI_SUCCESS                Find the specified variable.\r
+  @retval EFI_NOT_FOUND              Not found.\r
+  @retval EFI_BUFFER_TO_SMALL        DataSize is too small for the result.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+RuntimeServiceGetNextVariableName (\r
+  IN OUT  UINTN                             *VariableNameSize,\r
+  IN OUT  CHAR16                            *VariableName,\r
+  IN OUT  EFI_GUID                          *VendorGuid\r
+  )\r
+{\r
+  EFI_STATUS                                      Status;\r
+  UINTN                                           PayloadSize;\r
+  SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *SmmGetNextVariableName;\r
+\r
+  if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  \r
+  //\r
+  // Init the communicate buffer. The buffer data size is:\r
+  // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.\r
+  //\r
+  PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name) + *VariableNameSize; \r
+  Status = InitCommunicateBuffer ((VOID **)&SmmGetNextVariableName, PayloadSize, SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  ASSERT (SmmGetNextVariableName != NULL);\r
+\r
+  SmmGetNextVariableName->NameSize = *VariableNameSize;\r
+  CopyGuid (&SmmGetNextVariableName->Guid, VendorGuid);\r
+  CopyMem (SmmGetNextVariableName->Name, VariableName, *VariableNameSize);\r
+\r
+  //\r
+  // Send data to SMM\r
+  //\r
+  Status = SendCommunicateBuffer (PayloadSize);\r
+\r
+  //\r
+  // Get data from SMM.\r
+  //\r
+  *VariableNameSize = SmmGetNextVariableName->NameSize;    \r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  \r
+  CopyGuid (VendorGuid, &SmmGetNextVariableName->Guid);\r
+  CopyMem (VariableName, SmmGetNextVariableName->Name, SmmGetNextVariableName->NameSize);  \r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  This code sets variable in storage blocks (Volatile or Non-Volatile).\r
+\r
+  @param[in] VariableName                 Name of Variable to be found.\r
+  @param[in] VendorGuid                   Variable vendor GUID.\r
+  @param[in] Attributes                   Attribute value of the variable found\r
+  @param[in] DataSize                     Size of Data found. If size is less than the\r
+                                          data, this value contains the required size.\r
+  @param[in] Data                         Data pointer.\r
+\r
+  @retval EFI_INVALID_PARAMETER           Invalid parameter.\r
+  @retval EFI_SUCCESS                     Set successfully.\r
+  @retval EFI_OUT_OF_RESOURCES            Resource not enough to set variable.\r
+  @retval EFI_NOT_FOUND                   Not found.\r
+  @retval EFI_WRITE_PROTECTED             Variable is read-only.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+RuntimeServiceSetVariable (\r
+  IN CHAR16                                 *VariableName,\r
+  IN EFI_GUID                               *VendorGuid,\r
+  IN UINT32                                 Attributes,\r
+  IN UINTN                                  DataSize,\r
+  IN VOID                                   *Data\r
+  )\r
+{\r
+  EFI_STATUS                                Status;\r
+  UINTN                                     PayloadSize; \r
+  SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE  *SmmVariableHeader;\r
+    \r
+  //\r
+  // Check input parameters.\r
+  //\r
+  if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  } \r
+\r
+  if (DataSize != 0 && Data == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  \r
+  //\r
+  // Init the communicate buffer. The buffer data size is:\r
+  // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.\r
+  //\r
+  PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + StrSize (VariableName) + DataSize;\r
+  Status = InitCommunicateBuffer ((VOID **)&SmmVariableHeader, PayloadSize, SMM_VARIABLE_FUNCTION_SET_VARIABLE);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  ASSERT (SmmVariableHeader != NULL);\r
+\r
+  CopyGuid ((EFI_GUID *) &SmmVariableHeader->Guid, VendorGuid);\r
+  SmmVariableHeader->DataSize   = DataSize;\r
+  SmmVariableHeader->NameSize   = StrSize (VariableName);\r
+  SmmVariableHeader->Attributes = Attributes;\r
+  CopyMem (SmmVariableHeader->Name, VariableName, SmmVariableHeader->NameSize);\r
+  CopyMem ((UINT8 *) SmmVariableHeader->Name + SmmVariableHeader->NameSize, Data, DataSize);\r
+\r
+  //\r
+  // Send data to SMM.\r
+  //\r
+  Status = SendCommunicateBuffer (PayloadSize);\r
\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  This code returns information about the EFI variables.\r
+\r
+  @param[in]  Attributes                   Attributes bitmask to specify the type of variables\r
+                                           on which to return information.\r
+  @param[out] MaximumVariableStorageSize   Pointer to the maximum size of the storage space available\r
+                                           for the EFI variables associated with the attributes specified.\r
+  @param[out] RemainingVariableStorageSize Pointer to the remaining size of the storage space available\r
+                                           for EFI variables associated with the attributes specified.\r
+  @param[out] MaximumVariableSize          Pointer to the maximum size of an individual EFI variables\r
+                                           associated with the attributes specified.\r
+\r
+  @retval EFI_INVALID_PARAMETER            An invalid combination of attribute bits was supplied.\r
+  @retval EFI_SUCCESS                      Query successfully.\r
+  @retval EFI_UNSUPPORTED                  The attribute is not supported on this platform.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+RuntimeServiceQueryVariableInfo (\r
+  IN  UINT32                                Attributes,\r
+  OUT UINT64                                *MaximumVariableStorageSize,\r
+  OUT UINT64                                *RemainingVariableStorageSize,\r
+  OUT UINT64                                *MaximumVariableSize\r
+  )\r
+{\r
+  EFI_STATUS                                Status;\r
+  UINTN                                     PayloadSize;\r
+  SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO *SmmQueryVariableInfo;\r
+\r
+  if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  \r
+  //\r
+  // Init the communicate buffer. The buffer data size is:\r
+  // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize;\r
+  //\r
+  PayloadSize = sizeof (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO);\r
+  Status = InitCommunicateBuffer ((VOID **)&SmmQueryVariableInfo, PayloadSize, SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  ASSERT (SmmQueryVariableInfo != NULL);\r
+\r
+  SmmQueryVariableInfo->Attributes  = Attributes;\r
+\r
+  //\r
+  // Send data to SMM.\r
+  //\r
+  Status = SendCommunicateBuffer (PayloadSize);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Get data from SMM.\r
+  //\r
+  *MaximumVariableSize          = SmmQueryVariableInfo->MaximumVariableSize;\r
+  *MaximumVariableStorageSize   = SmmQueryVariableInfo->MaximumVariableStorageSize;\r
+  *RemainingVariableStorageSize = SmmQueryVariableInfo->RemainingVariableStorageSize; \r
\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Exit Boot Services Event notification handler.\r
+\r
+  Notify SMM variable driver about the event.\r
+\r
+  @param[in]  Event     Event whose notification function is being invoked.\r
+  @param[in]  Context   Pointer to the notification function's context.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+OnExitBootServices (\r
+  IN      EFI_EVENT                         Event,\r
+  IN      VOID                              *Context\r
+  )\r
+{\r
+  //\r
+  // Init the communicate buffer. The buffer data size is:\r
+  // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.\r
+  //\r
+  InitCommunicateBuffer (NULL, 0, SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE); \r
+\r
+  //\r
+  // Send data to SMM.\r
+  //\r
+  SendCommunicateBuffer (0);\r
+}\r
+\r
+\r
+/**\r
+  On Ready To Boot Services Event notification handler.\r
+\r
+  Notify SMM variable driver about the event.\r
+\r
+  @param[in]  Event     Event whose notification function is being invoked\r
+  @param[in]  Context   Pointer to the notification function's context\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+OnReadyToBoot (\r
+  IN      EFI_EVENT                         Event,\r
+  IN      VOID                              *Context\r
+  )\r
+{\r
+  //\r
+  // Init the communicate buffer. The buffer data size is:\r
+  // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.\r
+  //\r
+  InitCommunicateBuffer (NULL, 0, SMM_VARIABLE_FUNCTION_READY_TO_BOOT);\r
+  \r
+  //\r
+  // Send data to SMM.\r
+  //\r
+  SendCommunicateBuffer (0);\r
+}\r
+\r
+\r
+/**\r
+  Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.\r
+\r
+  This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.\r
+  It convers pointer to new virtual address.\r
+\r
+  @param[in]  Event        Event whose notification function is being invoked.\r
+  @param[in]  Context      Pointer to the notification function's context.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+VariableAddressChangeEvent (\r
+  IN EFI_EVENT                              Event,\r
+  IN VOID                                   *Context\r
+  )\r
+{\r
+  EfiConvertPointer (0x0, (VOID **) &mVariableBuffer);\r
+  EfiConvertPointer (0x0, (VOID **) &mSmmCommunication);\r
+}\r
+\r
+\r
+/**\r
+  Initialize variable service and install Variable Architectural protocol.\r
+\r
+  @param[in] Event    Event whose notification function is being invoked.\r
+  @param[in] Context  Pointer to the notification function's context.\r
\r
+**/\r
+VOID\r
+EFIAPI\r
+SmmVariableReady (\r
+  IN  EFI_EVENT                             Event,\r
+  IN  VOID                                  *Context\r
+  )\r
+{\r
+  EFI_STATUS                                Status;\r
+\r
+  Status = gBS->LocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID **)&mSmmVariable);\r
+  if (EFI_ERROR (Status)) {\r
+    return;\r
+  }\r
+  \r
+  Status = gBS->LocateProtocol (&gEfiSmmCommunicationProtocolGuid, NULL, (VOID **) &mSmmCommunication);\r
+  ASSERT_EFI_ERROR (Status);\r
+  \r
+  //\r
+  // Allocate memory for variable store.\r
+  //\r
+  mVariableBufferSize  = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;\r
+  mVariableBufferSize += MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize));\r
+  mVariableBuffer      = AllocateRuntimePool (mVariableBufferSize);\r
+  ASSERT (mVariableBuffer != NULL);\r
+\r
+  //\r
+  // Save the buffer physical address used for SMM conmunication.\r
+  //\r
+  mVariableBufferPhysical = mVariableBuffer;\r
+\r
+  gRT->GetVariable         = RuntimeServiceGetVariable;\r
+  gRT->GetNextVariableName = RuntimeServiceGetNextVariableName;\r
+  gRT->SetVariable         = RuntimeServiceSetVariable;\r
+  gRT->QueryVariableInfo   = RuntimeServiceQueryVariableInfo;\r
\r
+  //\r
+  // Install the Variable Architectural Protocol on a new handle.\r
+  //\r
+  Status = gBS->InstallProtocolInterface (\r
+                  &mHandle,\r
+                  &gEfiVariableArchProtocolGuid, \r
+                  EFI_NATIVE_INTERFACE,\r
+                  NULL\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+}\r
+\r
+\r
+/**\r
+  SMM Non-Volatile variable write service is ready notify event handler.\r
+\r
+  @param[in] Event    Event whose notification function is being invoked.\r
+  @param[in] Context  Pointer to the notification function's context.\r
+  \r
+**/\r
+VOID\r
+EFIAPI\r
+SmmVariableWriteReady (\r
+  IN  EFI_EVENT                             Event,\r
+  IN  VOID                                  *Context\r
+  )\r
+{\r
+  EFI_STATUS                                Status;\r
+  VOID                                      *ProtocolOps;\r
+\r
+  //\r
+  // Check whether the protocol is installed or not.\r
+  //\r
+  Status = gBS->LocateProtocol (&gSmmVariableWriteGuid, NULL, (VOID **) &ProtocolOps);\r
+  if (EFI_ERROR (Status)) {\r
+    return;\r
+  }\r
\r
+  Status = gBS->InstallProtocolInterface (\r
+                  &mHandle,\r
+                  &gEfiVariableWriteArchProtocolGuid, \r
+                  EFI_NATIVE_INTERFACE,\r
+                  NULL\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);  \r
+}\r
+\r
+\r
+/**\r
+  Variable Driver main entry point. The Variable driver places the 4 EFI\r
+  runtime services in the EFI System Table and installs arch protocols \r
+  for variable read and write services being available. It also registers\r
+  a notification function for an EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.\r
+\r
+  @param[in] ImageHandle    The firmware allocated handle for the EFI image.  \r
+  @param[in] SystemTable    A pointer to the EFI System Table.\r
+  \r
+  @retval EFI_SUCCESS       Variable service successfully initialized.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+VariableSmmRuntimeInitialize (\r
+  IN EFI_HANDLE                             ImageHandle,\r
+  IN EFI_SYSTEM_TABLE                       *SystemTable\r
+  )\r
+{\r
+  VOID                                      *SmmVariableRegistration;\r
+  VOID                                      *SmmVariableWriteRegistration;\r
+  EFI_EVENT                                 OnReadyToBootEvent;\r
+  EFI_EVENT                                 ExitBootServiceEvent;\r
+  \r
+  //\r
+  // Smm variable service is ready\r
+  //\r
+  EfiCreateProtocolNotifyEvent (\r
+    &gEfiSmmVariableProtocolGuid, \r
+    TPL_CALLBACK, \r
+    SmmVariableReady, \r
+    NULL, \r
+    &SmmVariableRegistration\r
+    );\r
+\r
+  //\r
+  // Smm Non-Volatile variable write service is ready\r
+  //\r
+  EfiCreateProtocolNotifyEvent (\r
+    &gSmmVariableWriteGuid, \r
+    TPL_CALLBACK, \r
+    SmmVariableWriteReady, \r
+    NULL, \r
+    &SmmVariableWriteRegistration\r
+    );\r
+\r
+  //\r
+  // Register the event to reclaim variable for OS usage.\r
+  //\r
+  EfiCreateEventReadyToBootEx (\r
+    TPL_NOTIFY, \r
+    OnReadyToBoot, \r
+    NULL, \r
+    &OnReadyToBootEvent\r
+    );             \r
+\r
+  //\r
+  // Register the event to inform SMM variable that it is at runtime.\r
+  //\r
+  gBS->CreateEventEx (\r
+         EVT_NOTIFY_SIGNAL,\r
+         TPL_NOTIFY,\r
+         OnExitBootServices,\r
+         NULL,\r
+         &gEfiEventExitBootServicesGuid,\r
+         &ExitBootServiceEvent\r
+         ); \r
+\r
+  //\r
+  // Register the event to convert the pointer for runtime.\r
+  //\r
+  gBS->CreateEventEx (\r
+         EVT_NOTIFY_SIGNAL,\r
+         TPL_NOTIFY,\r
+         VariableAddressChangeEvent,\r
+         NULL,\r
+         &gEfiEventVirtualAddressChangeGuid,\r
+         &mVirtualAddressChangeEvent\r
+         );\r
+  \r
+  return EFI_SUCCESS;\r
+}\r
+\r
diff --git a/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmmRuntimeDxe.inf b/SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmmRuntimeDxe.inf
new file mode 100644 (file)
index 0000000..c1fb6ac
--- /dev/null
@@ -0,0 +1,68 @@
+## @file\r
+#  Component description file for Authenticated Variable SmmRuntimeDxe module.\r
+#\r
+#  This module is the Runtime DXE part correspond to SMM variable module. It \r
+#  installs variable arch protocol and variable write arch protocol and works \r
+#  with SMM variable module together. \r
+#\r
+# Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.<BR>\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = VariableSmmRuntimeDxe\r
+  FILE_GUID                      = 067E2381-7234-4798-B49C-D5FECBFF6D07\r
+  MODULE_TYPE                    = DXE_RUNTIME_DRIVER\r
+  VERSION_STRING                 = 1.0\r
+  ENTRY_POINT                    = VariableSmmRuntimeInitialize\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64\r
+#\r
+#  VIRTUAL_ADDRESS_MAP_CALLBACK  =  VariableAddressChangeEvent\r
+#\r
+\r
+[Sources]\r
+  VariableSmmRuntimeDxe.c\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+  SecurityPkg/SecurityPkg.dec\r
+\r
+[LibraryClasses]\r
+  MemoryAllocationLib\r
+  BaseLib  \r
+  UefiBootServicesTableLib\r
+  DebugLib\r
+  UefiRuntimeLib\r
+  DxeServicesTableLib\r
+  UefiDriverEntryPoint\r
+  PcdLib  \r
+\r
+[Protocols]\r
+  gEfiVariableWriteArchProtocolGuid             ## ALWAYS_PRODUCES\r
+  gEfiVariableArchProtocolGuid                  ## ALWAYS_PRODUCES  \r
+  gEfiSmmCommunicationProtocolGuid\r
+  gEfiSmmVariableProtocolGuid\r
+\r
+[Guids]\r
+  gEfiEventVirtualAddressChangeGuid             ## PRODUCES ## Event\r
+  gSmmVariableWriteGuid\r
+\r
+[Pcd]\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxHardwareErrorVariableSize\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase\r
+  \r
+[Depex]\r
+  gEfiSmmCommunicationProtocolGuid\r