--- /dev/null
+/** @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
--- /dev/null
+## @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+## @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+## @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
--- /dev/null
+/** @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
--- /dev/null
+## @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
--- /dev/null
+/** @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
--- /dev/null
+## @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+## @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
--- /dev/null
+## @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
--- /dev/null
+## @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+## @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+## @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
--- /dev/null
+/** @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
--- /dev/null
+## @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+## @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+## @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+## @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+## @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+## @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+## @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+## @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+## @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+## @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+## @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+/** @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
--- /dev/null
+## @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
--- /dev/null
+/** @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
--- /dev/null
+## @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
--- /dev/null
+/** @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
--- /dev/null
+## @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