diff --git a/SecurityPkg/Application/VariableInfo/VariableInfo.c b/SecurityPkg/Application/VariableInfo/VariableInfo.c
new file mode 100644
index 0000000000..418cec3e5b
--- /dev/null
+++ b/SecurityPkg/Application/VariableInfo/VariableInfo.c
@@ -0,0 +1,268 @@
+/** @file
+ If the Variable services have PcdVariableCollectStatistics set to TRUE then
+ this utility will print out the statistics information. You can use console
+ redirection to capture the data.
+
+Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#define EFI_VARIABLE_GUID \
+ { 0xddcf3616, 0x3275, 0x4164, { 0x98, 0xb6, 0xfe, 0x85, 0x70, 0x7f, 0xfe, 0x7d } }
+
+EFI_GUID mEfiVariableGuid = EFI_VARIABLE_GUID;
+EFI_SMM_COMMUNICATION_PROTOCOL *mSmmCommunication = NULL;
+
+/**
+
+ This function get the variable statistics data from SMM variable driver.
+
+ @param[in, out] SmmCommunicateHeader In input, a pointer to a collection of data that will
+ be passed into an SMM environment. In output, a pointer
+ to a collection of data that comes from an SMM environment.
+ @param[in, out] SmmCommunicateSize The size of the SmmCommunicateHeader.
+
+ @retval EFI_SUCCESS Get the statistics data information.
+ @retval EFI_NOT_FOUND Not found.
+ @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result.
+
+**/
+EFI_STATUS
+EFIAPI
+GetVariableStatisticsData (
+ IN OUT EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader,
+ IN OUT UINTN *SmmCommunicateSize
+ )
+{
+ EFI_STATUS Status;
+ SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader;
+
+ CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmVariableProtocolGuid);
+ SmmCommunicateHeader->MessageLength = *SmmCommunicateSize - OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data);
+
+ SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) &SmmCommunicateHeader->Data[0];
+ SmmVariableFunctionHeader->Function = SMM_VARIABLE_FUNCTION_GET_STATISTICS;
+
+ Status = mSmmCommunication->Communicate (mSmmCommunication, SmmCommunicateHeader, SmmCommunicateSize);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = SmmVariableFunctionHeader->ReturnStatus;
+ return Status;
+}
+
+
+/**
+
+ This function get and print the variable statistics data from SMM variable driver.
+
+ @retval EFI_SUCCESS Print the statistics information successfully.
+ @retval EFI_NOT_FOUND Not found the statistics information.
+
+**/
+EFI_STATUS
+PrintInfoFromSmm (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ VARIABLE_INFO_ENTRY *VariableInfo;
+ EFI_SMM_COMMUNICATE_HEADER *CommBuffer;
+ UINTN RealCommSize;
+ UINTN CommSize;
+ SMM_VARIABLE_COMMUNICATE_HEADER *FunctionHeader;
+ EFI_SMM_VARIABLE_PROTOCOL *Smmvariable;
+
+
+ Status = gBS->LocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID **) &Smmvariable);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->LocateProtocol (&gEfiSmmCommunicationProtocolGuid, NULL, (VOID **) &mSmmCommunication);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ CommSize = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
+ RealCommSize = CommSize;
+ CommBuffer = AllocateZeroPool (CommSize);
+ ASSERT (CommBuffer != NULL);
+
+ Print (L"Non-Volatile SMM Variables:\n");
+ do {
+ Status = GetVariableStatisticsData (CommBuffer, &CommSize);
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ FreePool (CommBuffer);
+ CommBuffer = AllocateZeroPool (CommSize);
+ ASSERT (CommBuffer != NULL);
+ RealCommSize = CommSize;
+ Status = GetVariableStatisticsData (CommBuffer, &CommSize);
+ }
+
+ if (EFI_ERROR (Status) || (CommSize <= SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE)) {
+ break;
+ }
+
+ if (CommSize < RealCommSize) {
+ CommSize = RealCommSize;
+ }
+
+ FunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) CommBuffer->Data;
+ VariableInfo = (VARIABLE_INFO_ENTRY *) FunctionHeader->Data;
+
+ if (!VariableInfo->Volatile) {
+ Print (
+ L"%g R%03d(%03d) W%03d D%03d:%s\n",
+ &VariableInfo->VendorGuid,
+ VariableInfo->ReadCount,
+ VariableInfo->CacheCount,
+ VariableInfo->WriteCount,
+ VariableInfo->DeleteCount,
+ (CHAR16 *)(VariableInfo + 1)
+ );
+ }
+ } while (TRUE);
+
+ Print (L"Volatile SMM Variables:\n");
+ ZeroMem (CommBuffer, CommSize);
+ do {
+ Status = GetVariableStatisticsData (CommBuffer, &CommSize);
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ FreePool (CommBuffer);
+ CommBuffer = AllocateZeroPool (CommSize);
+ ASSERT (CommBuffer != NULL);
+ RealCommSize = CommSize;
+ Status = GetVariableStatisticsData (CommBuffer, &CommSize);
+ }
+
+ if (EFI_ERROR (Status) || (CommSize <= SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE)) {
+ break;
+ }
+
+ if (CommSize < RealCommSize) {
+ CommSize = RealCommSize;
+ }
+
+ FunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) CommBuffer->Data;
+ VariableInfo = (VARIABLE_INFO_ENTRY *) FunctionHeader->Data;
+
+ if (VariableInfo->Volatile) {
+ Print (
+ L"%g R%03d(%03d) W%03d D%03d:%s\n",
+ &VariableInfo->VendorGuid,
+ VariableInfo->ReadCount,
+ VariableInfo->CacheCount,
+ VariableInfo->WriteCount,
+ VariableInfo->DeleteCount,
+ (CHAR16 *)(VariableInfo + 1)
+ );
+ }
+ } while (TRUE);
+
+ FreePool (CommBuffer);
+ return Status;
+}
+
+/**
+ The user Entry Point for Application. The user code starts with this function
+ as the real entry point for the image goes into a library that calls this
+ function.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The entry point is executed successfully.
+ @retval other Some error occurs when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+UefiMain (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ VARIABLE_INFO_ENTRY *VariableInfo;
+ VARIABLE_INFO_ENTRY *Entry;
+
+ Status = EfiGetSystemConfigurationTable (&mEfiVariableGuid, (VOID **)&Entry);
+ if (EFI_ERROR (Status) || (Entry == NULL)) {
+ Status = EfiGetSystemConfigurationTable (&gEfiAuthenticatedVariableGuid, (VOID **)&Entry);
+ }
+
+ if (EFI_ERROR (Status) || (Entry == NULL)) {
+ Status = PrintInfoFromSmm ();
+ if (!EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ if (!EFI_ERROR (Status) && (Entry != NULL)) {
+ Print (L"Non-Volatile EFI Variables:\n");
+ VariableInfo = Entry;
+ do {
+ if (!VariableInfo->Volatile) {
+ Print (
+ L"%g R%03d(%03d) W%03d D%03d:%s\n",
+ &VariableInfo->VendorGuid,
+ VariableInfo->ReadCount,
+ VariableInfo->CacheCount,
+ VariableInfo->WriteCount,
+ VariableInfo->DeleteCount,
+ VariableInfo->Name
+ );
+ }
+
+ VariableInfo = VariableInfo->Next;
+ } while (VariableInfo != NULL);
+
+ Print (L"Volatile EFI Variables:\n");
+ VariableInfo = Entry;
+ do {
+ if (VariableInfo->Volatile) {
+ Print (
+ L"%g R%03d(%03d) W%03d D%03d:%s\n",
+ &VariableInfo->VendorGuid,
+ VariableInfo->ReadCount,
+ VariableInfo->CacheCount,
+ VariableInfo->WriteCount,
+ VariableInfo->DeleteCount,
+ VariableInfo->Name
+ );
+ }
+ VariableInfo = VariableInfo->Next;
+ } while (VariableInfo != NULL);
+
+ } else {
+ Print (L"Warning: Variable Dxe driver doesn't enable the feature of statistical information!\n");
+ Print (L"If you want to see this info, please:\n");
+ Print (L" 1. Set PcdVariableCollectStatistics as TRUE\n");
+ Print (L" 2. Rebuild Variable Dxe driver\n");
+ Print (L" 3. Run \"VariableInfo\" cmd again\n");
+ }
+
+ return Status;
+}
diff --git a/SecurityPkg/Application/VariableInfo/VariableInfo.inf b/SecurityPkg/Application/VariableInfo/VariableInfo.inf
new file mode 100644
index 0000000000..a247d53ceb
--- /dev/null
+++ b/SecurityPkg/Application/VariableInfo/VariableInfo.inf
@@ -0,0 +1,54 @@
+## @file
+# This is a shell application that will display statistical information
+# about variable usage.
+# Note that if Variable Dxe driver doesn't enable the feature by setting
+# PcdVariableCollectStatistics as TRUE, The application will not display
+# variable statistical information.
+#
+# Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = VariableInfo
+ FILE_GUID = B9EF901F-A2A2-4fc8-8D2B-3A2E07B301CC
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = UefiMain
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ VariableInfo.c
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+ UefiApplicationEntryPoint
+ UefiLib
+ UefiBootServicesTableLib
+ BaseMemoryLib
+ MemoryAllocationLib
+
+[Protocols]
+ gEfiSmmCommunicationProtocolGuid
+ gEfiSmmVariableProtocolGuid
+
+[Guids]
+ gEfiAuthenticatedVariableGuid ## CONSUMES ## Configuration Table Guid
+
diff --git a/SecurityPkg/Include/Guid/AuthenticatedVariableFormat.h b/SecurityPkg/Include/Guid/AuthenticatedVariableFormat.h
new file mode 100644
index 0000000000..245339c3df
--- /dev/null
+++ b/SecurityPkg/Include/Guid/AuthenticatedVariableFormat.h
@@ -0,0 +1,174 @@
+/** @file
+ The variable data structures are related to EDKII-specific
+ implementation of UEFI authenticated variables.
+ AuthenticatedVariableFormat.h defines variable data headers
+ and variable storage region headers.
+
+Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __AUTHENTICATED_VARIABLE_FORMAT_H__
+#define __AUTHENTICATED_VARIABLE_FORMAT_H__
+
+#define EFI_AUTHENTICATED_VARIABLE_GUID \
+ { 0xaaf32c78, 0x947b, 0x439a, { 0xa1, 0x80, 0x2e, 0x14, 0x4e, 0xc3, 0x77, 0x92 } }
+
+extern EFI_GUID gEfiAuthenticatedVariableGuid;
+
+///
+/// Alignment of variable name and data, according to the architecture:
+/// * For IA-32 and Intel(R) 64 architectures: 1.
+/// * For IA-64 architecture: 8.
+///
+#if defined (MDE_CPU_IPF)
+#define ALIGNMENT 8
+#else
+#define ALIGNMENT 1
+#endif
+
+//
+// GET_PAD_SIZE calculates the miminal pad bytes needed to make the current pad size satisfy the alignment requirement.
+//
+#if (ALIGNMENT == 1)
+#define GET_PAD_SIZE(a) (0)
+#else
+#define GET_PAD_SIZE(a) (((~a) + 1) & (ALIGNMENT - 1))
+#endif
+
+///
+/// Alignment of Variable Data Header in Variable Store region.
+///
+#define HEADER_ALIGNMENT 4
+#define HEADER_ALIGN(Header) (((UINTN) (Header) + HEADER_ALIGNMENT - 1) & (~(HEADER_ALIGNMENT - 1)))
+
+///
+/// Status of Variable Store Region.
+///
+typedef enum {
+ EfiRaw,
+ EfiValid,
+ EfiInvalid,
+ EfiUnknown
+} VARIABLE_STORE_STATUS;
+
+#pragma pack(1)
+
+#define VARIABLE_STORE_SIGNATURE EFI_AUTHENTICATED_VARIABLE_GUID
+
+///
+/// Variable Store Header Format and State.
+///
+#define VARIABLE_STORE_FORMATTED 0x5a
+#define VARIABLE_STORE_HEALTHY 0xfe
+
+///
+/// Variable Store region header.
+///
+typedef struct {
+ ///
+ /// Variable store region signature.
+ ///
+ EFI_GUID Signature;
+ ///
+ /// Size of entire variable store,
+ /// including size of variable store header but not including the size of FvHeader.
+ ///
+ UINT32 Size;
+ ///
+ /// Variable region format state.
+ ///
+ UINT8 Format;
+ ///
+ /// Variable region healthy state.
+ ///
+ UINT8 State;
+ UINT16 Reserved;
+ UINT32 Reserved1;
+} VARIABLE_STORE_HEADER;
+
+///
+/// Variable data start flag.
+///
+#define VARIABLE_DATA 0x55AA
+
+///
+/// Variable State flags.
+///
+#define VAR_IN_DELETED_TRANSITION 0xfe ///< Variable is in obsolete transition.
+#define VAR_DELETED 0xfd ///< Variable is obsolete.
+#define VAR_HEADER_VALID_ONLY 0x7f ///< Variable header has been valid.
+#define VAR_ADDED 0x3f ///< Variable has been completely added.
+
+///
+/// Single Variable Data Header Structure.
+///
+typedef struct {
+ ///
+ /// Variable Data Start Flag.
+ ///
+ UINT16 StartId;
+ ///
+ /// Variable State defined above.
+ ///
+ UINT8 State;
+ UINT8 Reserved;
+ ///
+ /// Attributes of variable defined in UEFI specification.
+ ///
+ UINT32 Attributes;
+ ///
+ /// Associated monotonic count value against replay attack.
+ ///
+ UINT64 MonotonicCount;
+ ///
+ /// Associated TimeStamp value against replay attack.
+ ///
+ EFI_TIME TimeStamp;
+ ///
+ /// Index of associated public key in database.
+ ///
+ UINT32 PubKeyIndex;
+ ///
+ /// Size of variable null-terminated Unicode string name.
+ ///
+ UINT32 NameSize;
+ ///
+ /// Size of the variable data without this header.
+ ///
+ UINT32 DataSize;
+ ///
+ /// A unique identifier for the vendor that produces and consumes this varaible.
+ ///
+ EFI_GUID VendorGuid;
+} VARIABLE_HEADER;
+
+#pragma pack()
+
+typedef struct _VARIABLE_INFO_ENTRY VARIABLE_INFO_ENTRY;
+
+///
+/// This structure contains the variable list that is put in EFI system table.
+/// The variable driver collects all variables that were used at boot service time and produces this list.
+/// This is an optional feature to dump all used variables in shell environment.
+///
+struct _VARIABLE_INFO_ENTRY {
+ VARIABLE_INFO_ENTRY *Next; ///< Pointer to next entry.
+ EFI_GUID VendorGuid; ///< Guid of Variable.
+ CHAR16 *Name; ///< Name of Variable.
+ UINT32 Attributes; ///< Attributes of variable defined in UEFI spec.
+ UINT32 ReadCount; ///< Number of times to read this variable.
+ UINT32 WriteCount; ///< Number of times to write this variable.
+ UINT32 DeleteCount; ///< Number of times to delete this variable.
+ UINT32 CacheCount; ///< Number of times that cache hits this variable.
+ BOOLEAN Volatile; ///< TRUE if volatile, FALSE if non-volatile.
+};
+
+#endif // __AUTHENTICATED_VARIABLE_FORMAT_H__
diff --git a/SecurityPkg/Include/Guid/PhysicalPresenceData.h b/SecurityPkg/Include/Guid/PhysicalPresenceData.h
new file mode 100644
index 0000000000..1ae8095e54
--- /dev/null
+++ b/SecurityPkg/Include/Guid/PhysicalPresenceData.h
@@ -0,0 +1,76 @@
+/** @file
+ Define the variable data structures used for TCG physical presence.
+ The TPM request from firmware or OS is saved to variable. And it is
+ cleared after it is processed in the next boot cycle. The TPM response
+ is saved to variable.
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __PHYSICAL_PRESENCE_DATA_GUID_H__
+#define __PHYSICAL_PRESENCE_DATA_GUID_H__
+
+#define EFI_PHYSICAL_PRESENCE_DATA_GUID \
+ { \
+ 0xf6499b1, 0xe9ad, 0x493d, { 0xb9, 0xc2, 0x2f, 0x90, 0x81, 0x5c, 0x6c, 0xbc }\
+ }
+
+#define PHYSICAL_PRESENCE_VARIABLE L"PhysicalPresence"
+
+typedef struct {
+ UINT8 PPRequest; ///< Physical Presence request command.
+ UINT8 LastPPRequest;
+ UINT32 PPResponse;
+ UINT8 Flags;
+} EFI_PHYSICAL_PRESENCE;
+
+//
+// The definition bit of the flags
+//
+#define FLAG_NO_PPI_PROVISION BIT0
+#define FLAG_NO_PPI_CLEAR BIT1
+#define FLAG_NO_PPI_MAINTENANCE BIT2
+#define FLAG_RESET_TRACK BIT3
+
+#define H2NS(x) ((((x) << 8) | ((x) >> 8)) & 0xffff)
+#define H2NL(x) (H2NS ((x) >> 16) | (H2NS ((x) & 0xffff) << 16))
+
+//
+// The definition of physical presence operation actions
+//
+#define NO_ACTION 0
+#define ENABLE 1
+#define DISABLE 2
+#define ACTIVATE 3
+#define DEACTIVATE 4
+#define CLEAR 5
+#define ENABLE_ACTIVATE 6
+#define DEACTIVATE_DISABLE 7
+#define SET_OWNER_INSTALL_TRUE 8
+#define SET_OWNER_INSTALL_FALSE 9
+#define ENABLE_ACTIVATE_OWNER_TRUE 10
+#define DEACTIVATE_DISABLE_OWNER_FALSE 11
+#define DEFERRED_PP_UNOWNERED_FIELD_UPGRADE 12
+#define SET_OPERATOR_AUTH 13
+#define CLEAR_ENABLE_ACTIVATE 14
+#define SET_NO_PPI_PROVISION_FALSE 15
+#define SET_NO_PPI_PROVISION_TRUE 16
+#define SET_NO_PPI_CLEAR_FALSE 17
+#define SET_NO_PPI_CLEAR_TRUE 18
+#define SET_NO_PPI_MAINTENANCE_FALSE 19
+#define SET_NO_PPI_MAINTENANCE_TRUE 20
+#define ENABLE_ACTIVATE_CLEAR 21
+#define ENABLE_ACTIVATE_CLEAR_ENABLE_ACTIVATE 22
+
+extern EFI_GUID gEfiPhysicalPresenceGuid;
+
+#endif
+
diff --git a/SecurityPkg/Include/Guid/SecurityPkgTokenSpace.h b/SecurityPkg/Include/Guid/SecurityPkgTokenSpace.h
new file mode 100644
index 0000000000..b1b7666f18
--- /dev/null
+++ b/SecurityPkg/Include/Guid/SecurityPkgTokenSpace.h
@@ -0,0 +1,25 @@
+/** @file
+ GUID for SecurityPkg PCD Token Space.
+
+Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _SECURITYPKG_TOKEN_SPACE_GUID_H_
+#define _SECURITYPKG_TOKEN_SPACE_GUID_H_
+
+#define SECURITYPKG_TOKEN_SPACE_GUID \
+ { \
+ 0xd3fb176, 0x9569, 0x4d51, { 0xa3, 0xef, 0x7d, 0x61, 0xc6, 0x4f, 0xea, 0xba } \
+ }
+
+extern EFI_GUID gEfiSecurityPkgTokenSpaceGuid;
+
+#endif
diff --git a/SecurityPkg/Include/Guid/TcgEventHob.h b/SecurityPkg/Include/Guid/TcgEventHob.h
new file mode 100644
index 0000000000..e88bd3a5f4
--- /dev/null
+++ b/SecurityPkg/Include/Guid/TcgEventHob.h
@@ -0,0 +1,30 @@
+/** @file
+ Defines the HOB GUID used to pass a TCG_PCR_EVENT from a TPM PEIM to
+ a TPM DXE Driver. A GUIDed HOB is generated for each measurement
+ made in the PEI Phase.
+
+Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _TCG_EVENT_HOB_H_
+#define _TCG_EVENT_HOB_H_
+
+///
+/// The Global ID of a GUIDed HOB used to pass a TCG_PCR_EVENT from a TPM PEIM to a TPM DXE Driver.
+///
+#define EFI_TCG_EVENT_HOB_GUID \
+ { \
+ 0x2e3044ac, 0x879f, 0x490f, {0x97, 0x60, 0xbb, 0xdf, 0xaf, 0x69, 0x5f, 0x50 } \
+ }
+
+extern EFI_GUID gTcgEventEntryHobGuid;
+
+#endif
diff --git a/SecurityPkg/Include/Library/PlatformSecureLib.h b/SecurityPkg/Include/Library/PlatformSecureLib.h
new file mode 100644
index 0000000000..c544719ba2
--- /dev/null
+++ b/SecurityPkg/Include/Library/PlatformSecureLib.h
@@ -0,0 +1,42 @@
+/** @file
+ Provides a secure platform-specific method to clear PK(Platform Key).
+
+Copyright (c) 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __PLATFORM_SECURE_LIB_H__
+#define __PLATFORM_SECURE_LIB_H__
+
+
+/**
+
+ This function detects whether a secure platform-specific method to clear PK(Platform Key)
+ is configured by platform owner. This method is provided for users force to clear PK
+ in case incorrect enrollment mis-haps.
+
+ UEFI231 spec chapter 27.5.2 stipulates: The platform key may also be cleared using
+ a secure platform-specific method. In this case, the global variable SetupMode
+ must also be updated to 1.
+
+ NOTE THAT: This function cannot depend on any EFI Variable Service since they are
+ not available when this function is called in AuthenticateVariable driver.
+
+ @retval TRUE The Platform owner wants to force clear PK.
+ @retval FALSE The Platform owner doesn't want to force clear PK.
+
+**/
+BOOLEAN
+EFIAPI
+ForceClearPK (
+ VOID
+ );
+
+#endif
\ No newline at end of file
diff --git a/SecurityPkg/Include/Library/TpmCommLib.h b/SecurityPkg/Include/Library/TpmCommLib.h
new file mode 100644
index 0000000000..175dd8d9b6
--- /dev/null
+++ b/SecurityPkg/Include/Library/TpmCommLib.h
@@ -0,0 +1,286 @@
+/** @file
+ Ihis library is only intended to be used by TPM modules.
+ It provides basic TPM Interface Specification (TIS) and Command functions.
+
+Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _TPM_COMM_LIB_H_
+#define _TPM_COMM_LIB_H_
+
+#include
+
+typedef EFI_HANDLE TIS_TPM_HANDLE;
+
+///
+/// TPM register base address.
+///
+#define TPM_BASE_ADDRESS 0xfed40000
+
+//
+// Set structure alignment to 1-byte
+//
+#pragma pack (1)
+
+//
+// Register set map as specified in TIS specification Chapter 10
+//
+typedef struct {
+ ///
+ /// Used to gain ownership for this particular port.
+ ///
+ UINT8 Access; // 0
+ UINT8 Reserved1[7]; // 1
+ ///
+ /// Controls interrupts.
+ ///
+ UINT32 IntEnable; // 8
+ ///
+ /// SIRQ vector to be used by the TPM.
+ ///
+ UINT8 IntVector; // 0ch
+ UINT8 Reserved2[3]; // 0dh
+ ///
+ /// What caused interrupt.
+ ///
+ UINT32 IntSts; // 10h
+ ///
+ /// Shows which interrupts are supported by that particular TPM.
+ ///
+ UINT32 IntfCapability; // 14h
+ ///
+ /// Status Register. Provides status of the TPM.
+ ///
+ UINT8 Status; // 18h
+ ///
+ /// Number of consecutive writes that can be done to the TPM.
+ ///
+ UINT16 BurstCount; // 19h
+ UINT8 Reserved3[9];
+ ///
+ /// Read or write FIFO, depending on transaction.
+ ///
+ UINT32 DataFifo; // 24
+ UINT8 Reserved4[0xed8]; // 28h
+ ///
+ /// Vendor ID
+ ///
+ UINT16 Vid; // 0f00h
+ ///
+ /// Device ID
+ ///
+ UINT16 Did; // 0f02h
+ ///
+ /// Revision ID
+ ///
+ UINT8 Rid; // 0f04h
+ ///
+ /// TCG defined configuration registers.
+ ///
+ UINT8 TcgDefined[0x7b]; // 0f05h
+ ///
+ /// Alias to I/O legacy space.
+ ///
+ UINT32 LegacyAddress1; // 0f80h
+ ///
+ /// Additional 8 bits for I/O legacy space extension.
+ ///
+ UINT32 LegacyAddress1Ex; // 0f84h
+ ///
+ /// Alias to second I/O legacy space.
+ ///
+ UINT32 LegacyAddress2; // 0f88h
+ ///
+ /// Additional 8 bits for second I/O legacy space extension.
+ ///
+ UINT32 LegacyAddress2Ex; // 0f8ch
+ ///
+ /// Vendor-defined configuration registers.
+ ///
+ UINT8 VendorDefined[0x70];// 0f90h
+} TIS_PC_REGISTERS;
+
+//
+// Restore original structure alignment
+//
+#pragma pack ()
+
+//
+// Define pointer types used to access TIS registers on PC
+//
+typedef TIS_PC_REGISTERS *TIS_PC_REGISTERS_PTR;
+
+//
+// TCG Platform Type based on TCG ACPI Specification Version 1.00
+//
+#define TCG_PLATFORM_TYPE_CLIENT 0
+#define TCG_PLATFORM_TYPE_SERVER 1
+
+//
+// Define bits of ACCESS and STATUS registers
+//
+
+///
+/// This bit is a 1 to indicate that the other bits in this register are valid.
+///
+#define TIS_PC_VALID BIT7
+///
+/// Indicate that this locality is active.
+///
+#define TIS_PC_ACC_ACTIVE BIT5
+///
+/// Set to 1 to indicate that this locality had the TPM taken away while
+/// this locality had the TIS_PC_ACC_ACTIVE bit set.
+///
+#define TIS_PC_ACC_SEIZED BIT4
+///
+/// Set to 1 to indicate that TPM MUST reset the
+/// TIS_PC_ACC_ACTIVE bit and remove ownership for localities less than the
+/// locality that is writing this bit.
+///
+#define TIS_PC_ACC_SEIZE BIT3
+///
+/// When this bit is 1, another locality is requesting usage of the TPM.
+///
+#define TIS_PC_ACC_PENDIND BIT2
+///
+/// Set to 1 to indicate that this locality is requesting to use TPM.
+///
+#define TIS_PC_ACC_RQUUSE BIT1
+///
+/// A value of 1 indicates that a T/OS has not been established on the platform
+///
+#define TIS_PC_ACC_ESTABLISH BIT0
+
+///
+/// When this bit is 1, TPM is in the Ready state,
+/// indicating it is ready to receive a new command.
+///
+#define TIS_PC_STS_READY BIT6
+///
+/// Write a 1 to this bit to cause the TPM to execute that command.
+///
+#define TIS_PC_STS_GO BIT5
+///
+/// This bit indicates that the TPM has data available as a response.
+///
+#define TIS_PC_STS_DATA BIT4
+///
+/// The TPM sets this bit to a value of 1 when it expects another byte of data for a command.
+///
+#define TIS_PC_STS_EXPECT BIT3
+///
+/// Writes a 1 to this bit to force the TPM to re-send the response.
+///
+#define TIS_PC_STS_RETRY BIT1
+
+//
+// Default TimeOut value
+//
+#define TIS_TIMEOUT_B 2000 * 1000 // 2s
+#define TIS_TIMEOUT_C 750 * 1000 // 750ms
+#define TIS_TIMEOUT_D 750 * 1000 // 750ms
+
+//
+// Max TPM command/reponse length
+//
+#define TPMCMDBUFLENGTH 1024
+
+/**
+ Check whether the value of a TPM chip register satisfies the input BIT setting.
+
+ @param[in] Register Address port of register to be checked.
+ @param[in] BitSet Check these data bits are set.
+ @param[in] BitClear Check these data bits are clear.
+ @param[in] TimeOut The max wait time (unit MicroSecond) when checking register.
+
+ @retval EFI_SUCCESS The register satisfies the check bit.
+ @retval EFI_TIMEOUT The register can't run into the expected status in time.
+**/
+EFI_STATUS
+EFIAPI
+TisPcWaitRegisterBits (
+ IN UINT8 *Register,
+ IN UINT8 BitSet,
+ IN UINT8 BitClear,
+ IN UINT32 TimeOut
+ );
+
+/**
+ Get BurstCount by reading the burstCount field of a TIS regiger
+ in the time of default TIS_TIMEOUT_D.
+
+ @param[in] TisReg Pointer to TIS register.
+ @param[out] BurstCount Pointer to a buffer to store the got BurstConut.
+
+ @retval EFI_SUCCESS Get BurstCount.
+ @retval EFI_INVALID_PARAMETER TisReg is NULL or BurstCount is NULL.
+ @retval EFI_TIMEOUT BurstCount can't be got in time.
+**/
+EFI_STATUS
+EFIAPI
+TisPcReadBurstCount (
+ IN TIS_PC_REGISTERS_PTR TisReg,
+ OUT UINT16 *BurstCount
+ );
+
+/**
+ Set TPM chip to ready state by sending ready command TIS_PC_STS_READY
+ to Status Register in time.
+
+ @param[in] TisReg Pointer to TIS register.
+
+ @retval EFI_SUCCESS TPM chip enters into ready state.
+ @retval EFI_INVALID_PARAMETER TisReg is NULL.
+ @retval EFI_TIMEOUT TPM chip can't be set to ready state in time.
+**/
+EFI_STATUS
+EFIAPI
+TisPcPrepareCommand (
+ IN TIS_PC_REGISTERS_PTR TisReg
+ );
+
+/**
+ Get the control of TPM chip by sending requestUse command TIS_PC_ACC_RQUUSE
+ to ACCESS Register in the time of default TIS_TIMEOUT_D.
+
+ @param[in] TisReg Pointer to TIS register.
+
+ @retval EFI_SUCCESS Get the control of TPM chip.
+ @retval EFI_INVALID_PARAMETER TisReg is NULL.
+ @retval EFI_NOT_FOUND TPM chip doesn't exit.
+ @retval EFI_TIMEOUT Can't get the TPM control in time.
+**/
+EFI_STATUS
+EFIAPI
+TisPcRequestUseTpm (
+ IN TIS_PC_REGISTERS_PTR TisReg
+ );
+
+/**
+ Single function calculates SHA1 digest value for all raw data. It
+ combines Sha1Init(), Sha1Update() and Sha1Final().
+
+ @param[in] Data Raw data to be digested.
+ @param[in] DataLen Size of the raw data.
+ @param[out] Digest Pointer to a buffer that stores the final digest.
+
+ @retval EFI_SUCCESS Always successfully calculate the final digest.
+**/
+EFI_STATUS
+EFIAPI
+TpmCommHashAll (
+ IN CONST UINT8 *Data,
+ IN UINTN DataLen,
+ OUT TPM_DIGEST *Digest
+ );
+
+#endif
diff --git a/SecurityPkg/Include/Ppi/LockPhysicalPresence.h b/SecurityPkg/Include/Ppi/LockPhysicalPresence.h
new file mode 100644
index 0000000000..0ae3b7b0ab
--- /dev/null
+++ b/SecurityPkg/Include/Ppi/LockPhysicalPresence.h
@@ -0,0 +1,60 @@
+/** @file
+ This file defines the lock physical Presence PPI. This PPI is
+ produced by a platform specific PEIM and consumed by the TPM
+ PEIM.
+
+Copyright (c) 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __PEI_LOCK_PHYSICAL_PRESENCE_H__
+#define __PEI_LOCK_PHYSICAL_PRESENCE_H__
+
+///
+/// Global ID for the PEI_LOCK_PHYSICAL_PRESENCE_PPI_GUID.
+///
+#define PEI_LOCK_PHYSICAL_PRESENCE_PPI_GUID \
+ { \
+ 0xef9aefe5, 0x2bd3, 0x4031, { 0xaf, 0x7d, 0x5e, 0xfe, 0x5a, 0xbb, 0x9a, 0xd } \
+ }
+
+///
+/// Forward declaration for the PEI_LOCK_PHYSICAL_PRESENCE_PPI
+///
+typedef struct _PEI_LOCK_PHYSICAL_PRESENCE_PPI PEI_LOCK_PHYSICAL_PRESENCE_PPI;
+
+/**
+ This interface returns whether TPM physical presence needs be locked.
+
+ @param[in] PeiServices The pointer to the PEI Services Table.
+
+ @retval TRUE The TPM physical presence should be locked.
+ @retval FALSE The TPM physical presence cannot be locked.
+
+**/
+typedef
+BOOLEAN
+(EFIAPI *PEI_LOCK_PHYSICAL_PRESENCE)(
+ IN CONST EFI_PEI_SERVICES **PeiServices
+);
+
+///
+/// This service abstracts TPM physical presence lock interface. It is necessary for
+/// safety to convey this information to the TPM driver so that TPM physical presence
+/// can be locked as early as possible. This PPI is produced by a platform specific
+/// PEIM and consumed by the TPM PEIM.
+///
+struct _PEI_LOCK_PHYSICAL_PRESENCE_PPI {
+ PEI_LOCK_PHYSICAL_PRESENCE LockPhysicalPresence;
+};
+
+extern EFI_GUID gPeiLockPhysicalPresencePpiGuid;
+
+#endif // __PEI_LOCK_PHYSICAL_PRESENCE_H__
\ No newline at end of file
diff --git a/SecurityPkg/Include/Ppi/TpmInitialized.h b/SecurityPkg/Include/Ppi/TpmInitialized.h
new file mode 100644
index 0000000000..dbbd415989
--- /dev/null
+++ b/SecurityPkg/Include/Ppi/TpmInitialized.h
@@ -0,0 +1,30 @@
+/** @file
+ Tag GUID that must be installed by the TPM PEIM after the TPM hardware is
+ initialized. PEIMs that must execute after TPM hardware initialization
+ may use this GUID in their dependency expressions.
+
+Copyright (c) 2008 - 2010, Intel Corporation. All rights reserved.
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _PEI_TPM_INITIALIZED_PPI_H_
+#define _PEI_TPM_INITIALIZED_PPI_H_
+
+///
+/// Global ID for the PEI_TPM_INITIALIZED_PPI which always uses a NULL interface.
+///
+#define PEI_TPM_INITIALIZED_PPI_GUID \
+ { \
+ 0xe9db0d58, 0xd48d, 0x47f6, 0x9c, 0x6e, 0x6f, 0x40, 0xe8, 0x6c, 0x7b, 0x41 \
+ }
+
+extern EFI_GUID gPeiTpmInitializedPpiGuid;
+
+#endif
diff --git a/SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.c b/SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.c
new file mode 100644
index 0000000000..f7fe594060
--- /dev/null
+++ b/SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.c
@@ -0,0 +1,858 @@
+/** @file
+ Implement defer image load services for user identification in UEFI2.2.
+
+Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "DxeDeferImageLoadLib.h"
+
+//
+// Handle for the Deferred Image Load Protocol instance produced by this driver.
+//
+EFI_HANDLE mDeferredImageHandle = NULL;
+BOOLEAN mIsProtocolInstalled = FALSE;
+EFI_USER_MANAGER_PROTOCOL *mUserManager = NULL;
+DEFERRED_IMAGE_TABLE mDeferredImage = {
+ 0, // Deferred image count
+ NULL // The deferred image info
+};
+
+EFI_DEFERRED_IMAGE_LOAD_PROTOCOL gDeferredImageLoad = {
+ GetDefferedImageInfo
+};
+
+/**
+ Get the image type.
+
+ @param[in] File This is a pointer to the device path of the file
+ that is being dispatched.
+
+ @return UINT32 Image Type
+
+**/
+UINT32
+GetFileType (
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *File
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE DeviceHandle;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+
+ //
+ // First check to see if File is from a Firmware Volume
+ //
+ DeviceHandle = NULL;
+ TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File;
+ Status = gBS->LocateDevicePath (
+ &gEfiFirmwareVolume2ProtocolGuid,
+ &TempDevicePath,
+ &DeviceHandle
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->OpenProtocol (
+ DeviceHandle,
+ &gEfiFirmwareVolume2ProtocolGuid,
+ NULL,
+ NULL,
+ NULL,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+ if (!EFI_ERROR (Status)) {
+ return IMAGE_FROM_FV;
+ }
+ }
+
+ //
+ // Next check to see if File is from a Block I/O device
+ //
+ DeviceHandle = NULL;
+ TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File;
+ Status = gBS->LocateDevicePath (
+ &gEfiBlockIoProtocolGuid,
+ &TempDevicePath,
+ &DeviceHandle
+ );
+ if (!EFI_ERROR (Status)) {
+ BlockIo = NULL;
+ Status = gBS->OpenProtocol (
+ DeviceHandle,
+ &gEfiBlockIoProtocolGuid,
+ (VOID **) &BlockIo,
+ NULL,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (!EFI_ERROR (Status) && BlockIo != NULL) {
+ if (BlockIo->Media != NULL) {
+ if (BlockIo->Media->RemovableMedia) {
+ //
+ // Block I/O is present and specifies the media is removable
+ //
+ return IMAGE_FROM_REMOVABLE_MEDIA;
+ } else {
+ //
+ // Block I/O is present and specifies the media is not removable
+ //
+ return IMAGE_FROM_FIXED_MEDIA;
+ }
+ }
+ }
+ }
+
+ //
+ // File is not in a Firmware Volume or on a Block I/O device, so check to see if
+ // the device path supports the Simple File System Protocol.
+ //
+ DeviceHandle = NULL;
+ TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File;
+ Status = gBS->LocateDevicePath (
+ &gEfiSimpleFileSystemProtocolGuid,
+ &TempDevicePath,
+ &DeviceHandle
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Simple File System is present without Block I/O, so assume media is fixed.
+ //
+ return IMAGE_FROM_FIXED_MEDIA;
+ }
+
+ //
+ // File is not from an FV, Block I/O or Simple File System, so the only options
+ // left are a PCI Option ROM and a Load File Protocol such as a PXE Boot from a NIC.
+ //
+ TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File;
+ while (!IsDevicePathEndType (TempDevicePath)) {
+ switch (DevicePathType (TempDevicePath)) {
+
+ case MEDIA_DEVICE_PATH:
+ if (DevicePathSubType (TempDevicePath) == MEDIA_RELATIVE_OFFSET_RANGE_DP) {
+ return IMAGE_FROM_OPTION_ROM;
+ }
+ break;
+
+ case MESSAGING_DEVICE_PATH:
+ if (DevicePathSubType(TempDevicePath) == MSG_MAC_ADDR_DP) {
+ return IMAGE_FROM_REMOVABLE_MEDIA;
+ }
+ break;
+
+ default:
+ break;
+ }
+ TempDevicePath = NextDevicePathNode (TempDevicePath);
+ }
+ return IMAGE_UNKNOWN;
+}
+
+
+/**
+ Get current user's access right.
+
+ @param[out] AccessControl Points to the user's access control data, the
+ caller should free data buffer.
+ @param[in] AccessType The type of user access control.
+
+ @retval EFI_SUCCESS Get current user access control successfully
+ @retval others Fail to get current user access control
+
+**/
+EFI_STATUS
+GetAccessControl (
+ OUT EFI_USER_INFO_ACCESS_CONTROL **AccessControl,
+ IN UINT32 AccessType
+ )
+{
+ EFI_STATUS Status;
+ EFI_USER_INFO_HANDLE UserInfo;
+ EFI_USER_INFO *Info;
+ UINTN InfoSize;
+ EFI_USER_INFO_ACCESS_CONTROL *Access;
+ EFI_USER_PROFILE_HANDLE CurrentUser;
+ UINTN CheckLen;
+ EFI_USER_MANAGER_PROTOCOL *UserManager;
+
+ CurrentUser = NULL;
+ Status = gBS->LocateProtocol (
+ &gEfiUserManagerProtocolGuid,
+ NULL,
+ (VOID **) &UserManager
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Get current user access information.
+ //
+ UserManager->Current (UserManager, &CurrentUser);
+
+ UserInfo = NULL;
+ Info = NULL;
+ InfoSize = 0;
+ while (TRUE) {
+ //
+ // Get next user information.
+ //
+ Status = UserManager->GetNextInfo (UserManager, CurrentUser, &UserInfo);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = UserManager->GetInfo (
+ UserManager,
+ CurrentUser,
+ UserInfo,
+ Info,
+ &InfoSize
+ );
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ if (Info != NULL) {
+ FreePool (Info);
+ }
+ Info = AllocateZeroPool (InfoSize);
+ ASSERT (Info != NULL);
+ Status = UserManager->GetInfo (
+ UserManager,
+ CurrentUser,
+ UserInfo,
+ Info,
+ &InfoSize
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ ASSERT (Info != NULL);
+ if (Info->InfoType != EFI_USER_INFO_ACCESS_POLICY_RECORD) {
+ continue;
+ }
+
+ //
+ // Get specified access information.
+ //
+ CheckLen = 0;
+ while (CheckLen < Info->InfoSize - sizeof (EFI_USER_INFO)) {
+ Access = (EFI_USER_INFO_ACCESS_CONTROL *) ((UINT8 *) (Info + 1) + CheckLen);
+ if ((Access->Type == AccessType)) {
+ *AccessControl = AllocateZeroPool (Access->Size);
+ ASSERT (*AccessControl != NULL);
+ CopyMem (*AccessControl, Access, Access->Size);
+ FreePool (Info);
+ return EFI_SUCCESS;
+ }
+ CheckLen += Access->Size;
+ }
+ }
+
+ if (Info != NULL) {
+ FreePool (Info);
+ }
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ Convert the '/' to '\' in the specified string.
+
+ @param[in, out] Str Points to the string to convert.
+
+**/
+VOID
+ConvertDPStr (
+ IN OUT EFI_STRING Str
+ )
+{
+ INTN Count;
+ INTN Index;
+
+ Count = StrSize(Str) / 2 - 1;
+
+ if (Count < 4) {
+ return;
+ }
+
+ //
+ // Convert device path string.
+ //
+ Index = Count - 1;
+ while (Index > 0) {
+ //
+ // Find the last '/'.
+ //
+ for (Index = Count - 1; Index > 0; Index--) {
+ if (Str[Index] == L'/')
+ break;
+ }
+
+ //
+ // Check next char.
+ //
+ if (Str[Index + 1] == L'\\')
+ return;
+
+ Str[Index] = L'\\';
+
+ //
+ // Check previous char.
+ //
+ if ((Index > 0) && (Str[Index - 1] == L'\\')) {
+ CopyMem (&Str[Index - 1], &Str[Index], (UINTN) ((Count - Index + 1) * sizeof (CHAR16)));
+ return;
+ }
+ Index--;
+ }
+}
+
+
+/**
+ Check whether the DevicePath2 is identical with DevicePath1, or identical with
+ DevicePath1's child device path.
+
+ If DevicePath2 is identical with DevicePath1, or with DevicePath1's child device
+ path, then TRUE returned. Otherwise, FALSE is returned.
+
+ If DevicePath1 is NULL, then ASSERT().
+ If DevicePath2 is NULL, then ASSERT().
+
+ @param[in] DevicePath1 A pointer to a device path.
+ @param[in] DevicePath2 A pointer to a device path.
+
+ @retval TRUE Two device paths are identical , or DevicePath2 is
+ DevicePath1's child device path.
+ @retval FALSE Two device paths are not identical, and DevicePath2
+ is not DevicePath1's child device path.
+
+**/
+BOOLEAN
+CheckDevicePath (
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath1,
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath2
+ )
+{
+ EFI_STATUS Status;
+ EFI_STRING DevicePathStr1;
+ EFI_STRING DevicePathStr2;
+ UINTN StrLen1;
+ UINTN StrLen2;
+ EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *DevicePathText;
+ BOOLEAN DevicePathEqual;
+
+ ASSERT (DevicePath1 != NULL);
+ ASSERT (DevicePath2 != NULL);
+
+ DevicePathEqual = FALSE;
+ DevicePathText = NULL;
+ Status = gBS->LocateProtocol (
+ &gEfiDevicePathToTextProtocolGuid,
+ NULL,
+ (VOID **) &DevicePathText
+ );
+ ASSERT (Status == EFI_SUCCESS);
+
+ //
+ // Get first device path string.
+ //
+ DevicePathStr1 = DevicePathText->ConvertDevicePathToText (DevicePath1, TRUE, TRUE);
+ ConvertDPStr (DevicePathStr1);
+ //
+ // Get second device path string.
+ //
+ DevicePathStr2 = DevicePathText->ConvertDevicePathToText (DevicePath2, TRUE, TRUE);
+ ConvertDPStr (DevicePathStr2);
+
+ //
+ // Compare device path string.
+ //
+ StrLen1 = StrSize (DevicePathStr1);
+ StrLen2 = StrSize (DevicePathStr2);
+ if (StrLen1 > StrLen2) {
+ DevicePathEqual = FALSE;
+ goto Done;
+ }
+
+ if (CompareMem (DevicePathStr1, DevicePathStr2, StrLen1) == 0) {
+ DevicePathEqual = TRUE;
+ }
+
+Done:
+ FreePool (DevicePathStr1);
+ FreePool (DevicePathStr2);
+ return DevicePathEqual;
+}
+
+
+/**
+ Check whether the image pointed to by DevicePath is in the device path list
+ specified by AccessType.
+
+ @param[in] DevicePath Points to device path.
+ @param[in] AccessType The type of user access control.
+
+ @retval TURE The DevicePath is in the specified List.
+ @retval FALSE The DevicePath is not in the specified List.
+
+**/
+BOOLEAN
+IsDevicePathInList (
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ IN UINT32 AccessType
+ )
+{
+ EFI_STATUS Status;
+ EFI_USER_INFO_ACCESS_CONTROL *Access;
+ EFI_DEVICE_PATH_PROTOCOL *Path;
+ UINTN OffSet;
+
+ Status = GetAccessControl (&Access, AccessType);
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ OffSet = 0;
+ while (OffSet < Access->Size - sizeof (EFI_USER_INFO_ACCESS_CONTROL)) {
+ Path = (EFI_DEVICE_PATH_PROTOCOL*)((UINT8*)(Access + 1) + OffSet);
+ if (CheckDevicePath (Path, DevicePath)) {
+ //
+ // The device path is found in list.
+ //
+ FreePool (Access);
+ return TRUE;
+ }
+ OffSet += GetDevicePathSize (Path);
+ }
+
+ FreePool (Access);
+ return FALSE;
+}
+
+
+/**
+ Check whether the image pointed to by DevicePath is permitted to load.
+
+ @param[in] DevicePath Points to device path
+
+ @retval TURE The image pointed by DevicePath is permitted to load.
+ @retval FALSE The image pointed by DevicePath is forbidden to load.
+
+**/
+BOOLEAN
+VerifyDevicePath (
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ if (IsDevicePathInList (DevicePath, EFI_USER_INFO_ACCESS_PERMIT_LOAD)) {
+ //
+ // This access control overrides any restrictions put in place by the
+ // EFI_USER_INFO_ACCESS_FORBID_LOAD record.
+ //
+ return TRUE;
+ }
+
+ if (IsDevicePathInList (DevicePath, EFI_USER_INFO_ACCESS_FORBID_LOAD)) {
+ //
+ // The device path is found in the forbidden list.
+ //
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/**
+ Check the image pointed by DevicePath is a boot option or not.
+
+ @param[in] DevicePath Points to device path.
+
+ @retval TURE The image pointed by DevicePath is a boot option.
+ @retval FALSE The image pointed by DevicePath is not a boot option.
+
+**/
+BOOLEAN
+IsBootOption (
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ EFI_STATUS Status;
+ UINT16 *BootOrderList;
+ UINTN BootOrderListSize;
+ UINTN Index;
+ CHAR16 StrTemp[20];
+ UINT8 *OptionBuffer;
+ UINT8 *OptionPtr;
+ EFI_DEVICE_PATH_PROTOCOL *OptionDevicePath;
+
+ //
+ // Get BootOrder
+ //
+ BootOrderListSize = 0;
+ BootOrderList = NULL;
+ Status = gRT->GetVariable (
+ L"BootOrder",
+ &gEfiGlobalVariableGuid,
+ NULL,
+ &BootOrderListSize,
+ NULL
+ );
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ BootOrderList = AllocateZeroPool (BootOrderListSize);
+ ASSERT (BootOrderList != NULL);
+ Status = gRT->GetVariable (
+ L"BootOrder",
+ &gEfiGlobalVariableGuid,
+ NULL,
+ &BootOrderListSize,
+ BootOrderList
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+ //
+ // No Boot option
+ //
+ return FALSE;
+ }
+
+ OptionBuffer = NULL;
+ for (Index = 0; Index < BootOrderListSize / sizeof (UINT16); Index++) {
+ //
+ // Try to find the DevicePath in BootOption
+ //
+ UnicodeSPrint (StrTemp, sizeof (StrTemp), L"Boot%04x", Index);
+ OptionBuffer = GetEfiGlobalVariable (StrTemp);
+ if (OptionBuffer == NULL) {
+ continue;
+ }
+
+ //
+ // Check whether the image is forbidden.
+ //
+
+ OptionPtr = OptionBuffer;
+ //
+ // Skip attribute.
+ //
+ OptionPtr += sizeof (UINT32);
+
+ //
+ // Skip device path length.
+ //
+ OptionPtr += sizeof (UINT16);
+
+ //
+ // Skip descript string
+ //
+ OptionPtr += StrSize ((UINT16 *) OptionPtr);
+
+ //
+ // Now OptionPtr points to Device Path.
+ //
+ OptionDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) OptionPtr;
+
+ if (CheckDevicePath (DevicePath, OptionDevicePath)) {
+ FreePool (OptionBuffer);
+ OptionBuffer = NULL;
+ return TRUE;
+ }
+ FreePool (OptionBuffer);
+ OptionBuffer = NULL;
+ }
+
+ if (BootOrderList != NULL) {
+ FreePool (BootOrderList);
+ }
+
+ return FALSE;
+}
+
+
+/**
+ Add the image info to a deferred image list.
+
+ @param[in] ImageDevicePath A pointer to the device path of a image.
+ @param[in] Image Points to the first byte of the image, or NULL if the
+ image is not available.
+ @param[in] ImageSize The size of the image, or 0 if the image is not available.
+
+**/
+VOID
+PutDefferedImageInfo (
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *ImageDevicePath,
+ IN VOID *Image,
+ IN UINTN ImageSize
+ )
+{
+ DEFERRED_IMAGE_INFO *CurImageInfo;
+ UINTN PathSize;
+
+ //
+ // Expand memory for the new deferred image.
+ //
+ if (mDeferredImage.Count == 0) {
+ mDeferredImage.ImageInfo = AllocatePool (sizeof (DEFERRED_IMAGE_INFO));
+ ASSERT (mDeferredImage.ImageInfo != NULL);
+ } else {
+ CurImageInfo = AllocatePool ((mDeferredImage.Count + 1) * sizeof (DEFERRED_IMAGE_INFO));
+ ASSERT (CurImageInfo != NULL);
+
+ CopyMem (
+ CurImageInfo,
+ mDeferredImage.ImageInfo,
+ mDeferredImage.Count * sizeof (DEFERRED_IMAGE_INFO)
+ );
+ FreePool (mDeferredImage.ImageInfo);
+ mDeferredImage.ImageInfo = CurImageInfo;
+ }
+ mDeferredImage.Count++;
+
+ //
+ // Save the deferred image information.
+ //
+ CurImageInfo = &mDeferredImage.ImageInfo[mDeferredImage.Count - 1];
+ PathSize = GetDevicePathSize (ImageDevicePath);
+ CurImageInfo->ImageDevicePath = AllocateZeroPool (PathSize);
+ ASSERT (CurImageInfo->ImageDevicePath != NULL);
+ CopyMem (CurImageInfo->ImageDevicePath, ImageDevicePath, PathSize);
+
+ CurImageInfo->Image = Image;
+ CurImageInfo->ImageSize = ImageSize;
+ CurImageInfo->BootOption = IsBootOption (ImageDevicePath);
+}
+
+
+/**
+ Returns information about a deferred image.
+
+ This function returns information about a single deferred image. The deferred images are
+ numbered consecutively, starting with 0. If there is no image which corresponds to
+ ImageIndex, then EFI_NOT_FOUND is returned. All deferred images may be returned by
+ iteratively calling this function until EFI_NOT_FOUND is returned.
+ Image may be NULL and ImageSize set to 0 if the decision to defer execution was made
+ because of the location of the executable image, rather than its actual contents.
+
+ @param[in] This Points to this instance of the EFI_DEFERRED_IMAGE_LOAD_PROTOCOL.
+ @param[in] ImageIndex Zero-based index of the deferred index.
+ @param[out] ImageDevicePath On return, points to a pointer to the device path of the image.
+ The device path should not be freed by the caller.
+ @param[out] Image On return, points to the first byte of the image or NULL if the
+ image is not available. The image should not be freed by the caller
+ unless LoadImage() has been successfully called.
+ @param[out] ImageSize On return, the size of the image, or 0 if the image is not available.
+ @param[out] BootOption On return, points to TRUE if the image was intended as a boot option
+ or FALSE if it was not intended as a boot option.
+
+ @retval EFI_SUCCESS Image information returned successfully.
+ @retval EFI_NOT_FOUND ImageIndex does not refer to a valid image.
+ @retval EFI_INVALID_PARAMETER ImageDevicePath is NULL or Image is NULL or ImageSize is NULL or
+ BootOption is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+GetDefferedImageInfo (
+ IN EFI_DEFERRED_IMAGE_LOAD_PROTOCOL *This,
+ IN UINTN ImageIndex,
+ OUT EFI_DEVICE_PATH_PROTOCOL **ImageDevicePath,
+ OUT VOID **Image,
+ OUT UINTN *ImageSize,
+ OUT BOOLEAN *BootOption
+ )
+{
+ DEFERRED_IMAGE_INFO *ReqImageInfo;
+
+ //
+ // Check the parameter.
+ //
+
+ if ((This == NULL) || (ImageSize == NULL) || (Image == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((ImageDevicePath == NULL) || (BootOption == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (ImageIndex >= mDeferredImage.Count) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Get the request deferred image.
+ //
+ ReqImageInfo = &mDeferredImage.ImageInfo[ImageIndex];
+
+ *ImageDevicePath = ReqImageInfo->ImageDevicePath;
+ *Image = ReqImageInfo->Image;
+ *ImageSize = ReqImageInfo->ImageSize;
+ *BootOption = ReqImageInfo->BootOption;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Provides the service of deferring image load based on platform policy control,
+ and installs Deferred Image Load Protocol.
+
+ @param[in] AuthenticationStatus This is the authentication status returned from the
+ security measurement services for the input file.
+ @param[in] File This is a pointer to the device path of the file that
+ is being dispatched. This will optionally be used for
+ logging.
+ @param[in] FileBuffer File buffer matches the input file device path.
+ @param[in] FileSize Size of File buffer matches the input file device path.
+
+ @retval EFI_SUCCESS The file specified by File did authenticate, and the
+ platform policy dictates that the DXE Core may use File.
+ @retval EFI_INVALID_PARAMETER File is NULL.
+ @retval EFI_SECURITY_VIOLATION The file specified by File did not authenticate, and
+ the platform policy dictates that File should be placed
+ in the untrusted state. A file may be promoted from
+ the untrusted to the trusted state at a future time
+ with a call to the Trust() DXE Service.
+ @retval EFI_ACCESS_DENIED The file specified by File did not authenticate, and
+ the platform policy dictates that File should not be
+ used for any purpose.
+
+**/
+EFI_STATUS
+EFIAPI
+DxeDeferImageLoadHandler (
+ IN UINT32 AuthenticationStatus,
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *File,
+ IN VOID *FileBuffer,
+ IN UINTN FileSize
+ )
+
+{
+ EFI_STATUS Status;
+ EFI_USER_PROFILE_HANDLE CurrentUser;
+ UINT32 Policy;
+ UINT32 FileType;
+
+ if (File == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check whether user has a logon.
+ //
+ CurrentUser = NULL;
+ if (mUserManager != NULL) {
+ mUserManager->Current (mUserManager, &CurrentUser);
+ if (CurrentUser != NULL) {
+ //
+ // The user is logon; verify the FilePath by current user access policy.
+ //
+ if (!VerifyDevicePath (File)) {
+ DEBUG ((EFI_D_ERROR, "[Security] The image is forbidden to load!\n"));
+ return EFI_ACCESS_DENIED;
+ }
+ return EFI_SUCCESS;
+ }
+ }
+
+ //
+ // Still no user logon.
+ // Check the file type and get policy setting.
+ //
+ FileType = GetFileType (File);
+ Policy = PcdGet32 (PcdDeferImageLoadPolicy);
+ if ((Policy & FileType) == FileType) {
+ //
+ // This file type is secure to load.
+ //
+ return EFI_SUCCESS;
+ }
+
+ DEBUG ((EFI_D_ERROR, "[Security] No user identified, the image is deferred to load!\n"));
+ PutDefferedImageInfo (File, NULL, 0);
+
+ //
+ // Install the Deferred Image Load Protocol onto a new handle.
+ //
+ if (!mIsProtocolInstalled) {
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mDeferredImageHandle,
+ &gEfiDeferredImageLoadProtocolGuid,
+ &gDeferredImageLoad,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+ mIsProtocolInstalled = TRUE;
+ }
+
+ return EFI_ACCESS_DENIED;
+}
+
+/**
+ Locate user manager protocol when user manager is installed.
+
+ @param[in] Event The Event that is being processed, not used.
+ @param[in] Context Event Context, not used.
+
+**/
+VOID
+EFIAPI
+FindUserManagerProtocol (
+ IN EFI_EVENT Event,
+ IN VOID* Context
+ )
+{
+ gBS->LocateProtocol (
+ &gEfiUserManagerProtocolGuid,
+ NULL,
+ (VOID **) &mUserManager
+ );
+
+}
+
+
+/**
+ Register security handler for deferred image load.
+
+ @param[in] ImageHandle ImageHandle of the loaded driver.
+ @param[in] SystemTable Pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The handlers were registered successfully.
+**/
+EFI_STATUS
+EFIAPI
+DxeDeferImageLoadLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ VOID *Registration;
+
+ //
+ // Register user manager notification function.
+ //
+ EfiCreateProtocolNotifyEvent (
+ &gEfiUserManagerProtocolGuid,
+ TPL_CALLBACK,
+ FindUserManagerProtocol,
+ NULL,
+ &Registration
+ );
+
+ return RegisterSecurityHandler (
+ DxeDeferImageLoadHandler,
+ EFI_AUTH_OPERATION_DEFER_IMAGE_LOAD
+ );
+}
+
+
diff --git a/SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.h b/SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.h
new file mode 100644
index 0000000000..52eb81b796
--- /dev/null
+++ b/SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.h
@@ -0,0 +1,106 @@
+/** @file
+ The internal header file includes the common header files, defines
+ internal structure and functions used by DeferImageLoadLib.
+
+Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __DEFER_IMAGE_LOAD_LIB_H__
+#define __DEFER_IMAGE_LOAD_LIB_H__
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+//
+// Image type definitions.
+//
+#define IMAGE_UNKNOWN 0x00000001
+#define IMAGE_FROM_FV 0x00000002
+#define IMAGE_FROM_OPTION_ROM 0x00000004
+#define IMAGE_FROM_REMOVABLE_MEDIA 0x00000008
+#define IMAGE_FROM_FIXED_MEDIA 0x00000010
+
+//
+// The struct to save the deferred image information.
+//
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL *ImageDevicePath;
+ VOID *Image;
+ UINTN ImageSize;
+ BOOLEAN BootOption;
+} DEFERRED_IMAGE_INFO;
+
+//
+// The table to save the deferred image item.
+//
+typedef struct {
+ UINTN Count; ///< deferred image count
+ DEFERRED_IMAGE_INFO *ImageInfo; ///< deferred image item
+} DEFERRED_IMAGE_TABLE;
+
+/**
+ Returns information about a deferred image.
+
+ This function returns information about a single deferred image. The deferred images are
+ numbered consecutively, starting with 0. If there is no image which corresponds to
+ ImageIndex, then EFI_NOT_FOUND is returned. All deferred images may be returned by
+ iteratively calling this function until EFI_NOT_FOUND is returned.
+ Image may be NULL and ImageSize set to 0 if the decision to defer execution was made
+ because of the location of the executable image, rather than its actual contents.
+
+ @param[in] This Points to this instance of the EFI_DEFERRED_IMAGE_LOAD_PROTOCOL.
+ @param[in] ImageIndex Zero-based index of the deferred index.
+ @param[out] ImageDevicePath On return, points to a pointer to the device path of the image.
+ The device path should not be freed by the caller.
+ @param[out] Image On return, points to the first byte of the image or NULL if the
+ image is not available. The image should not be freed by the caller
+ unless LoadImage() has been called successfully.
+ @param[out] ImageSize On return, the size of the image, or 0 if the image is not available.
+ @param[out] BootOption On return, points to TRUE if the image was intended as a boot option
+ or FALSE if it was not intended as a boot option.
+
+ @retval EFI_SUCCESS Image information returned successfully.
+ @retval EFI_NOT_FOUND ImageIndex does not refer to a valid image.
+ @retval EFI_INVALID_PARAMETER ImageDevicePath is NULL or Image is NULL or ImageSize is NULL or
+ BootOption is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+GetDefferedImageInfo (
+ IN EFI_DEFERRED_IMAGE_LOAD_PROTOCOL *This,
+ IN UINTN ImageIndex,
+ OUT EFI_DEVICE_PATH_PROTOCOL **ImageDevicePath,
+ OUT VOID **Image,
+ OUT UINTN *ImageSize,
+ OUT BOOLEAN *BootOption
+ );
+
+#endif
diff --git a/SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.inf b/SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.inf
new file mode 100644
index 0000000000..e16fe8dc04
--- /dev/null
+++ b/SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.inf
@@ -0,0 +1,62 @@
+## @file
+# The library instance provides security service of deferring image load.
+#
+# Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeDeferImageLoadLib
+ FILE_GUID = 5E2FAE1F-41DA-4fbd-BC81-603CE5CD8497
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = NULL|DXE_DRIVER UEFI_DRIVER DXE_RUNTIME_DRIVER UEFI_APPLICATION
+ CONSTRUCTOR = DxeDeferImageLoadLibConstructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ DxeDeferImageLoadLib.c
+ DxeDeferImageLoadLib.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+ UefiRuntimeServicesTableLib
+ UefiBootServicesTableLib
+ SecurityManagementLib
+ MemoryAllocationLib
+ DevicePathLib
+ BaseMemoryLib
+ PrintLib
+ DebugLib
+ UefiLib
+ PcdLib
+
+[Protocols]
+ gEfiFirmwareVolume2ProtocolGuid
+ gEfiBlockIoProtocolGuid
+ gEfiSimpleFileSystemProtocolGuid
+ gEfiUserManagerProtocolGuid
+ gEfiDeferredImageLoadProtocolGuid
+ gEfiDevicePathToTextProtocolGuid
+
+[Guids]
+ gEfiGlobalVariableGuid
+
+[Pcd]
+ gEfiSecurityPkgTokenSpaceGuid.PcdDeferImageLoadPolicy
diff --git a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c
new file mode 100644
index 0000000000..148dbd5a89
--- /dev/null
+++ b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c
@@ -0,0 +1,1368 @@
+/** @file
+ Implement image verification services for secure boot service in UEFI2.3.1.
+
+Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "DxeImageVerificationLib.h"
+
+EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION mNtHeader;
+UINTN mImageSize;
+UINT32 mPeCoffHeaderOffset;
+UINT8 mImageDigest[MAX_DIGEST_SIZE];
+UINTN mImageDigestSize;
+EFI_IMAGE_DATA_DIRECTORY *mSecDataDir = NULL;
+UINT8 *mImageBase = NULL;
+EFI_GUID mCertType;
+
+//
+// Notify string for authorization UI.
+//
+CHAR16 mNotifyString1[MAX_NOTIFY_STRING_LEN] = L"Image verification pass but not found in authorized database!";
+CHAR16 mNotifyString2[MAX_NOTIFY_STRING_LEN] = L"Launch this image anyway? (Yes/Defer/No)";
+//
+// Public Exponent of RSA Key.
+//
+CONST UINT8 mRsaE[] = { 0x01, 0x00, 0x01 };
+
+
+//
+// OID ASN.1 Value for Hash Algorithms
+//
+UINT8 mHashOidValue[] = {
+ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, // OBJ_md5
+ 0x2B, 0x0E, 0x03, 0x02, 0x1A, // OBJ_sha1
+ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, // OBJ_sha224
+ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, // OBJ_sha256
+ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, // OBJ_sha384
+ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, // OBJ_sha512
+ };
+
+HASH_TABLE mHash[] = {
+ { L"SHA1", 20, &mHashOidValue[8], 5, Sha1GetContextSize, Sha1Init, Sha1Update, Sha1Final },
+ { L"SHA224", 28, &mHashOidValue[13], 9, NULL, NULL, NULL, NULL },
+ { L"SHA256", 32, &mHashOidValue[22], 9, Sha256GetContextSize,Sha256Init, Sha256Update, Sha256Final},
+ { L"SHA384", 48, &mHashOidValue[31], 9, NULL, NULL, NULL, NULL },
+ { L"SHA512", 64, &mHashOidValue[40], 9, NULL, NULL, NULL, NULL }
+};
+
+
+/**
+ Get the image type.
+
+ @param[in] File This is a pointer to the device path of the file that is
+ being dispatched.
+
+ @return UINT32 Image Type
+
+**/
+UINT32
+GetImageType (
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *File
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE DeviceHandle;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+
+ //
+ // First check to see if File is from a Firmware Volume
+ //
+ DeviceHandle = NULL;
+ TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File;
+ Status = gBS->LocateDevicePath (
+ &gEfiFirmwareVolume2ProtocolGuid,
+ &TempDevicePath,
+ &DeviceHandle
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->OpenProtocol (
+ DeviceHandle,
+ &gEfiFirmwareVolume2ProtocolGuid,
+ NULL,
+ NULL,
+ NULL,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+ if (!EFI_ERROR (Status)) {
+ return IMAGE_FROM_FV;
+ }
+ }
+
+ //
+ // Next check to see if File is from a Block I/O device
+ //
+ DeviceHandle = NULL;
+ TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File;
+ Status = gBS->LocateDevicePath (
+ &gEfiBlockIoProtocolGuid,
+ &TempDevicePath,
+ &DeviceHandle
+ );
+ if (!EFI_ERROR (Status)) {
+ BlockIo = NULL;
+ Status = gBS->OpenProtocol (
+ DeviceHandle,
+ &gEfiBlockIoProtocolGuid,
+ (VOID **) &BlockIo,
+ NULL,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (!EFI_ERROR (Status) && BlockIo != NULL) {
+ if (BlockIo->Media != NULL) {
+ if (BlockIo->Media->RemovableMedia) {
+ //
+ // Block I/O is present and specifies the media is removable
+ //
+ return IMAGE_FROM_REMOVABLE_MEDIA;
+ } else {
+ //
+ // Block I/O is present and specifies the media is not removable
+ //
+ return IMAGE_FROM_FIXED_MEDIA;
+ }
+ }
+ }
+ }
+
+ //
+ // File is not in a Firmware Volume or on a Block I/O device, so check to see if
+ // the device path supports the Simple File System Protocol.
+ //
+ DeviceHandle = NULL;
+ TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File;
+ Status = gBS->LocateDevicePath (
+ &gEfiSimpleFileSystemProtocolGuid,
+ &TempDevicePath,
+ &DeviceHandle
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Simple File System is present without Block I/O, so assume media is fixed.
+ //
+ return IMAGE_FROM_FIXED_MEDIA;
+ }
+
+ //
+ // File is not from an FV, Block I/O or Simple File System, so the only options
+ // left are a PCI Option ROM and a Load File Protocol such as a PXE Boot from a NIC.
+ //
+ TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File;
+ while (!IsDevicePathEndType (TempDevicePath)) {
+ switch (DevicePathType (TempDevicePath)) {
+
+ case MEDIA_DEVICE_PATH:
+ if (DevicePathSubType (TempDevicePath) == MEDIA_RELATIVE_OFFSET_RANGE_DP) {
+ return IMAGE_FROM_OPTION_ROM;
+ }
+ break;
+
+ case MESSAGING_DEVICE_PATH:
+ if (DevicePathSubType(TempDevicePath) == MSG_MAC_ADDR_DP) {
+ return IMAGE_FROM_REMOVABLE_MEDIA;
+ }
+ break;
+
+ default:
+ break;
+ }
+ TempDevicePath = NextDevicePathNode (TempDevicePath);
+ }
+ return IMAGE_UNKNOWN;
+}
+
+/**
+ Caculate hash of Pe/Coff image based on the authenticode image hashing in
+ PE/COFF Specification 8.0 Appendix A
+
+ @param[in] HashAlg Hash algorithm type.
+
+ @retval TRUE Successfully hash image.
+ @retval FALSE Fail in hash image.
+
+**/
+BOOLEAN
+HashPeImage (
+ IN UINT32 HashAlg
+ )
+{
+ BOOLEAN Status;
+ UINT16 Magic;
+ EFI_IMAGE_SECTION_HEADER *Section;
+ VOID *HashCtx;
+ UINTN CtxSize;
+ UINT8 *HashBase;
+ UINTN HashSize;
+ UINTN SumOfBytesHashed;
+ EFI_IMAGE_SECTION_HEADER *SectionHeader;
+ UINTN Index;
+ UINTN Pos;
+
+ HashCtx = NULL;
+ SectionHeader = NULL;
+ Status = FALSE;
+
+ if ((HashAlg != HASHALG_SHA1) && (HashAlg != HASHALG_SHA256)) {
+ return FALSE;
+ }
+
+ //
+ // Initialize context of hash.
+ //
+ ZeroMem (mImageDigest, MAX_DIGEST_SIZE);
+
+ if (HashAlg == HASHALG_SHA1) {
+ mImageDigestSize = SHA1_DIGEST_SIZE;
+ mCertType = gEfiCertSha1Guid;
+ } else if (HashAlg == HASHALG_SHA256) {
+ mImageDigestSize = SHA256_DIGEST_SIZE;
+ mCertType = gEfiCertSha256Guid;
+ } else {
+ return FALSE;
+ }
+
+ CtxSize = mHash[HashAlg].GetContextSize();
+
+ HashCtx = AllocatePool (CtxSize);
+ ASSERT (HashCtx != NULL);
+
+ // 1. Load the image header into memory.
+
+ // 2. Initialize a SHA hash context.
+ Status = mHash[HashAlg].HashInit(HashCtx);
+
+ if (!Status) {
+ goto Done;
+ }
+ //
+ // Measuring PE/COFF Image Header;
+ // But CheckSum field and SECURITY data directory (certificate) are excluded
+ //
+ Magic = mNtHeader.Pe32->OptionalHeader.Magic;
+ //
+ // 3. Calculate the distance from the base of the image header to the image checksum address.
+ // 4. Hash the image header from its base to beginning of the image checksum.
+ //
+ HashBase = mImageBase;
+ if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ //
+ // Use PE32 offset.
+ //
+ HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32->OptionalHeader.CheckSum) - HashBase);
+ } else {
+ //
+ // Use PE32+ offset.
+ //
+ HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32Plus->OptionalHeader.CheckSum) - HashBase);
+ }
+
+ Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);
+ if (!Status) {
+ goto Done;
+ }
+ //
+ // 5. Skip over the image checksum (it occupies a single ULONG).
+ // 6. Get the address of the beginning of the Cert Directory.
+ // 7. Hash everything from the end of the checksum to the start of the Cert Directory.
+ //
+ if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ //
+ // Use PE32 offset.
+ //
+ HashBase = (UINT8 *) &mNtHeader.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);
+ HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase);
+ } else {
+ //
+ // Use PE32+ offset.
+ //
+ HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);
+ HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase);
+ }
+
+ Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);
+ if (!Status) {
+ goto Done;
+ }
+ //
+ // 8. Skip over the Cert Directory. (It is sizeof(IMAGE_DATA_DIRECTORY) bytes.)
+ // 9. Hash everything from the end of the Cert Directory to the end of image header.
+ //
+ if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ //
+ // Use PE32 offset
+ //
+ HashBase = (UINT8 *) &mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];
+ HashSize = mNtHeader.Pe32->OptionalHeader.SizeOfHeaders - (UINTN) ((UINT8 *) (&mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]) - mImageBase);
+ } else {
+ //
+ // Use PE32+ offset.
+ //
+ HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];
+ HashSize = mNtHeader.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN) ((UINT8 *) (&mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]) - mImageBase);
+ }
+
+ Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);
+ if (!Status) {
+ goto Done;
+ }
+ //
+ // 10. Set the SUM_OF_BYTES_HASHED to the size of the header.
+ //
+ if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ //
+ // Use PE32 offset.
+ //
+ SumOfBytesHashed = mNtHeader.Pe32->OptionalHeader.SizeOfHeaders;
+ } else {
+ //
+ // Use PE32+ offset
+ //
+ SumOfBytesHashed = mNtHeader.Pe32Plus->OptionalHeader.SizeOfHeaders;
+ }
+
+ //
+ // 11. Build a temporary table of pointers to all the IMAGE_SECTION_HEADER
+ // structures in the image. The 'NumberOfSections' field of the image
+ // header indicates how big the table should be. Do not include any
+ // IMAGE_SECTION_HEADERs in the table whose 'SizeOfRawData' field is zero.
+ //
+ SectionHeader = (EFI_IMAGE_SECTION_HEADER *) AllocateZeroPool (sizeof (EFI_IMAGE_SECTION_HEADER) * mNtHeader.Pe32->FileHeader.NumberOfSections);
+ ASSERT (SectionHeader != NULL);
+ //
+ // 12. Using the 'PointerToRawData' in the referenced section headers as
+ // a key, arrange the elements in the table in ascending order. In other
+ // words, sort the section headers according to the disk-file offset of
+ // the section.
+ //
+ Section = (EFI_IMAGE_SECTION_HEADER *) (
+ mImageBase +
+ mPeCoffHeaderOffset +
+ sizeof (UINT32) +
+ sizeof (EFI_IMAGE_FILE_HEADER) +
+ mNtHeader.Pe32->FileHeader.SizeOfOptionalHeader
+ );
+ for (Index = 0; Index < mNtHeader.Pe32->FileHeader.NumberOfSections; Index++) {
+ Pos = Index;
+ while ((Pos > 0) && (Section->PointerToRawData < SectionHeader[Pos - 1].PointerToRawData)) {
+ CopyMem (&SectionHeader[Pos], &SectionHeader[Pos - 1], sizeof (EFI_IMAGE_SECTION_HEADER));
+ Pos--;
+ }
+ CopyMem (&SectionHeader[Pos], Section, sizeof (EFI_IMAGE_SECTION_HEADER));
+ Section += 1;
+ }
+
+ //
+ // 13. Walk through the sorted table, bring the corresponding section
+ // into memory, and hash the entire section (using the 'SizeOfRawData'
+ // field in the section header to determine the amount of data to hash).
+ // 14. Add the section's 'SizeOfRawData' to SUM_OF_BYTES_HASHED .
+ // 15. Repeat steps 13 and 14 for all the sections in the sorted table.
+ //
+ for (Index = 0; Index < mNtHeader.Pe32->FileHeader.NumberOfSections; Index++) {
+ Section = &SectionHeader[Index];
+ if (Section->SizeOfRawData == 0) {
+ continue;
+ }
+ HashBase = mImageBase + Section->PointerToRawData;
+ HashSize = (UINTN) Section->SizeOfRawData;
+
+ Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);
+ if (!Status) {
+ goto Done;
+ }
+
+ SumOfBytesHashed += HashSize;
+ }
+
+ //
+ // 16. If the file size is greater than SUM_OF_BYTES_HASHED, there is extra
+ // data in the file that needs to be added to the hash. This data begins
+ // at file offset SUM_OF_BYTES_HASHED and its length is:
+ // FileSize - (CertDirectory->Size)
+ //
+ if (mImageSize > SumOfBytesHashed) {
+ HashBase = mImageBase + SumOfBytesHashed;
+ if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ //
+ // Use PE32 offset.
+ //
+ HashSize = (UINTN)(
+ mImageSize -
+ mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size -
+ SumOfBytesHashed);
+ } else {
+ //
+ // Use PE32+ offset.
+ //
+ HashSize = (UINTN)(
+ mImageSize -
+ mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size -
+ SumOfBytesHashed);
+ }
+
+ Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);
+ if (!Status) {
+ goto Done;
+ }
+ }
+ Status = mHash[HashAlg].HashFinal(HashCtx, mImageDigest);
+
+Done:
+ if (HashCtx != NULL) {
+ FreePool (HashCtx);
+ }
+ if (SectionHeader != NULL) {
+ FreePool (SectionHeader);
+ }
+ return Status;
+}
+
+/**
+ Recognize the Hash algorithm in PE/COFF Authenticode and caculate hash of
+ Pe/Coff image based on the authenticode image hashing in PE/COFF Specification
+ 8.0 Appendix A
+
+ @retval EFI_UNSUPPORTED Hash algorithm is not supported.
+ @retval EFI_SUCCESS Hash successfully.
+
+**/
+EFI_STATUS
+HashPeImageByType (
+ VOID
+ )
+{
+ UINT8 Index;
+ WIN_CERTIFICATE_EFI_PKCS *PkcsCertData;
+
+ PkcsCertData = (WIN_CERTIFICATE_EFI_PKCS *) (mImageBase + mSecDataDir->VirtualAddress);
+
+ for (Index = 0; Index < HASHALG_MAX; Index++) {
+ //
+ // Check the Hash algorithm in PE/COFF Authenticode.
+ // According to PKCS#7 Definition:
+ // SignedData ::= SEQUENCE {
+ // version Version,
+ // digestAlgorithms DigestAlgorithmIdentifiers,
+ // contentInfo ContentInfo,
+ // .... }
+ // The DigestAlgorithmIdentifiers can be used to determine the hash algorithm in PE/COFF hashing
+ // This field has the fixed offset (+32) in final Authenticode ASN.1 data.
+ //
+ if (CompareMem (PkcsCertData->CertData + 32, mHash[Index].OidValue, mHash[Index].OidLength) == 0) {
+ break;
+ }
+ }
+
+ if (Index == HASHALG_MAX) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // HASH PE Image based on Hash algorithm in PE/COFF Authenticode.
+ //
+ if (!HashPeImage(Index)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Returns the size of a given image execution info table in bytes.
+
+ This function returns the size, in bytes, of the image execution info table specified by
+ ImageExeInfoTable. If ImageExeInfoTable is NULL, then 0 is returned.
+
+ @param ImageExeInfoTable A pointer to a image execution info table structure.
+
+ @retval 0 If ImageExeInfoTable is NULL.
+ @retval Others The size of a image execution info table in bytes.
+
+**/
+UINTN
+GetImageExeInfoTableSize (
+ EFI_IMAGE_EXECUTION_INFO_TABLE *ImageExeInfoTable
+ )
+{
+ UINTN Index;
+ EFI_IMAGE_EXECUTION_INFO *ImageExeInfoItem;
+ UINTN TotalSize;
+
+ if (ImageExeInfoTable == NULL) {
+ return 0;
+ }
+
+ ImageExeInfoItem = (EFI_IMAGE_EXECUTION_INFO *) ((UINT8 *) ImageExeInfoTable + sizeof (EFI_IMAGE_EXECUTION_INFO_TABLE));
+ TotalSize = sizeof (EFI_IMAGE_EXECUTION_INFO_TABLE);
+ for (Index = 0; Index < ImageExeInfoTable->NumberOfImages; Index++) {
+ TotalSize += ReadUnaligned32 ((UINT32 *) &ImageExeInfoItem->InfoSize);
+ ImageExeInfoItem = (EFI_IMAGE_EXECUTION_INFO *) ((UINT8 *) ImageExeInfoItem + ReadUnaligned32 ((UINT32 *) &ImageExeInfoItem->InfoSize));
+ }
+
+ return TotalSize;
+}
+
+/**
+ Create an Image Execution Information Table entry and add it to system configuration table.
+
+ @param[in] Action Describes the action taken by the firmware regarding this image.
+ @param[in] Name Input a null-terminated, user-friendly name.
+ @param[in] DevicePath Input device path pointer.
+ @param[in] Signature Input signature info in EFI_SIGNATURE_LIST data structure.
+ @param[in] SignatureSize Size of signature.
+
+**/
+VOID
+AddImageExeInfo (
+ IN EFI_IMAGE_EXECUTION_ACTION Action,
+ IN CHAR16 *Name OPTIONAL,
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ IN EFI_SIGNATURE_LIST *Signature OPTIONAL,
+ IN UINTN SignatureSize
+ )
+{
+ EFI_STATUS Status;
+ EFI_IMAGE_EXECUTION_INFO_TABLE *ImageExeInfoTable;
+ EFI_IMAGE_EXECUTION_INFO_TABLE *NewImageExeInfoTable;
+ EFI_IMAGE_EXECUTION_INFO *ImageExeInfoEntry;
+ UINTN ImageExeInfoTableSize;
+ UINTN NewImageExeInfoEntrySize;
+ UINTN NameStringLen;
+ UINTN DevicePathSize;
+
+ ASSERT (DevicePath != NULL);
+ ImageExeInfoTable = NULL;
+ NewImageExeInfoTable = NULL;
+ ImageExeInfoEntry = NULL;
+ NameStringLen = 0;
+
+ if (Name != NULL) {
+ NameStringLen = StrSize (Name);
+ }
+
+ ImageExeInfoTable = NULL;
+ EfiGetSystemConfigurationTable (&gEfiImageSecurityDatabaseGuid, (VOID**)&ImageExeInfoTable);
+ if (ImageExeInfoTable != NULL) {
+ //
+ // The table has been found!
+ // We must enlarge the table to accmodate the new exe info entry.
+ //
+ ImageExeInfoTableSize = GetImageExeInfoTableSize (ImageExeInfoTable);
+ } else {
+ //
+ // Not Found!
+ // We should create a new table to append to the configuration table.
+ //
+ ImageExeInfoTableSize = sizeof (EFI_IMAGE_EXECUTION_INFO_TABLE);
+ }
+
+ DevicePathSize = GetDevicePathSize (DevicePath);
+ NewImageExeInfoEntrySize = sizeof (EFI_IMAGE_EXECUTION_INFO) + NameStringLen + DevicePathSize + SignatureSize;
+ NewImageExeInfoTable = (EFI_IMAGE_EXECUTION_INFO_TABLE *) AllocateRuntimePool (ImageExeInfoTableSize + NewImageExeInfoEntrySize);
+ ASSERT (NewImageExeInfoTable != NULL);
+
+ if (ImageExeInfoTable != NULL) {
+ CopyMem (NewImageExeInfoTable, ImageExeInfoTable, ImageExeInfoTableSize);
+ } else {
+ NewImageExeInfoTable->NumberOfImages = 0;
+ }
+ NewImageExeInfoTable->NumberOfImages++;
+ ImageExeInfoEntry = (EFI_IMAGE_EXECUTION_INFO *) ((UINT8 *) NewImageExeInfoTable + ImageExeInfoTableSize);
+ //
+ // Update new item's infomation.
+ //
+ WriteUnaligned32 ((UINT32 *) &ImageExeInfoEntry->Action, Action);
+ WriteUnaligned32 ((UINT32 *) &ImageExeInfoEntry->InfoSize, (UINT32) NewImageExeInfoEntrySize);
+
+ if (Name != NULL) {
+ CopyMem ((UINT8 *) &ImageExeInfoEntry->InfoSize + sizeof (UINT32), Name, NameStringLen);
+ }
+ CopyMem (
+ (UINT8 *) &ImageExeInfoEntry->InfoSize + sizeof (UINT32) + NameStringLen,
+ DevicePath,
+ DevicePathSize
+ );
+ if (Signature != NULL) {
+ CopyMem (
+ (UINT8 *) &ImageExeInfoEntry->InfoSize + sizeof (UINT32) + NameStringLen + DevicePathSize,
+ Signature,
+ SignatureSize
+ );
+ }
+ //
+ // Update/replace the image execution table.
+ //
+ Status = gBS->InstallConfigurationTable (&gEfiImageSecurityDatabaseGuid, (VOID *) NewImageExeInfoTable);
+ ASSERT_EFI_ERROR (Status);
+ //
+ // Free Old table data!
+ //
+ if (ImageExeInfoTable != NULL) {
+ FreePool (ImageExeInfoTable);
+ }
+}
+
+/**
+ Discover if the UEFI image is authorized by user's policy setting.
+
+ @param[in] Policy Specify platform's policy setting.
+
+ @retval EFI_ACCESS_DENIED Image is not allowed to run.
+ @retval EFI_SECURITY_VIOLATION Image is deferred.
+ @retval EFI_SUCCESS Image is authorized to run.
+
+**/
+EFI_STATUS
+ImageAuthorization (
+ IN UINT32 Policy
+ )
+{
+ EFI_STATUS Status;
+ EFI_INPUT_KEY Key;
+
+ Status = EFI_ACCESS_DENIED;
+
+ switch (Policy) {
+
+ case QUERY_USER_ON_SECURITY_VIOLATION:
+ do {
+ CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, mNotifyString1, mNotifyString2, NULL);
+ if (Key.UnicodeChar == L'Y' || Key.UnicodeChar == L'y') {
+ Status = EFI_SUCCESS;
+ break;
+ } else if (Key.UnicodeChar == L'N' || Key.UnicodeChar == L'n') {
+ Status = EFI_ACCESS_DENIED;
+ break;
+ } else if (Key.UnicodeChar == L'D' || Key.UnicodeChar == L'd') {
+ Status = EFI_SECURITY_VIOLATION;
+ break;
+ }
+ } while (TRUE);
+ break;
+
+ case ALLOW_EXECUTE_ON_SECURITY_VIOLATION:
+ Status = EFI_SUCCESS;
+ break;
+
+ case DEFER_EXECUTE_ON_SECURITY_VIOLATION:
+ Status = EFI_SECURITY_VIOLATION;
+ break;
+
+ case DENY_EXECUTE_ON_SECURITY_VIOLATION:
+ Status = EFI_ACCESS_DENIED;
+ break;
+ }
+
+ return Status;
+}
+
+/**
+ Check whether signature is in specified database.
+
+ @param[in] VariableName Name of database variable that is searched in.
+ @param[in] Signature Pointer to signature that is searched for.
+ @param[in] CertType Pointer to hash algrithom.
+ @param[in] SignatureSize Size of Signature.
+
+ @return TRUE Found the signature in the variable database.
+ @return FALSE Not found the signature in the variable database.
+
+**/
+BOOLEAN
+IsSignatureFoundInDatabase (
+ IN CHAR16 *VariableName,
+ IN UINT8 *Signature,
+ IN EFI_GUID *CertType,
+ IN UINTN SignatureSize
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIGNATURE_LIST *CertList;
+ EFI_SIGNATURE_DATA *Cert;
+ UINTN DataSize;
+ UINT8 *Data;
+ UINTN Index;
+ UINTN CertCount;
+ BOOLEAN IsFound;
+ //
+ // Read signature database variable.
+ //
+ IsFound = FALSE;
+ Data = NULL;
+ DataSize = 0;
+ Status = gRT->GetVariable (VariableName, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, NULL);
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ return FALSE;
+ }
+
+ Data = (UINT8 *) AllocateZeroPool (DataSize);
+ ASSERT (Data != NULL);
+
+ Status = gRT->GetVariable (VariableName, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, Data);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ //
+ // Enumerate all signature data in SigDB to check if executable's signature exists.
+ //
+ CertList = (EFI_SIGNATURE_LIST *) Data;
+ while ((DataSize > 0) && (DataSize >= CertList->SignatureListSize)) {
+ CertCount = (CertList->SignatureListSize - CertList->SignatureHeaderSize) / CertList->SignatureSize;
+ Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
+ if ((CertList->SignatureSize == sizeof(EFI_SIGNATURE_DATA) - 1 + SignatureSize) && (CompareGuid(&CertList->SignatureType, CertType))) {
+ for (Index = 0; Index < CertCount; Index++) {
+ if (CompareMem (Cert->SignatureData, Signature, SignatureSize) == 0) {
+ //
+ // Find the signature in database.
+ //
+ IsFound = TRUE;
+ break;
+ }
+
+ Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);
+ }
+
+ if (IsFound) {
+ break;
+ }
+ }
+
+ DataSize -= CertList->SignatureListSize;
+ CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
+ }
+
+Done:
+ if (Data != NULL) {
+ FreePool (Data);
+ }
+
+ return IsFound;
+}
+
+/**
+ Verify certificate in WIN_CERT_TYPE_PKCS_SIGNED_DATA format .
+
+ @retval EFI_SUCCESS Image pass verification.
+ @retval EFI_SECURITY_VIOLATION Image fail verification.
+ @retval other error value
+
+**/
+EFI_STATUS
+VerifyCertPkcsSignedData (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN VerifyStatus;
+ WIN_CERTIFICATE_EFI_PKCS *PkcsCertData;
+ EFI_SIGNATURE_LIST *CertList;
+ EFI_SIGNATURE_DATA *Cert;
+ UINTN DataSize;
+ UINT8 *Data;
+ UINT8 *RootCert;
+ UINTN RootCertSize;
+ UINTN Index;
+ UINTN CertCount;
+
+ Data = NULL;
+ CertList = NULL;
+ Cert = NULL;
+ RootCert = NULL;
+ RootCertSize = 0;
+ VerifyStatus = FALSE;
+ PkcsCertData = (WIN_CERTIFICATE_EFI_PKCS *) (mImageBase + mSecDataDir->VirtualAddress);
+
+ //
+ // 1: Find certificate from KEK database and try to verify authenticode struct.
+ //
+ DataSize = 0;
+ Status = gRT->GetVariable (EFI_KEY_EXCHANGE_KEY_NAME, &gEfiGlobalVariableGuid, NULL, &DataSize, NULL);
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ Data = (UINT8 *)AllocateZeroPool (DataSize);
+ ASSERT (Data != NULL);
+
+ Status = gRT->GetVariable (EFI_KEY_EXCHANGE_KEY_NAME, &gEfiGlobalVariableGuid, NULL, &DataSize, (VOID *)Data);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Find Cert Enrolled in KEK database to verify the signature in pkcs7 signed data.
+ //
+ CertList = (EFI_SIGNATURE_LIST *) Data;
+ while ((DataSize > 0) && (DataSize >= CertList->SignatureListSize)) {
+ if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {
+ Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
+ CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
+ for (Index = 0; Index < CertCount; Index++) {
+ //
+ // Iterate each Signature Data Node within this CertList for a verify
+ //
+ RootCert = Cert->SignatureData;
+ RootCertSize = CertList->SignatureSize;
+
+ //
+ // Call AuthenticodeVerify library to Verify Authenticode struct.
+ //
+ VerifyStatus = AuthenticodeVerify (
+ PkcsCertData->CertData,
+ mSecDataDir->Size - sizeof(PkcsCertData->Hdr),
+ RootCert,
+ RootCertSize,
+ mImageDigest,
+ mImageDigestSize
+ );
+
+ if (VerifyStatus) {
+ goto Done;
+ }
+ Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);
+ }
+ }
+ DataSize -= CertList->SignatureListSize;
+ CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
+ }
+ }
+
+
+
+ //
+ // 2: Find certificate from DB database and try to verify authenticode struct.
+ //
+ DataSize = 0;
+ Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, NULL);
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ Data = (UINT8 *)AllocateZeroPool (DataSize);
+ ASSERT (Data != NULL);
+
+ Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, (VOID *)Data);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Find Cert Enrolled in DB database to verify the signature in pkcs7 signed data.
+ //
+ CertList = (EFI_SIGNATURE_LIST *) Data;
+ while ((DataSize > 0) && (DataSize >= CertList->SignatureListSize)) {
+ if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {
+ Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
+ CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
+ for (Index = 0; Index < CertCount; Index++) {
+ //
+ // Iterate each Signature Data Node within this CertList for a verify
+ //
+ RootCert = Cert->SignatureData;
+ RootCertSize = CertList->SignatureSize;
+
+ //
+ // Call AuthenticodeVerify library to Verify Authenticode struct.
+ //
+ VerifyStatus = AuthenticodeVerify (
+ PkcsCertData->CertData,
+ mSecDataDir->Size - sizeof(PkcsCertData->Hdr),
+ RootCert,
+ RootCertSize,
+ mImageDigest,
+ mImageDigestSize
+ );
+
+ if (VerifyStatus) {
+ goto Done;
+ }
+ Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);
+ }
+ }
+ DataSize -= CertList->SignatureListSize;
+ CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
+ }
+ }
+
+Done:
+ if (Data != NULL) {
+ FreePool (Data);
+ }
+
+ if (VerifyStatus) {
+ return EFI_SUCCESS;
+ } else {
+ return EFI_SECURITY_VIOLATION;
+ }
+}
+
+/**
+ Verify certificate in WIN_CERTIFICATE_UEFI_GUID format.
+
+ @retval EFI_SUCCESS Image pass verification.
+ @retval EFI_SECURITY_VIOLATION Image fail verification.
+ @retval other error value
+
+**/
+EFI_STATUS
+VerifyCertUefiGuid (
+ VOID
+ )
+{
+ BOOLEAN Status;
+ WIN_CERTIFICATE_UEFI_GUID *EfiCert;
+ EFI_SIGNATURE_LIST *KekList;
+ EFI_SIGNATURE_DATA *KekItem;
+ EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlock;
+ VOID *Rsa;
+ UINTN KekCount;
+ UINTN Index;
+ UINTN KekDataSize;
+ BOOLEAN IsFound;
+ EFI_STATUS Result;
+
+ EfiCert = NULL;
+ KekList = NULL;
+ KekItem = NULL;
+ CertBlock = NULL;
+ Rsa = NULL;
+ Status = FALSE;
+ IsFound = FALSE;
+ KekDataSize = 0;
+
+ EfiCert = (WIN_CERTIFICATE_UEFI_GUID *) (mImageBase + mSecDataDir->VirtualAddress);
+ CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) EfiCert->CertData;
+ if (!CompareGuid (&EfiCert->CertType, &gEfiCertTypeRsa2048Sha256Guid)) {
+ //
+ // Invalid Certificate Data Type.
+ //
+ return EFI_SECURITY_VIOLATION;
+ }
+
+ //
+ // Get KEK database variable data size
+ //
+ Result = gRT->GetVariable (EFI_KEY_EXCHANGE_KEY_NAME, &gEfiGlobalVariableGuid, NULL, &KekDataSize, NULL);
+ if (Result != EFI_BUFFER_TOO_SMALL) {
+ return EFI_SECURITY_VIOLATION;
+ }
+
+ //
+ // Get KEK database variable.
+ //
+ KekList = GetEfiGlobalVariable (EFI_KEY_EXCHANGE_KEY_NAME);
+ if (KekList == NULL) {
+ return EFI_SECURITY_VIOLATION;
+ }
+
+ //
+ // Enumerate all Kek items in this list to verify the variable certificate data.
+ // If anyone is authenticated successfully, it means the variable is correct!
+ //
+ while ((KekDataSize > 0) && (KekDataSize >= KekList->SignatureListSize)) {
+ if (CompareGuid (&KekList->SignatureType, &gEfiCertRsa2048Guid)) {
+ KekItem = (EFI_SIGNATURE_DATA *) ((UINT8 *) KekList + sizeof (EFI_SIGNATURE_LIST) + KekList->SignatureHeaderSize);
+ KekCount = (KekList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - KekList->SignatureHeaderSize) / KekList->SignatureSize;
+ for (Index = 0; Index < KekCount; Index++) {
+ if (CompareMem (KekItem->SignatureData, CertBlock->PublicKey, EFI_CERT_TYPE_RSA2048_SIZE) == 0) {
+ IsFound = TRUE;
+ break;
+ }
+ KekItem = (EFI_SIGNATURE_DATA *) ((UINT8 *) KekItem + KekList->SignatureSize);
+ }
+ }
+ KekDataSize -= KekList->SignatureListSize;
+ KekList = (EFI_SIGNATURE_LIST *) ((UINT8 *) KekList + KekList->SignatureListSize);
+ }
+
+ if (!IsFound) {
+ //
+ // Signed key is not a trust one.
+ //
+ goto Done;
+ }
+
+ //
+ // Now, we found the corresponding security policy.
+ // Verify the data payload.
+ //
+ Rsa = RsaNew ();
+ ASSERT (Rsa != NULL);
+ //
+ // Set RSA Key Components.
+ // NOTE: Only N and E are needed to be set as RSA public key for signature verification.
+ //
+ Status = RsaSetKey (Rsa, RsaKeyN, CertBlock->PublicKey, EFI_CERT_TYPE_RSA2048_SIZE);
+ if (!Status) {
+ goto Done;
+ }
+ Status = RsaSetKey (Rsa, RsaKeyE, mRsaE, sizeof (mRsaE));
+ if (!Status) {
+ goto Done;
+ }
+ //
+ // Verify the signature.
+ //
+ Status = RsaPkcs1Verify (
+ Rsa,
+ mImageDigest,
+ mImageDigestSize,
+ CertBlock->Signature,
+ EFI_CERT_TYPE_RSA2048_SHA256_SIZE
+ );
+
+Done:
+ if (KekList != NULL) {
+ FreePool (KekList);
+ }
+ if (Rsa != NULL ) {
+ RsaFree (Rsa);
+ }
+ if (Status) {
+ return EFI_SUCCESS;
+ } else {
+ return EFI_SECURITY_VIOLATION;
+ }
+}
+
+/**
+ Provide verification service for signed images, which include both signature validation
+ and platform policy control. For signature types, both UEFI WIN_CERTIFICATE_UEFI_GUID and
+ MSFT Authenticode type signatures are supported.
+
+ In this implementation, only verify external executables when in USER MODE.
+ Executables from FV is bypass, so pass in AuthenticationStatus is ignored.
+
+ @param[in] AuthenticationStatus
+ This is the authentication status returned from the security
+ measurement services for the input file.
+ @param[in] File This is a pointer to the device path of the file that is
+ being dispatched. This will optionally be used for logging.
+ @param[in] FileBuffer File buffer matches the input file device path.
+ @param[in] FileSize Size of File buffer matches the input file device path.
+
+ @retval EFI_SUCCESS The file specified by File did authenticate, and the
+ platform policy dictates that the DXE Core may use File.
+ @retval EFI_INVALID_PARAMETER File is NULL.
+ @retval EFI_SECURITY_VIOLATION The file specified by File did not authenticate, and
+ the platform policy dictates that File should be placed
+ in the untrusted state. A file may be promoted from
+ the untrusted to the trusted state at a future time
+ with a call to the Trust() DXE Service.
+ @retval EFI_ACCESS_DENIED The file specified by File did not authenticate, and
+ the platform policy dictates that File should not be
+ used for any purpose.
+
+**/
+EFI_STATUS
+EFIAPI
+DxeImageVerificationHandler (
+ IN UINT32 AuthenticationStatus,
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *File,
+ IN VOID *FileBuffer,
+ IN UINTN FileSize
+ )
+
+{
+ EFI_STATUS Status;
+ UINT16 Magic;
+ EFI_IMAGE_DOS_HEADER *DosHdr;
+ EFI_STATUS VerifyStatus;
+ UINT8 *SetupMode;
+ EFI_SIGNATURE_LIST *SignatureList;
+ UINTN SignatureListSize;
+ EFI_SIGNATURE_DATA *Signature;
+ EFI_IMAGE_EXECUTION_ACTION Action;
+ WIN_CERTIFICATE *WinCertificate;
+ UINT32 Policy;
+
+ if (File == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ SignatureList = NULL;
+ SignatureListSize = 0;
+ WinCertificate = NULL;
+ Action = EFI_IMAGE_EXECUTION_AUTH_UNTESTED;
+ Status = EFI_ACCESS_DENIED;
+ //
+ // Check the image type and get policy setting.
+ //
+ switch (GetImageType (File)) {
+
+ case IMAGE_FROM_FV:
+ Policy = ALWAYS_EXECUTE;
+ break;
+
+ case IMAGE_FROM_OPTION_ROM:
+ Policy = PcdGet32 (PcdOptionRomImageVerificationPolicy);
+ break;
+
+ case IMAGE_FROM_REMOVABLE_MEDIA:
+ Policy = PcdGet32 (PcdRemovableMediaImageVerificationPolicy);
+ break;
+
+ case IMAGE_FROM_FIXED_MEDIA:
+ Policy = PcdGet32 (PcdFixedMediaImageVerificationPolicy);
+ break;
+
+ default:
+ Policy = DENY_EXECUTE_ON_SECURITY_VIOLATION;
+ break;
+ }
+ //
+ // If policy is always/never execute, return directly.
+ //
+ if (Policy == ALWAYS_EXECUTE) {
+ return EFI_SUCCESS;
+ } else if (Policy == NEVER_EXECUTE) {
+ return EFI_ACCESS_DENIED;
+ }
+ SetupMode = GetEfiGlobalVariable (EFI_SETUP_MODE_NAME);
+
+ //
+ // SetupMode doesn't exist means no AuthVar driver is dispatched,
+ // skip verification.
+ //
+ if (SetupMode == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // If platform is in SETUP MODE, skip verification.
+ //
+ if (*SetupMode == SETUP_MODE) {
+ FreePool (SetupMode);
+ return EFI_SUCCESS;
+ }
+ //
+ // Read the Dos header.
+ //
+ ASSERT (FileBuffer != NULL);
+ mImageBase = (UINT8 *) FileBuffer;
+ mImageSize = FileSize;
+ DosHdr = (EFI_IMAGE_DOS_HEADER *) (mImageBase);
+ if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
+ //
+ // DOS image header is present,
+ // so read the PE header after the DOS image header.
+ //
+ mPeCoffHeaderOffset = DosHdr->e_lfanew;
+ } else {
+ mPeCoffHeaderOffset = 0;
+ }
+ //
+ // Check PE/COFF image.
+ //
+ mNtHeader.Pe32 = (EFI_IMAGE_NT_HEADERS32 *) (mImageBase + mPeCoffHeaderOffset);
+ if (mNtHeader.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {
+ //
+ // It is not a valid Pe/Coff file.
+ //
+ return EFI_ACCESS_DENIED;
+ }
+
+ Magic = mNtHeader.Pe32->OptionalHeader.Magic;
+ if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ //
+ // Use PE32 offset.
+ //
+ mSecDataDir = (EFI_IMAGE_DATA_DIRECTORY *)&mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];
+ } else {
+ //
+ // Use PE32+ offset.
+ //
+ mSecDataDir = (EFI_IMAGE_DATA_DIRECTORY *)&mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];
+ }
+
+ if (mSecDataDir->Size == 0) {
+ //
+ // This image is not signed.
+ //
+ Action = EFI_IMAGE_EXECUTION_AUTH_UNTESTED;
+ Status = EFI_ACCESS_DENIED;
+ goto Done;
+ }
+ //
+ // Verify signature of executables.
+ //
+ WinCertificate = (WIN_CERTIFICATE *) (mImageBase + mSecDataDir->VirtualAddress);
+
+ switch (WinCertificate->wCertificateType) {
+
+ case WIN_CERT_TYPE_EFI_GUID:
+ //
+ // Verify UEFI GUID type.
+ //
+ if (!HashPeImage (HASHALG_SHA256)) {
+ goto Done;
+ }
+
+ VerifyStatus = VerifyCertUefiGuid ();
+ break;
+
+ case WIN_CERT_TYPE_PKCS_SIGNED_DATA:
+ //
+ // Verify Pkcs signed data type.
+ //
+ Status = HashPeImageByType();
+ if (EFI_ERROR(Status)) {
+ goto Done;
+ }
+
+ VerifyStatus = VerifyCertPkcsSignedData ();
+
+ //
+ // For image verification against enrolled certificate(root or intermediate),
+ // no need to check image's hash in the allowed database.
+ //
+ if (!EFI_ERROR (VerifyStatus)) {
+ return EFI_SUCCESS;
+ }
+
+ default:
+ return EFI_ACCESS_DENIED;
+ }
+ //
+ // Get image hash value as executable's signature.
+ //
+ SignatureListSize = sizeof (EFI_SIGNATURE_LIST) + sizeof (EFI_SIGNATURE_DATA) - 1 + mImageDigestSize;
+ SignatureList = (EFI_SIGNATURE_LIST *) AllocateZeroPool (SignatureListSize);
+ ASSERT (SignatureList != NULL);
+ SignatureList->SignatureHeaderSize = 0;
+ SignatureList->SignatureListSize = (UINT32) SignatureListSize;
+ SignatureList->SignatureSize = (UINT32) mImageDigestSize;
+ CopyMem (&SignatureList->SignatureType, &mCertType, sizeof (EFI_GUID));
+ Signature = (EFI_SIGNATURE_DATA *) ((UINT8 *) SignatureList + sizeof (EFI_SIGNATURE_LIST));
+ CopyMem (Signature->SignatureData, mImageDigest, mImageDigestSize);
+ //
+ // Signature database check after verification.
+ //
+ if (EFI_ERROR (VerifyStatus)) {
+ //
+ // Verification failure.
+ //
+ Action = EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED;
+ Status = EFI_ACCESS_DENIED;
+ } else if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE1, Signature->SignatureData, &mCertType, mImageDigestSize)) {
+ //
+ // Executable signature verification passes, but is found in forbidden signature database.
+ //
+ Action = EFI_IMAGE_EXECUTION_AUTH_SIG_FOUND;
+ Status = EFI_ACCESS_DENIED;
+ } else if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE, Signature->SignatureData, &mCertType, mImageDigestSize)) {
+ //
+ // Executable signature is found in authorized signature database.
+ //
+ Status = EFI_SUCCESS;
+ } else {
+ //
+ // Executable signature verification passes, but cannot be found in authorized signature database.
+ // Get platform policy to determine the action.
+ //
+ Action = EFI_IMAGE_EXECUTION_AUTH_SIG_PASSED;
+ Status = ImageAuthorization (Policy);
+ }
+
+Done:
+ if (Status != EFI_SUCCESS) {
+ //
+ // Policy decides to defer or reject the image; add its information in image executable information table.
+ //
+ AddImageExeInfo (Action, NULL, File, SignatureList, SignatureListSize);
+ }
+
+ if (SignatureList != NULL) {
+ FreePool (SignatureList);
+ }
+
+ FreePool (SetupMode);
+
+ return Status;
+}
+
+/**
+ When VariableWriteArchProtocol install, create "SecureBoot" variable.
+
+ @param[in] Event Event whose notification function is being invoked.
+ @param[in] Context Pointer to the notification function's context.
+
+**/
+VOID
+EFIAPI
+VariableWriteCallBack (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ UINT8 SecureBootMode;
+ UINT8 *SecureBootModePtr;
+ EFI_STATUS Status;
+ VOID *ProtocolPointer;
+
+ Status = gBS->LocateProtocol (&gEfiVariableWriteArchProtocolGuid, NULL, &ProtocolPointer);
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ //
+ // Check whether "SecureBoot" variable exists.
+ // If this library is built-in, it means firmware has capability to perform
+ // driver signing verification.
+ //
+ SecureBootModePtr = GetEfiGlobalVariable (EFI_SECURE_BOOT_MODE_NAME);
+ if (SecureBootModePtr == NULL) {
+ SecureBootMode = SECURE_BOOT_MODE_DISABLE;
+ //
+ // Authenticated variable driver will update "SecureBoot" depending on SetupMode variable.
+ //
+ gRT->SetVariable (
+ EFI_SECURE_BOOT_MODE_NAME,
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ sizeof (UINT8),
+ &SecureBootMode
+ );
+ } else {
+ FreePool (SecureBootModePtr);
+ }
+}
+
+/**
+ Register security measurement handler.
+
+ @param ImageHandle ImageHandle of the loaded driver.
+ @param SystemTable Pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The handlers were registered successfully.
+**/
+EFI_STATUS
+EFIAPI
+DxeImageVerificationLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ VOID *Registration;
+
+ //
+ // Register callback function upon VariableWriteArchProtocol.
+ //
+ EfiCreateProtocolNotifyEvent (
+ &gEfiVariableWriteArchProtocolGuid,
+ TPL_CALLBACK,
+ VariableWriteCallBack,
+ NULL,
+ &Registration
+ );
+
+ return RegisterSecurityHandler (
+ DxeImageVerificationHandler,
+ EFI_AUTH_OPERATION_VERIFY_IMAGE | EFI_AUTH_OPERATION_IMAGE_REQUIRED
+ );
+}
diff --git a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.h b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.h
new file mode 100644
index 0000000000..34ed0c89a1
--- /dev/null
+++ b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.h
@@ -0,0 +1,201 @@
+/** @file
+ The internal header file includes the common header files, defines
+ internal structure and functions used by ImageVerificationLib.
+
+Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __IMAGEVERIFICATIONLIB_H__
+#define __IMAGEVERIFICATIONLIB_H__
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define EFI_CERT_TYPE_RSA2048_SHA256_SIZE 256
+#define EFI_CERT_TYPE_RSA2048_SIZE 256
+#define MAX_NOTIFY_STRING_LEN 64
+
+//
+// Image type definitions
+//
+#define IMAGE_UNKNOWN 0x00000000
+#define IMAGE_FROM_FV 0x00000001
+#define IMAGE_FROM_OPTION_ROM 0x00000002
+#define IMAGE_FROM_REMOVABLE_MEDIA 0x00000003
+#define IMAGE_FROM_FIXED_MEDIA 0x00000004
+
+//
+// Authorization policy bit definition
+//
+#define ALWAYS_EXECUTE 0x00000000
+#define NEVER_EXECUTE 0x00000001
+#define ALLOW_EXECUTE_ON_SECURITY_VIOLATION 0x00000002
+#define DEFER_EXECUTE_ON_SECURITY_VIOLATION 0x00000003
+#define DENY_EXECUTE_ON_SECURITY_VIOLATION 0x00000004
+#define QUERY_USER_ON_SECURITY_VIOLATION 0x00000005
+
+//
+// Support hash types
+//
+#define HASHALG_SHA1 0x00000000
+#define HASHALG_SHA224 0x00000001
+#define HASHALG_SHA256 0x00000002
+#define HASHALG_SHA384 0x00000003
+#define HASHALG_SHA512 0x00000004
+#define HASHALG_MAX 0x00000005
+
+//
+// Set max digest size as SHA256 Output (32 bytes) by far
+//
+#define MAX_DIGEST_SIZE SHA256_DIGEST_SIZE
+//
+//
+// PKCS7 Certificate definition
+//
+typedef struct {
+ WIN_CERTIFICATE Hdr;
+ UINT8 CertData[1];
+} WIN_CERTIFICATE_EFI_PKCS;
+
+
+/**
+ Retrieves the size, in bytes, of the context buffer required for hash operations.
+
+ @return The size, in bytes, of the context buffer required for hash operations.
+
+**/
+typedef
+UINTN
+(EFIAPI *HASH_GET_CONTEXT_SIZE)(
+ VOID
+ );
+
+/**
+ Initializes user-supplied memory pointed by HashContext as hash context for
+ subsequent use.
+
+ If HashContext is NULL, then ASSERT().
+
+ @param[in, out] HashContext Pointer to Context being initialized.
+
+ @retval TRUE HASH context initialization succeeded.
+ @retval FALSE HASH context initialization failed.
+
+**/
+typedef
+BOOLEAN
+(EFIAPI *HASH_INIT)(
+ IN OUT VOID *HashContext
+ );
+
+
+/**
+ Performs digest on a data buffer of the specified length. This function can
+ be called multiple times to compute the digest of long or discontinuous data streams.
+
+ If HashContext is NULL, then ASSERT().
+
+ @param[in, out] HashContext Pointer to the MD5 context.
+ @param[in] Data Pointer to the buffer containing the data to be hashed.
+ @param[in] DataLength Length of Data buffer in bytes.
+
+ @retval TRUE HASH data digest succeeded.
+ @retval FALSE Invalid HASH context. After HashFinal function has been called, the
+ HASH context cannot be reused.
+
+**/
+typedef
+BOOLEAN
+(EFIAPI *HASH_UPDATE)(
+ IN OUT VOID *HashContext,
+ IN CONST VOID *Data,
+ IN UINTN DataLength
+ );
+
+/**
+ Completes hash computation and retrieves the digest value into the specified
+ memory. After this function has been called, the context cannot be used again.
+
+ If HashContext is NULL, then ASSERT().
+ If HashValue is NULL, then ASSERT().
+
+ @param[in, out] HashContext Pointer to the MD5 context
+ @param[out] HashValue Pointer to a buffer that receives the HASH digest
+ value.
+
+ @retval TRUE HASH digest computation succeeded.
+ @retval FALSE HASH digest computation failed.
+
+**/
+typedef
+BOOLEAN
+(EFIAPI *HASH_FINAL)(
+ IN OUT VOID *HashContext,
+ OUT UINT8 *HashValue
+ );
+
+
+//
+// Hash Algorithm Table
+//
+typedef struct {
+ //
+ // Name for Hash Algorithm
+ //
+ CHAR16 *Name;
+ //
+ // Digest Length
+ //
+ UINTN DigestLength;
+ //
+ // Hash Algorithm OID ASN.1 Value
+ //
+ UINT8 *OidValue;
+ //
+ // Length of Hash OID Value
+ //
+ UINTN OidLength;
+ //
+ // Pointer to Hash GetContentSize function
+ //
+ HASH_GET_CONTEXT_SIZE GetContextSize;
+ //
+ // Pointer to Hash Init function
+ //
+ HASH_INIT HashInit;
+ //
+ // Pointer to Hash Update function
+ //
+ HASH_UPDATE HashUpdate;
+ //
+ // Pointer to Hash Final function
+ //
+ HASH_FINAL HashFinal;
+} HASH_TABLE;
+
+#endif
diff --git a/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.inf b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.inf
new file mode 100644
index 0000000000..5874d6b66b
--- /dev/null
+++ b/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.inf
@@ -0,0 +1,73 @@
+## @file
+# The library instance provides security service of image verification.
+# Image verification Library module supports UEFI2.3.1
+#
+# Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeImageVerificationLib
+ FILE_GUID = 0CA970E1-43FA-4402-BC0A-81AF336BFFD6
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = NULL|DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SAL_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER
+ CONSTRUCTOR = DxeImageVerificationLibConstructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ DxeImageVerificationLib.c
+ DxeImageVerificationLib.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ CryptoPkg/CryptoPkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+ MemoryAllocationLib
+ BaseLib
+ UefiLib
+ UefiBootServicesTableLib
+ UefiRuntimeServicesTableLib
+ BaseMemoryLib
+ DebugLib
+ DevicePathLib
+ BaseCryptLib
+ SecurityManagementLib
+
+[Protocols]
+ gEfiFirmwareVolume2ProtocolGuid
+ gEfiBlockIoProtocolGuid
+ gEfiSimpleFileSystemProtocolGuid
+ gEfiVariableWriteArchProtocolGuid
+
+[Guids]
+ gEfiCertTypeRsa2048Sha256Guid
+ gEfiImageSecurityDatabaseGuid
+ gEfiCertSha1Guid
+ gEfiCertSha256Guid
+ gEfiCertX509Guid
+ gEfiCertRsa2048Guid
+
+[Pcd]
+ gEfiSecurityPkgTokenSpaceGuid.PcdOptionRomImageVerificationPolicy
+ gEfiSecurityPkgTokenSpaceGuid.PcdRemovableMediaImageVerificationPolicy
+ gEfiSecurityPkgTokenSpaceGuid.PcdFixedMediaImageVerificationPolicy
+
+
+
+
diff --git a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c
new file mode 100644
index 0000000000..c012f130d9
--- /dev/null
+++ b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c
@@ -0,0 +1,830 @@
+/** @file
+ The library instance provides security service of TPM measure boot.
+
+Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+//
+// Flag to check GPT partition. It only need be measured once.
+//
+BOOLEAN mMeasureGptTableFlag = FALSE;
+EFI_GUID mZeroGuid = {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}};
+UINTN mMeasureGptCount = 0;
+
+/**
+ Reads contents of a PE/COFF image in memory buffer.
+
+ @param FileHandle Pointer to the file handle to read the PE/COFF image.
+ @param FileOffset Offset into the PE/COFF image to begin the read operation.
+ @param ReadSize On input, the size in bytes of the requested read operation.
+ On output, the number of bytes actually read.
+ @param Buffer Output buffer that contains the data read from the PE/COFF image.
+
+ @retval EFI_SUCCESS The specified portion of the PE/COFF image was read and the size
+**/
+EFI_STATUS
+EFIAPI
+ImageRead (
+ IN VOID *FileHandle,
+ IN UINTN FileOffset,
+ IN OUT UINTN *ReadSize,
+ OUT VOID *Buffer
+ )
+{
+ CopyMem (Buffer, (UINT8 *)((UINTN) FileHandle + FileOffset), *ReadSize);
+ return EFI_SUCCESS;
+}
+
+/**
+ Measure GPT table data into TPM log.
+
+ @param TcgProtocol Pointer to the located TCG protocol instance.
+ @param GptHandle Handle that GPT partition was installed.
+
+ @retval EFI_SUCCESS Successfully measure GPT table.
+ @retval EFI_UNSUPPORTED Not support GPT table on the given handle.
+ @retval EFI_DEVICE_ERROR Can't get GPT table because device error.
+ @retval EFI_OUT_OF_RESOURCES No enough resource to measure GPT table.
+ @retval other error value
+**/
+EFI_STATUS
+EFIAPI
+TcgMeasureGptTable (
+ IN EFI_TCG_PROTOCOL *TcgProtocol,
+ IN EFI_HANDLE GptHandle
+ )
+{
+ EFI_STATUS Status;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ EFI_DISK_IO_PROTOCOL *DiskIo;
+ EFI_PARTITION_TABLE_HEADER *PrimaryHeader;
+ EFI_PARTITION_ENTRY *PartitionEntry;
+ UINT8 *EntryPtr;
+ UINTN NumberOfPartition;
+ UINT32 Index;
+ TCG_PCR_EVENT *TcgEvent;
+ EFI_GPT_DATA *GptData;
+ UINT32 EventSize;
+ UINT32 EventNumber;
+ EFI_PHYSICAL_ADDRESS EventLogLastEntry;
+
+ if (mMeasureGptCount > 0) {
+ return EFI_SUCCESS;
+ }
+
+ Status = gBS->HandleProtocol (GptHandle, &gEfiBlockIoProtocolGuid, (VOID**)&BlockIo);
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+ Status = gBS->HandleProtocol (GptHandle, &gEfiDiskIoProtocolGuid, (VOID**)&DiskIo);
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Read the EFI Partition Table Header
+ //
+ PrimaryHeader = (EFI_PARTITION_TABLE_HEADER *) AllocatePool (BlockIo->Media->BlockSize);
+ if (PrimaryHeader == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ BlockIo->Media->MediaId,
+ 1 * BlockIo->Media->BlockSize,
+ BlockIo->Media->BlockSize,
+ (UINT8 *)PrimaryHeader
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Failed to Read Partition Table Header!\n"));
+ FreePool (PrimaryHeader);
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Read the partition entry.
+ //
+ EntryPtr = (UINT8 *)AllocatePool (PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry);
+ if (EntryPtr == NULL) {
+ FreePool (PrimaryHeader);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Status = DiskIo->ReadDisk (
+ DiskIo,
+ BlockIo->Media->MediaId,
+ MultU64x32(PrimaryHeader->PartitionEntryLBA, BlockIo->Media->BlockSize),
+ PrimaryHeader->NumberOfPartitionEntries * PrimaryHeader->SizeOfPartitionEntry,
+ EntryPtr
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (PrimaryHeader);
+ FreePool (EntryPtr);
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Count the valid partition
+ //
+ PartitionEntry = (EFI_PARTITION_ENTRY *)EntryPtr;
+ NumberOfPartition = 0;
+ for (Index = 0; Index < PrimaryHeader->NumberOfPartitionEntries; Index++) {
+ if (!CompareGuid (&PartitionEntry->PartitionTypeGUID, &mZeroGuid)) {
+ NumberOfPartition++;
+ }
+ PartitionEntry++;
+ }
+
+ //
+ // Parepare Data for Measurement
+ //
+ EventSize = (UINT32)(sizeof (EFI_GPT_DATA) - sizeof (GptData->Partitions)
+ + NumberOfPartition * PrimaryHeader->SizeOfPartitionEntry);
+ TcgEvent = (TCG_PCR_EVENT *) AllocateZeroPool (EventSize + sizeof (TCG_PCR_EVENT));
+ if (TcgEvent == NULL) {
+ FreePool (PrimaryHeader);
+ FreePool (EntryPtr);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ TcgEvent->PCRIndex = 5;
+ TcgEvent->EventType = EV_EFI_GPT_EVENT;
+ TcgEvent->EventSize = EventSize;
+ GptData = (EFI_GPT_DATA *) TcgEvent->Event;
+
+ //
+ // Copy the EFI_PARTITION_TABLE_HEADER and NumberOfPartition
+ //
+ CopyMem ((UINT8 *)GptData, (UINT8*)PrimaryHeader, sizeof (EFI_PARTITION_TABLE_HEADER));
+ GptData->NumberOfPartitions = NumberOfPartition;
+ //
+ // Copy the valid partition entry
+ //
+ PartitionEntry = (EFI_PARTITION_ENTRY*)EntryPtr;
+ NumberOfPartition = 0;
+ for (Index = 0; Index < PrimaryHeader->NumberOfPartitionEntries; Index++) {
+ if (!CompareGuid (&PartitionEntry->PartitionTypeGUID, &mZeroGuid)) {
+ CopyMem (
+ (UINT8 *)&GptData->Partitions + NumberOfPartition * sizeof (EFI_PARTITION_ENTRY),
+ (UINT8 *)PartitionEntry,
+ sizeof (EFI_PARTITION_ENTRY)
+ );
+ NumberOfPartition++;
+ }
+ PartitionEntry++;
+ }
+
+ //
+ // Measure the GPT data
+ //
+ EventNumber = 1;
+ Status = TcgProtocol->HashLogExtendEvent (
+ TcgProtocol,
+ (EFI_PHYSICAL_ADDRESS) (UINTN) (VOID *) GptData,
+ (UINT64) TcgEvent->EventSize,
+ TPM_ALG_SHA,
+ TcgEvent,
+ &EventNumber,
+ &EventLogLastEntry
+ );
+ if (!EFI_ERROR (Status)) {
+ mMeasureGptCount++;
+ }
+
+ FreePool (PrimaryHeader);
+ FreePool (EntryPtr);
+ FreePool (TcgEvent);
+
+ return Status;
+}
+
+/**
+ Measure PE image into TPM log based on the authenticode image hashing in
+ PE/COFF Specification 8.0 Appendix A.
+
+ @param[in] TcgProtocol Pointer to the located TCG protocol instance.
+ @param[in] ImageAddress Start address of image buffer.
+ @param[in] ImageSize Image size
+ @param[in] LinkTimeBase Address that the image is loaded into memory.
+ @param[in] ImageType Image subsystem type.
+ @param[in] FilePath File path is corresponding to the input image.
+
+ @retval EFI_SUCCESS Successfully measure image.
+ @retval EFI_OUT_OF_RESOURCES No enough resource to measure image.
+ @retval other error value
+**/
+EFI_STATUS
+EFIAPI
+TcgMeasurePeImage (
+ IN EFI_TCG_PROTOCOL *TcgProtocol,
+ IN EFI_PHYSICAL_ADDRESS ImageAddress,
+ IN UINTN ImageSize,
+ IN UINTN LinkTimeBase,
+ IN UINT16 ImageType,
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath
+ )
+{
+ EFI_STATUS Status;
+ TCG_PCR_EVENT *TcgEvent;
+ EFI_IMAGE_LOAD_EVENT *ImageLoad;
+ UINT32 FilePathSize;
+ VOID *Sha1Ctx;
+ UINTN CtxSize;
+ EFI_IMAGE_DOS_HEADER *DosHdr;
+ UINT32 PeCoffHeaderOffset;
+ EFI_IMAGE_SECTION_HEADER *Section;
+ UINT8 *HashBase;
+ UINTN HashSize;
+ UINTN SumOfBytesHashed;
+ EFI_IMAGE_SECTION_HEADER *SectionHeader;
+ UINTN Index, Pos;
+ UINT16 Magic;
+ UINT32 EventSize;
+ UINT32 EventNumber;
+ EFI_PHYSICAL_ADDRESS EventLogLastEntry;
+ EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
+
+ Status = EFI_SUCCESS;
+ ImageLoad = NULL;
+ SectionHeader = NULL;
+ Sha1Ctx = NULL;
+ FilePathSize = (UINT32) GetDevicePathSize (FilePath);
+
+ //
+ // Determine destination PCR by BootPolicy
+ //
+ EventSize = sizeof (*ImageLoad) - sizeof (ImageLoad->DevicePath) + FilePathSize;
+ TcgEvent = AllocateZeroPool (EventSize + sizeof (TCG_PCR_EVENT));
+ if (TcgEvent == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ TcgEvent->EventSize = EventSize;
+ ImageLoad = (EFI_IMAGE_LOAD_EVENT *) TcgEvent->Event;
+
+ switch (ImageType) {
+ case EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION:
+ TcgEvent->EventType = EV_EFI_BOOT_SERVICES_APPLICATION;
+ TcgEvent->PCRIndex = 4;
+ break;
+ case EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER:
+ TcgEvent->EventType = EV_EFI_BOOT_SERVICES_DRIVER;
+ TcgEvent->PCRIndex = 2;
+ break;
+ case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER:
+ TcgEvent->EventType = EV_EFI_RUNTIME_SERVICES_DRIVER;
+ TcgEvent->PCRIndex = 2;
+ break;
+ default:
+ DEBUG ((
+ EFI_D_ERROR,
+ "TcgMeasurePeImage: Unknown subsystem type %d",
+ ImageType
+ ));
+ ASSERT (FALSE);
+ TcgEvent->EventType = ImageType;
+ Status = EFI_UNSUPPORTED;
+ goto Finish;
+ }
+
+ ImageLoad->ImageLocationInMemory = ImageAddress;
+ ImageLoad->ImageLengthInMemory = ImageSize;
+ ImageLoad->ImageLinkTimeAddress = LinkTimeBase;
+ ImageLoad->LengthOfDevicePath = FilePathSize;
+ CopyMem (ImageLoad->DevicePath, FilePath, FilePathSize);
+
+ //
+ // Check PE/COFF image
+ //
+ DosHdr = (EFI_IMAGE_DOS_HEADER *) (UINTN) ImageAddress;
+ PeCoffHeaderOffset = 0;
+ if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
+ PeCoffHeaderOffset = DosHdr->e_lfanew;
+ }
+ if (((EFI_TE_IMAGE_HEADER *)((UINT8 *) (UINTN) ImageAddress + PeCoffHeaderOffset))->Signature
+ == EFI_TE_IMAGE_HEADER_SIGNATURE) {
+ goto Finish;
+ }
+
+ //
+ // PE/COFF Image Measurement
+ //
+ // NOTE: The following codes/steps are based upon the authenticode image hashing in
+ // PE/COFF Specification 8.0 Appendix A.
+ //
+ //
+
+ // 1. Load the image header into memory.
+
+ // 2. Initialize a SHA hash context.
+ CtxSize = Sha1GetContextSize ();
+ Sha1Ctx = AllocatePool (CtxSize);
+ if (Sha1Ctx == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Finish;
+ }
+
+ Sha1Init (Sha1Ctx);
+
+ //
+ // Measuring PE/COFF Image Header;
+ // But CheckSum field and SECURITY data directory (certificate) are excluded
+ //
+ Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINT8 *) (UINTN) ImageAddress + PeCoffHeaderOffset);
+ Magic = Hdr.Pe32->OptionalHeader.Magic;
+
+ //
+ // 3. Calculate the distance from the base of the image header to the image checksum address.
+ // 4. Hash the image header from its base to beginning of the image checksum.
+ //
+ HashBase = (UINT8 *) (UINTN) ImageAddress;
+ if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ //
+ // Use PE32 offset
+ //
+ HashSize = (UINTN) ((UINT8 *)(&Hdr.Pe32->OptionalHeader.CheckSum) - HashBase);
+ } else {
+ //
+ // Use PE32+ offset
+ //
+ HashSize = (UINTN) ((UINT8 *)(&Hdr.Pe32Plus->OptionalHeader.CheckSum) - HashBase);
+ }
+
+ Sha1Update (Sha1Ctx, HashBase, HashSize);
+
+ //
+ // 5. Skip over the image checksum (it occupies a single ULONG).
+ // 6. Get the address of the beginning of the Cert Directory.
+ // 7. Hash everything from the end of the checksum to the start of the Cert Directory.
+ //
+ if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ //
+ // Use PE32 offset
+ //
+ HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);
+ HashSize = (UINTN) ((UINT8 *)(&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase);
+ } else {
+ //
+ // Use PE32+ offset
+ //
+ HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);
+ HashSize = (UINTN) ((UINT8 *)(&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase);
+ }
+
+ Sha1Update (Sha1Ctx, HashBase, HashSize);
+
+ //
+ // 8. Skip over the Cert Directory. (It is sizeof(IMAGE_DATA_DIRECTORY) bytes.)
+ // 9. Hash everything from the end of the Cert Directory to the end of image header.
+ //
+ if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ //
+ // Use PE32 offset
+ //
+ HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];
+ HashSize = Hdr.Pe32->OptionalHeader.SizeOfHeaders -
+ (UINTN) ((UINT8 *)(&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]) - (UINT8 *) (UINTN) ImageAddress);
+ } else {
+ //
+ // Use PE32+ offset
+ //
+ HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];
+ HashSize = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders -
+ (UINTN) ((UINT8 *)(&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]) - (UINT8 *) (UINTN) ImageAddress);
+ }
+
+ Sha1Update (Sha1Ctx, HashBase, HashSize);
+
+ //
+ // 10. Set the SUM_OF_BYTES_HASHED to the size of the header
+ //
+ if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ //
+ // Use PE32 offset
+ //
+ SumOfBytesHashed = Hdr.Pe32->OptionalHeader.SizeOfHeaders;
+ } else {
+ //
+ // Use PE32+ offset
+ //
+ SumOfBytesHashed = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders;
+ }
+
+ //
+ // 11. Build a temporary table of pointers to all the IMAGE_SECTION_HEADER
+ // structures in the image. The 'NumberOfSections' field of the image
+ // header indicates how big the table should be. Do not include any
+ // IMAGE_SECTION_HEADERs in the table whose 'SizeOfRawData' field is zero.
+ //
+ SectionHeader = (EFI_IMAGE_SECTION_HEADER *)AllocateZeroPool (sizeof (EFI_IMAGE_SECTION_HEADER) * Hdr.Pe32->FileHeader.NumberOfSections);
+ if (SectionHeader == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Finish;
+ }
+
+ //
+ // 12. Using the 'PointerToRawData' in the referenced section headers as
+ // a key, arrange the elements in the table in ascending order. In other
+ // words, sort the section headers according to the disk-file offset of
+ // the section.
+ //
+ Section = (EFI_IMAGE_SECTION_HEADER *) (
+ (UINT8 *) (UINTN) ImageAddress +
+ PeCoffHeaderOffset +
+ sizeof(UINT32) +
+ sizeof(EFI_IMAGE_FILE_HEADER) +
+ Hdr.Pe32->FileHeader.SizeOfOptionalHeader
+ );
+ for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {
+ Pos = Index;
+ while ((Pos > 0) && (Section->PointerToRawData < SectionHeader[Pos - 1].PointerToRawData)) {
+ CopyMem (&SectionHeader[Pos], &SectionHeader[Pos - 1], sizeof(EFI_IMAGE_SECTION_HEADER));
+ Pos--;
+ }
+ CopyMem (&SectionHeader[Pos], Section, sizeof(EFI_IMAGE_SECTION_HEADER));
+ Section += 1;
+ }
+
+ //
+ // 13. Walk through the sorted table, bring the corresponding section
+ // into memory, and hash the entire section (using the 'SizeOfRawData'
+ // field in the section header to determine the amount of data to hash).
+ // 14. Add the section's 'SizeOfRawData' to SUM_OF_BYTES_HASHED .
+ // 15. Repeat steps 13 and 14 for all the sections in the sorted table.
+ //
+ for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {
+ Section = (EFI_IMAGE_SECTION_HEADER *) &SectionHeader[Index];
+ if (Section->SizeOfRawData == 0) {
+ continue;
+ }
+ HashBase = (UINT8 *) (UINTN) ImageAddress + Section->PointerToRawData;
+ HashSize = (UINTN) Section->SizeOfRawData;
+
+ Sha1Update (Sha1Ctx, HashBase, HashSize);
+
+ SumOfBytesHashed += HashSize;
+ }
+
+ //
+ // 16. If the file size is greater than SUM_OF_BYTES_HASHED, there is extra
+ // data in the file that needs to be added to the hash. This data begins
+ // at file offset SUM_OF_BYTES_HASHED and its length is:
+ // FileSize - (CertDirectory->Size)
+ //
+ if (ImageSize > SumOfBytesHashed) {
+ HashBase = (UINT8 *) (UINTN) ImageAddress + SumOfBytesHashed;
+ if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ //
+ // Use PE32 offset
+ //
+ HashSize = (UINTN)(ImageSize -
+ Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size -
+ SumOfBytesHashed);
+ } else {
+ //
+ // Use PE32+ offset
+ //
+ HashSize = (UINTN)(ImageSize -
+ Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size -
+ SumOfBytesHashed);
+ }
+
+ Sha1Update (Sha1Ctx, HashBase, HashSize);
+ }
+
+ //
+ // 17. Finalize the SHA hash.
+ //
+ Sha1Final (Sha1Ctx, (UINT8 *)&TcgEvent->Digest);
+
+ //
+ // Log the PE data
+ //
+ EventNumber = 1;
+ Status = TcgProtocol->HashLogExtendEvent (
+ TcgProtocol,
+ (EFI_PHYSICAL_ADDRESS) (UINTN) (VOID *) NULL,
+ 0,
+ TPM_ALG_SHA,
+ TcgEvent,
+ &EventNumber,
+ &EventLogLastEntry
+ );
+
+Finish:
+ FreePool (TcgEvent);
+
+ if (SectionHeader != NULL) {
+ FreePool (SectionHeader);
+ }
+
+ if (Sha1Ctx != NULL ) {
+ FreePool (Sha1Ctx);
+ }
+ return Status;
+}
+
+/**
+ The security handler is used to abstract platform-specific policy
+ from the DXE core response to an attempt to use a file that returns a
+ given status for the authentication check from the section extraction protocol.
+
+ The possible responses in a given SAP implementation may include locking
+ flash upon failure to authenticate, attestation logging for all signed drivers,
+ and other exception operations. The File parameter allows for possible logging
+ within the SAP of the driver.
+
+ If File is NULL, then EFI_INVALID_PARAMETER is returned.
+
+ If the file specified by File with an authentication status specified by
+ AuthenticationStatus is safe for the DXE Core to use, then EFI_SUCCESS is returned.
+
+ If the file specified by File with an authentication status specified by
+ AuthenticationStatus is not safe for the DXE Core to use under any circumstances,
+ then EFI_ACCESS_DENIED is returned.
+
+ If the file specified by File with an authentication status specified by
+ AuthenticationStatus is not safe for the DXE Core to use right now, but it
+ might be possible to use it at a future time, then EFI_SECURITY_VIOLATION is
+ returned.
+
+ @param[in, out] AuthenticationStatus This is the authentication status returned
+ from the securitymeasurement services for the
+ input file.
+ @param[in] File This is a pointer to the device path of the file that is
+ being dispatched. This will optionally be used for logging.
+ @param[in] FileBuffer File buffer matches the input file device path.
+ @param[in] FileSize Size of File buffer matches the input file device path.
+
+ @retval EFI_SUCCESS The file specified by File did authenticate, and the
+ platform policy dictates that the DXE Core may use File.
+ @retval EFI_INVALID_PARAMETER File is NULL.
+ @retval EFI_SECURITY_VIOLATION The file specified by File did not authenticate, and
+ the platform policy dictates that File should be placed
+ in the untrusted state. A file may be promoted from
+ the untrusted to the trusted state at a future time
+ with a call to the Trust() DXE Service.
+ @retval EFI_ACCESS_DENIED The file specified by File did not authenticate, and
+ the platform policy dictates that File should not be
+ used for any purpose.
+
+**/
+EFI_STATUS
+EFIAPI
+DxeTpmMeasureBootHandler (
+ IN OUT UINT32 AuthenticationStatus,
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *File,
+ IN VOID *FileBuffer OPTIONAL,
+ IN UINTN FileSize OPTIONAL
+ )
+{
+ EFI_TCG_PROTOCOL *TcgProtocol;
+ EFI_STATUS Status;
+ TCG_EFI_BOOT_SERVICE_CAPABILITY ProtocolCapability;
+ UINT32 TCGFeatureFlags;
+ EFI_PHYSICAL_ADDRESS EventLogLocation;
+ EFI_PHYSICAL_ADDRESS EventLogLastEntry;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
+ EFI_DEVICE_PATH_PROTOCOL *OrigDevicePathNode;
+ EFI_HANDLE Handle;
+ BOOLEAN ApplicationRequired;
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
+
+ if (File == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = gBS->LocateProtocol (&gEfiTcgProtocolGuid, NULL, (VOID **) &TcgProtocol);
+ if (EFI_ERROR (Status)) {
+ //
+ // TCG protocol is not installed. So, TPM is not present.
+ // Don't do any measurement, and directly return EFI_SUCCESS.
+ //
+ return EFI_SUCCESS;
+ }
+
+ ProtocolCapability.Size = (UINT8) sizeof (ProtocolCapability);
+ Status = TcgProtocol->StatusCheck (
+ TcgProtocol,
+ &ProtocolCapability,
+ &TCGFeatureFlags,
+ &EventLogLocation,
+ &EventLogLastEntry
+ );
+ if (EFI_ERROR (Status) || ProtocolCapability.TPMDeactivatedFlag) {
+ //
+ // TPM device doesn't work or activate.
+ //
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Copy File Device Path
+ //
+ OrigDevicePathNode = DuplicateDevicePath (File);
+ ASSERT (OrigDevicePathNode != NULL);
+
+ //
+ // 1. Check whether this device path support BlockIo protocol.
+ // Is so, this device path may be a GPT device path.
+ //
+ DevicePathNode = OrigDevicePathNode;
+ Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &DevicePathNode, &Handle);
+ if (!EFI_ERROR (Status) && !mMeasureGptTableFlag) {
+ //
+ // Find the gpt partion on the given devicepath
+ //
+ DevicePathNode = OrigDevicePathNode;
+ while (!IsDevicePathEnd (DevicePathNode)) {
+ //
+ // Find the Gpt partition
+ //
+ if (DevicePathType (DevicePathNode) == MEDIA_DEVICE_PATH &&
+ DevicePathSubType (DevicePathNode) == MEDIA_HARDDRIVE_DP) {
+ //
+ // Check whether it is a gpt partition or not
+ //
+ if (((HARDDRIVE_DEVICE_PATH *) DevicePathNode)->MBRType == MBR_TYPE_EFI_PARTITION_TABLE_HEADER &&
+ ((HARDDRIVE_DEVICE_PATH *) DevicePathNode)->SignatureType == SIGNATURE_TYPE_GUID) {
+
+ //
+ // Change the partition device path to its parent device path (disk) and get the handle.
+ //
+ DevicePathNode->Type = END_DEVICE_PATH_TYPE;
+ DevicePathNode->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE;
+ DevicePathNode = OrigDevicePathNode;
+ Status = gBS->LocateDevicePath (
+ &gEfiDiskIoProtocolGuid,
+ &DevicePathNode,
+ &Handle
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Measure GPT disk.
+ //
+ Status = TcgMeasureGptTable (TcgProtocol, Handle);
+ if (!EFI_ERROR (Status)) {
+ //
+ // GPT disk check done.
+ //
+ mMeasureGptTableFlag = TRUE;
+ }
+ }
+ FreePool (OrigDevicePathNode);
+ OrigDevicePathNode = DuplicateDevicePath (File);
+ ASSERT (OrigDevicePathNode != NULL);
+ break;
+ }
+ }
+ DevicePathNode = NextDevicePathNode (DevicePathNode);
+ }
+ }
+
+ //
+ // 2. Measure PE image.
+ //
+ ApplicationRequired = FALSE;
+
+ //
+ // Check whether this device path support FV2 protocol.
+ //
+ DevicePathNode = OrigDevicePathNode;
+ Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &DevicePathNode, &Handle);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Don't check FV image, and directly return EFI_SUCCESS.
+ // It can be extended to the specific FV authentication according to the different requirement.
+ //
+ if (IsDevicePathEnd (DevicePathNode)) {
+ return EFI_SUCCESS;
+ }
+ //
+ // The image from Firmware image will not be mearsured.
+ // Current policy doesn't measure PeImage from Firmware if it is driver
+ // If the got PeImage is application, it will be still be measured.
+ //
+ ApplicationRequired = TRUE;
+ }
+
+ //
+ // File is not found.
+ //
+ if (FileBuffer == NULL) {
+ Status = EFI_SECURITY_VIOLATION;
+ goto Finish;
+ }
+
+ //
+ // Measure PE Image
+ //
+ DevicePathNode = OrigDevicePathNode;
+ ZeroMem (&ImageContext, sizeof (ImageContext));
+ ImageContext.Handle = (VOID *) FileBuffer;
+ ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) ImageRead;
+
+ //
+ // Get information about the image being loaded
+ //
+ Status = PeCoffLoaderGetImageInfo (&ImageContext);
+ if (EFI_ERROR (Status)) {
+ //
+ // The information can't be got from the invalid PeImage
+ //
+ goto Finish;
+ }
+
+ //
+ // Measure only application if Application flag is set
+ // Measure drivers and applications if Application flag is not set
+ //
+ if ((!ApplicationRequired) ||
+ (ApplicationRequired && ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION)) {
+ //
+ // Print the image path to be measured.
+ //
+ DEBUG_CODE_BEGIN ();
+ CHAR16 *ToText;
+ EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *DevPathToText;
+ Status = gBS->LocateProtocol (
+ &gEfiDevicePathToTextProtocolGuid,
+ NULL,
+ (VOID **) &DevPathToText
+ );
+ if (!EFI_ERROR (Status)) {
+ ToText = DevPathToText->ConvertDevicePathToText (
+ DevicePathNode,
+ FALSE,
+ TRUE
+ );
+ if (ToText != NULL) {
+ DEBUG ((DEBUG_INFO, "The measured image path is %s.\n", ToText));
+ }
+ }
+ DEBUG_CODE_END ();
+
+ //
+ // Measure PE image into TPM log.
+ //
+ Status = TcgMeasurePeImage (
+ TcgProtocol,
+ (EFI_PHYSICAL_ADDRESS) (UINTN) FileBuffer,
+ FileSize,
+ (UINTN) ImageContext.ImageAddress,
+ ImageContext.ImageType,
+ DevicePathNode
+ );
+ }
+
+ //
+ // Done, free the allocated resource.
+ //
+Finish:
+ FreePool (OrigDevicePathNode);
+
+ return Status;
+}
+
+/**
+ Register the security handler to provide TPM measure boot service.
+
+ @param ImageHandle ImageHandle of the loaded driver.
+ @param SystemTable Pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS Register successfully.
+ @retval EFI_OUT_OF_RESOURCES No enough memory to register this handler.
+**/
+EFI_STATUS
+EFIAPI
+DxeTpmMeasureBootLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ return RegisterSecurityHandler (
+ DxeTpmMeasureBootHandler,
+ EFI_AUTH_OPERATION_MEASURE_IMAGE | EFI_AUTH_OPERATION_IMAGE_REQUIRED
+ );
+}
diff --git a/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.inf b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.inf
new file mode 100644
index 0000000000..bf83bf1022
--- /dev/null
+++ b/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.inf
@@ -0,0 +1,54 @@
+## @file
+# The library instance provides security service of TPM measure boot.
+#
+# Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeTpmMeasureBootLib
+ FILE_GUID = 6C60C7D0-922A-4b7c-87D7-E503EDD73BBF
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = NULL|DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SAL_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER
+ CONSTRUCTOR = DxeTpmMeasureBootLibConstructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ DxeTpmMeasureBootLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ SecurityPkg/SecurityPkg.dec
+ CryptoPkg/CryptoPkg.dec
+
+[LibraryClasses]
+ BaseMemoryLib
+ DebugLib
+ MemoryAllocationLib
+ DevicePathLib
+ UefiBootServicesTableLib
+ BaseCryptLib
+ PeCoffLib
+ BaseLib
+ SecurityManagementLib
+
+[Protocols]
+ gEfiTcgProtocolGuid ## CONSUMES
+ gEfiFirmwareVolume2ProtocolGuid ## CONSUMES
+ gEfiBlockIoProtocolGuid ## CONSUMES
+ gEfiDiskIoProtocolGuid ## CONSUMES
+ gEfiDevicePathToTextProtocolGuid ## SOMETIMES_CONSUMES (Only used in debug mode)
diff --git a/SecurityPkg/Library/PlatformSecureLibNull/PlatformSecureLibNull.c b/SecurityPkg/Library/PlatformSecureLibNull/PlatformSecureLibNull.c
new file mode 100644
index 0000000000..f085d62b77
--- /dev/null
+++ b/SecurityPkg/Library/PlatformSecureLibNull/PlatformSecureLibNull.c
@@ -0,0 +1,39 @@
+/** @file
+ Provides a secure platform-specific method to clear PK(Platform Key).
+
+Copyright (c) 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+/**
+
+ This function detects whether a secure platform-specific method to clear PK(Platform Key)
+ is configured by platform owner. This method is provided for users force to clear PK
+ in case incorrect enrollment mis-haps.
+
+ UEFI231 spec chapter 27.5.2 stipulates: The platform key may also be cleared using
+ a secure platform-specific method. In this case, the global variable SetupMode
+ must also be updated to 1.
+
+ NOTE THAT: This function cannot depend on any EFI Variable Service since they are
+ not available when this function is called in AuthenticateVariable driver.
+
+ @retval TRUE The Platform owner wants to force clear PK.
+ @retval FALSE The Platform owner doesn't want to force clear PK.
+
+**/
+BOOLEAN
+EFIAPI
+ForceClearPK (
+ VOID
+ )
+{
+ return FALSE;
+}
diff --git a/SecurityPkg/Library/PlatformSecureLibNull/PlatformSecureLibNull.inf b/SecurityPkg/Library/PlatformSecureLibNull/PlatformSecureLibNull.inf
new file mode 100644
index 0000000000..5750198aa7
--- /dev/null
+++ b/SecurityPkg/Library/PlatformSecureLibNull/PlatformSecureLibNull.inf
@@ -0,0 +1,33 @@
+## @file
+# Provides a secure platform-specific method to clear PK(Platform Key).
+#
+# Copyright (c) 2011, Intel Corporation. All rights reserved.
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PlatformSecureLibNull
+ FILE_GUID = 7FA68D82-10A4-4e71-9524-D3D9500D3CDF
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = PlatformSecureLib|DXE_RUNTIME_DRIVER DXE_SMM_DRIVER
+
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ PlatformSecureLibNull.c
+
+[Packages]
+ MdePkg/MdePkg.dec
diff --git a/SecurityPkg/Library/TpmCommLib/CommonHeader.h b/SecurityPkg/Library/TpmCommLib/CommonHeader.h
new file mode 100644
index 0000000000..b8496c7276
--- /dev/null
+++ b/SecurityPkg/Library/TpmCommLib/CommonHeader.h
@@ -0,0 +1,29 @@
+/** @file
+ The intenal header file for TpmCommLib.
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _TPMCOMMLIB_COMMON_HEADER_H_
+#define _TPMCOMMLIB_COMMON_HEADER_H_
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#endif
diff --git a/SecurityPkg/Library/TpmCommLib/TisPc.c b/SecurityPkg/Library/TpmCommLib/TisPc.c
new file mode 100644
index 0000000000..3d74a012df
--- /dev/null
+++ b/SecurityPkg/Library/TpmCommLib/TisPc.c
@@ -0,0 +1,180 @@
+/** @file
+ Basic TIS (TPM Interface Specification) functions.
+
+Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "CommonHeader.h"
+
+/**
+ Check whether TPM chip exist.
+
+ @param[in] TisReg Pointer to TIS register.
+
+ @retval TRUE TPM chip exists.
+ @retval FALSE TPM chip is not found.
+**/
+BOOLEAN
+TisPcPresenceCheck (
+ IN TIS_PC_REGISTERS_PTR TisReg
+ )
+{
+ UINT8 RegRead;
+
+ RegRead = MmioRead8 ((UINTN)&TisReg->Access);
+ return (BOOLEAN)(RegRead != (UINT8)-1);
+}
+
+/**
+ Check whether the value of a TPM chip register satisfies the input BIT setting.
+
+ @param[in] Register Address port of register to be checked.
+ @param[in] BitSet Check these data bits are set.
+ @param[in] BitClear Check these data bits are clear.
+ @param[in] TimeOut The max wait time (unit MicroSecond) when checking register.
+
+ @retval EFI_SUCCESS The register satisfies the check bit.
+ @retval EFI_TIMEOUT The register can't run into the expected status in time.
+**/
+EFI_STATUS
+EFIAPI
+TisPcWaitRegisterBits (
+ IN UINT8 *Register,
+ IN UINT8 BitSet,
+ IN UINT8 BitClear,
+ IN UINT32 TimeOut
+ )
+{
+ UINT8 RegRead;
+ UINT32 WaitTime;
+
+ for (WaitTime = 0; WaitTime < TimeOut; WaitTime += 30){
+ RegRead = MmioRead8 ((UINTN)Register);
+ if ((RegRead & BitSet) == BitSet && (RegRead & BitClear) == 0)
+ return EFI_SUCCESS;
+ MicroSecondDelay (30);
+ }
+ return EFI_TIMEOUT;
+}
+
+/**
+ Get BurstCount by reading the burstCount field of a TIS regiger
+ in the time of default TIS_TIMEOUT_D.
+
+ @param[in] TisReg Pointer to TIS register.
+ @param[out] BurstCount Pointer to a buffer to store the got BurstConut.
+
+ @retval EFI_SUCCESS Get BurstCount.
+ @retval EFI_INVALID_PARAMETER TisReg is NULL or BurstCount is NULL.
+ @retval EFI_TIMEOUT BurstCount can't be got in time.
+**/
+EFI_STATUS
+EFIAPI
+TisPcReadBurstCount (
+ IN TIS_PC_REGISTERS_PTR TisReg,
+ OUT UINT16 *BurstCount
+ )
+{
+ UINT32 WaitTime;
+ UINT8 DataByte0;
+ UINT8 DataByte1;
+
+ if (BurstCount == NULL || TisReg == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ WaitTime = 0;
+ do {
+ //
+ // TIS_PC_REGISTERS_PTR->burstCount is UINT16, but it is not 2bytes aligned,
+ // so it needs to use MmioRead8 to read two times
+ //
+ DataByte0 = MmioRead8 ((UINTN)&TisReg->BurstCount);
+ DataByte1 = MmioRead8 ((UINTN)&TisReg->BurstCount + 1);
+ *BurstCount = (UINT16)((DataByte1 << 8) + DataByte0);
+ if (*BurstCount != 0) {
+ return EFI_SUCCESS;
+ }
+ MicroSecondDelay (30);
+ WaitTime += 30;
+ } while (WaitTime < TIS_TIMEOUT_D);
+
+ return EFI_TIMEOUT;
+}
+
+/**
+ Set TPM chip to ready state by sending ready command TIS_PC_STS_READY
+ to Status Register in time.
+
+ @param[in] TisReg Pointer to TIS register.
+
+ @retval EFI_SUCCESS TPM chip enters into ready state.
+ @retval EFI_INVALID_PARAMETER TisReg is NULL.
+ @retval EFI_TIMEOUT TPM chip can't be set to ready state in time.
+**/
+EFI_STATUS
+EFIAPI
+TisPcPrepareCommand (
+ IN TIS_PC_REGISTERS_PTR TisReg
+ )
+{
+ EFI_STATUS Status;
+
+ if (TisReg == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ MmioWrite8((UINTN)&TisReg->Status, TIS_PC_STS_READY);
+ Status = TisPcWaitRegisterBits (
+ &TisReg->Status,
+ TIS_PC_STS_READY,
+ 0,
+ TIS_TIMEOUT_B
+ );
+ return Status;
+}
+
+/**
+ Get the control of TPM chip by sending requestUse command TIS_PC_ACC_RQUUSE
+ to ACCESS Register in the time of default TIS_TIMEOUT_D.
+
+ @param[in] TisReg Pointer to TIS register.
+
+ @retval EFI_SUCCESS Get the control of TPM chip.
+ @retval EFI_INVALID_PARAMETER TisReg is NULL.
+ @retval EFI_NOT_FOUND TPM chip doesn't exit.
+ @retval EFI_TIMEOUT Can't get the TPM control in time.
+**/
+EFI_STATUS
+EFIAPI
+TisPcRequestUseTpm (
+ IN TIS_PC_REGISTERS_PTR TisReg
+ )
+{
+ EFI_STATUS Status;
+
+ if (TisReg == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!TisPcPresenceCheck (TisReg)) {
+ return EFI_NOT_FOUND;
+ }
+
+ MmioWrite8((UINTN)&TisReg->Access, TIS_PC_ACC_RQUUSE);
+ Status = TisPcWaitRegisterBits (
+ &TisReg->Access,
+ (UINT8)(TIS_PC_ACC_ACTIVE |TIS_PC_VALID),
+ 0,
+ TIS_TIMEOUT_D
+ );
+ return Status;
+}
diff --git a/SecurityPkg/Library/TpmCommLib/TpmComm.c b/SecurityPkg/Library/TpmCommLib/TpmComm.c
new file mode 100644
index 0000000000..3197f96a99
--- /dev/null
+++ b/SecurityPkg/Library/TpmCommLib/TpmComm.c
@@ -0,0 +1,50 @@
+/** @file
+ Basic TPM command functions.
+
+Copyright (c) 2005 - 2010, Intel Corporation. All rights reserved.
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "CommonHeader.h"
+
+/**
+ Single function calculates SHA1 digest value for all raw data. It
+ combines Sha1Init(), Sha1Update() and Sha1Final().
+
+ @param[in] Data Raw data to be digested.
+ @param[in] DataLen Size of the raw data.
+ @param[out] Digest Pointer to a buffer that stores the final digest.
+
+ @retval EFI_SUCCESS Always successfully calculate the final digest.
+**/
+EFI_STATUS
+EFIAPI
+TpmCommHashAll (
+ IN CONST UINT8 *Data,
+ IN UINTN DataLen,
+ OUT TPM_DIGEST *Digest
+ )
+{
+ VOID *Sha1Ctx;
+ UINTN CtxSize;
+
+ CtxSize = Sha1GetContextSize ();
+ Sha1Ctx = AllocatePool (CtxSize);
+ ASSERT (Sha1Ctx != NULL);
+
+ Sha1Init (Sha1Ctx);
+ Sha1Update (Sha1Ctx, Data, DataLen);
+ Sha1Final (Sha1Ctx, (UINT8 *)Digest);
+
+ FreePool (Sha1Ctx);
+
+ return EFI_SUCCESS;
+}
+
diff --git a/SecurityPkg/Library/TpmCommLib/TpmCommLib.inf b/SecurityPkg/Library/TpmCommLib/TpmCommLib.inf
new file mode 100644
index 0000000000..7188a3b165
--- /dev/null
+++ b/SecurityPkg/Library/TpmCommLib/TpmCommLib.inf
@@ -0,0 +1,46 @@
+## @file
+# TpmCommLib instance implements basis TPM Interface Specification (TIS) and TPM command functions.
+#
+# Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = TpmCommLib
+ FILE_GUID = 7d9fe32e-a6a9-4cdf-abff-10cc7f22e1c9
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = TpmCommLib|DXE_DRIVER UEFI_DRIVER PEIM DXE_SMM_DRIVER
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF
+#
+
+[Sources]
+ TisPc.c
+ TpmComm.c
+ CommonHeader.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ SecurityPkg/SecurityPkg.dec
+ CryptoPkg/CryptoPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ IoLib
+ TimerLib
+ BaseCryptLib
+ MemoryAllocationLib
+ DebugLib
+
diff --git a/SecurityPkg/SecurityPkg.dec b/SecurityPkg/SecurityPkg.dec
new file mode 100644
index 0000000000..8121f390a5
--- /dev/null
+++ b/SecurityPkg/SecurityPkg.dec
@@ -0,0 +1,122 @@
+## @file SecurityPkg.dec
+# This package includes the security drivers, defintions(including PPIs/PROTOCOLs/GUIDs
+# and library classes) and libraries instances.
+#
+# Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+# This program and the accompanying materials are licensed and made available under
+# the terms and conditions of the BSD License which accompanies this distribution.
+# The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ DEC_SPECIFICATION = 0x00010005
+ PACKAGE_NAME = SecurityPkg
+ PACKAGE_GUID = 24369CAC-6AA6-4fb8-88DB-90BF061668AD
+ PACKAGE_VERSION = 0.91
+
+[Includes]
+ Include
+
+[LibraryClasses]
+ ## @libraryclass Definitions for common TPM commands as library API for TPM
+ # module use.
+ TpmCommLib|Include/Library/TpmCommLib.h
+
+[Guids]
+ ## Security package token space guid
+ # Include/Guid/SecurityPkgTokenSpace.h
+ gEfiSecurityPkgTokenSpaceGuid = { 0xd3fb176, 0x9569, 0x4d51, { 0xa3, 0xef, 0x7d, 0x61, 0xc6, 0x4f, 0xea, 0xba }}
+ ## Guid acted as the authenticated variable store header's signature, and to specify the variable list entries put in the EFI system table.
+ # Include/Guid/AuthenticatedVariableFormat.h
+ gEfiAuthenticatedVariableGuid = { 0xaaf32c78, 0x947b, 0x439a, { 0xa1, 0x80, 0x2e, 0x14, 0x4e, 0xc3, 0x77, 0x92 } }
+
+ ## Include/Guid/TcgEventHob.h
+ gTcgEventEntryHobGuid = { 0x2e3044ac, 0x879f, 0x490f, {0x97, 0x60, 0xbb, 0xdf, 0xaf, 0x69, 0x5f, 0x50 }}
+
+ ## Include/Guid/PhysicalPresenceData.h
+ gEfiPhysicalPresenceGuid = { 0xf6499b1, 0xe9ad, 0x493d, { 0xb9, 0xc2, 0x2f, 0x90, 0x81, 0x5c, 0x6c, 0xbc }}
+
+[Ppis]
+ ## Include/Ppi/LockPhysicalPresence.h
+ gPeiLockPhysicalPresencePpiGuid = { 0xef9aefe5, 0x2bd3, 0x4031, { 0xaf, 0x7d, 0x5e, 0xfe, 0x5a, 0xbb, 0x9a, 0xd } }
+
+ ## Include/Ppi/TpmInitialized.h
+ gPeiTpmInitializedPpiGuid = { 0xe9db0d58, 0xd48d, 0x47f6, { 0x9c, 0x6e, 0x6f, 0x40, 0xe8, 0x6c, 0x7b, 0x41 }}
+
+[PcdsFixedAtBuild]
+ ## Pcd for OptionRom.
+ # Image verification policy settings:
+ # ALWAYS_EXECUTE 0x00000000
+ # NEVER_EXECUTE 0x00000001
+ # ALLOW_EXECUTE_ON_SECURITY_VIOLATION 0x00000002
+ # DEFER_EXECUTE_ON_SECURITY_VIOLATION 0x00000003
+ # DENY_EXECUTE_ON_SECURITY_VIOLATION 0x00000004
+ # QUERY_USER_ON_SECURITY_VIOLATION 0x00000005
+ gEfiSecurityPkgTokenSpaceGuid.PcdOptionRomImageVerificationPolicy|0x00|UINT32|0x00000001
+
+ ## Pcd for removable media.
+ # Removable media include CD-ROM, Floppy, USB and network.
+ # Image verification policy settings:
+ # ALWAYS_EXECUTE 0x00000000
+ # NEVER_EXECUTE 0x00000001
+ # ALLOW_EXECUTE_ON_SECURITY_VIOLATION 0x00000002
+ # DEFER_EXECUTE_ON_SECURITY_VIOLATION 0x00000003
+ # DENY_EXECUTE_ON_SECURITY_VIOLATION 0x00000004
+ # QUERY_USER_ON_SECURITY_VIOLATION 0x00000005
+ gEfiSecurityPkgTokenSpaceGuid.PcdRemovableMediaImageVerificationPolicy|0x05|UINT32|0x00000002
+
+ ## Pcd for fixed media.
+ # Fixed media include hard disk.
+ # Image verification policy settings:
+ # ALWAYS_EXECUTE 0x00000000
+ # NEVER_EXECUTE 0x00000001
+ # ALLOW_EXECUTE_ON_SECURITY_VIOLATION 0x00000002
+ # DEFER_EXECUTE_ON_SECURITY_VIOLATION 0x00000003
+ # DENY_EXECUTE_ON_SECURITY_VIOLATION 0x00000004
+ # QUERY_USER_ON_SECURITY_VIOLATION 0x00000005
+ gEfiSecurityPkgTokenSpaceGuid.PcdFixedMediaImageVerificationPolicy|0x05|UINT32|0x00000003
+
+ ## Defer Image Load policy settings.
+ # The policy is bitwise.
+ # If bit is set, the image from corresponding device will be trust when loading.
+ #
+ # IMAGE_UNKNOWN 0x00000001
+ # IMAGE_FROM_FV 0x00000002
+ # IMAGE_FROM_OPTION_ROM 0x00000004
+ # IMAGE_FROM_REMOVABLE_MEDIA 0x00000008
+ # IMAGE_FROM_FIXED_MEDIA 0x00000010
+ gEfiSecurityPkgTokenSpaceGuid.PcdDeferImageLoadPolicy|0x0000001F|UINT32|0x0000004
+
+ ## The token file name used to save credential in USB credential provider driver.
+ # The specified file should be saved at the root directory of USB storage disk.
+ gEfiSecurityPkgTokenSpaceGuid.PcdFixedUsbCredentialProviderTokenFileName|L"Token.bin"|VOID*|0x00000005
+
+ ## The size of Append variable buffer. This buffer is reserved for runtime use, OS can append data into one existing variable.
+ gEfiSecurityPkgTokenSpaceGuid.PcdMaxAppendVariableSize|0x2000|UINT32|0x30000005
+
+ ## This PCD specifies the type of TCG platform that contains TPM chip.
+ # This PCD is only avaiable when PcdTpmPhysicalPresence is TRUE.
+ # If 0, TCG platform type is PC client.
+ # If 1, TCG platform type is server.
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpmPlatformClass|0|UINT8|0x00000006
+
+ ## The PCD is used to control whether to support hiding the TPM.
+ # If TRUE, PcdHideTpm controls whether to hide the TPM.
+ gEfiSecurityPkgTokenSpaceGuid.PcdHideTpmSupport|FALSE|BOOLEAN|0x00000007
+
+[PcdsDynamic, PcdsDynamicEx]
+ ## The PCD is used to control whether to hide the TPM.
+ gEfiSecurityPkgTokenSpaceGuid.PcdHideTpm|FALSE|BOOLEAN|0x00010002
+
+ ## The PCD is used to specify whether or not MOR (MemoryOverwriteControl) feature is enabled.
+ gEfiSecurityPkgTokenSpaceGuid.PcdMorEnable|FALSE|BOOLEAN|0x00010000
+
+[PcdsFixedAtBuild, PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx]
+ ## This PCD indicates the presence or absence of the platform operator.
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpmPhysicalPresence|TRUE|BOOLEAN|0x00010001
+
diff --git a/SecurityPkg/SecurityPkg.dsc b/SecurityPkg/SecurityPkg.dsc
new file mode 100644
index 0000000000..09aa8fcca0
--- /dev/null
+++ b/SecurityPkg/SecurityPkg.dsc
@@ -0,0 +1,125 @@
+## @file
+# Security Module Package for All Architectures.
+#
+# Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ PLATFORM_NAME = SecurityPkg
+ PLATFORM_GUID = B2C4614D-AE76-47ba-B876-5988BFED064F
+ PLATFORM_VERSION = 0.91
+ DSC_SPECIFICATION = 0x00010005
+ OUTPUT_DIRECTORY = Build/SecurityPkg
+ SUPPORTED_ARCHITECTURES = IA32|IPF|X64|EBC
+ BUILD_TARGETS = DEBUG|RELEASE
+ SKUID_IDENTIFIER = DEFAULT
+
+[LibraryClasses]
+ DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf
+ DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf
+ BaseLib|MdePkg/Library/BaseLib/BaseLib.inf
+ SynchronizationLib|MdePkg/Library/BaseSynchronizationLib/BaseSynchronizationLib.inf
+ TimerLib|MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTemplate.inf
+ BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
+ MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
+ PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf
+ UefiApplicationEntryPoint|MdePkg/Library/UefiApplicationEntryPoint/UefiApplicationEntryPoint.inf
+
+ DxeServicesLib|MdePkg/Library/DxeServicesLib/DxeServicesLib.inf
+ UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf
+ UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf
+ DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf
+ UefiLib|MdePkg/Library/UefiLib/UefiLib.inf
+ DxeServicesTableLib|MdePkg/Library/DxeServicesTableLib/DxeServicesTableLib.inf
+ UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf
+ UefiRuntimeLib|MdePkg/Library/UefiRuntimeLib/UefiRuntimeLib.inf
+ HiiLib|MdeModulePkg/Library/UefiHiiLib/UefiHiiLib.inf
+ UefiHiiServicesLib|MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.inf
+ PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
+ BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf
+ IntrinsicLib|CryptoPkg/Library/IntrinsicLib/IntrinsicLib.inf
+ OpensslLib|CryptoPkg/Library/OpensslLib/OpensslLib.inf
+ IoLib|MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf
+ TpmCommLib|SecurityPkg/Library/TpmCommLib/TpmCommLib.inf
+ PlatformSecureLib|SecurityPkg/Library/PlatformSecureLibNull/PlatformSecureLibNull.inf
+
+[LibraryClasses.common.PEIM]
+ PeimEntryPoint|MdePkg/Library/PeimEntryPoint/PeimEntryPoint.inf
+ PeiServicesLib|MdePkg/Library/PeiServicesLib/PeiServicesLib.inf
+ PeiServicesTablePointerLib|MdePkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointerLib.inf
+ HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf
+ MemoryAllocationLib|MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllocationLib.inf
+
+[LibraryClasses.common.DXE_DRIVER]
+ HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf
+ ReportStatusCodeLib|MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf
+
+[LibraryClasses.common.UEFI_DRIVER, LibraryClasses.common.DXE_RUNTIME_DRIVER, LibraryClasses.common.DXE_SAL_DRIVER,]
+ MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
+ DebugLib|MdePkg/Library/UefiDebugLibConOut/UefiDebugLibConOut.inf
+
+[LibraryClasses.IPF.DXE_SAL_DRIVER]
+ ExtendedSalLib|MdePkg/Library/DxeRuntimeExtendedSalLib/DxeRuntimeExtendedSalLib.inf
+
+[LibraryClasses.common.DXE_SMM_DRIVER]
+ SmmServicesTableLib|MdePkg/Library/SmmServicesTableLib/SmmServicesTableLib.inf
+ MemoryAllocationLib|MdePkg/Library/SmmMemoryAllocationLib/SmmMemoryAllocationLib.inf
+ BaseCryptLib|CryptoPkg/Library/BaseCryptLib/SmmCryptLib.inf
+
+[Components]
+ SecurityPkg/VariableAuthenticated/Pei/VariablePei.inf
+ SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.inf
+ SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.inf
+ SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManagerDxe.inf
+ SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManagerDxe.inf
+ SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderDxe.inf
+ SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProviderDxe.inf
+
+ #
+ # Application
+ #
+ SecurityPkg/Application/VariableInfo/VariableInfo.inf
+
+ #
+ # TPM
+ #
+ SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.inf
+ SecurityPkg/Tcg/TcgPei/TcgPei.inf
+ SecurityPkg/Tcg/TcgDxe/TcgDxe.inf
+ SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePei.inf
+ SecurityPkg/Tcg/PhysicalPresenceDxe/PhysicalPresenceDxe.inf
+ SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.inf
+ SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDxe.inf {
+
+ PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf
+ }
+ SecurityPkg/Tcg/TcgSmm/TcgSmm.inf
+
+[Components.IA32, Components.X64]
+ SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableRuntimeDxe.inf {
+
+ BaseCryptLib|CryptoPkg/Library/BaseCryptLib/RuntimeCryptLib.inf
+ }
+
+ SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmm.inf
+ SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableSmmRuntimeDxe.inf
+
+[Components.IPF]
+ SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/EsalVariableDxeSal.inf
+
+[Components.EBC]
+# Build only
+ SecurityPkg/VariableAuthenticated/RuntimeDxe/VariableRuntimeDxe.inf
+
+[BuildOptions]
+ MSFT:*_*_IA32_DLINK_FLAGS = /ALIGN:256
+ INTEL:*_*_IA32_DLINK_FLAGS = /ALIGN:256
+
diff --git a/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.c b/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.c
new file mode 100644
index 0000000000..ce53112dc5
--- /dev/null
+++ b/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.c
@@ -0,0 +1,82 @@
+/** @file
+ TCG MOR (Memory Overwrite Request) Control Driver.
+
+ This driver initilize MemoryOverwriteRequestControl variable. It
+ will clear MOR_CLEAR_MEMORY_BIT bit if it is set.
+
+Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "TcgMor.h"
+
+/**
+ Entry Point for TCG MOR Control driver.
+
+ @param[in] ImageHandle Image handle of this driver.
+ @param[in] SystemTable A Pointer to the EFI System Table.
+
+ @retval EFI_SUCEESS
+ @return Others Some error occurs.
+**/
+EFI_STATUS
+EFIAPI
+MorDriverEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ UINT8 MorControl;
+ UINTN DataSize;
+
+ ///
+ /// The firmware is required to create the MemoryOverwriteRequestControl UEFI variable.
+ ///
+
+ DataSize = sizeof (MorControl);
+ Status = gRT->GetVariable (
+ MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,
+ &gEfiMemoryOverwriteControlDataGuid,
+ NULL,
+ &DataSize,
+ &MorControl
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Set default value to 0
+ //
+ MorControl = 0;
+ } else {
+ if (MOR_CLEAR_MEMORY_VALUE (MorControl) == 0x0) {
+ //
+ // MorControl is expected, directly return to avoid unnecessary variable operation
+ //
+ return EFI_SUCCESS;
+ }
+ //
+ // Clear MOR_CLEAR_MEMORY_BIT
+ //
+ DEBUG ((EFI_D_INFO, "TcgMor: Clear MorClearMemory bit\n"));
+ MorControl &= 0xFE;
+ }
+
+ Status = gRT->SetVariable (
+ MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,
+ &gEfiMemoryOverwriteControlDataGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ DataSize,
+ &MorControl
+ );
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+}
+
+
diff --git a/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.h b/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.h
new file mode 100644
index 0000000000..bfad2cf2f0
--- /dev/null
+++ b/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.h
@@ -0,0 +1,27 @@
+/** @file
+ The header file for TcgMor.
+
+Copyright (c) 2009, Intel Corporation. All rights reserved.
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __TCG_MOR_H__
+#define __TCG_MOR_H__
+
+#include
+
+#include
+
+#include
+#include
+#include
+
+#endif
+
diff --git a/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.inf b/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.inf
new file mode 100644
index 0000000000..e62a90447c
--- /dev/null
+++ b/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.inf
@@ -0,0 +1,50 @@
+## @file
+# Component description file for Memory Overwrite Control driver.
+#
+# Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = TcgMor
+ FILE_GUID = AD416CE3-A483-45b1-94C2-4B4E4D575562
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = MorDriverEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ TcgMor.c
+ TcgMor.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ UefiRuntimeServicesTableLib
+ ReportStatusCodeLib
+ DebugLib
+
+[Guids]
+ gEfiMemoryOverwriteControlDataGuid # GUID ALWAYS_CONSUMED
+
+[Depex]
+ gEfiVariableArchProtocolGuid AND
+ gEfiVariableWriteArchProtocolGuid AND
+ gEfiTcgProtocolGuid
+
diff --git a/SecurityPkg/Tcg/PhysicalPresenceDxe/PhysicalPresence.c b/SecurityPkg/Tcg/PhysicalPresenceDxe/PhysicalPresence.c
new file mode 100644
index 0000000000..187c3ca888
--- /dev/null
+++ b/SecurityPkg/Tcg/PhysicalPresenceDxe/PhysicalPresence.c
@@ -0,0 +1,1115 @@
+/** @file
+ This driver checks whether there is pending TPM request. If yes,
+ it will display TPM request information and ask for user confirmation.
+ The TPM request will be cleared after it is processed.
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "PhysicalPresence.h"
+
+EFI_HII_HANDLE mPpStringPackHandle;
+
+/**
+ Get TPM physical presence permanent flags.
+
+ @param[out] LifetimeLock Returns physicalPresenceLifetimeLock permanent flag.
+ @param[out] CmdEnable Returns physicalPresenceCMDEnable permanent flag.
+
+ @retval EFI_SUCCESS Flags were returns successfully.
+ @retval other Failed to locate EFI TCG Protocol.
+
+**/
+EFI_STATUS
+GetTpmCapability (
+ OUT BOOLEAN *LifetimeLock,
+ OUT BOOLEAN *CmdEnable
+ )
+{
+ EFI_STATUS Status;
+ EFI_TCG_PROTOCOL *TcgProtocol;
+ TPM_RQU_COMMAND_HDR *TpmRqu;
+ TPM_RSP_COMMAND_HDR *TpmRsp;
+ UINT32 *SendBufPtr;
+ UINT8 SendBuffer[sizeof (*TpmRqu) + sizeof (UINT32) * 3];
+ TPM_PERMANENT_FLAGS *TpmPermanentFlags;
+ UINT8 RecvBuffer[40];
+
+ Status = gBS->LocateProtocol (&gEfiTcgProtocolGuid, NULL, (VOID **)&TcgProtocol);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Fill request header
+ //
+ TpmRsp = (TPM_RSP_COMMAND_HDR*)RecvBuffer;
+ TpmRqu = (TPM_RQU_COMMAND_HDR*)SendBuffer;
+
+ TpmRqu->tag = H2NS (TPM_TAG_RQU_COMMAND);
+ TpmRqu->paramSize = H2NL (sizeof (SendBuffer));
+ TpmRqu->ordinal = H2NL (TPM_ORD_GetCapability);
+
+ //
+ // Set request parameter
+ //
+ SendBufPtr = (UINT32*)(TpmRqu + 1);
+ WriteUnaligned32 (SendBufPtr++, H2NL (TPM_CAP_FLAG));
+ WriteUnaligned32 (SendBufPtr++, H2NL (sizeof (TPM_CAP_FLAG_PERMANENT)));
+ WriteUnaligned32 (SendBufPtr, H2NL (TPM_CAP_FLAG_PERMANENT));
+
+ Status = TcgProtocol->PassThroughToTpm (
+ TcgProtocol,
+ sizeof (SendBuffer),
+ (UINT8*)TpmRqu,
+ sizeof (RecvBuffer),
+ (UINT8*)&RecvBuffer
+ );
+ ASSERT_EFI_ERROR (Status);
+ ASSERT (TpmRsp->tag == H2NS (TPM_TAG_RSP_COMMAND));
+ ASSERT (TpmRsp->returnCode == 0);
+
+ TpmPermanentFlags = (TPM_PERMANENT_FLAGS *)&RecvBuffer[sizeof (TPM_RSP_COMMAND_HDR) + sizeof (UINT32)];
+
+ if (LifetimeLock != NULL) {
+ *LifetimeLock = TpmPermanentFlags->physicalPresenceLifetimeLock;
+ }
+
+ if (CmdEnable != NULL) {
+ *CmdEnable = TpmPermanentFlags->physicalPresenceCMDEnable;
+ }
+
+ return Status;
+}
+
+/**
+ Issue TSC_PhysicalPresence command to TPM.
+
+ @param[in] PhysicalPresence The state to set the TPM's Physical Presence flags.
+
+ @retval EFI_SUCCESS TPM executed the command successfully.
+ @retval EFI_SECURITY_VIOLATION TPM returned error when executing the command.
+ @retval other Failed to locate EFI TCG Protocol.
+
+**/
+EFI_STATUS
+TpmPhysicalPresence (
+ IN TPM_PHYSICAL_PRESENCE PhysicalPresence
+ )
+{
+ EFI_STATUS Status;
+ EFI_TCG_PROTOCOL *TcgProtocol;
+ TPM_RQU_COMMAND_HDR *TpmRqu;
+ TPM_PHYSICAL_PRESENCE *TpmPp;
+ TPM_RSP_COMMAND_HDR TpmRsp;
+ UINT8 Buffer[sizeof (*TpmRqu) + sizeof (*TpmPp)];
+
+ Status = gBS->LocateProtocol (&gEfiTcgProtocolGuid, NULL, (VOID **)&TcgProtocol);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ TpmRqu = (TPM_RQU_COMMAND_HDR*)Buffer;
+ TpmPp = (TPM_PHYSICAL_PRESENCE*)(TpmRqu + 1);
+
+ TpmRqu->tag = H2NS (TPM_TAG_RQU_COMMAND);
+ TpmRqu->paramSize = H2NL (sizeof (Buffer));
+ TpmRqu->ordinal = H2NL (TSC_ORD_PhysicalPresence);
+ WriteUnaligned16 (TpmPp, (TPM_PHYSICAL_PRESENCE) H2NS (PhysicalPresence));
+
+ Status = TcgProtocol->PassThroughToTpm (
+ TcgProtocol,
+ sizeof (Buffer),
+ (UINT8*)TpmRqu,
+ sizeof (TpmRsp),
+ (UINT8*)&TpmRsp
+ );
+ ASSERT_EFI_ERROR (Status);
+ ASSERT (TpmRsp.tag == H2NS (TPM_TAG_RSP_COMMAND));
+ if (TpmRsp.returnCode != 0) {
+ //
+ // If it fails, some requirements may be needed for this command.
+ //
+ return EFI_SECURITY_VIOLATION;
+ }
+ return Status;
+}
+
+/**
+ Issue a TPM command for which no additional output data will be returned.
+
+ @param[in] TcgProtocol EFI TCG Protocol instance.
+ @param[in] Ordinal TPM command code.
+ @param[in] AdditionalParameterSize Additional parameter size.
+ @param[in] AdditionalParameters Pointer to the Additional paramaters.
+
+ @retval TPM_PP_BIOS_FAILURE Error occurred during sending command to TPM or
+ receiving response from TPM.
+ @retval Others Return code from the TPM device after command execution.
+
+**/
+TPM_RESULT
+TpmCommandNoReturnData (
+ IN EFI_TCG_PROTOCOL *TcgProtocol,
+ IN TPM_COMMAND_CODE Ordinal,
+ IN UINTN AdditionalParameterSize,
+ IN VOID *AdditionalParameters
+ )
+{
+ EFI_STATUS Status;
+ TPM_RQU_COMMAND_HDR *TpmRqu;
+ TPM_RSP_COMMAND_HDR TpmRsp;
+ UINT32 Size;
+
+ TpmRqu = (TPM_RQU_COMMAND_HDR*)AllocatePool (
+ sizeof (*TpmRqu) + AdditionalParameterSize
+ );
+ if (TpmRqu == NULL) {
+ return TPM_PP_BIOS_FAILURE;
+ }
+
+ TpmRqu->tag = H2NS (TPM_TAG_RQU_COMMAND);
+ Size = (UINT32)(sizeof (*TpmRqu) + AdditionalParameterSize);
+ TpmRqu->paramSize = H2NL (Size);
+ TpmRqu->ordinal = H2NL (Ordinal);
+ gBS->CopyMem (TpmRqu + 1, AdditionalParameters, AdditionalParameterSize);
+
+ Status = TcgProtocol->PassThroughToTpm (
+ TcgProtocol,
+ Size,
+ (UINT8*)TpmRqu,
+ (UINT32)sizeof (TpmRsp),
+ (UINT8*)&TpmRsp
+ );
+ FreePool (TpmRqu);
+ if (EFI_ERROR (Status) || (TpmRsp.tag != H2NS (TPM_TAG_RSP_COMMAND))) {
+ return TPM_PP_BIOS_FAILURE;
+ }
+ return H2NL (TpmRsp.returnCode);
+}
+
+/**
+ Execute physical presence operation requested by the OS.
+
+ @param[in] TcgProtocol EFI TCG Protocol instance.
+ @param[in] CommandCode Physical presence operation value.
+ @param[in, out] PpiFlags The physical presence interface flags.
+
+ @retval TPM_PP_BIOS_FAILURE Unknown physical presence operation.
+ @retval TPM_PP_BIOS_FAILURE Error occurred during sending command to TPM or
+ receiving response from TPM.
+ @retval Others Return code from the TPM device after command execution.
+
+**/
+TPM_RESULT
+ExecutePhysicalPresence (
+ IN EFI_TCG_PROTOCOL *TcgProtocol,
+ IN UINT8 CommandCode,
+ IN OUT UINT8 *PpiFlags
+ )
+{
+ BOOLEAN BoolVal;
+ TPM_RESULT TpmResponse;
+ UINT32 InData[5];
+
+ switch (CommandCode) {
+ case ENABLE:
+ return TpmCommandNoReturnData (
+ TcgProtocol,
+ TPM_ORD_PhysicalEnable,
+ 0,
+ NULL
+ );
+
+ case DISABLE:
+ return TpmCommandNoReturnData (
+ TcgProtocol,
+ TPM_ORD_PhysicalDisable,
+ 0,
+ NULL
+ );
+
+ case ACTIVATE:
+ BoolVal = FALSE;
+ return TpmCommandNoReturnData (
+ TcgProtocol,
+ TPM_ORD_PhysicalSetDeactivated,
+ sizeof (BoolVal),
+ &BoolVal
+ );
+
+ case DEACTIVATE:
+ BoolVal = TRUE;
+ return TpmCommandNoReturnData (
+ TcgProtocol,
+ TPM_ORD_PhysicalSetDeactivated,
+ sizeof (BoolVal),
+ &BoolVal
+ );
+
+ case CLEAR:
+ return TpmCommandNoReturnData (
+ TcgProtocol,
+ TPM_ORD_ForceClear,
+ 0,
+ NULL
+ );
+
+ case ENABLE_ACTIVATE:
+ TpmResponse = ExecutePhysicalPresence (TcgProtocol, ENABLE, PpiFlags);
+ if (TpmResponse == 0) {
+ TpmResponse = ExecutePhysicalPresence (TcgProtocol, ACTIVATE, PpiFlags);
+ }
+ return TpmResponse;
+
+ case DEACTIVATE_DISABLE:
+ TpmResponse = ExecutePhysicalPresence (TcgProtocol, DEACTIVATE, PpiFlags);
+ if (TpmResponse == 0) {
+ TpmResponse = ExecutePhysicalPresence (TcgProtocol, DISABLE, PpiFlags);
+ }
+ return TpmResponse;
+
+ case SET_OWNER_INSTALL_TRUE:
+ BoolVal = TRUE;
+ return TpmCommandNoReturnData (
+ TcgProtocol,
+ TPM_ORD_SetOwnerInstall,
+ sizeof (BoolVal),
+ &BoolVal
+ );
+
+ case SET_OWNER_INSTALL_FALSE:
+ BoolVal = FALSE;
+ return TpmCommandNoReturnData (
+ TcgProtocol,
+ TPM_ORD_SetOwnerInstall,
+ sizeof (BoolVal),
+ &BoolVal
+ );
+
+ case ENABLE_ACTIVATE_OWNER_TRUE:
+ //
+ // ENABLE_ACTIVATE + SET_OWNER_INSTALL_TRUE
+ // SET_OWNER_INSTALL_TRUE will be executed atfer reboot
+ //
+ if ((*PpiFlags & FLAG_RESET_TRACK) == 0) {
+ TpmResponse = ExecutePhysicalPresence (TcgProtocol, ENABLE_ACTIVATE, PpiFlags);
+ *PpiFlags |= FLAG_RESET_TRACK;
+ } else {
+ TpmResponse = ExecutePhysicalPresence (TcgProtocol, SET_OWNER_INSTALL_TRUE, PpiFlags);
+ *PpiFlags &= ~FLAG_RESET_TRACK;
+ }
+ return TpmResponse;
+
+ case DEACTIVATE_DISABLE_OWNER_FALSE:
+ TpmResponse = ExecutePhysicalPresence (TcgProtocol, SET_OWNER_INSTALL_FALSE, PpiFlags);
+ if (TpmResponse == 0) {
+ TpmResponse = ExecutePhysicalPresence (TcgProtocol, DEACTIVATE_DISABLE, PpiFlags);
+ }
+ return TpmResponse;
+
+ case DEFERRED_PP_UNOWNERED_FIELD_UPGRADE:
+ InData[0] = H2NL (TPM_SET_STCLEAR_DATA); // CapabilityArea
+ InData[1] = H2NL (sizeof(UINT32)); // SubCapSize
+ InData[2] = H2NL (TPM_SD_DEFERREDPHYSICALPRESENCE); // SubCap
+ InData[3] = H2NL (sizeof(UINT32)); // SetValueSize
+ InData[4] = H2NL (1); // UnownedFieldUpgrade; bit0
+ return TpmCommandNoReturnData (
+ TcgProtocol,
+ TPM_ORD_SetCapability,
+ sizeof (UINT32) * 5,
+ InData
+ );
+
+ case SET_OPERATOR_AUTH:
+ //
+ // TPM_SetOperatorAuth
+ // This command requires UI to prompt user for Auth data
+ // Here it is NOT implemented
+ //
+ return TPM_PP_BIOS_FAILURE;
+
+ case CLEAR_ENABLE_ACTIVATE:
+ TpmResponse = ExecutePhysicalPresence (TcgProtocol, CLEAR, PpiFlags);
+ if (TpmResponse == 0) {
+ TpmResponse = ExecutePhysicalPresence (TcgProtocol, ENABLE_ACTIVATE, PpiFlags);
+ }
+ return TpmResponse;
+
+ case SET_NO_PPI_PROVISION_FALSE:
+ *PpiFlags &= ~FLAG_NO_PPI_PROVISION;
+ return 0;
+
+ case SET_NO_PPI_PROVISION_TRUE:
+ *PpiFlags |= FLAG_NO_PPI_PROVISION;
+ return 0;
+
+ case SET_NO_PPI_CLEAR_FALSE:
+ *PpiFlags &= ~FLAG_NO_PPI_CLEAR;
+ return 0;
+
+ case SET_NO_PPI_CLEAR_TRUE:
+ *PpiFlags |= FLAG_NO_PPI_CLEAR;
+ return 0;
+
+ case SET_NO_PPI_MAINTENANCE_FALSE:
+ *PpiFlags &= ~FLAG_NO_PPI_MAINTENANCE;
+ return 0;
+
+ case SET_NO_PPI_MAINTENANCE_TRUE:
+ *PpiFlags |= FLAG_NO_PPI_MAINTENANCE;
+ return 0;
+
+ case ENABLE_ACTIVATE_CLEAR:
+ TpmResponse = ExecutePhysicalPresence (TcgProtocol, ENABLE_ACTIVATE, PpiFlags);
+ if (TpmResponse == 0) {
+ TpmResponse = ExecutePhysicalPresence (TcgProtocol, CLEAR, PpiFlags);
+ }
+ return TpmResponse;
+
+ case ENABLE_ACTIVATE_CLEAR_ENABLE_ACTIVATE:
+ //
+ // ENABLE_ACTIVATE + CLEAR_ENABLE_ACTIVATE
+ // CLEAR_ENABLE_ACTIVATE will be executed atfer reboot.
+ //
+ if ((*PpiFlags & FLAG_RESET_TRACK) == 0) {
+ TpmResponse = ExecutePhysicalPresence (TcgProtocol, ENABLE_ACTIVATE, PpiFlags);
+ *PpiFlags |= FLAG_RESET_TRACK;
+ } else {
+ TpmResponse = ExecutePhysicalPresence (TcgProtocol, CLEAR_ENABLE_ACTIVATE, PpiFlags);
+ *PpiFlags &= ~FLAG_RESET_TRACK;
+ }
+ return TpmResponse;
+
+ default:
+ ;
+ }
+ return TPM_PP_BIOS_FAILURE;
+}
+
+
+/**
+ Read the specified key for user confirmation.
+
+ @param[in] CautionKey If true, F12 is used as confirm key;
+ If false, F10 is used as confirm key.
+
+ @retval TRUE User confirmed the changes by input.
+ @retval FALSE User discarded the changes.
+
+**/
+BOOLEAN
+ReadUserKey (
+ IN BOOLEAN CautionKey
+ )
+{
+ EFI_STATUS Status;
+ EFI_INPUT_KEY Key;
+ UINT16 InputKey;
+ EFI_TPL OldTpl;
+
+ OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
+ gBS->RestoreTPL (TPL_APPLICATION);
+
+ InputKey = 0;
+ do {
+ Status = gBS->CheckEvent (gST->ConIn->WaitForKey);
+ if (!EFI_ERROR (Status)) {
+ Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
+ if (Key.ScanCode == SCAN_ESC) {
+ InputKey = Key.ScanCode;
+ }
+ if ((Key.ScanCode == SCAN_F10) && !CautionKey) {
+ InputKey = Key.ScanCode;
+ }
+ if ((Key.ScanCode == SCAN_F12) && CautionKey) {
+ InputKey = Key.ScanCode;
+ }
+ }
+ } while (InputKey == 0);
+
+ gBS->RaiseTPL (OldTpl);
+
+ if (InputKey != SCAN_ESC) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Display the confirm text and get user confirmation.
+
+ @param[in] TpmPpCommand The requested TPM physical presence command.
+
+ @retval TRUE The user has confirmed the changes.
+ @retval FALSE The user doesn't confirm the changes.
+**/
+BOOLEAN
+UserConfirm (
+ IN UINT8 TpmPpCommand
+ )
+{
+ CHAR16 *ConfirmText;
+ CHAR16 *TmpStr1;
+ CHAR16 *TmpStr2;
+ UINTN BufSize;
+ BOOLEAN CautionKey;
+ UINT16 Index;
+ CHAR16 DstStr[81];
+
+ TmpStr2 = NULL;
+ CautionKey = FALSE;
+ BufSize = CONFIRM_BUFFER_SIZE;
+ ConfirmText = AllocateZeroPool (BufSize);
+ ASSERT (ConfirmText != NULL);
+
+ mPpStringPackHandle = HiiAddPackages (
+ &gEfiPhysicalPresenceGuid,
+ NULL,
+ PhysicalPresenceDxeStrings,
+ NULL
+ );
+ ASSERT (mPpStringPackHandle != NULL);
+
+ switch (TpmPpCommand) {
+ case ENABLE:
+ TmpStr2 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_ENABLE), NULL);
+
+ TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_HEAD_STR), NULL);
+ UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);
+ FreePool (TmpStr1);
+
+ TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_ACCEPT_KEY), NULL);
+ StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+ break;
+
+ case DISABLE:
+ TmpStr2 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_DISABLE), NULL);
+
+ TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_HEAD_STR), NULL);
+ UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);
+ FreePool (TmpStr1);
+
+ TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_WARNING), NULL);
+ StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+
+ TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_ACCEPT_KEY), NULL);
+ StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+ break;
+
+ case ACTIVATE:
+ TmpStr2 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_ACTIVATE), NULL);
+
+ TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_HEAD_STR), NULL);
+ UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);
+ FreePool (TmpStr1);
+
+ TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_ACCEPT_KEY), NULL);
+ StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+ break;
+
+ case DEACTIVATE:
+ TmpStr2 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_DEACTIVATE), NULL);
+
+ TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_HEAD_STR), NULL);
+ UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);
+ FreePool (TmpStr1);
+
+ TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_WARNING), NULL);
+ StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+
+ TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_ACCEPT_KEY), NULL);
+ StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+ break;
+
+ case CLEAR:
+ CautionKey = TRUE;
+ TmpStr2 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_CLEAR), NULL);
+
+ TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_HEAD_STR), NULL);
+ UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);
+ FreePool (TmpStr1);
+
+ TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_WARNING_CLEAR), NULL);
+ StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);
+ StrnCat (ConfirmText, L" \n\n", (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+
+ TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_CAUTION_KEY), NULL);
+ StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+ break;
+
+ case ENABLE_ACTIVATE:
+ TmpStr2 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_ENABLE_ACTIVATE), NULL);
+
+ TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_HEAD_STR), NULL);
+ UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);
+ FreePool (TmpStr1);
+
+ TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_NOTE_ON), NULL);
+ StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+
+ TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_ACCEPT_KEY), NULL);
+ StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+ break;
+
+ case DEACTIVATE_DISABLE:
+ TmpStr2 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_DEACTIVATE_DISABLE), NULL);
+
+ TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_HEAD_STR), NULL);
+ UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);
+ FreePool (TmpStr1);
+
+ TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_NOTE_OFF), NULL);
+ StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+
+ TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_WARNING), NULL);
+ StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+
+ TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_ACCEPT_KEY), NULL);
+ StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+ break;
+
+ case SET_OWNER_INSTALL_TRUE:
+ TmpStr2 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_ALLOW_TAKE_OWNERSHIP), NULL);
+
+ TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_HEAD_STR), NULL);
+ UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);
+ FreePool (TmpStr1);
+
+ TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_ACCEPT_KEY), NULL);
+ StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+ break;
+
+ case SET_OWNER_INSTALL_FALSE:
+ TmpStr2 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_DISALLOW_TAKE_OWNERSHIP), NULL);
+
+ TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_HEAD_STR), NULL);
+ UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);
+ FreePool (TmpStr1);
+
+ TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_ACCEPT_KEY), NULL);
+ StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+ break;
+
+ case ENABLE_ACTIVATE_OWNER_TRUE:
+ TmpStr2 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_TURN_ON), NULL);
+
+ TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_HEAD_STR), NULL);
+ UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);
+ FreePool (TmpStr1);
+
+ TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_NOTE_ON), NULL);
+ StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+
+ TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_ACCEPT_KEY), NULL);
+ StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+ break;
+
+ case DEACTIVATE_DISABLE_OWNER_FALSE:
+ TmpStr2 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_TURN_OFF), NULL);
+
+ TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_HEAD_STR), NULL);
+ UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);
+ FreePool (TmpStr1);
+
+ TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_NOTE_OFF), NULL);
+ StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+
+ TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_WARNING), NULL);
+ StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+
+ TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_ACCEPT_KEY), NULL);
+ StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+ break;
+
+ case DEFERRED_PP_UNOWNERED_FIELD_UPGRADE:
+ CautionKey = TRUE;
+ TmpStr2 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_UNOWNED_FIELD_UPGRADE), NULL);
+
+ TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_UPGRADE_HEAD_STR), NULL);
+ UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);
+ FreePool (TmpStr1);
+
+ TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_WARNING_MAINTAIN), NULL);
+ StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+
+ TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_CAUTION_KEY), NULL);
+ StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+ break;
+
+ case SET_OPERATOR_AUTH:
+ //
+ // TPM_SetOperatorAuth
+ // This command requires UI to prompt user for Auth data
+ // Here it is NOT implemented
+ //
+ break;
+
+ case CLEAR_ENABLE_ACTIVATE:
+ CautionKey = TRUE;
+ TmpStr2 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_CLEAR_TURN_ON), NULL);
+
+ TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_HEAD_STR), NULL);
+ UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);
+ FreePool (TmpStr1);
+
+ TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_NOTE_ON), NULL);
+ StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+
+ TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_WARNING_CLEAR), NULL);
+ StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+
+ TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_WARNING_CLEAR_CONT), NULL);
+ StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+
+ TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_CAUTION_KEY), NULL);
+ StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+ break;
+
+ case SET_NO_PPI_PROVISION_TRUE:
+ TmpStr2 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_NO_PPI_PROVISION), NULL);
+
+ TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_PPI_HEAD_STR), NULL);
+ UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);
+ FreePool (TmpStr1);
+
+ TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_ACCEPT_KEY), NULL);
+ StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+
+ TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_NO_PPI_INFO), NULL);
+ StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+ break;
+
+ case SET_NO_PPI_CLEAR_TRUE:
+ CautionKey = TRUE;
+ TmpStr2 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_CLEAR), NULL);
+
+ TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_PPI_HEAD_STR), NULL);
+ UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);
+ FreePool (TmpStr1);
+
+ TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_NOTE_CLEAR), NULL);
+ StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+
+ TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_WARNING_CLEAR), NULL);
+ StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);
+ StrnCat (ConfirmText, L" \n\n", (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+
+ TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_CAUTION_KEY), NULL);
+ StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+
+ TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_NO_PPI_INFO), NULL);
+ StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+ break;
+
+ case SET_NO_PPI_MAINTENANCE_TRUE:
+ CautionKey = TRUE;
+ TmpStr2 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_NO_PPI_MAINTAIN), NULL);
+
+ TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_PPI_HEAD_STR), NULL);
+ UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);
+ FreePool (TmpStr1);
+
+ TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_WARNING_MAINTAIN), NULL);
+ StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+
+ TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_CAUTION_KEY), NULL);
+ StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+
+ TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_NO_PPI_INFO), NULL);
+ StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+ break;
+
+ case ENABLE_ACTIVATE_CLEAR:
+ CautionKey = TRUE;
+ TmpStr2 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_ENABLE_ACTIVATE_CLEAR), NULL);
+
+ TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_HEAD_STR), NULL);
+ UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);
+ FreePool (TmpStr1);
+
+ TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_WARNING_CLEAR), NULL);
+ StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);
+ StrnCat (ConfirmText, L" \n\n", (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+
+ TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_CAUTION_KEY), NULL);
+ StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+ break;
+
+ case ENABLE_ACTIVATE_CLEAR_ENABLE_ACTIVATE:
+ CautionKey = TRUE;
+ TmpStr2 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_ENABLE_ACTIVATE_CLEAR_ENABLE_ACTIVATE), NULL);
+
+ TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_HEAD_STR), NULL);
+ UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);
+ FreePool (TmpStr1);
+
+ TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_NOTE_ON), NULL);
+ StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+
+ TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_WARNING_CLEAR), NULL);
+ StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+
+ TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_WARNING_CLEAR_CONT), NULL);
+ StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+
+ TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_CAUTION_KEY), NULL);
+ StrnCat (ConfirmText, TmpStr1, (BufSize / sizeof (CHAR16 *)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+ break;
+
+ default:
+ ;
+ }
+
+ if (TmpStr2 == NULL) {
+ FreePool (ConfirmText);
+ return FALSE;
+ }
+
+ TmpStr1 = HiiGetString (mPpStringPackHandle, STRING_TOKEN (TPM_REJECT_KEY), NULL);
+ BufSize -= StrSize (ConfirmText);
+ UnicodeSPrint (ConfirmText + StrLen (ConfirmText), BufSize, TmpStr1, TmpStr2);
+
+ DstStr[80] = L'\0';
+ for (Index = 0; Index < StrLen (ConfirmText); Index += 80) {
+ StrnCpy(DstStr, ConfirmText + Index, 80);
+ Print (DstStr);
+ }
+
+ FreePool (TmpStr1);
+ FreePool (TmpStr2);
+ FreePool (ConfirmText);
+
+ if (ReadUserKey (CautionKey)) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Check and execute the requested physical presence command.
+
+ @param[in, out] TcgPpData Point to the physical presence NV variable.
+
+**/
+VOID
+ExecutePendingTpmRequest (
+ IN OUT EFI_PHYSICAL_PRESENCE *TcgPpData
+ )
+{
+ EFI_STATUS Status;
+ EFI_TCG_PROTOCOL *TcgProtocol;
+ UINTN DataSize;
+ UINT8 Flags;
+ BOOLEAN RequestConfirmed;
+
+ Flags = TcgPpData->Flags;
+ RequestConfirmed = FALSE;
+ switch (TcgPpData->PPRequest) {
+ case NO_ACTION:
+ return;
+ case ENABLE:
+ case DISABLE:
+ case ACTIVATE:
+ case DEACTIVATE:
+ case ENABLE_ACTIVATE:
+ case DEACTIVATE_DISABLE:
+ case SET_OWNER_INSTALL_TRUE:
+ case SET_OWNER_INSTALL_FALSE:
+ case ENABLE_ACTIVATE_OWNER_TRUE:
+ case DEACTIVATE_DISABLE_OWNER_FALSE:
+ case SET_OPERATOR_AUTH:
+ if ((Flags & FLAG_NO_PPI_PROVISION) != 0) {
+ RequestConfirmed = TRUE;
+ }
+ break;
+
+ case CLEAR:
+ case ENABLE_ACTIVATE_CLEAR:
+ if ((Flags & FLAG_NO_PPI_CLEAR) != 0) {
+ RequestConfirmed = TRUE;
+ }
+ break;
+
+ case DEFERRED_PP_UNOWNERED_FIELD_UPGRADE:
+ if ((Flags & FLAG_NO_PPI_MAINTENANCE) != 0) {
+ RequestConfirmed = TRUE;
+ }
+ break;
+
+ case CLEAR_ENABLE_ACTIVATE:
+ case ENABLE_ACTIVATE_CLEAR_ENABLE_ACTIVATE:
+ if ((Flags & FLAG_NO_PPI_CLEAR) != 0 && (Flags & FLAG_NO_PPI_PROVISION) != 0) {
+ RequestConfirmed = TRUE;
+ }
+ break;
+
+ case SET_NO_PPI_PROVISION_FALSE:
+ case SET_NO_PPI_CLEAR_FALSE:
+ case SET_NO_PPI_MAINTENANCE_FALSE:
+ RequestConfirmed = TRUE;
+ break;
+ }
+
+ if ((Flags & FLAG_RESET_TRACK) != 0) {
+ //
+ // It had been confirmed in last boot, it doesn't need confirm again.
+ //
+ RequestConfirmed = TRUE;
+ }
+
+ if (!RequestConfirmed) {
+ //
+ // Print confirm text and wait for approval.
+ //
+ RequestConfirmed = UserConfirm (TcgPpData->PPRequest);
+ }
+
+ //
+ // Execute requested physical presence command.
+ //
+ TcgPpData->PPResponse = TPM_PP_USER_ABORT;
+ if (RequestConfirmed) {
+ Status = gBS->LocateProtocol (&gEfiTcgProtocolGuid, NULL, (VOID**) &TcgProtocol);
+ ASSERT_EFI_ERROR (Status);
+ TcgPpData->PPResponse = ExecutePhysicalPresence (TcgProtocol, TcgPpData->PPRequest, &TcgPpData->Flags);
+ }
+
+ //
+ // Clear request
+ //
+ if ((TcgPpData->Flags & FLAG_RESET_TRACK) == 0) {
+ TcgPpData->LastPPRequest = TcgPpData->PPRequest;
+ TcgPpData->PPRequest = 0;
+ }
+
+ //
+ // Save changes
+ //
+ DataSize = sizeof (EFI_PHYSICAL_PRESENCE);
+ Status = gRT->SetVariable (
+ PHYSICAL_PRESENCE_VARIABLE,
+ &gEfiPhysicalPresenceGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ DataSize,
+ TcgPpData
+ );
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ if (TcgPpData->PPResponse == TPM_PP_USER_ABORT) {
+ return;
+ }
+
+ //
+ // Reset system to make new TPM settings in effect
+ //
+ switch (TcgPpData->LastPPRequest) {
+ case ACTIVATE:
+ case DEACTIVATE:
+ case CLEAR:
+ case ENABLE_ACTIVATE:
+ case DEACTIVATE_DISABLE:
+ case ENABLE_ACTIVATE_OWNER_TRUE:
+ case DEACTIVATE_DISABLE_OWNER_FALSE:
+ case DEFERRED_PP_UNOWNERED_FIELD_UPGRADE:
+ case CLEAR_ENABLE_ACTIVATE:
+ case ENABLE_ACTIVATE_CLEAR:
+ case ENABLE_ACTIVATE_CLEAR_ENABLE_ACTIVATE:
+ break;
+ default:
+ if (TcgPpData->PPRequest != 0) {
+ break;
+ }
+ return;
+ }
+
+ Print (L"Rebooting system to make TPM settings in effect\n");
+ gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);
+ ASSERT (FALSE);
+}
+
+/**
+ Check and execute the physical presence command requested and
+ Lock physical presence.
+
+ @param[in] Event Event whose notification function is being invoked
+ @param[in] Context Pointer to the notification function's context
+
+**/
+VOID
+EFIAPI
+OnReadyToBoot (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN LifetimeLock;
+ BOOLEAN CmdEnable;
+ UINTN DataSize;
+ EFI_PHYSICAL_PRESENCE TcgPpData;
+
+ //
+ // Check pending request, if not exist, just return.
+ //
+ DataSize = sizeof (EFI_PHYSICAL_PRESENCE);
+ Status = gRT->GetVariable (
+ PHYSICAL_PRESENCE_VARIABLE,
+ &gEfiPhysicalPresenceGuid,
+ NULL,
+ &DataSize,
+ &TcgPpData
+ );
+ ASSERT_EFI_ERROR (Status);
+ DEBUG ((EFI_D_INFO, "[TPM] Flags=%x, PPRequest=%x\n", TcgPpData.Flags, TcgPpData.PPRequest));
+
+ Status = GetTpmCapability (&LifetimeLock, &CmdEnable);
+ if (EFI_ERROR (Status)) {
+ return ;
+ }
+
+ if (!CmdEnable) {
+ if (LifetimeLock) {
+ //
+ // physicalPresenceCMDEnable is locked, can't execute physical presence command.
+ //
+ return ;
+ }
+ Status = TpmPhysicalPresence (TPM_PHYSICAL_PRESENCE_CMD_ENABLE);
+ if (EFI_ERROR (Status)) {
+ return ;
+ }
+ }
+
+ //
+ // Set operator physical presence flags
+ //
+ TpmPhysicalPresence (TPM_PHYSICAL_PRESENCE_PRESENT);
+
+ //
+ // Execute pending TPM request.
+ //
+ ExecutePendingTpmRequest (&TcgPpData);
+ DEBUG ((EFI_D_INFO, "[TPM] PPResponse = %x\n", TcgPpData.PPResponse));
+
+ //
+ // Lock physical presence.
+ //
+ TpmPhysicalPresence (TPM_PHYSICAL_PRESENCE_NOTPRESENT | TPM_PHYSICAL_PRESENCE_LOCK);
+}
+
+/**
+ The driver's entry point.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The entry point is executed successfully.
+ @retval other Some error occurs when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+DriverEntry (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_EVENT Event;
+ EFI_STATUS Status;
+ UINTN DataSize;
+ EFI_PHYSICAL_PRESENCE TcgPpData;
+
+ //
+ // Initialize physical presence variable exists.
+ //
+ DataSize = sizeof (EFI_PHYSICAL_PRESENCE);
+ Status = gRT->GetVariable (
+ PHYSICAL_PRESENCE_VARIABLE,
+ &gEfiPhysicalPresenceGuid,
+ NULL,
+ &DataSize,
+ &TcgPpData
+ );
+ if (EFI_ERROR (Status)) {
+ if (Status == EFI_NOT_FOUND) {
+ ZeroMem ((VOID*)&TcgPpData, sizeof (TcgPpData));
+ TcgPpData.Flags |= FLAG_NO_PPI_PROVISION;
+ DataSize = sizeof (EFI_PHYSICAL_PRESENCE);
+ Status = gRT->SetVariable (
+ PHYSICAL_PRESENCE_VARIABLE,
+ &gEfiPhysicalPresenceGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ DataSize,
+ &TcgPpData
+ );
+ }
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ //
+ // TPL Level of physical presence should be larger
+ // than one of TcgDxe driver (TPL_CALLBACK)
+ //
+ Status = EfiCreateEventReadyToBootEx (
+ TPL_CALLBACK,
+ OnReadyToBoot,
+ NULL,
+ &Event
+ );
+ return Status;
+}
+
diff --git a/SecurityPkg/Tcg/PhysicalPresenceDxe/PhysicalPresence.h b/SecurityPkg/Tcg/PhysicalPresenceDxe/PhysicalPresence.h
new file mode 100644
index 0000000000..63d6f21cae
--- /dev/null
+++ b/SecurityPkg/Tcg/PhysicalPresenceDxe/PhysicalPresence.h
@@ -0,0 +1,38 @@
+/** @file
+ The header file for TPM physical presence driver.
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __PHYSICAL_PRESENCE_H__
+#define __PHYSICAL_PRESENCE_H__
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define TPM_PP_USER_ABORT ((TPM_RESULT)(-0x10))
+#define TPM_PP_BIOS_FAILURE ((TPM_RESULT)(-0x0f))
+
+#define CONFIRM_BUFFER_SIZE 4096
+
+#endif
diff --git a/SecurityPkg/Tcg/PhysicalPresenceDxe/PhysicalPresenceDxe.inf b/SecurityPkg/Tcg/PhysicalPresenceDxe/PhysicalPresenceDxe.inf
new file mode 100644
index 0000000000..9b4aded16f
--- /dev/null
+++ b/SecurityPkg/Tcg/PhysicalPresenceDxe/PhysicalPresenceDxe.inf
@@ -0,0 +1,61 @@
+## @file
+# Component file for PhysicalPresenceDxe driver.
+#
+# Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PhysicalPresenceDxe
+ FILE_GUID = D85A4A0C-2E73-4491-92E1-DCEFC3882A68
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = DriverEntry
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF
+#
+
+[Sources]
+ PhysicalPresence.c
+ PhysicalPresence.h
+ PhysicalPresenceStrings.uni
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+ MemoryAllocationLib
+ UefiLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ UefiRuntimeServicesTableLib
+ BaseMemoryLib
+ DebugLib
+ PrintLib
+ HiiLib
+
+[Protocols]
+ gEfiTcgProtocolGuid
+
+[Guids]
+ gEfiPhysicalPresenceGuid
+
+[Depex]
+ gEfiTcgProtocolGuid AND
+ gEfiVariableArchProtocolGuid AND
+ gEfiVariableWriteArchProtocolGuid AND
+ gEfiResetArchProtocolGuid
+
diff --git a/SecurityPkg/Tcg/PhysicalPresenceDxe/PhysicalPresenceStrings.uni b/SecurityPkg/Tcg/PhysicalPresenceDxe/PhysicalPresenceStrings.uni
new file mode 100644
index 0000000000..2034af7a95
Binary files /dev/null and b/SecurityPkg/Tcg/PhysicalPresenceDxe/PhysicalPresenceStrings.uni differ
diff --git a/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePei.c b/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePei.c
new file mode 100644
index 0000000000..e694db8cf1
--- /dev/null
+++ b/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePei.c
@@ -0,0 +1,134 @@
+/** @file
+ This driver produces PEI_LOCK_PHYSICAL_PRESENCE_PPI to indicate
+ whether TPM need be locked or not. It can be replaced by a platform
+ specific driver.
+
+Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+/**
+ This interface returns whether TPM physical presence needs be locked or not.
+
+ @param[in] PeiServices The pointer to the PEI Services Table.
+
+ @retval TRUE The TPM physical presence should be locked.
+ @retval FALSE The TPM physical presence cannot be locked.
+
+**/
+BOOLEAN
+EFIAPI
+LockTpmPhysicalPresence (
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ );
+
+//
+// Gobal defintions for lock physical presence PPI and its descriptor.
+//
+PEI_LOCK_PHYSICAL_PRESENCE_PPI mLockPhysicalPresencePpi = {
+ LockTpmPhysicalPresence
+};
+
+EFI_PEI_PPI_DESCRIPTOR mLockPhysicalPresencePpiList = {
+ EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
+ &gPeiLockPhysicalPresencePpiGuid,
+ &mLockPhysicalPresencePpi
+};
+
+/**
+ This interface returns whether TPM physical presence needs be locked or not.
+
+ @param[in] PeiServices The pointer to the PEI Services Table.
+
+ @retval TRUE The TPM physical presence should be locked.
+ @retval FALSE The TPM physical presence cannot be locked.
+
+**/
+BOOLEAN
+EFIAPI
+LockTpmPhysicalPresence (
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ EFI_STATUS Status;
+ EFI_PEI_READ_ONLY_VARIABLE2_PPI *Variable;
+ UINTN DataSize;
+ EFI_PHYSICAL_PRESENCE TcgPpData;
+
+ //
+ // The CRTM has sensed the physical presence assertion of the user. For example,
+ // the user has pressed the startup button or inserted a USB dongle. The details
+ // of the implementation are vendor-specific. Here we read a PCD value to indicate
+ // whether operator physical presence.
+ //
+ if (!PcdGetBool (PcdTpmPhysicalPresence)) {
+ return TRUE;
+ }
+
+ //
+ // Check the pending TPM requests. Lock TPM physical presence if there is no TPM
+ // request.
+ //
+ Status = PeiServicesLocatePpi (
+ &gEfiPeiReadOnlyVariable2PpiGuid,
+ 0,
+ NULL,
+ (VOID **)&Variable
+ );
+ if (!EFI_ERROR (Status)) {
+ DataSize = sizeof (EFI_PHYSICAL_PRESENCE);
+ Status = Variable->GetVariable (
+ Variable,
+ PHYSICAL_PRESENCE_VARIABLE,
+ &gEfiPhysicalPresenceGuid,
+ NULL,
+ &DataSize,
+ &TcgPpData
+ );
+ if (!EFI_ERROR (Status)) {
+ if (TcgPpData.PPRequest != 0) {
+ return FALSE;
+ }
+ }
+ }
+
+ //
+ // Lock TPM physical presence by default.
+ //
+ return TRUE;
+}
+
+/**
+ Entry point of this module.
+
+ It installs lock physical presence PPI.
+
+ @param[in] FileHandle Handle of the file being invoked.
+ @param[in] PeiServices Describes the list of possible PEI Services.
+
+ @return Status of install lock physical presence PPI.
+
+**/
+EFI_STATUS
+EFIAPI
+PeimEntry (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ return PeiServicesInstallPpi (&mLockPhysicalPresencePpiList);
+}
diff --git a/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePei.inf b/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePei.inf
new file mode 100644
index 0000000000..da4e032299
--- /dev/null
+++ b/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePei.inf
@@ -0,0 +1,55 @@
+## @file
+# Component description file for physical presence PEI module.
+#
+# Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved.
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PhysicalPresencePei
+ FILE_GUID = 4FE772E8-FE3E-4086-B638-8C493C490488
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = PeimEntry
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF
+#
+
+[Sources]
+ PhysicalPresencePei.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+ PeimEntryPoint
+ PeiServicesLib
+
+[Ppis]
+ gPeiLockPhysicalPresencePpiGuid
+ gEfiPeiReadOnlyVariable2PpiGuid
+
+[Guids]
+ gEfiPhysicalPresenceGuid
+
+[Pcd]
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpmPhysicalPresence
+
+[Depex]
+ gEfiPeiMemoryDiscoveredPpiGuid AND
+ gEfiPeiReadOnlyVariable2PpiGuid AND
+ gPeiTpmInitializedPpiGuid
diff --git a/SecurityPkg/Tcg/TcgConfigDxe/TcgConfig.vfr b/SecurityPkg/Tcg/TcgConfigDxe/TcgConfig.vfr
new file mode 100644
index 0000000000..360e5569f2
--- /dev/null
+++ b/SecurityPkg/Tcg/TcgConfigDxe/TcgConfig.vfr
@@ -0,0 +1,114 @@
+/** @file
+ VFR file used by the TCG configuration component.
+
+Copyright (c) 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "TcgConfigNvData.h"
+
+formset
+ guid = TCG_CONFIG_PRIVATE_GUID,
+ title = STRING_TOKEN(STR_TPM_TITLE),
+ help = STRING_TOKEN(STR_TPM_HELP),
+ classguid = EFI_HII_PLATFORM_SETUP_FORMSET_GUID,
+
+ varstore TCG_CONFIGURATION,
+ varid = TCG_CONFIGURATION_VARSTORE_ID,
+ name = TCG_CONFIGURATION,
+ guid = TCG_CONFIG_PRIVATE_GUID;
+
+ form formid = TCG_CONFIGURATION_FORM_ID,
+ title = STRING_TOKEN(STR_TPM_TITLE);
+
+ subtitle text = STRING_TOKEN(STR_NULL);
+
+ suppressif TRUE;
+ checkbox varid = TCG_CONFIGURATION.TpmEnable,
+ prompt = STRING_TOKEN(STR_NULL),
+ help = STRING_TOKEN(STR_NULL),
+ endcheckbox;
+ endif;
+
+ suppressif TRUE;
+ checkbox varid = TCG_CONFIGURATION.TpmActivate,
+ prompt = STRING_TOKEN(STR_NULL),
+ help = STRING_TOKEN(STR_NULL),
+ endcheckbox;
+ endif;
+
+ suppressif TRUE;
+ checkbox varid = TCG_CONFIGURATION.OriginalHideTpm,
+ prompt = STRING_TOKEN(STR_NULL),
+ help = STRING_TOKEN(STR_NULL),
+ endcheckbox;
+ endif;
+
+ text
+ help = STRING_TOKEN(STR_TPM_STATE_HELP),
+ text = STRING_TOKEN(STR_TPM_STATE_PROMPT),
+ text = STRING_TOKEN(STR_TPM_STATE_CONTENT);
+
+ subtitle text = STRING_TOKEN(STR_NULL);
+
+ label LABEL_TCG_CONFIGURATION_HIDETPM;
+
+ checkbox varid = TCG_CONFIGURATION.HideTpm,
+ questionid = KEY_HIDE_TPM,
+ prompt = STRING_TOKEN(STR_HIDE_TPM_PROMPT),
+ help = STRING_TOKEN(STR_HIDE_TPM_HELP),
+ flags = RESET_REQUIRED,
+ endcheckbox;
+
+ label LABEL_END;
+
+ grayoutif ideqval TCG_CONFIGURATION.OriginalHideTpm == 1;
+ oneof varid = TCG_CONFIGURATION.TpmOperation,
+ questionid = KEY_TPM_ACTION,
+ prompt = STRING_TOKEN(STR_TPM_OPERATION),
+ help = STRING_TOKEN(STR_TPM_OPERATION_HELP),
+ flags = INTERACTIVE,
+ //
+ // Disable (TPM_ORD_PhysicalDisable) command is not available when disabled.
+ // Activate/deactivate (TPM_ORD_physicalSetDeactivated) command is not available when disabled.
+ //
+ suppressif ideqval TCG_CONFIGURATION.TpmEnable == 0;
+ option text = STRING_TOKEN(STR_DISABLE), value = DISABLE, flags = 0;
+ option text = STRING_TOKEN(STR_TPM_ACTIVATE), value = ACTIVATE, flags = 0;
+ option text = STRING_TOKEN(STR_TPM_DEACTIVATE), value = DEACTIVATE, flags = 0;
+ option text = STRING_TOKEN(STR_TPM_DEACTIVATE_DISABLE), value = DEACTIVATE_DISABLE, flags = 0;
+ endif
+ //
+ // Clear (TPM_ORD_ForceClear) command is not available when disabled or deactivated.
+ //
+ suppressif ideqval TCG_CONFIGURATION.TpmEnable == 0 OR
+ ideqval TCG_CONFIGURATION.TpmActivate == 0;
+ option text = STRING_TOKEN(STR_TPM_CLEAR), value = CLEAR, flags = 0;
+ option text = STRING_TOKEN(STR_TPM_CLEAR_ENABLE_ACTIVATE), value = CLEAR_ENABLE_ACTIVATE, flags = 0;
+ endif
+
+ option text = STRING_TOKEN(STR_ENABLE), value = ENABLE, flags = 0;
+ option text = STRING_TOKEN(STR_TPM_ENABLE_ACTIVATE), value = ENABLE_ACTIVATE, flags = 0;
+ option text = STRING_TOKEN(STR_TPM_ENABLE_ACTIVATE_CLEAR), value = ENABLE_ACTIVATE_CLEAR, flags = 0;
+ option text = STRING_TOKEN(STR_TPM_ENABLE_ACTIVATE_CLEAR_E_A), value = ENABLE_ACTIVATE_CLEAR_ENABLE_ACTIVATE, flags = 0;
+ endoneof;
+
+ subtitle text = STRING_TOKEN(STR_NULL);
+
+ checkbox varid = TCG_CONFIGURATION.MorState,
+ questionid = KEY_TPM_MOR_ENABLE,
+ prompt = STRING_TOKEN(STR_MOR_PROMPT),
+ help = STRING_TOKEN(STR_MOR_HELP),
+ endcheckbox;
+ endif;
+
+ endform;
+
+endformset;
diff --git a/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDriver.c b/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDriver.c
new file mode 100644
index 0000000000..4b2008f577
--- /dev/null
+++ b/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDriver.c
@@ -0,0 +1,147 @@
+/** @file
+ The module entry point for Tcg configuration module.
+
+Copyright (c) 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "TcgConfigImpl.h"
+
+EFI_GUID gTcgConfigPrivateGuid = TCG_CONFIG_PRIVATE_GUID;
+
+/**
+ The entry point for Tcg configuration driver.
+
+ @param[in] ImageHandle The image handle of the driver.
+ @param[in] SystemTable The system table.
+
+ @retval EFI_ALREADY_STARTED The driver already exists in system.
+ @retval EFI_OUT_OF_RESOURCES Fail to execute entry point due to lack of resources.
+ @retval EFI_SUCCES All the related protocols are installed on the driver.
+ @retval Others Fail to install protocols as indicated.
+
+**/
+EFI_STATUS
+EFIAPI
+TcgConfigDriverEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ TCG_CONFIG_PRIVATE_DATA *PrivateData;
+ EFI_TCG_PROTOCOL *TcgProtocol;
+
+ Status = TisPcRequestUseTpm ((TIS_TPM_HANDLE) (UINTN) TPM_BASE_ADDRESS);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "TPM not detected!\n"));
+ return Status;
+ }
+
+ Status = gBS->LocateProtocol (&gEfiTcgProtocolGuid, NULL, (VOID **) &TcgProtocol);
+ if (EFI_ERROR (Status)) {
+ TcgProtocol = NULL;
+ }
+
+ Status = gBS->OpenProtocol (
+ ImageHandle,
+ &gTcgConfigPrivateGuid,
+ NULL,
+ ImageHandle,
+ ImageHandle,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+ if (!EFI_ERROR (Status)) {
+ return EFI_ALREADY_STARTED;
+ }
+
+ //
+ // Create a private data structure.
+ //
+ PrivateData = AllocateCopyPool (sizeof (TCG_CONFIG_PRIVATE_DATA), &mTcgConfigPrivateDateTemplate);
+ if (PrivateData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ PrivateData->TcgProtocol = TcgProtocol;
+ PrivateData->HideTpm = PcdGetBool (PcdHideTpmSupport) && PcdGetBool (PcdHideTpm);
+
+ //
+ // Install TCG configuration form
+ //
+ Status = InstallTcgConfigForm (PrivateData);
+ if (EFI_ERROR (Status)) {
+ goto ErrorExit;
+ }
+
+ //
+ // Install private GUID.
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &ImageHandle,
+ &gTcgConfigPrivateGuid,
+ PrivateData,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto ErrorExit;
+ }
+
+ return EFI_SUCCESS;
+
+ErrorExit:
+ if (PrivateData != NULL) {
+ UninstallTcgConfigForm (PrivateData);
+ }
+
+ return Status;
+}
+
+/**
+ Unload the Tcg configuration form.
+
+ @param[in] ImageHandle The driver's image handle.
+
+ @retval EFI_SUCCESS The Tcg configuration form is unloaded.
+ @retval Others Failed to unload the form.
+
+**/
+EFI_STATUS
+EFIAPI
+TcgConfigDriverUnload (
+ IN EFI_HANDLE ImageHandle
+ )
+{
+ EFI_STATUS Status;
+ TCG_CONFIG_PRIVATE_DATA *PrivateData;
+
+ Status = gBS->HandleProtocol (
+ ImageHandle,
+ &gTcgConfigPrivateGuid,
+ (VOID **) &PrivateData
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ASSERT (PrivateData->Signature == TCG_CONFIG_PRIVATE_DATA_SIGNATURE);
+
+ gBS->UninstallMultipleProtocolInterfaces (
+ &ImageHandle,
+ &gTcgConfigPrivateGuid,
+ PrivateData,
+ NULL
+ );
+
+ UninstallTcgConfigForm (PrivateData);
+
+ return EFI_SUCCESS;
+}
diff --git a/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDxe.inf b/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDxe.inf
new file mode 100644
index 0000000000..d9d3102668
--- /dev/null
+++ b/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDxe.inf
@@ -0,0 +1,75 @@
+## @file
+# Component name for Tcg configuration module.
+#
+# Copyright (c) 2011, Intel Corporation. All rights reserved.
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = TcgConfigDxe
+ FILE_GUID = 1FA4DAFE-FA5D-4d75-BEA6-5863862C520A
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = TcgConfigDriverEntryPoint
+ UNLOAD_IMAGE = TcgConfigDriverUnload
+
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ TcgConfigDriver.c
+ TcgConfigImpl.c
+ TcgConfigImpl.h
+ TcgConfig.vfr
+ TcgConfigStrings.uni
+ TcgConfigNvData.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ MemoryAllocationLib
+ UefiLib
+ UefiBootServicesTableLib
+ UefiRuntimeServicesTableLib
+ UefiDriverEntryPoint
+ UefiHiiServicesLib
+ DebugLib
+ HiiLib
+ PcdLib
+ PrintLib
+ TpmCommLib
+
+[Guids]
+ gEfiPhysicalPresenceGuid
+ gEfiIfrTianoGuid
+
+[Protocols]
+ gEfiHiiConfigAccessProtocolGuid ## PRODUCES
+ gEfiHiiConfigRoutingProtocolGuid ## CONSUMES
+ gEfiTcgProtocolGuid ## CONSUMES
+
+[FixedPcd]
+ gEfiSecurityPkgTokenSpaceGuid.PcdHideTpmSupport
+
+[Pcd]
+ gEfiSecurityPkgTokenSpaceGuid.PcdMorEnable
+ gEfiSecurityPkgTokenSpaceGuid.PcdHideTpm
+
+[Depex]
+ gEfiHiiConfigRoutingProtocolGuid AND
+ gEfiHiiDatabaseProtocolGuid AND
+ gEfiVariableArchProtocolGuid AND
+ gEfiVariableWriteArchProtocolGuid
\ No newline at end of file
diff --git a/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigImpl.c b/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigImpl.c
new file mode 100644
index 0000000000..535f5e852a
--- /dev/null
+++ b/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigImpl.c
@@ -0,0 +1,555 @@
+/** @file
+ HII Config Access protocol implementation of TCG configuration module.
+
+Copyright (c) 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "TcgConfigImpl.h"
+
+EFI_GUID mTcgFormSetGuid = TCG_CONFIG_PRIVATE_GUID;
+CHAR16 mTcgStorageName[] = L"TCG_CONFIGURATION";
+
+TCG_CONFIG_PRIVATE_DATA mTcgConfigPrivateDateTemplate = {
+ TCG_CONFIG_PRIVATE_DATA_SIGNATURE,
+ {
+ TcgExtractConfig,
+ TcgRouteConfig,
+ TcgCallback
+ }
+};
+
+HII_VENDOR_DEVICE_PATH mTcgHiiVendorDevicePath = {
+ {
+ {
+ HARDWARE_DEVICE_PATH,
+ HW_VENDOR_DP,
+ {
+ (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
+ (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
+ }
+ },
+ TCG_CONFIG_PRIVATE_GUID
+ },
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ (UINT8) (END_DEVICE_PATH_LENGTH),
+ (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
+ }
+ }
+};
+
+/**
+ Get current state of TPM device.
+
+ @param[in] TcgProtocol Point to EFI_TCG_PROTOCOL instance.
+ @param[out] TpmEnable Flag to indicate TPM is enabled or not.
+ @param[out] TpmActivate Flag to indicate TPM is activated or not.
+
+ @retval EFI_SUCCESS State is successfully returned.
+ @retval EFI_DEVICE_ERROR Failed to get TPM response.
+ @retval Others Other errors as indicated.
+
+**/
+EFI_STATUS
+GetTpmState (
+ IN EFI_TCG_PROTOCOL *TcgProtocol,
+ OUT BOOLEAN *TpmEnable, OPTIONAL
+ OUT BOOLEAN *TpmActivate OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ TPM_RSP_COMMAND_HDR *TpmRsp;
+ UINT32 TpmSendSize;
+ TPM_PERMANENT_FLAGS *TpmPermanentFlags;
+ UINT8 CmdBuf[64];
+
+ ASSERT (TcgProtocol != NULL);
+
+ //
+ // Get TPM Permanent flags (TpmEnable, TpmActivate)
+ //
+ if ((TpmEnable != NULL) || (TpmActivate != NULL)) {
+ TpmSendSize = sizeof (TPM_RQU_COMMAND_HDR) + sizeof (UINT32) * 3;
+ *(UINT16*)&CmdBuf[0] = H2NS (TPM_TAG_RQU_COMMAND);
+ *(UINT32*)&CmdBuf[2] = H2NL (TpmSendSize);
+ *(UINT32*)&CmdBuf[6] = H2NL (TPM_ORD_GetCapability);
+
+ *(UINT32*)&CmdBuf[10] = H2NL (TPM_CAP_FLAG);
+ *(UINT32*)&CmdBuf[14] = H2NL (sizeof (TPM_CAP_FLAG_PERMANENT));
+ *(UINT32*)&CmdBuf[18] = H2NL (TPM_CAP_FLAG_PERMANENT);
+
+ Status = TcgProtocol->PassThroughToTpm (
+ TcgProtocol,
+ TpmSendSize,
+ CmdBuf,
+ sizeof (CmdBuf),
+ CmdBuf
+ );
+ TpmRsp = (TPM_RSP_COMMAND_HDR *) &CmdBuf[0];
+ if (EFI_ERROR (Status) || (TpmRsp->tag != H2NS (TPM_TAG_RSP_COMMAND)) || (TpmRsp->returnCode != 0)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ TpmPermanentFlags = (TPM_PERMANENT_FLAGS *) &CmdBuf[sizeof (TPM_RSP_COMMAND_HDR) + sizeof (UINT32)];
+
+ if (TpmEnable != NULL) {
+ *TpmEnable = (BOOLEAN) !TpmPermanentFlags->disable;
+ }
+
+ if (TpmActivate != NULL) {
+ *TpmActivate = (BOOLEAN) !TpmPermanentFlags->deactivated;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function allows a caller to extract the current configuration for one
+ or more named elements from the target driver.
+
+ @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param[in] Request A null-terminated Unicode string in
+ format.
+ @param[out] Progress On return, points to a character in the Request
+ string. Points to the string's null terminator if
+ request was successful. Points to the most recent
+ '&' before the first failing name/value pair (or
+ the beginning of the string if the failure is in
+ the first name/value pair) if the request was not
+ successful.
+ @param[out] Results A null-terminated Unicode string in
+ format which has all values filled
+ in for the names in the Request string. String to
+ be allocated by the called function.
+
+ @retval EFI_SUCCESS The Results is filled with the requested values.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results.
+ @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name.
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in this
+ driver.
+
+**/
+EFI_STATUS
+EFIAPI
+TcgExtractConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Request,
+ OUT EFI_STRING *Progress,
+ OUT EFI_STRING *Results
+ )
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+ TCG_CONFIGURATION Configuration;
+ TCG_CONFIG_PRIVATE_DATA *PrivateData;
+ EFI_STRING ConfigRequestHdr;
+ EFI_STRING ConfigRequest;
+ BOOLEAN AllocatedRequest;
+ UINTN Size;
+ BOOLEAN TpmEnable;
+ BOOLEAN TpmActivate;
+ CHAR16 State[32];
+
+ if (Progress == NULL || Results == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *Progress = Request;
+ if ((Request != NULL) && !HiiIsConfigHdrMatch (Request, &mTcgFormSetGuid, mTcgStorageName)) {
+ return EFI_NOT_FOUND;
+ }
+
+ ConfigRequestHdr = NULL;
+ ConfigRequest = NULL;
+ AllocatedRequest = FALSE;
+ Size = 0;
+
+ PrivateData = TCG_CONFIG_PRIVATE_DATA_FROM_THIS (This);
+
+ //
+ // Convert buffer data to by helper function BlockToConfig()
+ //
+ ZeroMem (&Configuration, sizeof (TCG_CONFIGURATION));
+
+ Configuration.MorState = PcdGetBool (PcdMorEnable);
+ Configuration.TpmOperation = ENABLE;
+ Configuration.HideTpm = PcdGetBool (PcdHideTpmSupport) && PcdGetBool (PcdHideTpm);
+ //
+ // Read the original value of HideTpm from PrivateData which won't be changed by Setup in this boot.
+ //
+ Configuration.OriginalHideTpm = PrivateData->HideTpm;
+
+ //
+ // Display current TPM state.
+ //
+ if (PrivateData->TcgProtocol != NULL) {
+ Status = GetTpmState (PrivateData->TcgProtocol, &TpmEnable, &TpmActivate);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ UnicodeSPrint (
+ State,
+ sizeof (State),
+ L"%s, and %s",
+ TpmEnable ? L"Enabled" : L"Disabled",
+ TpmActivate ? L"Activated" : L"Deactivated"
+ );
+ Configuration.TpmEnable = TpmEnable;
+ Configuration.TpmActivate = TpmActivate;
+
+ HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_TPM_STATE_CONTENT), State, NULL);
+ }
+
+ BufferSize = sizeof (Configuration);
+ ConfigRequest = Request;
+ if ((Request == NULL) || (StrStr (Request, L"OFFSET") == NULL)) {
+ //
+ // Request has no request element, construct full request string.
+ // Allocate and fill a buffer large enough to hold the template
+ // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator
+ //
+ ConfigRequestHdr = HiiConstructConfigHdr (&mTcgFormSetGuid, mTcgStorageName, PrivateData->DriverHandle);
+ Size = (StrLen (ConfigRequestHdr) + 32 + 1) * sizeof (CHAR16);
+ ConfigRequest = AllocateZeroPool (Size);
+ ASSERT (ConfigRequest != NULL);
+ AllocatedRequest = TRUE;
+ UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", ConfigRequestHdr, (UINT64) BufferSize);
+ FreePool (ConfigRequestHdr);
+ }
+
+ Status = gHiiConfigRouting->BlockToConfig (
+ gHiiConfigRouting,
+ ConfigRequest,
+ (UINT8 *) &Configuration,
+ BufferSize,
+ Results,
+ Progress
+ );
+ //
+ // Free the allocated config request string.
+ //
+ if (AllocatedRequest) {
+ FreePool (ConfigRequest);
+ }
+ //
+ // Set Progress string to the original request string.
+ //
+ if (Request == NULL) {
+ *Progress = NULL;
+ } else if (StrStr (Request, L"OFFSET") == NULL) {
+ *Progress = Request + StrLen (Request);
+ }
+
+ return Status;
+}
+
+/**
+ This function processes the results of changes in configuration.
+
+ @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param[in] Configuration A null-terminated Unicode string in
+ format.
+ @param[out] Progress A pointer to a string filled in with the offset of
+ the most recent '&' before the first failing
+ name/value pair (or the beginning of the string if
+ the failure is in the first name/value pair) or
+ the terminating NULL if all was successful.
+
+ @retval EFI_SUCCESS The Results is processed successfully.
+ @retval EFI_INVALID_PARAMETER Configuration is NULL.
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in this
+ driver.
+
+**/
+EFI_STATUS
+EFIAPI
+TcgRouteConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Configuration,
+ OUT EFI_STRING *Progress
+ )
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+ TCG_CONFIGURATION TcgConfiguration;
+
+ if (Configuration == NULL || Progress == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *Progress = Configuration;
+ if (!HiiIsConfigHdrMatch (Configuration, &mTcgFormSetGuid, mTcgStorageName)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Convert to buffer data by helper function ConfigToBlock()
+ //
+ BufferSize = sizeof (TCG_CONFIGURATION);
+ Status = gHiiConfigRouting->ConfigToBlock (
+ gHiiConfigRouting,
+ Configuration,
+ (UINT8 *) &TcgConfiguration,
+ &BufferSize,
+ Progress
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ PcdSetBool (PcdMorEnable, TcgConfiguration.MorState);
+ PcdSetBool (PcdHideTpm, TcgConfiguration.HideTpm);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Save TPM request to variable space.
+
+ @param[in] PpRequest Physical Presence request command.
+
+ @retval EFI_SUCCESS The operation is finished successfully.
+ @retval Others Other errors as indicated.
+
+**/
+EFI_STATUS
+SavePpRequest (
+ IN UINT8 PpRequest
+ )
+{
+ EFI_STATUS Status;
+ UINTN DataSize;
+ EFI_PHYSICAL_PRESENCE PpData;
+
+ //
+ // Save TPM command to variable.
+ //
+ DataSize = sizeof (EFI_PHYSICAL_PRESENCE);
+ Status = gRT->GetVariable (
+ PHYSICAL_PRESENCE_VARIABLE,
+ &gEfiPhysicalPresenceGuid,
+ NULL,
+ &DataSize,
+ &PpData
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ PpData.PPRequest = PpRequest;
+ Status = gRT->SetVariable (
+ PHYSICAL_PRESENCE_VARIABLE,
+ &gEfiPhysicalPresenceGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ DataSize,
+ &PpData
+ );
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ //
+ // Reset system.
+ //
+ gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function processes the results of changes in configuration.
+
+ @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param[in] Action Specifies the type of action taken by the browser.
+ @param[in] QuestionId A unique value which is sent to the original
+ exporting driver so that it can identify the type
+ of data to expect.
+ @param[in] Type The type of value for the question.
+ @param[in] Value A pointer to the data being sent to the original
+ exporting driver.
+ @param[out] ActionRequest On return, points to the action requested by the
+ callback function.
+
+ @retval EFI_SUCCESS The callback successfully handled the action.
+ @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the
+ variable and its data.
+ @retval EFI_DEVICE_ERROR The variable could not be saved.
+ @retval EFI_UNSUPPORTED The specified Action is not supported by the
+ callback.
+
+**/
+EFI_STATUS
+EFIAPI
+TcgCallback (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN EFI_BROWSER_ACTION Action,
+ IN EFI_QUESTION_ID QuestionId,
+ IN UINT8 Type,
+ IN EFI_IFR_TYPE_VALUE *Value,
+ OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
+ )
+{
+ if ((This == NULL) || (Value == NULL) || (ActionRequest == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Action != EFI_BROWSER_ACTION_CHANGING) || (QuestionId != KEY_TPM_ACTION)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ SavePpRequest (Value->u8);
+ ASSERT (FALSE);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function publish the TCG configuration Form for TPM device.
+
+ @param[in, out] PrivateData Points to TCG configuration private data.
+
+ @retval EFI_SUCCESS HII Form is installed for this network device.
+ @retval EFI_OUT_OF_RESOURCES Not enough resource for HII Form installation.
+ @retval Others Other errors as indicated.
+
+**/
+EFI_STATUS
+InstallTcgConfigForm (
+ IN OUT TCG_CONFIG_PRIVATE_DATA *PrivateData
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_HANDLE HiiHandle;
+ EFI_HANDLE DriverHandle;
+ VOID *StartOpCodeHandle;
+ VOID *EndOpCodeHandle;
+ EFI_IFR_GUID_LABEL *StartLabel;
+ EFI_IFR_GUID_LABEL *EndLabel;
+
+ EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
+
+ DriverHandle = NULL;
+ ConfigAccess = &PrivateData->ConfigAccess;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &DriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mTcgHiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ ConfigAccess,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ PrivateData->DriverHandle = DriverHandle;
+
+ //
+ // Publish the HII package list
+ //
+ HiiHandle = HiiAddPackages (
+ &mTcgFormSetGuid,
+ DriverHandle,
+ TcgConfigDxeStrings,
+ TcgConfigBin,
+ NULL
+ );
+ if (HiiHandle == NULL) {
+ gBS->UninstallMultipleProtocolInterfaces (
+ DriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mTcgHiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ ConfigAccess,
+ NULL
+ );
+
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ PrivateData->HiiHandle = HiiHandle;
+
+ //
+ // Remove the Hide TPM question from the IFR
+ //
+ if (!PcdGetBool (PcdHideTpmSupport)) {
+ //
+ // Allocate space for creation of UpdateData Buffer
+ //
+ StartOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (StartOpCodeHandle != NULL);
+
+ EndOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (EndOpCodeHandle != NULL);
+
+ //
+ // Create Hii Extend Label OpCode as the start opcode
+ //
+ StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
+ StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
+ StartLabel->Number = LABEL_TCG_CONFIGURATION_HIDETPM;
+
+ //
+ // Create Hii Extend Label OpCode as the end opcode
+ //
+ EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (EndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
+ EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
+ EndLabel->Number = LABEL_END;
+
+ HiiUpdateForm (HiiHandle, NULL, TCG_CONFIGURATION_FORM_ID, StartOpCodeHandle, EndOpCodeHandle);
+
+ HiiFreeOpCodeHandle (StartOpCodeHandle);
+ HiiFreeOpCodeHandle (EndOpCodeHandle);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function removes TCG configuration Form.
+
+ @param[in, out] PrivateData Points to TCG configuration private data.
+
+**/
+VOID
+UninstallTcgConfigForm (
+ IN OUT TCG_CONFIG_PRIVATE_DATA *PrivateData
+ )
+{
+ //
+ // Uninstall HII package list
+ //
+ if (PrivateData->HiiHandle != NULL) {
+ HiiRemovePackages (PrivateData->HiiHandle);
+ PrivateData->HiiHandle = NULL;
+ }
+
+ //
+ // Uninstall HII Config Access Protocol
+ //
+ if (PrivateData->DriverHandle != NULL) {
+ gBS->UninstallMultipleProtocolInterfaces (
+ PrivateData->DriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mTcgHiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ &PrivateData->ConfigAccess,
+ NULL
+ );
+ PrivateData->DriverHandle = NULL;
+ }
+
+ FreePool (PrivateData);
+}
diff --git a/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigImpl.h b/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigImpl.h
new file mode 100644
index 0000000000..cbfca74392
--- /dev/null
+++ b/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigImpl.h
@@ -0,0 +1,195 @@
+/** @file
+ The header file of HII Config Access protocol implementation of TCG
+ configuration module.
+
+Copyright (c) 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __TCG_CONFIG_IMPL_H__
+#define __TCG_CONFIG_IMPL_H__
+
+#include
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#include "TcgConfigNvData.h"
+
+//
+// Tool generated IFR binary data and String package data
+//
+extern UINT8 TcgConfigBin[];
+extern UINT8 TcgConfigDxeStrings[];
+
+///
+/// HII specific Vendor Device Path definition.
+///
+typedef struct {
+ VENDOR_DEVICE_PATH VendorDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} HII_VENDOR_DEVICE_PATH;
+
+typedef struct {
+ UINTN Signature;
+
+ EFI_HII_CONFIG_ACCESS_PROTOCOL ConfigAccess;
+ EFI_HII_HANDLE HiiHandle;
+ EFI_HANDLE DriverHandle;
+
+ EFI_TCG_PROTOCOL *TcgProtocol;
+
+ BOOLEAN HideTpm;
+} TCG_CONFIG_PRIVATE_DATA;
+
+extern TCG_CONFIG_PRIVATE_DATA mTcgConfigPrivateDateTemplate;
+
+#define TCG_CONFIG_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('T', 'C', 'G', 'D')
+#define TCG_CONFIG_PRIVATE_DATA_FROM_THIS(a) CR (a, TCG_CONFIG_PRIVATE_DATA, ConfigAccess, TCG_CONFIG_PRIVATE_DATA_SIGNATURE)
+
+
+/**
+ This function publish the TCG configuration Form for TPM device.
+
+ @param[in, out] PrivateData Points to TCG configuration private data.
+
+ @retval EFI_SUCCESS HII Form is installed for this network device.
+ @retval EFI_OUT_OF_RESOURCES Not enough resource for HII Form installation.
+ @retval Others Other errors as indicated.
+
+**/
+EFI_STATUS
+InstallTcgConfigForm (
+ IN OUT TCG_CONFIG_PRIVATE_DATA *PrivateData
+ );
+
+/**
+ This function removes TCG configuration Form.
+
+ @param[in, out] PrivateData Points to TCG configuration private data.
+
+**/
+VOID
+UninstallTcgConfigForm (
+ IN OUT TCG_CONFIG_PRIVATE_DATA *PrivateData
+ );
+
+/**
+ This function allows a caller to extract the current configuration for one
+ or more named elements from the target driver.
+
+ @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param[in] Request A null-terminated Unicode string in
+ format.
+ @param[out] Progress On return, points to a character in the Request
+ string. Points to the string's null terminator if
+ request was successful. Points to the most recent
+ '&' before the first failing name/value pair (or
+ the beginning of the string if the failure is in
+ the first name/value pair) if the request was not
+ successful.
+ @param[out] Results A null-terminated Unicode string in
+ format which has all values filled
+ in for the names in the Request string. String to
+ be allocated by the called function.
+
+ @retval EFI_SUCCESS The Results is filled with the requested values.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results.
+ @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name.
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in this
+ driver.
+
+**/
+EFI_STATUS
+EFIAPI
+TcgExtractConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Request,
+ OUT EFI_STRING *Progress,
+ OUT EFI_STRING *Results
+ );
+
+/**
+ This function processes the results of changes in configuration.
+
+ @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param[in] Configuration A null-terminated Unicode string in
+ format.
+ @param[out] Progress A pointer to a string filled in with the offset of
+ the most recent '&' before the first failing
+ name/value pair (or the beginning of the string if
+ the failure is in the first name/value pair) or
+ the terminating NULL if all was successful.
+
+ @retval EFI_SUCCESS The Results is processed successfully.
+ @retval EFI_INVALID_PARAMETER Configuration is NULL.
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in this
+ driver.
+
+**/
+EFI_STATUS
+EFIAPI
+TcgRouteConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Configuration,
+ OUT EFI_STRING *Progress
+ );
+
+/**
+ This function processes the results of changes in configuration.
+
+ @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param[in] Action Specifies the type of action taken by the browser.
+ @param[in] QuestionId A unique value which is sent to the original
+ exporting driver so that it can identify the type
+ of data to expect.
+ @param[in] Type The type of value for the question.
+ @param[in] Value A pointer to the data being sent to the original
+ exporting driver.
+ @param[out] ActionRequest On return, points to the action requested by the
+ callback function.
+
+ @retval EFI_SUCCESS The callback successfully handled the action.
+ @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the
+ variable and its data.
+ @retval EFI_DEVICE_ERROR The variable could not be saved.
+ @retval EFI_UNSUPPORTED The specified Action is not supported by the
+ callback.
+
+**/
+EFI_STATUS
+EFIAPI
+TcgCallback (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN EFI_BROWSER_ACTION Action,
+ IN EFI_QUESTION_ID QuestionId,
+ IN UINT8 Type,
+ IN EFI_IFR_TYPE_VALUE *Value,
+ OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
+ );
+
+#endif
diff --git a/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigNvData.h b/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigNvData.h
new file mode 100644
index 0000000000..982764c65c
--- /dev/null
+++ b/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigNvData.h
@@ -0,0 +1,48 @@
+/** @file
+ Header file for NV data structure definition.
+
+Copyright (c) 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __TCG_CONFIG_NV_DATA_H__
+#define __TCG_CONFIG_NV_DATA_H__
+
+#include
+#include
+
+#define TCG_CONFIG_PRIVATE_GUID \
+ { \
+ 0xb0f901e4, 0xc424, 0x45de, {0x90, 0x81, 0x95, 0xe2, 0xb, 0xde, 0x6f, 0xb5 } \
+ }
+
+#define TCG_CONFIGURATION_VARSTORE_ID 0x0001
+#define TCG_CONFIGURATION_FORM_ID 0x0001
+
+#define KEY_HIDE_TPM 0x2000
+#define KEY_TPM_ACTION 0x3000
+#define KEY_TPM_MOR_ENABLE 0x4000
+
+#define LABEL_TCG_CONFIGURATION_HIDETPM 0x0001
+#define LABEL_END 0xffff
+
+//
+// Nv Data structure referenced by IFR
+//
+typedef struct {
+ BOOLEAN HideTpm;
+ BOOLEAN OriginalHideTpm;
+ BOOLEAN MorState;
+ UINT8 TpmOperation;
+ BOOLEAN TpmEnable;
+ BOOLEAN TpmActivate;
+} TCG_CONFIGURATION;
+
+#endif
diff --git a/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigStrings.uni b/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigStrings.uni
new file mode 100644
index 0000000000..df39f62093
Binary files /dev/null and b/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigStrings.uni differ
diff --git a/SecurityPkg/Tcg/TcgDxe/TcgDxe.c b/SecurityPkg/Tcg/TcgDxe/TcgDxe.c
new file mode 100644
index 0000000000..4cb5d3084b
--- /dev/null
+++ b/SecurityPkg/Tcg/TcgDxe/TcgDxe.c
@@ -0,0 +1,1212 @@
+/** @file
+ This module implements TCG EFI Protocol.
+
+Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "TpmComm.h"
+
+#define EFI_TCG_LOG_AREA_SIZE 0x10000
+
+#pragma pack (1)
+
+typedef struct _EFI_TCG_CLIENT_ACPI_TABLE {
+ EFI_ACPI_DESCRIPTION_HEADER Header;
+ UINT16 PlatformClass;
+ UINT32 Laml;
+ EFI_PHYSICAL_ADDRESS Lasa;
+} EFI_TCG_CLIENT_ACPI_TABLE;
+
+typedef struct _EFI_TCG_SERVER_ACPI_TABLE {
+ EFI_ACPI_DESCRIPTION_HEADER Header;
+ UINT16 PlatformClass;
+ UINT16 Reserved0;
+ UINT64 Laml;
+ EFI_PHYSICAL_ADDRESS Lasa;
+ UINT16 SpecRev;
+ UINT8 DeviceFlags;
+ UINT8 InterruptFlags;
+ UINT8 Gpe;
+ UINT8 Reserved1[3];
+ UINT32 GlobalSysInt;
+ EFI_ACPI_3_0_GENERIC_ADDRESS_STRUCTURE BaseAddress;
+ UINT32 Reserved2;
+ EFI_ACPI_3_0_GENERIC_ADDRESS_STRUCTURE ConfigAddress;
+ UINT8 PciSegNum;
+ UINT8 PciBusNum;
+ UINT8 PciDevNum;
+ UINT8 PciFuncNum;
+} EFI_TCG_SERVER_ACPI_TABLE;
+
+#pragma pack ()
+
+#define TCG_DXE_DATA_FROM_THIS(this) \
+ BASE_CR (this, TCG_DXE_DATA, TcgProtocol)
+
+typedef struct _TCG_DXE_DATA {
+ EFI_TCG_PROTOCOL TcgProtocol;
+ TCG_EFI_BOOT_SERVICE_CAPABILITY BsCap;
+ EFI_TCG_CLIENT_ACPI_TABLE *TcgClientAcpiTable;
+ EFI_TCG_SERVER_ACPI_TABLE *TcgServerAcpiTable;
+ UINTN EventLogSize;
+ UINT8 *LastEvent;
+ TIS_TPM_HANDLE TpmHandle;
+} TCG_DXE_DATA;
+
+
+
+EFI_TCG_CLIENT_ACPI_TABLE mTcgClientAcpiTemplate = {
+ {
+ EFI_ACPI_3_0_TRUSTED_COMPUTING_PLATFORM_ALLIANCE_CAPABILITIES_TABLE_SIGNATURE,
+ sizeof (mTcgClientAcpiTemplate),
+ 0x02 //Revision
+ //
+ // Compiler initializes the remaining bytes to 0
+ // These fields should be filled in in production
+ //
+ },
+ 0, // 0 for PC Client Platform Class
+ 0, // Log Area Max Length
+ (EFI_PHYSICAL_ADDRESS) (SIZE_4GB - 1) // Log Area Start Address
+};
+
+//
+// The following EFI_TCG_SERVER_ACPI_TABLE default setting is just one example,
+// the TPM device connectes to LPC, and also defined the ACPI _UID as 0xFF,
+// this _UID can be changed and should match with the _UID setting of the TPM
+// ACPI device object
+//
+EFI_TCG_SERVER_ACPI_TABLE mTcgServerAcpiTemplate = {
+ {
+ EFI_ACPI_3_0_TRUSTED_COMPUTING_PLATFORM_ALLIANCE_CAPABILITIES_TABLE_SIGNATURE,
+ sizeof (mTcgServerAcpiTemplate),
+ 0x02 //Revision
+ //
+ // Compiler initializes the remaining bytes to 0
+ // These fields should be filled in in production
+ //
+ },
+ 1, // 1 for Server Platform Class
+ 0, // Reserved
+ 0, // Log Area Max Length
+ (EFI_PHYSICAL_ADDRESS) (SIZE_4GB - 1), // Log Area Start Address
+ 0x0100, // TCG Specification revision 1.0
+ 2, // Device Flags
+ 0, // Interrupt Flags
+ 0, // GPE
+ {0}, // Reserved 3 bytes
+ 0, // Global System Interrupt
+ {
+ EFI_ACPI_3_0_SYSTEM_MEMORY,
+ 0,
+ 0,
+ EFI_ACPI_3_0_BYTE,
+ TPM_BASE_ADDRESS // Base Address
+ },
+ 0, // Reserved
+ {0}, // Configuration Address
+ 0xFF, // ACPI _UID value of the device, can be changed for different platforms
+ 0, // ACPI _UID value of the device, can be changed for different platforms
+ 0, // ACPI _UID value of the device, can be changed for different platforms
+ 0 // ACPI _UID value of the device, can be changed for different platforms
+};
+
+UINTN mBootAttempts = 0;
+CHAR16 mBootVarName[] = L"BootOrder";
+
+/**
+ This service provides EFI protocol capability information, state information
+ about the TPM, and Event Log state information.
+
+ @param[in] This Indicates the calling context
+ @param[out] ProtocolCapability The callee allocates memory for a TCG_BOOT_SERVICE_CAPABILITY
+ structure and fills in the fields with the EFI protocol
+ capability information and the current TPM state information.
+ @param[out] TCGFeatureFlags This is a pointer to the feature flags. No feature
+ flags are currently defined so this parameter
+ MUST be set to 0. However, in the future,
+ feature flags may be defined that, for example,
+ enable hash algorithm agility.
+ @param[out] EventLogLocation This is a pointer to the address of the event log in memory.
+ @param[out] EventLogLastEntry If the Event Log contains more than one entry,
+ this is a pointer to the address of the start of
+ the last entry in the event log in memory.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_INVALID_PARAMETER ProtocolCapability does not match TCG capability.
+
+**/
+EFI_STATUS
+EFIAPI
+TcgDxeStatusCheck (
+ IN EFI_TCG_PROTOCOL *This,
+ OUT TCG_EFI_BOOT_SERVICE_CAPABILITY *ProtocolCapability,
+ OUT UINT32 *TCGFeatureFlags,
+ OUT EFI_PHYSICAL_ADDRESS *EventLogLocation,
+ OUT EFI_PHYSICAL_ADDRESS *EventLogLastEntry
+ )
+{
+ TCG_DXE_DATA *TcgData;
+
+ TcgData = TCG_DXE_DATA_FROM_THIS (This);
+
+ if (ProtocolCapability != NULL) {
+ *ProtocolCapability = TcgData->BsCap;
+ }
+
+ if (TCGFeatureFlags != NULL) {
+ *TCGFeatureFlags = 0;
+ }
+
+ if (EventLogLocation != NULL) {
+ if (PcdGet8 (PcdTpmPlatformClass) == TCG_PLATFORM_TYPE_CLIENT) {
+ *EventLogLocation = TcgData->TcgClientAcpiTable->Lasa;
+ } else {
+ *EventLogLocation = TcgData->TcgServerAcpiTable->Lasa;
+ }
+ }
+
+ if (EventLogLastEntry != NULL) {
+ if (TcgData->BsCap.TPMDeactivatedFlag) {
+ *EventLogLastEntry = (EFI_PHYSICAL_ADDRESS)(UINTN)0;
+ } else {
+ *EventLogLastEntry = (EFI_PHYSICAL_ADDRESS)(UINTN)TcgData->LastEvent;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This service abstracts the capability to do a hash operation on a data buffer.
+
+ @param[in] This Indicates the calling context
+ @param[in] HashData Pointer to the data buffer to be hashed
+ @param[in] HashDataLen Length of the data buffer to be hashed
+ @param[in] AlgorithmId Identification of the Algorithm to use for the hashing operation
+ @param[in, out] HashedDataLen Resultant length of the hashed data
+ @param[in, out] HashedDataResult Resultant buffer of the hashed data
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_INVALID_PARAMETER HashDataLen is NULL.
+ @retval EFI_INVALID_PARAMETER HashDataLenResult is NULL.
+ @retval EFI_OUT_OF_RESOURCES Cannot allocate buffer of size *HashedDataLen.
+ @retval EFI_UNSUPPORTED AlgorithmId not supported.
+ @retval EFI_BUFFER_TOO_SMALL *HashedDataLen < sizeof (TCG_DIGEST).
+
+**/
+EFI_STATUS
+EFIAPI
+TcgDxeHashAll (
+ IN EFI_TCG_PROTOCOL *This,
+ IN UINT8 *HashData,
+ IN UINT64 HashDataLen,
+ IN TCG_ALGORITHM_ID AlgorithmId,
+ IN OUT UINT64 *HashedDataLen,
+ IN OUT UINT8 **HashedDataResult
+ )
+{
+ if (HashedDataLen == NULL || HashedDataResult == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ switch (AlgorithmId) {
+ case TPM_ALG_SHA:
+ if (*HashedDataLen == 0) {
+ *HashedDataLen = sizeof (TPM_DIGEST);
+ *HashedDataResult = AllocatePool ((UINTN) *HashedDataLen);
+ if (*HashedDataResult == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ if (*HashedDataLen < sizeof (TPM_DIGEST)) {
+ *HashedDataLen = sizeof (TPM_DIGEST);
+ return EFI_BUFFER_TOO_SMALL;
+ }
+ *HashedDataLen = sizeof (TPM_DIGEST);
+
+ return TpmCommHashAll (
+ HashData,
+ (UINTN) HashDataLen,
+ (TPM_DIGEST*)*HashedDataResult
+ );
+ default:
+ return EFI_UNSUPPORTED;
+ }
+}
+
+/**
+ Add a new entry to the Event Log.
+
+ @param[in] TcgData TCG_DXE_DATA structure.
+ @param[in] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR data structure.
+ @param[in] NewEventData Pointer to the new event data.
+
+ @retval EFI_SUCCESS The new event log entry was added.
+ @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.
+
+**/
+EFI_STATUS
+EFIAPI
+TcgDxeLogEventI (
+ IN TCG_DXE_DATA *TcgData,
+ IN TCG_PCR_EVENT_HDR *NewEventHdr,
+ IN UINT8 *NewEventData
+ )
+{
+ if (PcdGet8 (PcdTpmPlatformClass) == TCG_PLATFORM_TYPE_CLIENT) {
+ TcgData->LastEvent = (UINT8*)(UINTN)TcgData->TcgClientAcpiTable->Lasa;
+ return TpmCommLogEvent (
+ &TcgData->LastEvent,
+ &TcgData->EventLogSize,
+ (UINTN)TcgData->TcgClientAcpiTable->Laml,
+ NewEventHdr,
+ NewEventData
+ );
+ } else {
+ TcgData->LastEvent = (UINT8*)(UINTN)TcgData->TcgServerAcpiTable->Lasa;
+ return TpmCommLogEvent (
+ &TcgData->LastEvent,
+ &TcgData->EventLogSize,
+ (UINTN)TcgData->TcgServerAcpiTable->Laml,
+ NewEventHdr,
+ NewEventData
+ );
+ }
+}
+
+/**
+ This service abstracts the capability to add an entry to the Event Log.
+
+ @param[in] This Indicates the calling context
+ @param[in] TCGLogData Pointer to the start of the data buffer containing
+ the TCG_PCR_EVENT data structure. All fields in
+ this structure are properly filled by the caller.
+ @param[in, out] EventNumber The event number of the event just logged
+ @param[in] Flags Indicate additional flags. Only one flag has been
+ defined at this time, which is 0x01 and means the
+ extend operation should not be performed. All
+ other bits are reserved.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_OUT_OF_RESOURCES Insufficient memory in the event log to complete this action.
+
+**/
+EFI_STATUS
+EFIAPI
+TcgDxeLogEvent (
+ IN EFI_TCG_PROTOCOL *This,
+ IN TCG_PCR_EVENT *TCGLogData,
+ IN OUT UINT32 *EventNumber,
+ IN UINT32 Flags
+ )
+{
+ TCG_DXE_DATA *TcgData;
+
+ TcgData = TCG_DXE_DATA_FROM_THIS (This);
+
+ if (TcgData->BsCap.TPMDeactivatedFlag) {
+ return EFI_DEVICE_ERROR;
+ }
+ return TcgDxeLogEventI (
+ TcgData,
+ (TCG_PCR_EVENT_HDR*)TCGLogData,
+ TCGLogData->Event
+ );
+}
+
+/**
+ This service is a proxy for commands to the TPM.
+
+ @param[in] This Indicates the calling context
+ @param[in] TpmInputParameterBlockSize Size of the TPM input parameter block
+ @param[in] TpmInputParameterBlock Pointer to the TPM input parameter block
+ @param[in] TpmOutputParameterBlockSize Size of the TPM output parameter block
+ @param[in] TpmOutputParameterBlock Pointer to the TPM output parameter block
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid ordinal.
+ @retval EFI_UNSUPPORTED Current Task Priority Level >= EFI_TPL_CALLBACK.
+ @retval EFI_TIMEOUT The TIS timed-out.
+
+**/
+EFI_STATUS
+EFIAPI
+TcgDxePassThroughToTpm (
+ IN EFI_TCG_PROTOCOL *This,
+ IN UINT32 TpmInputParameterBlockSize,
+ IN UINT8 *TpmInputParameterBlock,
+ IN UINT32 TpmOutputParameterBlockSize,
+ IN UINT8 *TpmOutputParameterBlock
+ )
+{
+ TCG_DXE_DATA *TcgData;
+
+ TcgData = TCG_DXE_DATA_FROM_THIS (This);
+
+ return TisPcExecute (
+ TcgData->TpmHandle,
+ "%r%/%r",
+ TpmInputParameterBlock,
+ (UINTN) TpmInputParameterBlockSize,
+ TpmOutputParameterBlock,
+ (UINTN) TpmOutputParameterBlockSize
+ );
+}
+
+/**
+ Do a hash operation on a data buffer, extend a specific TPM PCR with the hash result,
+ and add an entry to the Event Log.
+
+ @param[in] TcgData TCG_DXE_DATA structure.
+ @param[in] HashData Physical address of the start of the data buffer
+ to be hashed, extended, and logged.
+ @param[in] HashDataLen The length, in bytes, of the buffer referenced by HashData
+ @param[in, out] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR data structure.
+ @param[in] NewEventData Pointer to the new event data.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+
+**/
+EFI_STATUS
+EFIAPI
+TcgDxeHashLogExtendEventI (
+ IN TCG_DXE_DATA *TcgData,
+ IN UINT8 *HashData,
+ IN UINT64 HashDataLen,
+ IN OUT TCG_PCR_EVENT_HDR *NewEventHdr,
+ IN UINT8 *NewEventData
+ )
+{
+ EFI_STATUS Status;
+
+ if (HashDataLen > 0) {
+ Status = TpmCommHashAll (
+ HashData,
+ (UINTN) HashDataLen,
+ &NewEventHdr->Digest
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ Status = TpmCommExtend (
+ TcgData->TpmHandle,
+ &NewEventHdr->Digest,
+ NewEventHdr->PCRIndex,
+ NULL
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = TcgDxeLogEventI (TcgData, NewEventHdr, NewEventData);
+ }
+
+ return Status;
+}
+
+/**
+ This service abstracts the capability to do a hash operation on a data buffer,
+ extend a specific TPM PCR with the hash result, and add an entry to the Event Log
+
+ @param[in] This Indicates the calling context
+ @param[in] HashData Physical address of the start of the data buffer
+ to be hashed, extended, and logged.
+ @param[in] HashDataLen The length, in bytes, of the buffer referenced by HashData
+ @param[in] AlgorithmId Identification of the Algorithm to use for the hashing operation
+ @param[in, out] TCGLogData The physical address of the start of the data
+ buffer containing the TCG_PCR_EVENT data structure.
+ @param[in, out] EventNumber The event number of the event just logged.
+ @param[out] EventLogLastEntry Physical address of the first byte of the entry
+ just placed in the Event Log. If the Event Log was
+ empty when this function was called then this physical
+ address will be the same as the physical address of
+ the start of the Event Log.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_UNSUPPORTED AlgorithmId != TPM_ALG_SHA.
+ @retval EFI_UNSUPPORTED Current TPL >= EFI_TPL_CALLBACK.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+
+**/
+EFI_STATUS
+EFIAPI
+TcgDxeHashLogExtendEvent (
+ IN EFI_TCG_PROTOCOL *This,
+ IN EFI_PHYSICAL_ADDRESS HashData,
+ IN UINT64 HashDataLen,
+ IN TPM_ALGORITHM_ID AlgorithmId,
+ IN OUT TCG_PCR_EVENT *TCGLogData,
+ IN OUT UINT32 *EventNumber,
+ OUT EFI_PHYSICAL_ADDRESS *EventLogLastEntry
+ )
+{
+ TCG_DXE_DATA *TcgData;
+
+ TcgData = TCG_DXE_DATA_FROM_THIS (This);
+
+ if (TcgData->BsCap.TPMDeactivatedFlag) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (AlgorithmId != TPM_ALG_SHA) {
+ return EFI_UNSUPPORTED;
+ }
+
+ return TcgDxeHashLogExtendEventI (
+ TcgData,
+ (UINT8 *) (UINTN) HashData,
+ HashDataLen,
+ (TCG_PCR_EVENT_HDR*)TCGLogData,
+ TCGLogData->Event
+ );
+}
+
+TCG_DXE_DATA mTcgDxeData = {
+ {
+ TcgDxeStatusCheck,
+ TcgDxeHashAll,
+ TcgDxeLogEvent,
+ TcgDxePassThroughToTpm,
+ TcgDxeHashLogExtendEvent
+ },
+ {
+ sizeof (mTcgDxeData.BsCap),
+ { 1, 2, 0, 0 },
+ { 1, 2, 0, 0 },
+ 1,
+ TRUE,
+ FALSE
+ },
+ &mTcgClientAcpiTemplate,
+ &mTcgServerAcpiTemplate,
+ 0,
+ NULL,
+ NULL
+};
+
+/**
+ Initialize the Event Log and log events passed from the PEI phase.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_OUT_OF_RESOURCES Out of memory.
+
+**/
+EFI_STATUS
+EFIAPI
+SetupEventLog (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ TCG_PCR_EVENT *TcgEvent;
+ EFI_PEI_HOB_POINTERS GuidHob;
+ EFI_PHYSICAL_ADDRESS Lasa;
+
+ if (PcdGet8 (PcdTpmPlatformClass) == TCG_PLATFORM_TYPE_CLIENT) {
+ Lasa = mTcgClientAcpiTemplate.Lasa;
+
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiACPIMemoryNVS,
+ EFI_SIZE_TO_PAGES (EFI_TCG_LOG_AREA_SIZE),
+ &Lasa
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ mTcgClientAcpiTemplate.Lasa = Lasa;
+ //
+ // To initialize them as 0xFF is recommended
+ // because the OS can know the last entry for that.
+ //
+ SetMem ((VOID *)(UINTN)mTcgClientAcpiTemplate.Lasa, EFI_TCG_LOG_AREA_SIZE, 0xFF);
+ mTcgClientAcpiTemplate.Laml = EFI_TCG_LOG_AREA_SIZE;
+
+ } else {
+ Lasa = mTcgServerAcpiTemplate.Lasa;
+
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiACPIMemoryNVS,
+ EFI_SIZE_TO_PAGES (EFI_TCG_LOG_AREA_SIZE),
+ &Lasa
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ mTcgServerAcpiTemplate.Lasa = Lasa;
+ //
+ // To initialize them as 0xFF is recommended
+ // because the OS can know the last entry for that.
+ //
+ SetMem ((VOID *)(UINTN)mTcgServerAcpiTemplate.Lasa, EFI_TCG_LOG_AREA_SIZE, 0xFF);
+ mTcgServerAcpiTemplate.Laml = EFI_TCG_LOG_AREA_SIZE;
+ }
+
+ GuidHob.Raw = GetHobList ();
+ while (!EFI_ERROR (Status) &&
+ (GuidHob.Raw = GetNextGuidHob (&gTcgEventEntryHobGuid, GuidHob.Raw)) != NULL) {
+ TcgEvent = GET_GUID_HOB_DATA (GuidHob.Guid);
+ GuidHob.Raw = GET_NEXT_HOB (GuidHob);
+ Status = TcgDxeLogEventI (
+ &mTcgDxeData,
+ (TCG_PCR_EVENT_HDR*)TcgEvent,
+ TcgEvent->Event
+ );
+ }
+
+ return Status;
+}
+
+/**
+ Measure and log an action string, and extend the measurement result into PCR[5].
+
+ @param[in] String A specific string that indicates an Action event.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The operation was unsuccessful.
+
+**/
+EFI_STATUS
+EFIAPI
+TcgMeasureAction (
+ IN CHAR8 *String
+ )
+{
+ TCG_PCR_EVENT_HDR TcgEvent;
+
+ TcgEvent.PCRIndex = 5;
+ TcgEvent.EventType = EV_EFI_ACTION;
+ TcgEvent.EventSize = (UINT32)AsciiStrLen (String);
+ return TcgDxeHashLogExtendEventI (
+ &mTcgDxeData,
+ (UINT8*)String,
+ TcgEvent.EventSize,
+ &TcgEvent,
+ (UINT8 *) String
+ );
+}
+
+/**
+ Measure and log EFI handoff tables, and extend the measurement result into PCR[1].
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The operation was unsuccessful.
+
+**/
+EFI_STATUS
+EFIAPI
+MeasureHandoffTables (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ SMBIOS_TABLE_ENTRY_POINT *SmbiosTable;
+ TCG_PCR_EVENT_HDR TcgEvent;
+ EFI_HANDOFF_TABLE_POINTERS HandoffTables;
+
+ Status = EfiGetSystemConfigurationTable (
+ &gEfiSmbiosTableGuid,
+ (VOID **) &SmbiosTable
+ );
+
+ if (!EFI_ERROR (Status)) {
+ ASSERT (SmbiosTable != NULL);
+
+ TcgEvent.PCRIndex = 1;
+ TcgEvent.EventType = EV_EFI_HANDOFF_TABLES;
+ TcgEvent.EventSize = sizeof (HandoffTables);
+
+ HandoffTables.NumberOfTables = 1;
+ HandoffTables.TableEntry[0].VendorGuid = gEfiSmbiosTableGuid;
+ HandoffTables.TableEntry[0].VendorTable = SmbiosTable;
+
+ DEBUG ((DEBUG_INFO, "The Smbios Table starts at: 0x%x\n", SmbiosTable->TableAddress));
+ DEBUG ((DEBUG_INFO, "The Smbios Table size: 0x%x\n", SmbiosTable->TableLength));
+
+ Status = TcgDxeHashLogExtendEventI (
+ &mTcgDxeData,
+ (UINT8*)(UINTN)SmbiosTable->TableAddress,
+ SmbiosTable->TableLength,
+ &TcgEvent,
+ (UINT8*)&HandoffTables
+ );
+ }
+
+ return Status;
+}
+
+/**
+ Measure and log Separator event, and extend the measurement result into a specific PCR.
+
+ @param[in] PCRIndex PCR index.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The operation was unsuccessful.
+
+**/
+EFI_STATUS
+EFIAPI
+MeasureSeparatorEvent (
+ IN TPM_PCRINDEX PCRIndex
+ )
+{
+ TCG_PCR_EVENT_HDR TcgEvent;
+ UINT32 EventData;
+
+ EventData = 0;
+ TcgEvent.PCRIndex = PCRIndex;
+ TcgEvent.EventType = EV_SEPARATOR;
+ TcgEvent.EventSize = (UINT32)sizeof (EventData);
+ return TcgDxeHashLogExtendEventI (
+ &mTcgDxeData,
+ (UINT8 *)&EventData,
+ sizeof (EventData),
+ &TcgEvent,
+ (UINT8 *)&EventData
+ );
+}
+
+/**
+ Read an EFI Variable.
+
+ This function allocates a buffer to return the contents of the variable. The caller is
+ responsible for freeing the buffer.
+
+ @param[in] VarName A Null-terminated string that is the name of the vendor's variable.
+ @param[in] VendorGuid A unique identifier for the vendor.
+ @param[out] VarSize The size of the variable data.
+
+ @return A pointer to the buffer to return the contents of the variable.Otherwise NULL.
+
+**/
+VOID *
+EFIAPI
+ReadVariable (
+ IN CHAR16 *VarName,
+ IN EFI_GUID *VendorGuid,
+ OUT UINTN *VarSize
+ )
+{
+ EFI_STATUS Status;
+ VOID *VarData;
+
+ *VarSize = 0;
+ Status = gRT->GetVariable (
+ VarName,
+ VendorGuid,
+ NULL,
+ VarSize,
+ NULL
+ );
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ return NULL;
+ }
+
+ VarData = AllocatePool (*VarSize);
+ if (VarData != NULL) {
+ Status = gRT->GetVariable (
+ VarName,
+ VendorGuid,
+ NULL,
+ VarSize,
+ VarData
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (VarData);
+ VarData = NULL;
+ *VarSize = 0;
+ }
+ }
+ return VarData;
+}
+
+/**
+ Measure and log an EFI variable, and extend the measurement result into a specific PCR.
+
+ @param[in] PCRIndex PCR Index.
+ @param[in] EventType Event type.
+ @param[in] VarName A Null-terminated string that is the name of the vendor's variable.
+ @param[in] VendorGuid A unique identifier for the vendor.
+ @param[in] VarData The content of the variable data.
+ @param[in] VarSize The size of the variable data.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_OUT_OF_RESOURCES Out of memory.
+ @retval EFI_DEVICE_ERROR The operation was unsuccessful.
+
+**/
+EFI_STATUS
+EFIAPI
+MeasureVariable (
+ IN TPM_PCRINDEX PCRIndex,
+ IN TCG_EVENTTYPE EventType,
+ IN CHAR16 *VarName,
+ IN EFI_GUID *VendorGuid,
+ IN VOID *VarData,
+ IN UINTN VarSize
+ )
+{
+ EFI_STATUS Status;
+ TCG_PCR_EVENT_HDR TcgEvent;
+ UINTN VarNameLength;
+ EFI_VARIABLE_DATA *VarLog;
+
+ VarNameLength = StrLen (VarName);
+ TcgEvent.PCRIndex = PCRIndex;
+ TcgEvent.EventType = EventType;
+ TcgEvent.EventSize = (UINT32)(sizeof (*VarLog) + VarNameLength * sizeof (*VarName) + VarSize
+ - sizeof (VarLog->UnicodeName) - sizeof (VarLog->VariableData));
+
+ VarLog = (EFI_VARIABLE_DATA*)AllocatePool (TcgEvent.EventSize);
+ if (VarLog == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ VarLog->VariableName = *VendorGuid;
+ VarLog->UnicodeNameLength = VarNameLength;
+ VarLog->VariableDataLength = VarSize;
+ CopyMem (
+ VarLog->UnicodeName,
+ VarName,
+ VarNameLength * sizeof (*VarName)
+ );
+ CopyMem (
+ (CHAR16 *)VarLog->UnicodeName + VarNameLength,
+ VarData,
+ VarSize
+ );
+
+ Status = TcgDxeHashLogExtendEventI (
+ &mTcgDxeData,
+ (UINT8*)VarData,
+ VarSize,
+ &TcgEvent,
+ (UINT8*)VarLog
+ );
+ FreePool (VarLog);
+ return Status;
+}
+
+/**
+ Read then Measure and log an EFI boot variable, and extend the measurement result into PCR[5].
+
+ @param[in] VarName A Null-terminated string that is the name of the vendor's variable.
+ @param[in] VendorGuid A unique identifier for the vendor.
+ @param[out] VarSize The size of the variable data.
+ @param[out] VarData Pointer to the content of the variable.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_OUT_OF_RESOURCES Out of memory.
+ @retval EFI_DEVICE_ERROR The operation was unsuccessful.
+
+**/
+EFI_STATUS
+EFIAPI
+ReadAndMeasureBootVariable (
+ IN CHAR16 *VarName,
+ IN EFI_GUID *VendorGuid,
+ OUT UINTN *VarSize,
+ OUT VOID **VarData
+ )
+{
+ EFI_STATUS Status;
+
+ *VarData = ReadVariable (VarName, VendorGuid, VarSize);
+ if (*VarData == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ Status = MeasureVariable (
+ 5,
+ EV_EFI_VARIABLE_BOOT,
+ VarName,
+ VendorGuid,
+ *VarData,
+ *VarSize
+ );
+ return Status;
+}
+
+/**
+ Measure and log all EFI boot variables, and extend the measurement result into a specific PCR.
+
+ The EFI boot variables are BootOrder and Boot#### variables.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_OUT_OF_RESOURCES Out of memory.
+ @retval EFI_DEVICE_ERROR The operation was unsuccessful.
+
+**/
+EFI_STATUS
+EFIAPI
+MeasureAllBootVariables (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINT16 *BootOrder;
+ UINTN BootCount;
+ UINTN Index;
+ VOID *BootVarData;
+ UINTN Size;
+
+ Status = ReadAndMeasureBootVariable (
+ mBootVarName,
+ &gEfiGlobalVariableGuid,
+ &BootCount,
+ (VOID **) &BootOrder
+ );
+ if (Status == EFI_NOT_FOUND) {
+ return EFI_SUCCESS;
+ }
+ ASSERT (BootOrder != NULL);
+
+ if (EFI_ERROR (Status)) {
+ FreePool (BootOrder);
+ return Status;
+ }
+
+ BootCount /= sizeof (*BootOrder);
+ for (Index = 0; Index < BootCount; Index++) {
+ UnicodeSPrint (mBootVarName, sizeof (mBootVarName), L"Boot%04x", BootOrder[Index]);
+ Status = ReadAndMeasureBootVariable (
+ mBootVarName,
+ &gEfiGlobalVariableGuid,
+ &Size,
+ &BootVarData
+ );
+ if (!EFI_ERROR (Status)) {
+ FreePool (BootVarData);
+ }
+ }
+
+ FreePool (BootOrder);
+ return EFI_SUCCESS;
+}
+
+/**
+ Ready to Boot Event notification handler.
+
+ Sequence of OS boot events is measured in this event notification handler.
+
+ @param[in] Event Event whose notification function is being invoked
+ @param[in] Context Pointer to the notification function's context
+
+**/
+VOID
+EFIAPI
+OnReadyToBoot (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ TPM_PCRINDEX PcrIndex;
+
+ if (mBootAttempts == 0) {
+
+ //
+ // Measure handoff tables.
+ //
+ Status = MeasureHandoffTables ();
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "HOBs not Measured. Error!\n"));
+ }
+
+ //
+ // Measure BootOrder & Boot#### variables.
+ //
+ Status = MeasureAllBootVariables ();
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Boot Variables not Measured. Error!\n"));
+ }
+
+ //
+ // 1. This is the first boot attempt.
+ //
+ Status = TcgMeasureAction (
+ EFI_CALLING_EFI_APPLICATION
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // 2. Draw a line between pre-boot env and entering post-boot env.
+ //
+ for (PcrIndex = 0; PcrIndex < 8; PcrIndex++) {
+ Status = MeasureSeparatorEvent (PcrIndex);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ //
+ // 3. Measure GPT. It would be done in SAP driver.
+ //
+
+ //
+ // 4. Measure PE/COFF OS loader. It would be done in SAP driver.
+ //
+
+ //
+ // 5. Read & Measure variable. BootOrder already measured.
+ //
+ } else {
+ //
+ // 6. Not first attempt, meaning a return from last attempt
+ //
+ Status = TcgMeasureAction (
+ EFI_RETURNING_FROM_EFI_APPLICATOIN
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ DEBUG ((EFI_D_INFO, "TPM TcgDxe Measure Data when ReadyToBoot\n"));
+ //
+ // Increase boot attempt counter.
+ //
+ mBootAttempts++;
+}
+
+/**
+ Install TCG ACPI Table when ACPI Table Protocol is available.
+
+ A system¡¯s firmware uses an ACPI table to identify the system's TCG capabilities
+ to the Post-Boot environment. The information in this ACPI table is not guaranteed
+ to be valid until the Host Platform transitions from pre-boot state to post-boot state.
+
+ @param[in] Event Event whose notification function is being invoked
+ @param[in] Context Pointer to the notification function's context
+**/
+VOID
+EFIAPI
+InstallAcpiTable (
+ IN EFI_EVENT Event,
+ IN VOID* Context
+ )
+{
+ UINTN TableKey;
+ EFI_STATUS Status;
+ EFI_ACPI_TABLE_PROTOCOL *AcpiTable;
+ UINT8 Checksum;
+
+ Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **)&AcpiTable);
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ if (PcdGet8 (PcdTpmPlatformClass) == TCG_PLATFORM_TYPE_CLIENT) {
+
+ //
+ // The ACPI table must be checksumed before calling the InstallAcpiTable()
+ // service of the ACPI table protocol to install it.
+ //
+ Checksum = CalculateCheckSum8 ((UINT8 *)&mTcgClientAcpiTemplate, sizeof (mTcgClientAcpiTemplate));
+ mTcgClientAcpiTemplate.Header.Checksum = Checksum;
+
+ Status = AcpiTable->InstallAcpiTable (
+ AcpiTable,
+ &mTcgClientAcpiTemplate,
+ sizeof (mTcgClientAcpiTemplate),
+ &TableKey
+ );
+ } else {
+
+ //
+ // The ACPI table must be checksumed before calling the InstallAcpiTable()
+ // service of the ACPI table protocol to install it.
+ //
+ Checksum = CalculateCheckSum8 ((UINT8 *)&mTcgServerAcpiTemplate, sizeof (mTcgServerAcpiTemplate));
+ mTcgServerAcpiTemplate.Header.Checksum = Checksum;
+
+ Status = AcpiTable->InstallAcpiTable (
+ AcpiTable,
+ &mTcgServerAcpiTemplate,
+ sizeof (mTcgServerAcpiTemplate),
+ &TableKey
+ );
+ }
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ Exit Boot Services Event notification handler.
+
+ Measure invocation and success of ExitBootServices.
+
+ @param[in] Event Event whose notification function is being invoked
+ @param[in] Context Pointer to the notification function's context
+
+**/
+VOID
+EFIAPI
+OnExitBootServices (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Measure invocation of ExitBootServices,
+ //
+ Status = TcgMeasureAction (
+ EFI_EXIT_BOOT_SERVICES_INVOCATION
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Measure success of ExitBootServices
+ //
+ Status = TcgMeasureAction (
+ EFI_EXIT_BOOT_SERVICES_SUCCEEDED
+ );
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ Get TPM Deactivated state.
+
+ @param[out] TPMDeactivatedFlag Returns TPM Deactivated state.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The operation was unsuccessful.
+
+**/
+EFI_STATUS
+GetTpmStatus (
+ OUT BOOLEAN *TPMDeactivatedFlag
+ )
+{
+ EFI_STATUS Status;
+ TPM_STCLEAR_FLAGS VFlags;
+
+ Status = TpmCommGetFlags (
+ mTcgDxeData.TpmHandle,
+ TPM_CAP_FLAG_VOLATILE,
+ &VFlags,
+ sizeof (VFlags)
+ );
+ if (!EFI_ERROR (Status)) {
+ *TPMDeactivatedFlag = VFlags.deactivated;
+ }
+
+ return Status;
+}
+
+/**
+ The driver's entry point.
+
+ It publishes EFI TCG Protocol.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The entry point is executed successfully.
+ @retval other Some error occurs when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+DriverEntry (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_EVENT Event;
+ VOID *Registration;
+
+ mTcgDxeData.TpmHandle = (TIS_TPM_HANDLE)(UINTN)TPM_BASE_ADDRESS;
+ Status = TisPcRequestUseTpm (mTcgDxeData.TpmHandle);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "TPM not detected!\n"));
+ return Status;
+ }
+
+ Status = GetTpmStatus (&mTcgDxeData.BsCap.TPMDeactivatedFlag);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ EFI_D_ERROR,
+ "Line %d in file " __FILE__ ":\n "
+ "DriverEntry: TPM not working properly\n",
+ __LINE__
+ ));
+ return Status;
+ }
+
+ Status = gBS->InstallProtocolInterface (
+ &ImageHandle,
+ &gEfiTcgProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &mTcgDxeData.TcgProtocol
+ );
+ //
+ // Install ACPI Table
+ //
+ EfiCreateProtocolNotifyEvent (&gEfiAcpiTableProtocolGuid, TPL_CALLBACK, InstallAcpiTable, NULL, &Registration);
+
+ if (!EFI_ERROR (Status) && !mTcgDxeData.BsCap.TPMDeactivatedFlag) {
+ //
+ // Setup the log area and copy event log from hob list to it
+ //
+ Status = SetupEventLog ();
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Measure handoff tables, Boot#### variables etc.
+ //
+ Status = EfiCreateEventReadyToBootEx (
+ TPL_CALLBACK,
+ OnReadyToBoot,
+ NULL,
+ &Event
+ );
+
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ OnExitBootServices,
+ NULL,
+ &gEfiEventExitBootServicesGuid,
+ &Event
+ );
+ }
+
+ return Status;
+}
diff --git a/SecurityPkg/Tcg/TcgDxe/TcgDxe.inf b/SecurityPkg/Tcg/TcgDxe/TcgDxe.inf
new file mode 100644
index 0000000000..95f37737c4
--- /dev/null
+++ b/SecurityPkg/Tcg/TcgDxe/TcgDxe.inf
@@ -0,0 +1,70 @@
+## @file
+# Component file for module TcgDxe.
+# This module will produce TCG protocol and measure boot environment.
+#
+# Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = TcgDxe
+ FILE_GUID = A5683620-7998-4bb2-A377-1C1E31E1E215
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = DriverEntry
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF
+#
+
+[Sources]
+ TcgDxe.c
+ TisDxe.c
+ TpmComm.c
+ TpmComm.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+ MemoryAllocationLib
+ BaseLib
+ UefiBootServicesTableLib
+ HobLib
+ UefiDriverEntryPoint
+ UefiRuntimeServicesTableLib
+ BaseMemoryLib
+ DebugLib
+ TpmCommLib
+ PrintLib
+ UefiLib
+
+[Guids]
+ gEfiSmbiosTableGuid # ALWAYS_CONSUMED
+ gEfiGlobalVariableGuid # ALWAYS_CONSUMED
+ gTcgEventEntryHobGuid
+ gEfiEventReadyToBootGuid
+ gEfiEventExitBootServicesGuid
+
+[Protocols]
+ gEfiTcgProtocolGuid ## PRODUCES
+ gEfiAcpiTableProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiDevicePathProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+
+[Pcd]
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpmPlatformClass
+
+[Depex]
+ TRUE
+
diff --git a/SecurityPkg/Tcg/TcgDxe/TisDxe.c b/SecurityPkg/Tcg/TcgDxe/TisDxe.c
new file mode 100644
index 0000000000..635ff77e13
--- /dev/null
+++ b/SecurityPkg/Tcg/TcgDxe/TisDxe.c
@@ -0,0 +1,432 @@
+/** @file
+ TIS (TPM Interface Specification) functions used by TPM Dxe driver.
+
+Copyright (c) 2005 - 2010, Intel Corporation. All rights reserved.
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+STATIC UINT8 TpmCommandBuf[TPMCMDBUFLENGTH];
+
+/**
+ Send command to TPM for execution.
+
+ @param[in] TisReg TPM register space base address.
+ @param[in] TpmBuffer Buffer for TPM command data.
+ @param[in] DataLength TPM command data length.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_TIMEOUT The register can't run into the expected status in time.
+
+**/
+EFI_STATUS
+TisPcSend (
+ IN TIS_PC_REGISTERS_PTR TisReg,
+ IN UINT8 *TpmBuffer,
+ IN UINT32 DataLength
+ )
+{
+ UINT16 BurstCount;
+ UINT32 Index;
+ EFI_STATUS Status;
+
+ Status = TisPcPrepareCommand (TisReg);
+ if (EFI_ERROR (Status)){
+ DEBUG ((DEBUG_ERROR, "The Tpm not ready!\n"));
+ return Status;
+ }
+ Index = 0;
+ while (Index < DataLength) {
+ Status = TisPcReadBurstCount (TisReg, &BurstCount);
+ if (EFI_ERROR (Status)) {
+ return EFI_TIMEOUT;
+ }
+ for (; BurstCount > 0 && Index < DataLength; BurstCount--) {
+ MmioWrite8 ((UINTN) &TisReg->DataFifo, *(TpmBuffer + Index));
+ Index++;
+ }
+ }
+ //
+ // Ensure the Tpm status STS_EXPECT change from 1 to 0
+ //
+ Status = TisPcWaitRegisterBits (
+ &TisReg->Status,
+ (UINT8) TIS_PC_VALID,
+ TIS_PC_STS_EXPECT,
+ TIS_TIMEOUT_C
+ );
+ return Status;
+}
+
+/**
+ Receive response data of last command from TPM.
+
+ @param[in] TisReg TPM register space base address.
+ @param[out] TpmBuffer Buffer for response data.
+ @param[out] RespSize Response data length.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_TIMEOUT The register can't run into the expected status in time.
+ @retval EFI_DEVICE_ERROR Unexpected device status.
+ @retval EFI_BUFFER_TOO_SMALL Response data is too long.
+
+**/
+EFI_STATUS
+TisPcReceive (
+ IN TIS_PC_REGISTERS_PTR TisReg,
+ OUT UINT8 *TpmBuffer,
+ OUT UINT32 *RespSize
+ )
+{
+ EFI_STATUS Status;
+ UINT16 BurstCount;
+ UINT32 Index;
+ UINT32 ResponseSize;
+ UINT32 Data32;
+
+ //
+ // Wait for the command completion
+ //
+ Status = TisPcWaitRegisterBits (
+ &TisReg->Status,
+ (UINT8) (TIS_PC_VALID | TIS_PC_STS_DATA),
+ 0,
+ TIS_TIMEOUT_B
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_TIMEOUT;
+ }
+ //
+ // Read the response data header and check it
+ //
+ Index = 0;
+ BurstCount = 0;
+ while (Index < sizeof (TPM_RSP_COMMAND_HDR)) {
+ Status = TisPcReadBurstCount (TisReg, &BurstCount);
+ if (EFI_ERROR (Status)) {
+ return EFI_TIMEOUT;
+ }
+ for (; BurstCount > 0 ; BurstCount--) {
+ *(TpmBuffer + Index) = MmioRead8 ((UINTN) &TisReg->DataFifo);
+ Index++;
+ if (Index == sizeof (TPM_RSP_COMMAND_HDR))
+ break;
+ }
+ }
+ //
+ // Check the reponse data header (tag,parasize and returncode )
+ //
+ CopyMem (&Data32, (TpmBuffer + 2), sizeof (UINT32));
+ ResponseSize = SwapBytes32 (Data32);
+ *RespSize = ResponseSize;
+ if (ResponseSize == sizeof (TPM_RSP_COMMAND_HDR)) {
+ return EFI_SUCCESS;
+ }
+ if (ResponseSize < sizeof (TPM_RSP_COMMAND_HDR)) {
+ return EFI_DEVICE_ERROR;
+ }
+ if (ResponseSize > TPMCMDBUFLENGTH) {
+ return EFI_BUFFER_TOO_SMALL;
+ }
+ //
+ // Continue reading the remaining data
+ //
+ while (Index < ResponseSize) {
+ for (; BurstCount > 0 ; BurstCount--) {
+ *(TpmBuffer + Index) = MmioRead8 ((UINTN) &TisReg->DataFifo);
+ Index++;
+ if (Index == ResponseSize) {
+ return EFI_SUCCESS;
+ }
+ }
+ Status = TisPcReadBurstCount (TisReg, &BurstCount);
+ if (EFI_ERROR (Status) && (Index < ResponseSize)) {
+ return EFI_DEVICE_ERROR;
+ }
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Format TPM command data according to the format control character.
+
+ @param[in] FmtChar Format control character.
+ @param[in, out] ap List of arguments.
+ @param[in] TpmBuffer Buffer for TPM command data.
+ @param[out] DataLength TPM command data length.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid format control character.
+ @retval EFI_BUFFER_TOO_SMALL Buffer too small for command data.
+
+**/
+EFI_STATUS
+TisPcSendV (
+ IN UINT8 FmtChar,
+ IN OUT VA_LIST *ap,
+ UINT8 *TpmBuffer,
+ UINT32 *DataLength
+ )
+{
+ UINT8 DataByte;
+ UINT16 DataWord;
+ UINT32 DataDword;
+ TPM_RQU_COMMAND_HDR TpmCmdHdr;
+ TPM_RQU_COMMAND_HDR *TpmCmdPtr;
+ UINTN Size;
+ UINT8 *Raw;
+
+ switch (FmtChar) {
+
+ case 'b':
+ DataByte = VA_ARG (*ap, UINT8);
+ Raw = &DataByte;
+ Size = sizeof (DataByte);
+ break;
+
+ case 'w':
+ DataWord = VA_ARG (*ap, UINT16);
+ DataWord = SwapBytes16 (DataWord);
+ Raw = (UINT8*)&DataWord;
+ Size = sizeof (DataWord);
+ break;
+
+ case 'd':
+ DataDword = VA_ARG (*ap, UINT32);
+ DataDword = SwapBytes32 (DataDword);
+ Raw = (UINT8*)&DataDword;
+ Size = sizeof (DataDword);
+ break;
+
+ case 'h':
+ TpmCmdPtr = VA_ARG (*ap, TPM_RQU_COMMAND_HDR*);
+ TpmCmdHdr.tag = SwapBytes16 (TpmCmdPtr->tag);
+ TpmCmdHdr.paramSize = SwapBytes32 (TpmCmdPtr->paramSize);
+ TpmCmdHdr.ordinal = SwapBytes32 (TpmCmdPtr->ordinal);
+ Raw = (UINT8*) &TpmCmdHdr;
+ Size = sizeof (TpmCmdHdr);
+ break;
+
+ case 'r':
+ Raw = VA_ARG (*ap, UINT8*);
+ Size = VA_ARG (*ap, UINTN);
+ break;
+
+ case '\0':
+ return EFI_INVALID_PARAMETER;
+
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if(*DataLength + (UINT32) Size > TPMCMDBUFLENGTH) {
+ return EFI_BUFFER_TOO_SMALL;
+ }
+ CopyMem (TpmBuffer + *DataLength, Raw, Size);
+ *DataLength += (UINT32) Size;
+ return EFI_SUCCESS;
+}
+
+/**
+ Format reponse data according to the format control character.
+
+ @param[in] FmtChar Format control character.
+ @param[in, out] ap List of arguments.
+ @param[out] TpmBuffer Buffer for reponse data.
+ @param[in, out] DataIndex Data offset in reponse data buffer.
+ @param[in] RespSize Response data length.
+ @param[out] DataFinished Reach the end of Response data.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid format control character.
+ @retval EFI_BUFFER_TOO_SMALL Buffer too small for command data.
+
+**/
+EFI_STATUS
+TisPcReceiveV (
+ IN UINT8 FmtChar,
+ IN OUT VA_LIST *ap,
+ OUT UINT8 *TpmBuffer,
+ IN OUT UINT32 *DataIndex,
+ IN UINT32 RespSize,
+ OUT BOOLEAN *DataFinished
+ )
+{
+ UINT8 *Raw;
+ TPM_RSP_COMMAND_HDR *TpmRspPtr;
+ UINTN Size;
+
+ Raw = VA_ARG (*ap, UINT8*);
+ switch (FmtChar) {
+
+ case 'b':
+ Size = sizeof (UINT8);
+ break;
+
+ case 'w':
+ Size = sizeof (UINT16);
+ break;
+
+ case 'd':
+ Size = sizeof (UINT32);
+ break;
+
+ case 'h':
+ Size = sizeof (*TpmRspPtr);
+ break;
+
+ case 'r':
+ Size = VA_ARG (*ap, UINTN);
+ if(*DataIndex + (UINT32) Size <= RespSize) {
+ break;
+ }
+ *DataFinished = TRUE;
+ if (*DataIndex >= RespSize) {
+ return EFI_SUCCESS;
+ }
+ CopyMem (Raw, TpmBuffer + *DataIndex, RespSize - *DataIndex);
+ *DataIndex += RespSize - *DataIndex;
+ return EFI_SUCCESS;
+
+ case '\0':
+ return EFI_INVALID_PARAMETER;
+
+ default:
+ return EFI_WARN_UNKNOWN_GLYPH;
+ }
+
+ if(*DataIndex + (UINT32) Size > RespSize) {
+ *DataFinished = TRUE;
+ return EFI_SUCCESS;
+ }
+
+ if( *DataIndex + (UINT32) Size > TPMCMDBUFLENGTH )
+ return EFI_BUFFER_TOO_SMALL;
+
+ CopyMem (Raw, TpmBuffer + *DataIndex, Size);
+ *DataIndex += (UINT32) Size;
+
+ switch (FmtChar) {
+
+ case 'w':
+ *(UINT16*)Raw = SwapBytes16 (*(UINT16*) Raw);
+ break;
+
+ case 'd':
+ *(UINT32*)Raw = SwapBytes32 (*(UINT32*) Raw);
+ break;
+
+ case 'h':
+ TpmRspPtr = (TPM_RSP_COMMAND_HDR*) Raw;
+ TpmRspPtr->tag = SwapBytes16 (TpmRspPtr->tag);
+ TpmRspPtr->paramSize = SwapBytes32 (TpmRspPtr->paramSize);
+ TpmRspPtr->returnCode = SwapBytes32 (TpmRspPtr->returnCode);
+ break;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Send formatted command to TPM for execution and return formatted data from response.
+
+ @param[in] TisReg TPM Handle.
+ @param[in] Fmt Format control string.
+ @param[in] ... The variable argument list.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_TIMEOUT The register can't run into the expected status in time.
+
+**/
+EFI_STATUS
+EFIAPI
+TisPcExecute (
+ IN TIS_TPM_HANDLE TisReg,
+ IN CONST CHAR8 *Fmt,
+ ...
+ )
+{
+ EFI_STATUS Status;
+ VA_LIST Ap;
+ UINT32 BufSize;
+ UINT32 ResponseSize;
+ BOOLEAN DataFinished;
+
+ VA_START (Ap, Fmt);
+
+ //
+ // Put the formatted command to the TpmCommandBuf
+ //
+ BufSize = 0;
+ while (*Fmt != '\0') {
+ if (*Fmt == '%') Fmt++;
+ if (*Fmt == '/') break;
+ Status = TisPcSendV (*Fmt, &Ap, TpmCommandBuf, &BufSize);
+ if (EFI_ERROR( Status )) {
+ return Status;
+ }
+ Fmt++;
+ }
+ //
+ // Send the command to TPM
+ //
+ Status = TisPcSend (TisReg, TpmCommandBuf, BufSize);
+ if (EFI_ERROR (Status)) {
+ //
+ // Ensure the TPM state change from "Reception" to "Idle/Ready"
+ //
+ MmioWrite8 ((UINTN) &(((TIS_PC_REGISTERS_PTR) TisReg)->Status), TIS_PC_STS_READY);
+ return Status;
+ }
+
+ MmioWrite8 ((UINTN) &(((TIS_PC_REGISTERS_PTR) TisReg)->Status), TIS_PC_STS_GO);
+ Fmt++;
+ //
+ // Receive the response data from TPM
+ //
+ ZeroMem (TpmCommandBuf, TPMCMDBUFLENGTH);
+ Status = TisPcReceive (TisReg, TpmCommandBuf, &ResponseSize);
+ //
+ // Ensure the TPM state change from "Execution" or "Completion" to "Idle/Ready"
+ //
+ MmioWrite8 ((UINTN) &(((TIS_PC_REGISTERS_PTR) TisReg)->Status), TIS_PC_STS_READY);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Get the formatted data from the TpmCommandBuf.
+ //
+ BufSize =0;
+ DataFinished = FALSE;
+ while (*Fmt != '\0') {
+ if (*Fmt == '%') {
+ Fmt++;
+ }
+ Status = TisPcReceiveV (*Fmt, &Ap, TpmCommandBuf, &BufSize, ResponseSize, &DataFinished);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ if (DataFinished) {
+ return EFI_SUCCESS;
+ }
+ Fmt++;
+ }
+
+ VA_END (Ap);
+ return Status;
+}
+
diff --git a/SecurityPkg/Tcg/TcgDxe/TpmComm.c b/SecurityPkg/Tcg/TcgDxe/TpmComm.c
new file mode 100644
index 0000000000..c47794b4f6
--- /dev/null
+++ b/SecurityPkg/Tcg/TcgDxe/TpmComm.c
@@ -0,0 +1,163 @@
+/** @file
+ Utility functions used by TPM Dxe driver.
+
+Copyright (c) 2005 - 2010, Intel Corporation. All rights reserved.
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include
+#include
+#include
+#include
+
+#include "TpmComm.h"
+
+/**
+ Extend a TPM PCR.
+
+ @param[in] TpmHandle TPM handle.
+ @param[in] DigestToExtend The 160 bit value representing the event to be recorded.
+ @param[in] PcrIndex The PCR to be updated.
+ @param[out] NewPcrValue New PCR value after extend.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+
+**/
+EFI_STATUS
+TpmCommExtend (
+ IN TIS_TPM_HANDLE TpmHandle,
+ IN TPM_DIGEST *DigestToExtend,
+ IN TPM_PCRINDEX PcrIndex,
+ OUT TPM_DIGEST *NewPcrValue
+ )
+{
+ EFI_STATUS Status;
+ TPM_DIGEST NewValue;
+ TPM_RQU_COMMAND_HDR CmdHdr;
+ TPM_RSP_COMMAND_HDR RspHdr;
+
+ if (NewPcrValue == NULL) {
+ NewPcrValue = &NewValue;
+ }
+
+ CmdHdr.tag = TPM_TAG_RQU_COMMAND;
+ CmdHdr.paramSize =
+ sizeof (CmdHdr) + sizeof (PcrIndex) + sizeof (*DigestToExtend);
+ CmdHdr.ordinal = TPM_ORD_Extend;
+ Status = TisPcExecute (
+ TpmHandle,
+ "%h%d%r%/%h%r",
+ &CmdHdr,
+ PcrIndex,
+ DigestToExtend,
+ (UINTN)sizeof (*DigestToExtend),
+ &RspHdr,
+ NewPcrValue,
+ (UINTN)sizeof (*NewPcrValue)
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ if (RspHdr.returnCode != 0) {
+ return EFI_DEVICE_ERROR;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Get TPM capability flags.
+
+ @param[in] TpmHandle TPM handle.
+ @param[in] FlagSubcap Flag subcap.
+ @param[out] FlagBuffer Pointer to the buffer for returned flag structure.
+ @param[in] FlagSize Size of the buffer.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+
+**/
+EFI_STATUS
+TpmCommGetFlags (
+ IN TIS_TPM_HANDLE TpmHandle,
+ IN UINT32 FlagSubcap,
+ OUT VOID *FlagBuffer,
+ IN UINTN FlagSize
+ )
+{
+ EFI_STATUS Status;
+ TPM_RQU_COMMAND_HDR CmdHdr;
+ TPM_RSP_COMMAND_HDR RspHdr;
+ UINT32 Size;
+
+ CmdHdr.tag = TPM_TAG_RQU_COMMAND;
+ CmdHdr.paramSize = sizeof (CmdHdr) + sizeof (UINT32) * 3;
+ CmdHdr.ordinal = TPM_ORD_GetCapability;
+
+ Status = TisPcExecute (
+ TpmHandle,
+ "%h%d%d%d%/%h%d%r",
+ &CmdHdr,
+ TPM_CAP_FLAG,
+ sizeof (FlagSubcap),
+ FlagSubcap,
+ &RspHdr,
+ &Size,
+ FlagBuffer,
+ FlagSize
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ if (RspHdr.returnCode != 0) {
+ return EFI_DEVICE_ERROR;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Add a new entry to the Event Log.
+
+ @param[in, out] EventLogPtr Pointer to the Event Log data.
+ @param[in, out] LogSize Size of the Event Log.
+ @param[in] MaxSize Maximum size of the Event Log.
+ @param[in] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR data structure.
+ @param[in] NewEventData Pointer to the new event data.
+
+ @retval EFI_SUCCESS The new event log entry was added.
+ @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.
+
+**/
+EFI_STATUS
+TpmCommLogEvent (
+ IN OUT UINT8 **EventLogPtr,
+ IN OUT UINTN *LogSize,
+ IN UINTN MaxSize,
+ IN TCG_PCR_EVENT_HDR *NewEventHdr,
+ IN UINT8 *NewEventData
+ )
+{
+ UINT32 NewLogSize;
+
+ NewLogSize = sizeof (*NewEventHdr) + NewEventHdr->EventSize;
+ if (NewLogSize + *LogSize > MaxSize) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ *EventLogPtr += *LogSize;
+ *LogSize += NewLogSize;
+ CopyMem (*EventLogPtr, NewEventHdr, sizeof (*NewEventHdr));
+ CopyMem (
+ *EventLogPtr + sizeof (*NewEventHdr),
+ NewEventData,
+ NewEventHdr->EventSize
+ );
+ return EFI_SUCCESS;
+}
diff --git a/SecurityPkg/Tcg/TcgDxe/TpmComm.h b/SecurityPkg/Tcg/TcgDxe/TpmComm.h
new file mode 100644
index 0000000000..763ad76d62
--- /dev/null
+++ b/SecurityPkg/Tcg/TcgDxe/TpmComm.h
@@ -0,0 +1,99 @@
+/** @file
+ Definitions and function prototypes used by TPM DXE driver.
+
+Copyright (c) 2005 - 2010, Intel Corporation. All rights reserved.
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _TPM_COMM_H_
+#define _TPM_COMM_H_
+
+/**
+ Add a new entry to the Event Log.
+
+ @param[in, out] EventLogPtr Pointer to the Event Log data.
+ @param[in, out] LogSize Size of the Event Log.
+ @param[in] MaxSize Maximum size of the Event Log.
+ @param[in] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR data structure.
+ @param[in] NewEventData Pointer to the new event data.
+
+ @retval EFI_SUCCESS The new event log entry was added.
+ @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.
+
+**/
+EFI_STATUS
+TpmCommLogEvent (
+ IN OUT UINT8 **EventLogPtr,
+ IN OUT UINTN *LogSize,
+ IN UINTN MaxSize,
+ IN TCG_PCR_EVENT_HDR *NewEventHdr,
+ IN UINT8 *NewEventData
+ );
+
+/**
+ Extend a TPM PCR.
+
+ @param[in] TpmHandle TPM handle.
+ @param[in] DigestToExtend The 160 bit value representing the event to be recorded.
+ @param[in] PcrIndex The PCR to be updated.
+ @param[out] NewPcrValue New PCR value after extend.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+
+**/
+EFI_STATUS
+TpmCommExtend (
+ IN TIS_TPM_HANDLE TpmHandle,
+ IN TPM_DIGEST *DigestToExtend,
+ IN TPM_PCRINDEX PcrIndex,
+ OUT TPM_DIGEST *NewPcrValue
+ );
+
+/**
+ Get TPM capability flags.
+
+ @param[in] TpmHandle TPM handle.
+ @param[in] FlagSubcap Flag subcap.
+ @param[out] FlagBuffer Pointer to the buffer for returned flag structure.
+ @param[in] FlagSize Size of the buffer.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+
+**/
+EFI_STATUS
+TpmCommGetFlags (
+ IN TIS_TPM_HANDLE TpmHandle,
+ IN UINT32 FlagSubcap,
+ OUT VOID *Buffer,
+ IN UINTN Size
+ );
+
+/**
+ Send formatted command to TPM for execution and return formatted data from response.
+
+ @param[in] TisReg TPM Handle.
+ @param[in] Fmt Format control string.
+ @param[in] ... The variable argument list.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_TIMEOUT The register can't run into the expected status in time.
+
+**/
+EFI_STATUS
+EFIAPI
+TisPcExecute (
+ IN TIS_TPM_HANDLE TisReg,
+ IN CONST CHAR8 *Fmt,
+ ...
+ );
+
+#endif // _TPM_COMM_H_
diff --git a/SecurityPkg/Tcg/TcgPei/TcgPei.c b/SecurityPkg/Tcg/TcgPei/TcgPei.c
new file mode 100644
index 0000000000..63caddec8c
--- /dev/null
+++ b/SecurityPkg/Tcg/TcgPei/TcgPei.c
@@ -0,0 +1,593 @@
+/** @file
+ Initialize TPM device and measure FVs before handing off control to DXE.
+
+Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "TpmComm.h"
+
+BOOLEAN mImageInMemory = FALSE;
+
+EFI_PEI_PPI_DESCRIPTOR mTpmInitializedPpiList = {
+ EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
+ &gPeiTpmInitializedPpiGuid,
+ NULL
+};
+
+/**
+ Lock physical presence if needed.
+
+ @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
+ @param[in] NotifyDescriptor Address of the notification descriptor data structure.
+ @param[in] Ppi Address of the PPI that was installed.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+PhysicalPresencePpiNotifyCallback (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *Ppi
+ );
+
+/**
+ Measure and record the Firmware Volum Information once FvInfoPPI install.
+
+ @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param[in] NotifyDescriptor Address of the notification descriptor data structure.
+ @param[in] Ppi Address of the PPI that was installed.
+
+ @retval EFI_SUCCESS The FV Info is measured and recorded to TPM.
+ @return Others Fail to measure FV.
+
+**/
+EFI_STATUS
+EFIAPI
+FirmwareVolmeInfoPpiNotifyCallback (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *Ppi
+ );
+
+EFI_PEI_NOTIFY_DESCRIPTOR mNotifyList[] = {
+ {
+ EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,
+ &gPeiLockPhysicalPresencePpiGuid,
+ PhysicalPresencePpiNotifyCallback
+ },
+ {
+ (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEfiPeiFirmwareVolumeInfoPpiGuid,
+ FirmwareVolmeInfoPpiNotifyCallback
+ }
+};
+
+CHAR8 mSCrtmVersion[] = "{D20BC7C6-A1A5-415c-AE85-38290AB6BE04}";
+
+EFI_PLATFORM_FIRMWARE_BLOB mMeasuredFvInfo[FixedPcdGet32 (PcdPeiCoreMaxFvSupported)];
+UINT32 mMeasuredFvIndex = 0;
+
+/**
+ Do a hash operation on a data buffer, extend a specific TPM PCR with the hash result,
+ and build a GUIDed HOB recording the event which will be passed to the DXE phase and
+ added into the Event Log.
+
+ @param[in] PeiServices Describes the list of possible PEI Services.
+ @param[in] HashData Physical address of the start of the data buffer
+ to be hashed, extended, and logged.
+ @param[in] HashDataLen The length, in bytes, of the buffer referenced by HashData.
+ @param[in] TpmHandle TPM handle.
+ @param[in] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR data structure.
+ @param[in] NewEventData Pointer to the new event data.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+
+**/
+EFI_STATUS
+HashLogExtendEvent (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN UINT8 *HashData,
+ IN UINTN HashDataLen,
+ IN TIS_TPM_HANDLE TpmHandle,
+ IN TCG_PCR_EVENT_HDR *NewEventHdr,
+ IN UINT8 *NewEventData
+ )
+{
+ EFI_STATUS Status;
+ VOID *HobData;
+
+ HobData = NULL;
+ if (HashDataLen != 0) {
+ Status = TpmCommHashAll (
+ HashData,
+ HashDataLen,
+ &NewEventHdr->Digest
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ Status = TpmCommExtend (
+ PeiServices,
+ TpmHandle,
+ &NewEventHdr->Digest,
+ NewEventHdr->PCRIndex,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ HobData = BuildGuidHob (
+ &gTcgEventEntryHobGuid,
+ sizeof (*NewEventHdr) + NewEventHdr->EventSize
+ );
+ if (HobData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CopyMem (HobData, NewEventHdr, sizeof (*NewEventHdr));
+ HobData = (VOID *) ((UINT8*)HobData + sizeof (*NewEventHdr));
+ CopyMem (HobData, NewEventData, NewEventHdr->EventSize);
+ return EFI_SUCCESS;
+}
+
+/**
+ Measure CRTM version.
+
+ @param[in] PeiServices Describes the list of possible PEI Services.
+ @param[in] TpmHandle TPM handle.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+
+**/
+EFI_STATUS
+EFIAPI
+MeasureCRTMVersion (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN TIS_TPM_HANDLE TpmHandle
+ )
+{
+ TCG_PCR_EVENT_HDR TcgEventHdr;
+
+ //
+ // Here, only a static GUID is measured instead of real CRTM version.
+ // OEMs should get real CRTM version string and measure it.
+ //
+
+ TcgEventHdr.PCRIndex = 0;
+ TcgEventHdr.EventType = EV_S_CRTM_VERSION;
+ TcgEventHdr.EventSize = sizeof (mSCrtmVersion);
+ return HashLogExtendEvent (
+ PeiServices,
+ (UINT8*)&mSCrtmVersion,
+ TcgEventHdr.EventSize,
+ TpmHandle,
+ &TcgEventHdr,
+ (UINT8*)&mSCrtmVersion
+ );
+}
+
+/**
+ Measure FV image.
+ Add it into the measured FV list after the FV is measured successfully.
+
+ @param[in] FvBase Base address of FV image.
+ @param[in] FvLength Length of FV image.
+
+ @retval EFI_SUCCESS Fv image is measured successfully
+ or it has been already measured.
+ @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+
+**/
+EFI_STATUS
+EFIAPI
+MeasureFvImage (
+ IN EFI_PHYSICAL_ADDRESS FvBase,
+ IN UINT64 FvLength
+ )
+{
+ UINT32 Index;
+ EFI_STATUS Status;
+ EFI_PLATFORM_FIRMWARE_BLOB FvBlob;
+ TCG_PCR_EVENT_HDR TcgEventHdr;
+ TIS_TPM_HANDLE TpmHandle;
+
+ TpmHandle = (TIS_TPM_HANDLE) (UINTN) TPM_BASE_ADDRESS;
+
+ //
+ // Check whether FV is in the measured FV list.
+ //
+ for (Index = 0; Index < mMeasuredFvIndex; Index ++) {
+ if (mMeasuredFvInfo[Index].BlobBase == FvBase) {
+ return EFI_SUCCESS;
+ }
+ }
+
+ //
+ // Measure and record the FV to the TPM
+ //
+ FvBlob.BlobBase = FvBase;
+ FvBlob.BlobLength = FvLength;
+
+ DEBUG ((DEBUG_INFO, "The FV which is measured by TcgPei starts at: 0x%x\n", FvBlob.BlobBase));
+ DEBUG ((DEBUG_INFO, "The FV which is measured by TcgPei has the size: 0x%x\n", FvBlob.BlobLength));
+
+ TcgEventHdr.PCRIndex = 0;
+ TcgEventHdr.EventType = EV_EFI_PLATFORM_FIRMWARE_BLOB;
+ TcgEventHdr.EventSize = sizeof (FvBlob);
+
+ Status = HashLogExtendEvent (
+ (EFI_PEI_SERVICES **) GetPeiServicesTablePointer(),
+ (UINT8*) (UINTN) FvBlob.BlobBase,
+ (UINTN) FvBlob.BlobLength,
+ TpmHandle,
+ &TcgEventHdr,
+ (UINT8*) &FvBlob
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Add new FV into the measured FV list.
+ //
+ ASSERT (mMeasuredFvIndex < FixedPcdGet32 (PcdPeiCoreMaxFvSupported));
+ if (mMeasuredFvIndex < FixedPcdGet32 (PcdPeiCoreMaxFvSupported)) {
+ mMeasuredFvInfo[mMeasuredFvIndex].BlobBase = FvBase;
+ mMeasuredFvInfo[mMeasuredFvIndex++].BlobLength = FvLength;
+ }
+
+ return Status;
+}
+
+/**
+ Measure main BIOS.
+
+ @param[in] PeiServices Describes the list of possible PEI Services.
+ @param[in] TpmHandle TPM handle.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+
+**/
+EFI_STATUS
+EFIAPI
+MeasureMainBios (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN TIS_TPM_HANDLE TpmHandle
+ )
+{
+ EFI_STATUS Status;
+ UINT32 FvInstances;
+ EFI_PEI_FV_HANDLE VolumeHandle;
+ EFI_FV_INFO VolumeInfo;
+ EFI_PEI_FIRMWARE_VOLUME_PPI *FvPpi;
+
+ FvInstances = 0;
+ while (TRUE) {
+ //
+ // Traverse all firmware volume instances of Static Core Root of Trust for Measurement
+ // (S-CRTM), this firmware volume measure policy can be modified/enhanced by special
+ // platform for special CRTM TPM measuring.
+ //
+ Status = PeiServicesFfsFindNextVolume (FvInstances, &VolumeHandle);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ //
+ // Measure and record the firmware volume that is dispatched by PeiCore
+ //
+ Status = PeiServicesFfsGetVolumeInfo (VolumeHandle, &VolumeInfo);
+ ASSERT_EFI_ERROR (Status);
+ //
+ // Locate the corresponding FV_PPI according to founded FV's format guid
+ //
+ Status = PeiServicesLocatePpi (
+ &VolumeInfo.FvFormat,
+ 0,
+ NULL,
+ (VOID**)&FvPpi
+ );
+ if (!EFI_ERROR (Status)) {
+ MeasureFvImage ((EFI_PHYSICAL_ADDRESS) (UINTN) VolumeInfo.FvStart, VolumeInfo.FvSize);
+ }
+
+ FvInstances++;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Measure and record the Firmware Volum Information once FvInfoPPI install.
+
+ @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param[in] NotifyDescriptor Address of the notification descriptor data structure.
+ @param[in] Ppi Address of the PPI that was installed.
+
+ @retval EFI_SUCCESS The FV Info is measured and recorded to TPM.
+ @return Others Fail to measure FV.
+
+**/
+EFI_STATUS
+EFIAPI
+FirmwareVolmeInfoPpiNotifyCallback (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *Ppi
+ )
+{
+ EFI_PEI_FIRMWARE_VOLUME_INFO_PPI *Fv;
+ EFI_STATUS Status;
+ EFI_PEI_FIRMWARE_VOLUME_PPI *FvPpi;
+
+ Fv = (EFI_PEI_FIRMWARE_VOLUME_INFO_PPI *) Ppi;
+
+ //
+ // The PEI Core can not dispatch or load files from memory mapped FVs that do not support FvPpi.
+ //
+ Status = PeiServicesLocatePpi (
+ &Fv->FvFormat,
+ 0,
+ NULL,
+ (VOID**)&FvPpi
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // This is an FV from an FFS file, and the parent FV must have already been measured,
+ // No need to measure twice, so just returns
+ //
+ if (Fv->ParentFvName != NULL || Fv->ParentFileName != NULL ) {
+ return EFI_SUCCESS;
+ }
+
+ return MeasureFvImage ((EFI_PHYSICAL_ADDRESS) (UINTN) Fv->FvInfo, Fv->FvInfoSize);
+}
+
+/**
+ Lock physical presence if needed.
+
+ @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation
+ @param[in] NotifyDescriptor Address of the notification descriptor data structure.
+ @param[in] Ppi Address of the PPI that was installed.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_ABORTED physicalPresenceCMDEnable is locked.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+
+**/
+EFI_STATUS
+EFIAPI
+PhysicalPresencePpiNotifyCallback (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *Ppi
+ )
+{
+ EFI_STATUS Status;
+ PEI_LOCK_PHYSICAL_PRESENCE_PPI *LockPhysicalPresencePpi;
+ BOOLEAN LifetimeLock;
+ BOOLEAN CmdEnable;
+ TIS_TPM_HANDLE TpmHandle;
+
+ TpmHandle = (TIS_TPM_HANDLE) (UINTN) TPM_BASE_ADDRESS;
+ LockPhysicalPresencePpi = (PEI_LOCK_PHYSICAL_PRESENCE_PPI *) Ppi;
+
+ if (!LockPhysicalPresencePpi->LockPhysicalPresence ((CONST EFI_PEI_SERVICES**) PeiServices)) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Lock TPM physical presence.
+ //
+
+ Status = TpmCommGetCapability (PeiServices, TpmHandle, NULL, &LifetimeLock, &CmdEnable);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (!CmdEnable) {
+ if (LifetimeLock) {
+ //
+ // physicalPresenceCMDEnable is locked, can't change.
+ //
+ return EFI_ABORTED;
+ }
+
+ //
+ // Enable physical presence command
+ // It is necessary in order to lock physical presence
+ //
+ Status = TpmCommPhysicalPresence (
+ PeiServices,
+ TpmHandle,
+ TPM_PHYSICAL_PRESENCE_CMD_ENABLE
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // Lock physical presence
+ //
+ Status = TpmCommPhysicalPresence (
+ PeiServices,
+ TpmHandle,
+ TPM_PHYSICAL_PRESENCE_LOCK
+ );
+ return Status;
+}
+
+/**
+ Check if TPM chip is activeated or not.
+
+ @param[in] PeiServices Describes the list of possible PEI Services.
+ @param[in] TpmHandle TPM handle.
+
+ @retval TRUE TPM is activated.
+ @retval FALSE TPM is deactivated.
+
+**/
+BOOLEAN
+EFIAPI
+IsTpmUsable (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN TIS_TPM_HANDLE TpmHandle
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN Deactivated;
+
+ Status = TpmCommGetCapability (PeiServices, TpmHandle, &Deactivated, NULL, NULL);
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+ return (BOOLEAN)(!Deactivated);
+}
+
+/**
+ Do measurement after memory is ready.
+
+ @param[in] PeiServices Describes the list of possible PEI Services.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+
+**/
+EFI_STATUS
+EFIAPI
+PeimEntryMP (
+ IN EFI_PEI_SERVICES **PeiServices
+ )
+{
+ EFI_STATUS Status;
+ TIS_TPM_HANDLE TpmHandle;
+
+ TpmHandle = (TIS_TPM_HANDLE)(UINTN)TPM_BASE_ADDRESS;
+ Status = TisPcRequestUseTpm ((TIS_PC_REGISTERS_PTR)TpmHandle);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (IsTpmUsable (PeiServices, TpmHandle)) {
+ Status = MeasureCRTMVersion (PeiServices, TpmHandle);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = MeasureMainBios (PeiServices, TpmHandle);
+ }
+
+ //
+ // Post callbacks:
+ // 1). for the FvInfoPpi services to measure and record
+ // the additional Fvs to TPM
+ // 2). for the OperatorPresencePpi service to determine whether to
+ // lock the TPM
+ //
+ Status = PeiServicesNotifyPpi (&mNotifyList[0]);
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
+/**
+ Entry point of this module.
+
+ @param[in] FileHandle Handle of the file being invoked.
+ @param[in] PeiServices Describes the list of possible PEI Services.
+
+ @return Status.
+
+**/
+EFI_STATUS
+EFIAPI
+PeimEntryMA (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ EFI_STATUS Status;
+ EFI_BOOT_MODE BootMode;
+ TIS_TPM_HANDLE TpmHandle;
+
+ if (PcdGetBool (PcdHideTpmSupport) && PcdGetBool (PcdHideTpm)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Status = (**PeiServices).RegisterForShadow(FileHandle);
+ if (Status == EFI_ALREADY_STARTED) {
+ mImageInMemory = TRUE;
+ } else if (Status == EFI_NOT_FOUND) {
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ if (!mImageInMemory) {
+ //
+ // Initialize TPM device
+ //
+ Status = PeiServicesGetBootMode (&BootMode);
+ ASSERT_EFI_ERROR (Status);
+
+ TpmHandle = (TIS_TPM_HANDLE)(UINTN)TPM_BASE_ADDRESS;
+ Status = TisPcRequestUseTpm ((TIS_PC_REGISTERS_PTR)TpmHandle);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "TPM not detected!\n"));
+ return Status;
+ }
+
+ Status = TpmCommStartup ((EFI_PEI_SERVICES**)PeiServices, TpmHandle, BootMode);
+ if (EFI_ERROR (Status) ) {
+ return Status;
+ }
+ Status = TpmCommContinueSelfTest ((EFI_PEI_SERVICES**)PeiServices, TpmHandle);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = PeiServicesInstallPpi (&mTpmInitializedPpiList);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ if (mImageInMemory) {
+ Status = PeimEntryMP ((EFI_PEI_SERVICES**)PeiServices);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ return Status;
+}
diff --git a/SecurityPkg/Tcg/TcgPei/TcgPei.inf b/SecurityPkg/Tcg/TcgPei/TcgPei.inf
new file mode 100644
index 0000000000..60a3bfa5f1
--- /dev/null
+++ b/SecurityPkg/Tcg/TcgPei/TcgPei.inf
@@ -0,0 +1,67 @@
+## @file
+# This module will initialize TPM device and measure FVs in PEI phase.
+#
+# Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = TcgPei
+ FILE_GUID = 2BE1E4A6-6505-43b3-9FFC-A3C8330E0432
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ ENTRY_POINT = PeimEntryMA
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ TcgPei.c
+ TisPei.c
+ TpmComm.c
+ TpmComm.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+ HobLib
+ PeimEntryPoint
+ PeiServicesLib
+ BaseMemoryLib
+ DebugLib
+ TpmCommLib
+ TimerLib
+ IoLib
+ PeiServicesTablePointerLib
+
+[Guids]
+ gTcgEventEntryHobGuid
+
+[Ppis]
+ gPeiLockPhysicalPresencePpiGuid
+ gEfiPeiFirmwareVolumeInfoPpiGuid
+ gPeiTpmInitializedPpiGuid
+
+[Pcd]
+ gEfiSecurityPkgTokenSpaceGuid.PcdHideTpm
+
+[FixedPcd]
+ gEfiSecurityPkgTokenSpaceGuid.PcdHideTpmSupport
+ gEfiMdeModulePkgTokenSpaceGuid.PcdPeiCoreMaxFvSupported ## CONSUMES
+
+[Depex]
+ gEfiPeiMasterBootModePpiGuid AND
+ gEfiPeiReadOnlyVariable2PpiGuid
diff --git a/SecurityPkg/Tcg/TcgPei/TisPei.c b/SecurityPkg/Tcg/TcgPei/TisPei.c
new file mode 100644
index 0000000000..97d9628bda
--- /dev/null
+++ b/SecurityPkg/Tcg/TcgPei/TisPei.c
@@ -0,0 +1,160 @@
+/** @file
+ TIS (TPM Interface Specification) functions used by TPM PEI driver.
+
+Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+/**
+ Send a command to TPM for execution and return response data.
+
+ @param[in] PeiServices Describes the list of possible PEI Services.
+ @param[in] TisReg TPM register space base address.
+ @param[in] BufferIn Buffer for command data.
+ @param[in] SizeIn Size of command data.
+ @param[in, out] BufferOut Buffer for response data.
+ @param[in, out] SizeOut Size of response data.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_TIMEOUT The register can't run into the expected status in time.
+ @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+
+**/
+EFI_STATUS
+TisTpmCommand (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN TIS_PC_REGISTERS_PTR TisReg,
+ IN UINT8 *BufferIn,
+ IN UINT32 SizeIn,
+ IN OUT UINT8 *BufferOut,
+ IN OUT UINT32 *SizeOut
+ )
+{
+ EFI_STATUS Status;
+ UINT16 BurstCount;
+ UINT32 Index;
+ UINT32 TpmOutSize;
+ UINT16 Data16;
+ UINT32 Data32;
+
+ Status = TisPcPrepareCommand (TisReg);
+ if (EFI_ERROR (Status)){
+ DEBUG ((DEBUG_ERROR, "Tpm is not ready for command!\n"));
+ return Status;
+ }
+ //
+ // Send the command data to Tpm
+ //
+ Index = 0;
+ while (Index < SizeIn) {
+ Status = TisPcReadBurstCount (TisReg, &BurstCount);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_TIMEOUT;
+ goto Exit;
+ }
+ for (; BurstCount > 0 && Index < SizeIn; BurstCount--) {
+ MmioWrite8((UINTN)&TisReg->DataFifo, *(BufferIn + Index));
+ Index++;
+ }
+ }
+ //
+ // Check the Tpm status STS_EXPECT change from 1 to 0
+ //
+ Status = TisPcWaitRegisterBits (
+ &TisReg->Status,
+ (UINT8) TIS_PC_VALID,
+ TIS_PC_STS_EXPECT,
+ TIS_TIMEOUT_C
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "The send buffer too small!\n"));
+ Status = EFI_BUFFER_TOO_SMALL;
+ goto Exit;
+ }
+ //
+ // Executed the TPM command and waiting for the response data ready
+ //
+ MmioWrite8((UINTN)&TisReg->Status, TIS_PC_STS_GO);
+ Status = TisPcWaitRegisterBits (
+ &TisReg->Status,
+ (UINT8) (TIS_PC_VALID | TIS_PC_STS_DATA),
+ 0,
+ TIS_TIMEOUT_B
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Wait for Tpm response data time out!!\n"));
+ Status = EFI_TIMEOUT;
+ goto Exit;
+ }
+ //
+ // Get response data header
+ //
+ Index = 0;
+ BurstCount = 0;
+ while (Index < sizeof (TPM_RSP_COMMAND_HDR)) {
+ Status = TisPcReadBurstCount (TisReg, &BurstCount);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_TIMEOUT;
+ goto Exit;
+ }
+ for (; BurstCount > 0; BurstCount--) {
+ *(BufferOut + Index) = MmioRead8 ((UINTN)&TisReg->DataFifo);
+ Index++;
+ if (Index == sizeof (TPM_RSP_COMMAND_HDR)) break;
+ }
+ }
+ //
+ // Check the reponse data header (tag,parasize and returncode )
+ //
+ CopyMem (&Data16, BufferOut, sizeof (UINT16));
+ if (SwapBytes16 (Data16) != TPM_TAG_RSP_COMMAND ) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ CopyMem (&Data32, (BufferOut + 2), sizeof (UINT32));
+ TpmOutSize = SwapBytes32 (Data32);
+ if (*SizeOut < TpmOutSize) {
+ Status = EFI_BUFFER_TOO_SMALL;
+ goto Exit;
+ }
+ *SizeOut = TpmOutSize;
+ //
+ // Continue reading the remaining data
+ //
+ while ( Index < TpmOutSize ) {
+ for (; BurstCount > 0; BurstCount--) {
+ *(BufferOut + Index) = MmioRead8 ((UINTN)&TisReg->DataFifo);
+ Index++;
+ if (Index == TpmOutSize) {
+ Status = EFI_SUCCESS;
+ goto Exit;
+ }
+ }
+ Status = TisPcReadBurstCount (TisReg, &BurstCount);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_TIMEOUT;
+ goto Exit;
+ }
+ }
+Exit:
+ MmioWrite8((UINTN)&TisReg->Status, TIS_PC_STS_READY);
+ return Status;
+}
+
diff --git a/SecurityPkg/Tcg/TcgPei/TpmComm.c b/SecurityPkg/Tcg/TcgPei/TpmComm.c
new file mode 100644
index 0000000000..fb5011ee9d
--- /dev/null
+++ b/SecurityPkg/Tcg/TcgPei/TpmComm.c
@@ -0,0 +1,272 @@
+/** @file
+ Utility functions used by TPM PEI driver.
+
+Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "TpmComm.h"
+
+/**
+ Send a command to TPM for execution and return response data.
+
+ @param[in] PeiServices Describes the list of possible PEI Services.
+ @param[in] TisReg TPM register space base address.
+ @param[in] BufferIn Buffer for command data.
+ @param[in] SizeIn Size of command data.
+ @param[in, out] BufferOut Buffer for response data.
+ @param[in, out] SizeOut size of response data.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_TIMEOUT The register can't run into the expected status in time.
+ @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+
+**/
+EFI_STATUS
+TisTpmCommand (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN TIS_PC_REGISTERS_PTR TisReg,
+ IN UINT8 *BufferIn,
+ IN UINT32 SizeIn,
+ IN OUT UINT8 *BufferOut,
+ IN OUT UINT32 *SizeOut
+ );
+
+/**
+ Send TPM_Startup command to TPM.
+
+ @param[in] PeiServices Describes the list of possible PEI Services.
+ @param[in] TpmHandle TPM handle.
+ @param[in] BootMode Boot mode.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_TIMEOUT The register can't run into the expected status in time.
+ @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+
+**/
+EFI_STATUS
+TpmCommStartup (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN TIS_TPM_HANDLE TpmHandle,
+ IN EFI_BOOT_MODE BootMode
+ )
+{
+ EFI_STATUS Status;
+ TPM_STARTUP_TYPE TpmSt;
+ UINT32 TpmRecvSize;
+ UINT32 TpmSendSize;
+ TPM_CMD_START_UP SendBuffer;
+ UINT8 RecvBuffer[20];
+
+ TpmSt = TPM_ST_CLEAR;
+ if (BootMode == BOOT_ON_S3_RESUME) {
+ TpmSt = TPM_ST_STATE;
+ }
+ //
+ // send Tpm command TPM_ORD_Startup
+ //
+ TpmRecvSize = 20;
+ TpmSendSize = sizeof (TPM_CMD_START_UP);
+ SendBuffer.Hdr.tag = SwapBytes16 (TPM_TAG_RQU_COMMAND);
+ SendBuffer.Hdr.paramSize = SwapBytes32 (TpmSendSize);
+ SendBuffer.Hdr.ordinal = SwapBytes32 (TPM_ORD_Startup);
+ SendBuffer.TpmSt = SwapBytes16 (TpmSt);
+ Status = TisTpmCommand (PeiServices, TpmHandle, (UINT8 *)&SendBuffer, TpmSendSize, RecvBuffer, &TpmRecvSize);
+ return Status;
+}
+
+/**
+ Send TPM_ContinueSelfTest command to TPM.
+
+ @param[in] PeiServices Describes the list of possible PEI Services.
+ @param[in] TpmHandle TPM handle.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_TIMEOUT The register can't run into the expected status in time.
+ @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+
+**/
+EFI_STATUS
+TpmCommContinueSelfTest (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN TIS_TPM_HANDLE TpmHandle
+ )
+{
+ EFI_STATUS Status;
+ UINT32 TpmRecvSize;
+ UINT32 TpmSendSize;
+ TPM_CMD_SELF_TEST SendBuffer;
+ UINT8 RecvBuffer[20];
+
+ //
+ // send Tpm command TPM_ORD_ContinueSelfTest
+ //
+ TpmRecvSize = 20;
+ TpmSendSize = sizeof (TPM_CMD_SELF_TEST);
+ SendBuffer.Hdr.tag = SwapBytes16 (TPM_TAG_RQU_COMMAND);
+ SendBuffer.Hdr.paramSize = SwapBytes32 (TpmSendSize);
+ SendBuffer.Hdr.ordinal = SwapBytes32 (TPM_ORD_ContinueSelfTest);
+ Status = TisTpmCommand (PeiServices, TpmHandle, (UINT8 *)&SendBuffer, TpmSendSize, RecvBuffer, &TpmRecvSize);
+ return Status;
+}
+
+/**
+ Get TPM capability flags.
+
+ @param[in] PeiServices Describes the list of possible PEI Services.
+ @param[in] TpmHandle TPM handle.
+ @param[out] Deactivated Returns deactivated flag.
+ @param[out] LifetimeLock Returns physicalPresenceLifetimeLock permanent flag.
+ @param[out] CmdEnable Returns physicalPresenceCMDEnable permanent flag.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_TIMEOUT The register can't run into the expected status in time.
+ @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+
+**/
+EFI_STATUS
+TpmCommGetCapability (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN TIS_TPM_HANDLE TpmHandle,
+ OUT BOOLEAN *Deactivated, OPTIONAL
+ OUT BOOLEAN *LifetimeLock, OPTIONAL
+ OUT BOOLEAN *CmdEnable OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ UINT32 TpmRecvSize;
+ UINT32 TpmSendSize;
+ TPM_CMD_GET_CAPABILITY SendBuffer;
+ UINT8 RecvBuffer[40];
+ TPM_PERMANENT_FLAGS *TpmPermanentFlags;
+
+ //
+ // send Tpm command TPM_ORD_GetCapability
+ //
+ TpmRecvSize = 40;
+ TpmSendSize = sizeof (TPM_CMD_GET_CAPABILITY);
+ SendBuffer.Hdr.tag = SwapBytes16 (TPM_TAG_RQU_COMMAND);
+ SendBuffer.Hdr.paramSize = SwapBytes32 (TpmSendSize);
+ SendBuffer.Hdr.ordinal = SwapBytes32 (TPM_ORD_GetCapability);
+ SendBuffer.Capability = SwapBytes32 (TPM_CAP_FLAG);
+ SendBuffer.CapabilityFlagSize = SwapBytes32 (sizeof (TPM_CAP_FLAG_PERMANENT));
+ SendBuffer.CapabilityFlag = SwapBytes32 (TPM_CAP_FLAG_PERMANENT);
+ Status = TisTpmCommand (PeiServices, TpmHandle, (UINT8 *)&SendBuffer, TpmSendSize, RecvBuffer, &TpmRecvSize);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ TpmPermanentFlags = (TPM_PERMANENT_FLAGS *)&RecvBuffer[sizeof (TPM_RSP_COMMAND_HDR) + sizeof (UINT32)];
+ if (Deactivated != NULL) {
+ *Deactivated = TpmPermanentFlags->deactivated;
+ }
+
+ if (LifetimeLock != NULL) {
+ *LifetimeLock = TpmPermanentFlags->physicalPresenceLifetimeLock;
+ }
+
+ if (CmdEnable != NULL) {
+ *CmdEnable = TpmPermanentFlags->physicalPresenceCMDEnable;
+ }
+ return Status;
+}
+
+/**
+ Extend a TPM PCR.
+
+ @param[in] PeiServices Describes the list of possible PEI Services.
+ @param[in] TpmHandle TPM handle.
+ @param[in] DigestToExtend The 160 bit value representing the event to be recorded.
+ @param[in] PcrIndex The PCR to be updated.
+ @param[out] NewPcrValue New PCR value after extend.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_TIMEOUT The register can't run into the expected status in time.
+ @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+
+**/
+EFI_STATUS
+TpmCommExtend (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN TIS_TPM_HANDLE TpmHandle,
+ IN TPM_DIGEST *DigestToExtend,
+ IN TPM_PCRINDEX PcrIndex,
+ OUT TPM_DIGEST *NewPcrValue
+ )
+{
+ EFI_STATUS Status;
+ UINT32 TpmSendSize;
+ UINT32 TpmRecvSize;
+ TPM_CMD_EXTEND SendBuffer;
+ UINT8 RecvBuffer[10 + sizeof(TPM_DIGEST)];
+
+ //
+ // send Tpm command TPM_ORD_Extend
+ //
+ TpmRecvSize = sizeof (TPM_RSP_COMMAND_HDR) + sizeof (TPM_DIGEST);
+ TpmSendSize = sizeof (TPM_CMD_EXTEND);
+ SendBuffer.Hdr.tag = SwapBytes16 (TPM_TAG_RQU_COMMAND);
+ SendBuffer.Hdr.paramSize = SwapBytes32 (TpmSendSize);
+ SendBuffer.Hdr.ordinal = SwapBytes32 (TPM_ORD_Extend);
+ SendBuffer.PcrIndex = SwapBytes32 (PcrIndex);
+ CopyMem (&SendBuffer.TpmDigest, (UINT8 *)DigestToExtend, sizeof (TPM_DIGEST));
+ Status = TisTpmCommand (PeiServices, TpmHandle, (UINT8 *)&SendBuffer, TpmSendSize, RecvBuffer, &TpmRecvSize);
+ ASSERT_EFI_ERROR (Status);
+
+ if(NewPcrValue != NULL) {
+ CopyMem ((UINT8*)NewPcrValue, &RecvBuffer[10], sizeof (TPM_DIGEST));
+ }
+
+ return Status;
+}
+
+
+/**
+ Send TSC_PhysicalPresence command to TPM.
+
+ @param[in] PeiServices Describes the list of possible PEI Services.
+ @param[in] TpmHandle TPM handle.
+ @param[in] PhysicalPresence The state to set the TPMs Physical Presence flags.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_TIMEOUT The register can't run into the expected status in time.
+ @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+
+**/
+EFI_STATUS
+TpmCommPhysicalPresence (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN TIS_TPM_HANDLE TpmHandle,
+ IN TPM_PHYSICAL_PRESENCE PhysicalPresence
+ )
+{
+ EFI_STATUS Status;
+ UINT32 TpmSendSize;
+ UINT32 TpmRecvSize;
+ TPM_CMD_PHYSICAL_PRESENCE SendBuffer;
+ UINT8 RecvBuffer[10];
+
+ //
+ // send Tpm command TSC_ORD_PhysicalPresence
+ //
+ TpmRecvSize = 10;
+ TpmSendSize = sizeof (TPM_CMD_PHYSICAL_PRESENCE);
+ SendBuffer.Hdr.tag = SwapBytes16 (TPM_TAG_RQU_COMMAND);
+ SendBuffer.Hdr.paramSize = SwapBytes32 (TpmSendSize);
+ SendBuffer.Hdr.ordinal = SwapBytes32 (TSC_ORD_PhysicalPresence);
+ SendBuffer.PhysicalPresence = SwapBytes16 (PhysicalPresence);
+ Status = TisTpmCommand (PeiServices, TpmHandle, (UINT8 *)&SendBuffer, TpmSendSize, RecvBuffer, &TpmRecvSize);
+ return Status;
+}
diff --git a/SecurityPkg/Tcg/TcgPei/TpmComm.h b/SecurityPkg/Tcg/TcgPei/TpmComm.h
new file mode 100644
index 0000000000..52d7f2e20d
--- /dev/null
+++ b/SecurityPkg/Tcg/TcgPei/TpmComm.h
@@ -0,0 +1,163 @@
+/** @file
+ The header file for TPM PEI driver.
+
+Copyright (c) 2005 - 2010, Intel Corporation. All rights reserved.
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _TPM_COMM_H_
+#define _TPM_COMM_H_
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#pragma pack(1)
+
+typedef struct {
+ TPM_RQU_COMMAND_HDR Hdr;
+ TPM_STARTUP_TYPE TpmSt;
+} TPM_CMD_START_UP;
+
+typedef struct {
+ TPM_RQU_COMMAND_HDR Hdr;
+} TPM_CMD_SELF_TEST;
+
+typedef struct {
+ TPM_RQU_COMMAND_HDR Hdr;
+ UINT32 Capability;
+ UINT32 CapabilityFlagSize;
+ UINT32 CapabilityFlag;
+} TPM_CMD_GET_CAPABILITY;
+
+typedef struct {
+ TPM_RQU_COMMAND_HDR Hdr;
+ TPM_PCRINDEX PcrIndex;
+ TPM_DIGEST TpmDigest;
+} TPM_CMD_EXTEND;
+
+typedef struct {
+ TPM_RQU_COMMAND_HDR Hdr;
+ TPM_PHYSICAL_PRESENCE PhysicalPresence;
+} TPM_CMD_PHYSICAL_PRESENCE;
+
+#pragma pack()
+
+/**
+ Send TPM_Startup command to TPM.
+
+ @param[in] PeiServices Describes the list of possible PEI Services.
+ @param[in] TpmHandle TPM handle.
+ @param[in] BootMode Boot mode.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_TIMEOUT The register can't run into the expected status in time.
+ @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+
+**/
+EFI_STATUS
+TpmCommStartup (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN TIS_TPM_HANDLE TpmHandle,
+ IN EFI_BOOT_MODE BootMode
+ );
+
+/**
+ Send TPM_ContinueSelfTest command to TPM.
+
+ @param[in] PeiServices Describes the list of possible PEI Services.
+ @param[in] TpmHandle TPM handle.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_TIMEOUT The register can't run into the expected status in time.
+ @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+
+**/
+EFI_STATUS
+TpmCommContinueSelfTest (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN TIS_TPM_HANDLE TpmHandle
+ );
+
+/**
+ Get TPM capability flags.
+
+ @param[in] PeiServices Describes the list of possible PEI Services.
+ @param[in] TpmHandle TPM handle.
+ @param[out] Deactivated Returns deactivated flag.
+ @param[out] LifetimeLock Returns physicalPresenceLifetimeLock permanent flag.
+ @param[out] CmdEnable Returns physicalPresenceCMDEnable permanent flag.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_TIMEOUT The register can't run into the expected status in time.
+ @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+
+**/
+EFI_STATUS
+TpmCommGetCapability (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN TIS_TPM_HANDLE TpmHandle,
+ OUT BOOLEAN *Deactivated, OPTIONAL
+ OUT BOOLEAN *LifetimeLock, OPTIONAL
+ OUT BOOLEAN *CmdEnable OPTIONAL
+ );
+
+/**
+ Extend a TPM PCR.
+
+ @param[in] PeiServices Describes the list of possible PEI Services.
+ @param[in] TpmHandle TPM handle.
+ @param[in] DigestToExtend The 160 bit value representing the event to be recorded.
+ @param[in] PcrIndex The PCR to be updated.
+ @param[out] NewPcrValue New PCR value after extend.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_TIMEOUT The register can't run into the expected status in time.
+ @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+
+**/
+EFI_STATUS
+TpmCommExtend (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN TIS_TPM_HANDLE TpmHandle,
+ IN TPM_DIGEST *DigestToExtend,
+ IN TPM_PCRINDEX PcrIndex,
+ OUT TPM_DIGEST *NewPcrValue
+ );
+
+
+/**
+ Send TSC_PhysicalPresence command to TPM.
+
+ @param[in] PeiServices Describes the list of possible PEI Services.
+ @param[in] TpmHandle TPM handle.
+ @param[in] PhysicalPresence The state to set the TPMs Physical Presence flags.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_TIMEOUT The register can't run into the expected status in time.
+ @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+
+**/
+EFI_STATUS
+TpmCommPhysicalPresence (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN TIS_TPM_HANDLE TpmHandle,
+ IN TPM_PHYSICAL_PRESENCE PhysicalPresence
+ );
+
+#endif // _TPM_COMM_H_
diff --git a/SecurityPkg/Tcg/TcgSmm/TcgSmm.c b/SecurityPkg/Tcg/TcgSmm/TcgSmm.c
new file mode 100644
index 0000000000..9116944081
--- /dev/null
+++ b/SecurityPkg/Tcg/TcgSmm/TcgSmm.c
@@ -0,0 +1,455 @@
+/** @file
+ It updates TPM items in ACPI table and registers SMI callback
+ functions for physical presence and ClearMemory.
+
+Copyright (c) 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+//
+// AML parsing definitions
+//
+#define AML_OPREGION_OP 0x80
+#define AML_BYTE_PREFIX 0x0A
+#define AML_DWORD_PREFIX 0x0C
+
+#pragma pack(1)
+typedef struct {
+ UINT8 SoftwareSmi;
+ UINT32 Parameter;
+ UINT32 Response;
+ UINT32 Request;
+ UINT32 LastRequest;
+ UINT32 ReturnCode;
+} PHYSICAL_PRESENCE_NVS;
+
+typedef struct {
+ UINT8 SoftwareSmi;
+ UINT32 Parameter;
+ UINT32 Request;
+} MEMORY_CLEAR_NVS;
+
+typedef struct {
+ PHYSICAL_PRESENCE_NVS PhysicalPresence;
+ MEMORY_CLEAR_NVS MemoryClear;
+} TCG_NVS;
+
+typedef struct {
+ UINT8 OpRegionOp;
+ UINT32 NameString;
+ UINT8 RegionSpace;
+ UINT8 DWordPrefix;
+ UINT32 RegionOffset;
+ UINT8 BytePrefix;
+ UINT8 RegionLen;
+} AML_OP_REGION_32_8;
+#pragma pack()
+
+EFI_SMM_VARIABLE_PROTOCOL *mSmmVariable;
+TCG_NVS *mTcgNvs;
+
+/**
+ Software SMI callback for TPM physical presence which is called from ACPI method.
+
+ @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
+ @param[in] Context Points to an optional handler context which was specified when the
+ handler was registered.
+ @param[in, out] CommBuffer A pointer to a collection of data in memory that will
+ be conveyed from a non-SMM environment into an SMM environment.
+ @param[in, out] CommBufferSize The size of the CommBuffer.
+
+ @retval EFI_SUCCESS The interrupt was handled successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+PhysicalPresenceCallback (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *Context,
+ IN OUT VOID *CommBuffer,
+ IN OUT UINTN *CommBufferSize
+ )
+{
+ EFI_STATUS Status;
+ UINTN DataSize;
+ EFI_PHYSICAL_PRESENCE PpData;
+ UINT8 Flags;
+ BOOLEAN RequestConfirmed;
+
+ //
+ // Get the Physical Presence variable
+ //
+ DataSize = sizeof (EFI_PHYSICAL_PRESENCE);
+ Status = mSmmVariable->SmmGetVariable (
+ PHYSICAL_PRESENCE_VARIABLE,
+ &gEfiPhysicalPresenceGuid,
+ NULL,
+ &DataSize,
+ &PpData
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_SUCCESS;
+ }
+
+ DEBUG ((EFI_D_INFO, "[TPM] PP callback, Parameter = %x\n", mTcgNvs->PhysicalPresence.Parameter));
+ if (mTcgNvs->PhysicalPresence.Parameter == 5) {
+ //
+ // Return TPM Operation Response to OS Environment
+ //
+ mTcgNvs->PhysicalPresence.LastRequest = PpData.LastPPRequest;
+ mTcgNvs->PhysicalPresence.Response = PpData.PPResponse;
+
+ } else if ((mTcgNvs->PhysicalPresence.Parameter == 2) || (mTcgNvs->PhysicalPresence.Parameter == 7)) {
+ //
+ // Submit TPM Operation Request to Pre-OS Environment
+ //
+
+ if (mTcgNvs->PhysicalPresence.Request == SET_OPERATOR_AUTH) {
+ //
+ // This command requires UI to prompt user for Auth data, NOT implemented.
+ //
+ mTcgNvs->PhysicalPresence.ReturnCode = 1;
+ return EFI_SUCCESS;
+ }
+
+ if (PpData.PPRequest != mTcgNvs->PhysicalPresence.Request) {
+ PpData.PPRequest = (UINT8) mTcgNvs->PhysicalPresence.Request;
+ DataSize = sizeof (EFI_PHYSICAL_PRESENCE);
+ Status = mSmmVariable->SmmSetVariable (
+ PHYSICAL_PRESENCE_VARIABLE,
+ &gEfiPhysicalPresenceGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ DataSize,
+ &PpData
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+ //
+ // General failure.
+ //
+ mTcgNvs->PhysicalPresence.ReturnCode = 2;
+ return EFI_SUCCESS;
+ }
+ mTcgNvs->PhysicalPresence.ReturnCode = 0;
+ } else if (mTcgNvs->PhysicalPresence.Parameter == 8) {
+ //
+ // Get User Confirmation Status for Operation
+ //
+ Flags = PpData.Flags;
+ RequestConfirmed = FALSE;
+
+ switch (mTcgNvs->PhysicalPresence.Request) {
+ case ENABLE:
+ case DISABLE:
+ case ACTIVATE:
+ case DEACTIVATE:
+ case ENABLE_ACTIVATE:
+ case DEACTIVATE_DISABLE:
+ case SET_OWNER_INSTALL_TRUE:
+ case SET_OWNER_INSTALL_FALSE:
+ case ENABLE_ACTIVATE_OWNER_TRUE:
+ case DEACTIVATE_DISABLE_OWNER_FALSE:
+ if ((Flags & FLAG_NO_PPI_PROVISION) != 0) {
+ RequestConfirmed = TRUE;
+ }
+ break;
+
+ case CLEAR:
+ case ENABLE_ACTIVATE_CLEAR:
+ if ((Flags & FLAG_NO_PPI_CLEAR) != 0) {
+ RequestConfirmed = TRUE;
+ }
+ break;
+
+ case DEFERRED_PP_UNOWNERED_FIELD_UPGRADE:
+ if ((Flags & FLAG_NO_PPI_MAINTENANCE) != 0) {
+ RequestConfirmed = TRUE;
+ }
+ break;
+
+ case ENABLE_ACTIVATE_CLEAR_ENABLE_ACTIVATE:
+ case CLEAR_ENABLE_ACTIVATE:
+ if ((Flags & FLAG_NO_PPI_CLEAR) != 0 && (Flags & FLAG_NO_PPI_PROVISION) != 0) {
+ RequestConfirmed = TRUE;
+ }
+ break;
+
+ case SET_NO_PPI_PROVISION_FALSE:
+ case SET_NO_PPI_CLEAR_FALSE:
+ case SET_NO_PPI_MAINTENANCE_FALSE:
+ case NO_ACTION:
+ RequestConfirmed = TRUE;
+ break;
+
+ case SET_OPERATOR_AUTH:
+ //
+ // This command requires UI to prompt user for Auth data
+ // Here it is NOT implemented
+ //
+ mTcgNvs->PhysicalPresence.ReturnCode = 0;
+ return EFI_SUCCESS;
+ }
+
+ if (RequestConfirmed) {
+ //
+ // Allowed and physically present user not required
+ //
+ mTcgNvs->PhysicalPresence.ReturnCode = 4;
+ } else {
+ //
+ // Allowed and physically present user required
+ //
+ mTcgNvs->PhysicalPresence.ReturnCode = 3;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Software SMI callback for MemoryClear which is called from ACPI method.
+
+ @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
+ @param[in] Context Points to an optional handler context which was specified when the
+ handler was registered.
+ @param[in, out] CommBuffer A pointer to a collection of data in memory that will
+ be conveyed from a non-SMM environment into an SMM environment.
+ @param[in, out] CommBufferSize The size of the CommBuffer.
+
+ @retval EFI_SUCCESS The interrupt was handled successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+MemoryClearCallback (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *Context,
+ IN OUT VOID *CommBuffer,
+ IN OUT UINTN *CommBufferSize
+ )
+{
+ EFI_STATUS Status;
+ UINTN DataSize;
+ UINT8 MorControl;
+
+ if (mTcgNvs->MemoryClear.Parameter == 1) {
+ //
+ // Called from ACPI _DSM method, save the MOR data to variable.
+ //
+ MorControl = (UINT8) mTcgNvs->MemoryClear.Request;
+ } else if (mTcgNvs->MemoryClear.Parameter == 2) {
+ //
+ // Called from ACPI _PTS method, setup ClearMemory flags if needed.
+ //
+ DataSize = sizeof (UINT8);
+ Status = mSmmVariable->SmmGetVariable (
+ MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,
+ &gEfiMemoryOverwriteControlDataGuid,
+ NULL,
+ &DataSize,
+ &MorControl
+ );
+ if (EFI_ERROR (Status)) {
+ ASSERT (Status == EFI_NOT_FOUND);
+ return EFI_SUCCESS;
+ }
+
+ if (MOR_CLEAR_MEMORY_VALUE (MorControl) == 0x0) {
+ return EFI_SUCCESS;
+ }
+ MorControl &= ~MOR_CLEAR_MEMORY_BIT_MASK;
+ }
+
+ DataSize = sizeof (UINT8);
+ Status = mSmmVariable->SmmSetVariable (
+ MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,
+ &gEfiMemoryOverwriteControlDataGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ DataSize,
+ &MorControl
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Find the operation region in TCG ACPI table by given Name and Size,
+ and initialize it if the region is found.
+
+ @param[in, out] Table The TPM item in ACPI table.
+ @param[in] Name The name string to find in TPM table.
+ @param[in] Size The size of the region to find.
+
+ @return The allocated address for the found region.
+
+**/
+VOID *
+AssignOpRegion (
+ EFI_ACPI_DESCRIPTION_HEADER *Table,
+ UINT32 Name,
+ UINT16 Size
+ )
+{
+ EFI_STATUS Status;
+ AML_OP_REGION_32_8 *OpRegion;
+ EFI_PHYSICAL_ADDRESS MemoryAddress;
+
+ MemoryAddress = SIZE_4GB - 1;
+
+ //
+ // Patch some pointers for the ASL code before loading the SSDT.
+ //
+ for (OpRegion = (AML_OP_REGION_32_8 *) (Table + 1);
+ OpRegion <= (AML_OP_REGION_32_8 *) ((UINT8 *) Table + Table->Length);
+ OpRegion = (AML_OP_REGION_32_8 *) ((UINT8 *) OpRegion + 1)) {
+ if ((OpRegion->OpRegionOp == AML_OPREGION_OP) &&
+ (OpRegion->NameString == Name) &&
+ (OpRegion->RegionLen == Size) &&
+ (OpRegion->DWordPrefix == AML_DWORD_PREFIX) &&
+ (OpRegion->BytePrefix == AML_BYTE_PREFIX)) {
+
+ Status = gBS->AllocatePages(AllocateMaxAddress, EfiACPIMemoryNVS, EFI_SIZE_TO_PAGES (Size), &MemoryAddress);
+ ASSERT_EFI_ERROR (Status);
+ ZeroMem ((VOID *)(UINTN)MemoryAddress, Size);
+ OpRegion->RegionOffset = (UINT32) (UINTN) MemoryAddress;
+ break;
+ }
+ }
+
+ return (VOID *) (UINTN) MemoryAddress;
+}
+
+/**
+ Initialize and publish TPM items in ACPI table.
+
+ @retval EFI_SUCCESS The TCG ACPI table is published successfully.
+ @retval Others The TCG ACPI table is not published.
+
+**/
+EFI_STATUS
+PublishAcpiTable (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_ACPI_TABLE_PROTOCOL *AcpiTable;
+ UINTN TableKey;
+ EFI_ACPI_DESCRIPTION_HEADER *Table;
+ UINTN TableSize;
+
+ Status = GetSectionFromFv (
+ &gEfiCallerIdGuid,
+ EFI_SECTION_RAW,
+ 0,
+ (VOID **) &Table,
+ &TableSize
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ ASSERT (Table->OemTableId == SIGNATURE_64 ('T', 'c', 'g', 'T', 'a', 'b', 'l', 'e'));
+ mTcgNvs = AssignOpRegion (Table, SIGNATURE_32 ('T', 'N', 'V', 'S'), sizeof (TCG_NVS));
+ ASSERT (mTcgNvs != NULL);
+
+ //
+ // Publish the TPM ACPI table
+ //
+ Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTable);
+ ASSERT_EFI_ERROR (Status);
+
+ TableKey = 0;
+ Status = AcpiTable->InstallAcpiTable (
+ AcpiTable,
+ Table,
+ TableSize,
+ &TableKey
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
+/**
+ The driver's entry point.
+
+ It install callbacks for TPM physical presence and MemoryClear, and locate
+ SMM variable to be used in the callback function.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The entry point is executed successfully.
+ @retval Others Some error occurs when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeTcgSmm (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_SMM_SW_DISPATCH2_PROTOCOL *SwDispatch;
+ EFI_SMM_SW_REGISTER_CONTEXT SwContext;
+ EFI_HANDLE SwHandle;
+
+ Status = PublishAcpiTable ();
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Get the Sw dispatch protocol and register SMI callback functions.
+ //
+ Status = gSmst->SmmLocateProtocol (&gEfiSmmSwDispatch2ProtocolGuid, NULL, (VOID**)&SwDispatch);
+ ASSERT_EFI_ERROR (Status);
+ SwContext.SwSmiInputValue = (UINTN) -1;
+ Status = SwDispatch->Register (SwDispatch, PhysicalPresenceCallback, &SwContext, &SwHandle);
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ mTcgNvs->PhysicalPresence.SoftwareSmi = (UINT8) SwContext.SwSmiInputValue;
+
+ SwContext.SwSmiInputValue = (UINTN) -1;
+ Status = SwDispatch->Register (SwDispatch, MemoryClearCallback, &SwContext, &SwHandle);
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ mTcgNvs->MemoryClear.SoftwareSmi = (UINT8) SwContext.SwSmiInputValue;
+
+ //
+ // Locate SmmVariableProtocol.
+ //
+ Status = gSmst->SmmLocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID**)&mSmmVariable);
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
+
diff --git a/SecurityPkg/Tcg/TcgSmm/TcgSmm.inf b/SecurityPkg/Tcg/TcgSmm/TcgSmm.inf
new file mode 100644
index 0000000000..c8e7092e73
--- /dev/null
+++ b/SecurityPkg/Tcg/TcgSmm/TcgSmm.inf
@@ -0,0 +1,56 @@
+## @file
+# This driver implements TPM definition block in ACPI table and
+# registers SMI callback functions for physical presence and
+# MemoryClear to handle the requests from ACPI method.
+#
+# Copyright (c) 2011, Intel Corporation. All rights reserved.
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = TcgSmm
+ FILE_GUID = 42293093-76B9-4482-8C02-3BEFDEA9B35D
+ MODULE_TYPE = DXE_SMM_DRIVER
+ PI_SPECIFICATION_VERSION = 0x0001000A
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializeTcgSmm
+
+[Sources]
+ TcgSmm.c
+ Tpm.asl
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ UefiDriverEntryPoint
+ SmmServicesTableLib
+ UefiBootServicesTableLib
+ DebugLib
+ DxeServicesLib
+
+[Guids]
+ gEfiPhysicalPresenceGuid
+ gEfiMemoryOverwriteControlDataGuid
+
+[Protocols]
+ gEfiSmmSwDispatch2ProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiSmmVariableProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiAcpiTableProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+
+[Depex]
+ gEfiAcpiTableProtocolGuid AND
+ gEfiSmmSwDispatch2ProtocolGuid AND
+ gEfiSmmVariableProtocolGuid AND
+ gEfiTcgProtocolGuid
\ No newline at end of file
diff --git a/SecurityPkg/Tcg/TcgSmm/Tpm.asl b/SecurityPkg/Tcg/TcgSmm/Tpm.asl
new file mode 100644
index 0000000000..000fc661a9
--- /dev/null
+++ b/SecurityPkg/Tcg/TcgSmm/Tpm.asl
@@ -0,0 +1,354 @@
+/** @file
+ The TPM definition block in ACPI table for physical presence
+ and MemoryClear.
+
+Copyright (c) 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+DefinitionBlock (
+ "Tpm.aml",
+ "SSDT",
+ 1,
+ "Intel_",
+ "TcgTable",
+ 0x1000
+ )
+{
+ Scope (\_SB)
+ {
+ Device (TPM)
+ {
+ //
+ // Define _HID, "PNP0C31" is defined in
+ // "Secure Startup-FVE and TPM Admin BIOS and Platform Requirements"
+ //
+ Name (_HID, EISAID ("PNP0C31"))
+
+ //
+ // Readable name of this device, don't know if this way is correct yet
+ //
+ Name (_STR, Unicode ("TPM 1.2 Device"))
+
+ //
+ // Return the resource consumed by TPM device
+ //
+ Name (_CRS, ResourceTemplate () {
+ Memory32Fixed (ReadOnly, 0xfed40000, 0x5000)
+ })
+
+ //
+ // Operational region for Smi port access
+ //
+ OperationRegion (SMIP, SystemIO, 0xB2, 1)
+ Field (SMIP, ByteAcc, NoLock, Preserve)
+ {
+ IOB2, 8
+ }
+
+ //
+ // Operational region for TPM access
+ //
+ OperationRegion (TPMR, SystemMemory, 0xfed40000, 0x5000)
+ Field (TPMR, AnyAcc, NoLock, Preserve)
+ {
+ ACC0, 8,
+ }
+
+ //
+ // Operational region for TPM support, TPM Physical Presence and TPM Memory Clear
+ // Region Offset to be fixed at runtime
+ //
+ OperationRegion (TNVS, SystemMemory, 0xFFFF0000, 0x1E)
+ Field (TNVS, AnyAcc, NoLock, Preserve)
+ {
+ PPIN, 8, // Software SMI for Physical Presence Interface
+ PPIP, 32, // Used for save physical presence paramter
+ PPRP, 32, // Physical Presence request operation response
+ PPRQ, 32, // Physical Presence request operation
+ LPPR, 32, // Last Physical Presence request operation
+ FRET, 32, // Physical Presence function return code
+ MCIN, 8, // Software SMI for Memory Clear Interface
+ MCIP, 32, // Used for save the Mor paramter
+ MORD, 32 // Memory Overwrite Request Data
+ }
+
+ Method (PTS, 1, Serialized)
+ {
+ //
+ // Detect Sx state for MOR, only S4, S5 need to handle
+ //
+ If (LAnd (LLess (Arg0, 6), LGreater (Arg0, 3)))
+ {
+ //
+ // Bit4 -- DisableAutoDetect. 0 -- Firmware MAY autodetect.
+ //
+ If (LNot (And (MORD, 0x10)))
+ {
+ //
+ // Triggle the SMI through ACPI _PTS method.
+ //
+ Store (0x02, MCIP)
+
+ //
+ // Triggle the SMI interrupt
+ //
+ Store (MCIN, IOB2)
+ }
+ }
+ Return (0)
+ }
+
+ Method (_STA, 0)
+ {
+ if (LEqual (ACC0, 0xff))
+ {
+ Return (0)
+ }
+ Return (0x0f)
+ }
+
+ //
+ // TCG Hardware Information
+ //
+ Method (HINF, 3, Serialized, 0, {BuffObj, PkgObj}, {IntObj, IntObj, PkgObj})
+ {
+ //
+ // Switch by function index
+ //
+ Switch (ToInteger(Arg1))
+ {
+ Case (0)
+ {
+ //
+ // Standard query
+ //
+ Return (Buffer () {0x03})
+ }
+ Case (1)
+ {
+ //
+ // Return failure if no TPM present
+ //
+ Name(TPMV, Package () {0x01, Package () {ToBCD (1), ToBCD (20)}})
+ if (LEqual (_STA (), 0x00))
+ {
+ Return (Package () {0x00})
+ }
+
+ //
+ // Return TPM version
+ //
+ Return (TPMV)
+ }
+ Default {BreakPoint}
+ }
+ Return (Buffer () {0})
+ }
+
+ Name(TPM2, Package (0x02){
+ Zero,
+ Zero
+ })
+
+ Name(TPM3, Package (0x03){
+ Zero,
+ Zero,
+ Zero
+ })
+
+ //
+ // TCG Physical Presence Interface
+ //
+ Method (TPPI, 3, Serialized, 0, {BuffObj, PkgObj, IntObj, StrObj}, {IntObj, IntObj, PkgObj})
+ {
+ //
+ // Switch by function index
+ //
+ Switch (ToInteger(Arg1))
+ {
+ Case (0)
+ {
+ //
+ // Standard query, supports function 1-8
+ //
+ Return (Buffer () {0xFF, 0x01})
+ }
+ Case (1)
+ {
+ //
+ // a) Get Physical Presence Interface Version
+ //
+ Return ("1.2")
+ }
+ Case (2)
+ {
+ //
+ // b) Submit TPM Operation Request to Pre-OS Environment
+ //
+
+ Store (DerefOf (Index (Arg2, 0x00)), PPRQ)
+ Store (0x02, PPIP)
+
+ //
+ // Triggle the SMI interrupt
+ //
+ Store (PPIN, IOB2)
+ Return (FRET)
+
+
+ }
+ Case (3)
+ {
+ //
+ // c) Get Pending TPM Operation Requested By the OS
+ //
+
+ Store (PPRQ, Index (TPM2, 0x01))
+ Return (TPM2)
+ }
+ Case (4)
+ {
+ //
+ // d) Get Platform-Specific Action to Transition to Pre-OS Environment
+ //
+ Return (2)
+ }
+ Case (5)
+ {
+ //
+ // e) Return TPM Operation Response to OS Environment
+ //
+ Store (0x05, PPIP)
+
+ //
+ // Triggle the SMI interrupt
+ //
+ Store (PPIN, IOB2)
+
+ Store (LPPR, Index (TPM3, 0x01))
+ Store (PPRP, Index (TPM3, 0x02))
+
+ Return (TPM3)
+ }
+ Case (6)
+ {
+
+ //
+ // f) Submit preferred user language (Not implemented)
+ //
+
+ Return (3)
+
+ }
+ Case (7)
+ {
+ //
+ // g) Submit TPM Operation Request to Pre-OS Environment 2
+ //
+ Store (7, PPIP)
+ Store (DerefOf (Index (Arg2, 0x00)), PPRQ)
+
+ //
+ // Triggle the SMI interrupt
+ //
+ Store (PPIN, IOB2)
+ Return (FRET)
+ }
+ Case (8)
+ {
+ //
+ // e) Get User Confirmation Status for Operation
+ //
+ Store (8, PPIP)
+ Store (DerefOf (Index (Arg2, 0x00)), PPRQ)
+
+ //
+ // Triggle the SMI interrupt
+ //
+ Store (PPIN, IOB2)
+
+ Return (FRET)
+ }
+
+ Default {BreakPoint}
+ }
+ Return (1)
+ }
+
+ Method (TMCI, 3, Serialized, 0, IntObj, {IntObj, IntObj, PkgObj})
+ {
+ //
+ // Switch by function index
+ //
+ Switch (ToInteger (Arg1))
+ {
+ Case (0)
+ {
+ //
+ // Standard query, supports function 1-1
+ //
+ Return (Buffer () {0x03})
+ }
+ Case (1)
+ {
+ //
+ // Save the Operation Value of the Request to MORD (reserved memory)
+ //
+ Store (DerefOf (Index (Arg2, 0x00)), MORD)
+
+ //
+ // Triggle the SMI through ACPI _DSM method.
+ //
+ Store (0x01, MCIP)
+
+ //
+ // Triggle the SMI interrupt
+ //
+ Store (MCIN, IOB2)
+ Return (0)
+ }
+ Default {BreakPoint}
+ }
+ Return (1)
+ }
+
+ Method (_DSM, 4, Serialized, 0, UnknownObj, {BuffObj, IntObj, IntObj, PkgObj})
+ {
+
+ //
+ // TCG Hardware Information
+ //
+ If(LEqual(Arg0, ToUUID ("cf8e16a5-c1e8-4e25-b712-4f54a96702c8")))
+ {
+ Return (HINF (Arg1, Arg2, Arg3))
+ }
+
+ //
+ // TCG Physical Presence Interface
+ //
+ If(LEqual(Arg0, ToUUID ("3dddfaa6-361b-4eb4-a424-8d10089d1653")))
+ {
+ Return (TPPI (Arg1, Arg2, Arg3))
+ }
+
+ //
+ // TCG Memory Clear Interface
+ //
+ If(LEqual(Arg0, ToUUID ("376054ed-cc13-4675-901c-4756d7f2d45d")))
+ {
+ Return (TMCI (Arg1, Arg2, Arg3))
+ }
+
+ Return (Buffer () {0})
+ }
+ }
+ }
+}
diff --git a/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProvider.c b/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProvider.c
new file mode 100644
index 0000000000..ad1521040c
--- /dev/null
+++ b/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProvider.c
@@ -0,0 +1,1422 @@
+/** @file
+ Password Credential Provider driver implementation.
+
+Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "PwdCredentialProvider.h"
+
+CREDENTIAL_TABLE *mPwdTable = NULL;
+PWD_PROVIDER_CALLBACK_INFO *mCallbackInfo = NULL;
+PASSWORD_CREDENTIAL_INFO *mPwdInfoHandle = NULL;
+
+//
+// Used for save password credential and form browser.
+// Also used as provider identifier.
+//
+EFI_GUID mPwdCredentialGuid = PWD_CREDENTIAL_PROVIDER_GUID;
+
+HII_VENDOR_DEVICE_PATH mHiiVendorDevicePath = {
+ {
+ {
+ HARDWARE_DEVICE_PATH,
+ HW_VENDOR_DP,
+ {
+ (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
+ (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
+ }
+ },
+ { 0xeba7fc2b, 0xa465, 0x4d96, { 0x85, 0xa9, 0xd2, 0xf6, 0x64, 0xdf, 0x9b, 0x45 } }
+ },
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ (UINT8) (END_DEVICE_PATH_LENGTH),
+ (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
+ }
+ }
+};
+
+EFI_USER_CREDENTIAL_PROTOCOL gPwdCredentialProviderDriver = {
+ PWD_CREDENTIAL_PROVIDER_GUID,
+ EFI_USER_CREDENTIAL_CLASS_PASSWORD,
+ CredentialEnroll,
+ CredentialForm,
+ CredentialTile,
+ CredentialTitle,
+ CredentialUser,
+ CredentialSelect,
+ CredentialDeselect,
+ CredentialDefault,
+ CredentialGetInfo,
+ CredentialGetNextInfo
+};
+
+
+/**
+ Get string by string id from HII Interface.
+
+
+ @param[in] Id String ID to get the string from.
+
+ @retval CHAR16 * String from ID.
+ @retval NULL If error occurs.
+
+**/
+CHAR16 *
+GetStringById (
+ IN EFI_STRING_ID Id
+ )
+{
+ //
+ // Get the current string for the current Language.
+ //
+ return HiiGetString (mCallbackInfo->HiiHandle, Id, NULL);
+}
+
+
+/**
+ Expand password table size.
+
+**/
+VOID
+ExpandTableSize (
+ VOID
+ )
+{
+ CREDENTIAL_TABLE *NewTable;
+ UINTN Count;
+
+ Count = mPwdTable->MaxCount + PASSWORD_TABLE_INC;
+ //
+ // Create new credential table.
+ //
+ NewTable = (CREDENTIAL_TABLE *) AllocateZeroPool (
+ sizeof (CREDENTIAL_TABLE) +
+ (Count - 1) * sizeof (PASSWORD_INFO)
+ );
+ ASSERT (NewTable != NULL);
+
+ NewTable->MaxCount = Count;
+ NewTable->Count = mPwdTable->Count;
+ NewTable->ValidIndex = mPwdTable->ValidIndex;
+ //
+ // Copy old entries
+ //
+ CopyMem (
+ &NewTable->UserInfo,
+ &mPwdTable->UserInfo,
+ mPwdTable->Count * sizeof (PASSWORD_INFO)
+ );
+ FreePool (mPwdTable);
+ mPwdTable = NewTable;
+}
+
+
+/**
+ Add or delete info in table, and sync with NV variable.
+
+ @param[in] Index The index of the password in table. The index begin from 1.
+ If index is found in table, delete the info, else add the
+ into to table.
+ @param[in] Info The new password info to add into table.
+
+ @retval EFI_INVALID_PARAMETER Info is NULL when save the info.
+ @retval EFI_SUCCESS Modify the table successfully.
+ @retval Others Failed to modify the table.
+
+**/
+EFI_STATUS
+ModifyTable (
+ IN UINTN Index,
+ IN PASSWORD_INFO * Info OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+
+ if (Index < mPwdTable->Count) {
+ //
+ // Delete the specified entry.
+ //
+ mPwdTable->Count--;
+ if (Index != mPwdTable->Count) {
+ CopyMem (
+ &mPwdTable->UserInfo[Index],
+ &mPwdTable->UserInfo[mPwdTable->Count],
+ sizeof (PASSWORD_INFO)
+ );
+ }
+ } else {
+ //
+ // Add a new entry.
+ //
+ if (Info == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (mPwdTable->Count >= mPwdTable->MaxCount) {
+ ExpandTableSize ();
+ }
+
+ CopyMem (
+ &mPwdTable->UserInfo[mPwdTable->Count],
+ Info,
+ sizeof (PASSWORD_INFO)
+ );
+ mPwdTable->Count++;
+ }
+
+ //
+ // Save the credential table.
+ //
+ Status = gRT->SetVariable (
+ L"PwdCredential",
+ &mPwdCredentialGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ mPwdTable->Count * sizeof (PASSWORD_INFO),
+ &mPwdTable->UserInfo
+ );
+ return Status;
+}
+
+
+/**
+ Create a password table.
+
+ @retval EFI_SUCCESS Create a password table successfully.
+ @retval Others Failed to create a password.
+
+**/
+EFI_STATUS
+InitCredentialTable (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *Var;
+ UINTN VarSize;
+
+ //
+ // Get Password credential data from NV variable.
+ //
+ VarSize = 0;
+ Var = NULL;
+ Status = gRT->GetVariable (
+ L"PwdCredential",
+ &mPwdCredentialGuid,
+ NULL,
+ &VarSize,
+ Var
+ );
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ Var = AllocateZeroPool (VarSize);
+ if (Var == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Status = gRT->GetVariable (
+ L"PwdCredential",
+ &mPwdCredentialGuid,
+ NULL,
+ &VarSize,
+ Var
+ );
+ }
+ if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
+ return Status;
+ }
+
+ //
+ // Create the password credential table.
+ //
+ mPwdTable = AllocateZeroPool (
+ sizeof (CREDENTIAL_TABLE) - sizeof (PASSWORD_INFO) +
+ PASSWORD_TABLE_INC * sizeof (PASSWORD_INFO) +
+ VarSize
+ );
+ if (mPwdTable == NULL) {
+ FreePool (Var);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ mPwdTable->Count = VarSize / sizeof (PASSWORD_INFO);
+ mPwdTable->MaxCount = mPwdTable->Count + PASSWORD_TABLE_INC;
+ mPwdTable->ValidIndex = 0;
+ if (Var != NULL) {
+ CopyMem (mPwdTable->UserInfo, Var, VarSize);
+ FreePool (Var);
+ }
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Hash the password to get credential.
+
+ @param[in] Password Points to the input password.
+ @param[in] PasswordSize The size of password, in bytes.
+ @param[out] Credential Points to the hashed result.
+
+ @retval TRUE Hash the password successfully.
+ @retval FALSE Failed to hash the password.
+
+**/
+BOOLEAN
+GenerateCredential (
+ IN CHAR16 *Password,
+ IN UINTN PasswordSize,
+ OUT UINT8 *Credential
+ )
+{
+ BOOLEAN Status;
+ UINTN HashSize;
+ VOID *Hash;
+
+ HashSize = Sha1GetContextSize ();
+ Hash = AllocatePool (HashSize);
+ ASSERT (Hash != NULL);
+
+ Status = Sha1Init (Hash);
+ if (!Status) {
+ goto Done;
+ }
+
+ Status = Sha1Update (Hash, Password, PasswordSize);
+ if (!Status) {
+ goto Done;
+ }
+
+ Status = Sha1Final (Hash, Credential);
+
+Done:
+ FreePool (Hash);
+ return Status;
+}
+
+
+/**
+ Get password from user input.
+
+ @param[in] FirstPwd If True, prompt to input the first password.
+ If False, prompt to input password again.
+ @param[out] Credential Points to the input password.
+
+**/
+VOID
+GetPassword (
+ IN BOOLEAN FirstPwd,
+ OUT CHAR8 *Credential
+ )
+{
+ EFI_INPUT_KEY Key;
+ CHAR16 PasswordMask[CREDENTIAL_LEN + 1];
+ CHAR16 Password[CREDENTIAL_LEN];
+ UINTN PasswordLen;
+ CHAR16 *QuestionStr;
+ CHAR16 *LineStr;
+
+ PasswordLen = 0;
+ while (TRUE) {
+ PasswordMask[PasswordLen] = L'_';
+ PasswordMask[PasswordLen + 1] = L'\0';
+ LineStr = GetStringById (STRING_TOKEN (STR_DRAW_A_LINE));
+ if (FirstPwd) {
+ QuestionStr = GetStringById (STRING_TOKEN (STR_INPUT_PASSWORD));
+ } else {
+ QuestionStr = GetStringById (STRING_TOKEN (STR_INPUT_PASSWORD_AGAIN));
+ }
+ CreatePopUp (
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
+ &Key,
+ QuestionStr,
+ LineStr,
+ PasswordMask,
+ NULL
+ );
+ FreePool (QuestionStr);
+ FreePool (LineStr);
+
+ //
+ // Check key stroke
+ //
+ if (Key.ScanCode == SCAN_NULL) {
+ if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {
+ break;
+ } else if (Key.UnicodeChar == CHAR_BACKSPACE) {
+ if (PasswordLen > 0) {
+ PasswordLen--;
+ }
+ } else if ((Key.UnicodeChar == CHAR_NULL) ||
+ (Key.UnicodeChar == CHAR_TAB) ||
+ (Key.UnicodeChar == CHAR_LINEFEED)) {
+ continue;
+ } else {
+ Password[PasswordLen] = Key.UnicodeChar;
+ PasswordMask[PasswordLen] = L'*';
+ PasswordLen++;
+ if (PasswordLen == CREDENTIAL_LEN) {
+ break;
+ }
+ }
+ }
+ }
+
+ PasswordLen = PasswordLen * sizeof (CHAR16);
+ GenerateCredential (Password, PasswordLen, (UINT8 *)Credential);
+}
+
+/**
+ Check whether the password can be found on this provider.
+
+ @param[in] Password The password to be found.
+
+ @retval EFI_SUCCESS Found password sucessfully.
+ @retval EFI_NOT_FOUND Fail to find the password.
+
+**/
+EFI_STATUS
+CheckPassword (
+ IN CHAR8 *Password
+ )
+{
+ UINTN Index;
+ CHAR8 *Pwd;
+
+ //
+ // Check password credential.
+ //
+ mPwdTable->ValidIndex = 0;
+ for (Index = 0; Index < mPwdTable->Count; Index++) {
+ Pwd = mPwdTable->UserInfo[Index].Password;
+ if (CompareMem (Pwd, Password, CREDENTIAL_LEN) == 0) {
+ mPwdTable->ValidIndex = Index + 1;
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ Find a user infomation record by the information record type.
+
+ This function searches all user information records of User from beginning
+ until either the information is found, or there are no more user infomation
+ records. A match occurs when a Info.InfoType field matches the user information
+ record type.
+
+ @param[in] User Points to the user profile record to search.
+ @param[in] InfoType The infomation type to be searched.
+ @param[out] Info Points to the user info found, the caller is responsible
+ to free.
+
+ @retval EFI_SUCCESS Find the user information successfully.
+ @retval Others Fail to find the user information.
+
+**/
+EFI_STATUS
+FindUserInfoByType (
+ IN EFI_USER_PROFILE_HANDLE User,
+ IN UINT8 InfoType,
+ OUT EFI_USER_INFO **Info
+ )
+{
+ EFI_STATUS Status;
+ EFI_USER_INFO *UserInfo;
+ UINTN UserInfoSize;
+ EFI_USER_INFO_HANDLE UserInfoHandle;
+ EFI_USER_MANAGER_PROTOCOL *UserManager;
+
+ //
+ // Find user information by information type.
+ //
+ if (Info == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = gBS->LocateProtocol (
+ &gEfiUserManagerProtocolGuid,
+ NULL,
+ (VOID **) &UserManager
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Get each user information.
+ //
+
+ UserInfoHandle = NULL;
+ UserInfo = NULL;
+ UserInfoSize = 0;
+ while (TRUE) {
+ Status = UserManager->GetNextInfo (UserManager, User, &UserInfoHandle);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ //
+ // Get information.
+ //
+ Status = UserManager->GetInfo (
+ UserManager,
+ User,
+ UserInfoHandle,
+ UserInfo,
+ &UserInfoSize
+ );
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ if (UserInfo != NULL) {
+ FreePool (UserInfo);
+ }
+ UserInfo = AllocateZeroPool (UserInfoSize);
+ if (UserInfo == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Status = UserManager->GetInfo (
+ UserManager,
+ User,
+ UserInfoHandle,
+ UserInfo,
+ &UserInfoSize
+ );
+ }
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ ASSERT (UserInfo != NULL);
+ if (UserInfo->InfoType == InfoType) {
+ *Info = UserInfo;
+ return EFI_SUCCESS;
+ }
+ }
+
+ if (UserInfo != NULL) {
+ FreePool (UserInfo);
+ }
+ return Status;
+}
+
+
+/**
+ This function processes the results of changes in configuration.
+
+ @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param Action Specifies the type of action taken by the browser.
+ @param QuestionId A unique value which is sent to the original
+ exporting driver so that it can identify the type
+ of data to expect.
+ @param Type The type of value for the question.
+ @param Value A pointer to the data being sent to the original
+ exporting driver.
+ @param ActionRequest On return, points to the action requested by the
+ callback function.
+
+ @retval EFI_SUCCESS The callback successfully handled the action.
+ @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the
+ variable and its data.
+ @retval EFI_DEVICE_ERROR The variable could not be saved.
+ @retval EFI_UNSUPPORTED The specified Action is not supported by the
+ callback.
+
+**/
+EFI_STATUS
+EFIAPI
+CredentialDriverCallback (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN EFI_BROWSER_ACTION Action,
+ IN EFI_QUESTION_ID QuestionId,
+ IN UINT8 Type,
+ IN EFI_IFR_TYPE_VALUE *Value,
+ OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
+ )
+{
+ EFI_STATUS Status;
+ EFI_INPUT_KEY Key;
+ CHAR8 Password[CREDENTIAL_LEN];
+ CHAR16 *PromptStr;
+
+ if (Action == EFI_BROWSER_ACTION_CHANGING) {
+ if (QuestionId == KEY_GET_PASSWORD) {
+ //
+ // Get and check password.
+ //
+ GetPassword (TRUE, Password);
+ Status = CheckPassword (Password);
+ if (EFI_ERROR (Status)) {
+ PromptStr = GetStringById (STRING_TOKEN (STR_PASSWORD_INCORRECT));
+ CreatePopUp (
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
+ &Key,
+ L"",
+ PromptStr,
+ L"",
+ NULL
+ );
+ FreePool (PromptStr);
+ return Status;
+ }
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;
+ }
+ return EFI_SUCCESS;
+ }
+
+ //
+ // All other action return unsupported.
+ //
+ return EFI_UNSUPPORTED;
+}
+
+
+/**
+ This function allows a caller to extract the current configuration for one
+ or more named elements from the target driver.
+
+
+ @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param Request A null-terminated Unicode string in format.
+ @param Progress On return, points to a character in the Request string.
+ Points to the string's null terminator if request was successful.
+ Points to the most recent '&' before the first failing name/value
+ pair (or the beginning of the string if the failure is in the
+ first name/value pair) if the request was not successful.
+ @param Results A null-terminated Unicode string in format which
+ has all values filled in for the names in the Request string.
+ String to be allocated by the called function.
+
+ @retval EFI_SUCCESS The Results is filled with the requested values.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results.
+ @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name.
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in this driver.
+
+**/
+EFI_STATUS
+EFIAPI
+FakeExtractConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Request,
+ OUT EFI_STRING *Progress,
+ OUT EFI_STRING *Results
+ )
+{
+ if (Progress == NULL || Results == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ *Progress = Request;
+ return EFI_NOT_FOUND;
+}
+
+/**
+ This function processes the results of changes in configuration.
+
+
+ @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param Configuration A null-terminated Unicode string in format.
+ @param Progress A pointer to a string filled in with the offset of the most
+ recent '&' before the first failing name/value pair (or the
+ beginning of the string if the failure is in the first
+ name/value pair) or the terminating NULL if all was successful.
+
+ @retval EFI_SUCCESS The Results is processed successfully.
+ @retval EFI_INVALID_PARAMETER Configuration is NULL.
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in this driver.
+
+**/
+EFI_STATUS
+EFIAPI
+FakeRouteConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Configuration,
+ OUT EFI_STRING *Progress
+ )
+{
+ if (Configuration == NULL || Progress == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ This function initialize the data mainly used in form browser.
+
+ @retval EFI_SUCCESS Initialize form data successfully.
+ @retval Others Fail to Initialize form data.
+
+**/
+EFI_STATUS
+InitFormBrowser (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ PWD_PROVIDER_CALLBACK_INFO *CallbackInfo;
+
+ //
+ // Initialize driver private data.
+ //
+ CallbackInfo = AllocateZeroPool (sizeof (PWD_PROVIDER_CALLBACK_INFO));
+ if (CallbackInfo == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CallbackInfo->Signature = PWD_PROVIDER_SIGNATURE;
+ CallbackInfo->ConfigAccess.ExtractConfig = FakeExtractConfig;
+ CallbackInfo->ConfigAccess.RouteConfig = FakeRouteConfig;
+ CallbackInfo->ConfigAccess.Callback = CredentialDriverCallback;
+ CallbackInfo->DriverHandle = NULL;
+
+ //
+ // Install Device Path Protocol and Config Access protocol to driver handle.
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &CallbackInfo->DriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mHiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ &CallbackInfo->ConfigAccess,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Publish HII data.
+ //
+ CallbackInfo->HiiHandle = HiiAddPackages (
+ &mPwdCredentialGuid,
+ CallbackInfo->DriverHandle,
+ PwdCredentialProviderStrings,
+ PwdCredentialProviderVfrBin,
+ NULL
+ );
+ if (CallbackInfo->HiiHandle == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ mCallbackInfo = CallbackInfo;
+
+ return Status;
+}
+
+
+/**
+ Enroll a user on a credential provider.
+
+ This function enrolls and deletes a user profile using this credential provider.
+ If a user profile is successfully enrolled, it calls the User Manager Protocol
+ function Notify() to notify the user manager driver that credential information
+ has changed. If an enrolled user does exist, delete the user on the credential
+ provider.
+
+ @param[in] This Points to this instance of EFI_USER_CREDENTIAL_PROTOCOL.
+ @param[in] User The user profile to enroll.
+
+ @retval EFI_SUCCESS User profile was successfully enrolled.
+ @retval EFI_ACCESS_DENIED Current user profile does not permit enrollment on the
+ user profile handle. Either the user profile cannot enroll
+ on any user profile or cannot enroll on a user profile
+ other than the current user profile.
+ @retval EFI_UNSUPPORTED This credential provider does not support enrollment in
+ the pre-OS.
+ @retval EFI_DEVICE_ERROR The new credential could not be created because of a device
+ error.
+ @retval EFI_INVALID_PARAMETER User does not refer to a valid user profile handle.
+
+**/
+EFI_STATUS
+EFIAPI
+CredentialEnroll (
+ IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This,
+ IN EFI_USER_PROFILE_HANDLE User
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ PASSWORD_INFO PwdInfo;
+ EFI_USER_INFO *UserInfo;
+ CHAR8 Password[CREDENTIAL_LEN];
+ EFI_INPUT_KEY Key;
+ EFI_USER_MANAGER_PROTOCOL *UserManager;
+ UINT8 *UserId;
+ UINT8 *NewUserId;
+ CHAR16 *QuestionStr;
+ CHAR16 *PromptStr;
+
+ if ((This == NULL) || (User == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = gBS->LocateProtocol (
+ &gEfiUserManagerProtocolGuid,
+ NULL,
+ (VOID **) &UserManager
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Get User Identifier.
+ //
+ UserInfo = NULL;
+ Status = FindUserInfoByType (
+ User,
+ EFI_USER_INFO_IDENTIFIER_RECORD,
+ &UserInfo
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // If User exists in mPwdTable, delete User.
+ //
+ for (Index = 0; Index < mPwdTable->Count; Index++) {
+ UserId = (UINT8 *) &mPwdTable->UserInfo[Index].UserId;
+ NewUserId = (UINT8 *) (UserInfo + 1);
+ if (CompareMem (UserId, NewUserId, sizeof (EFI_USER_INFO_IDENTIFIER)) == 0) {
+ //
+ // Delete the existing password.
+ //
+ FreePool (UserInfo);
+ return ModifyTable (Index, NULL);
+ }
+ }
+
+ //
+ // The User doesn't exist in mPwdTable; Enroll the new User.
+ //
+ while (TRUE) {
+ //
+ // Input password.
+ //
+ GetPassword (TRUE, PwdInfo.Password);
+
+ //
+ // Input password again.
+ //
+ GetPassword (FALSE, Password);
+
+ //
+ // Compare the two password consistency.
+ //
+ if (CompareMem (PwdInfo.Password, Password, CREDENTIAL_LEN) == 0) {
+ break;
+ }
+
+ QuestionStr = GetStringById (STRING_TOKEN (STR_PASSWORD_MISMATCH));
+ PromptStr = GetStringById (STRING_TOKEN (STR_INPUT_PASSWORD_AGAIN));
+ CreatePopUp (
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
+ &Key,
+ QuestionStr,
+ L"",
+ PromptStr,
+ NULL
+ );
+ FreePool (QuestionStr);
+ FreePool (PromptStr);
+ }
+
+ CopyMem (
+ PwdInfo.UserId,
+ (UINT8 *) (UserInfo + 1),
+ sizeof (EFI_USER_INFO_IDENTIFIER)
+ );
+ FreePool (UserInfo);
+
+ //
+ // Save the new added entry.
+ //
+ Status = ModifyTable (mPwdTable->Count, &PwdInfo);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Notify the user manager driver that credential information has changed.
+ //
+ UserManager->Notify (UserManager, mCallbackInfo->DriverHandle);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Returns the user interface information used during user identification.
+
+ This function returns information about the form used when interacting with the
+ user during user identification. The form is the first enabled form in the form-set
+ class EFI_HII_USER_CREDENTIAL_FORMSET_GUID installed on the HII handle HiiHandle. If
+ the user credential provider does not require a form to identify the user, then this
+ function should return EFI_NOT_FOUND.
+
+ @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.
+ @param[out] Hii On return, holds the HII database handle.
+ @param[out] FormSetId On return, holds the identifier of the form set which contains
+ the form used during user identification.
+ @param[out] FormId On return, holds the identifier of the form used during user
+ identification.
+
+ @retval EFI_SUCCESS Form returned successfully.
+ @retval EFI_NOT_FOUND Form not returned.
+ @retval EFI_INVALID_PARAMETER Hii is NULL or FormSetId is NULL or FormId is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+CredentialForm (
+ IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This,
+ OUT EFI_HII_HANDLE *Hii,
+ OUT EFI_GUID *FormSetId,
+ OUT EFI_FORM_ID *FormId
+ )
+{
+ if ((This == NULL) || (Hii == NULL) ||
+ (FormSetId == NULL) || (FormId == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *Hii = mCallbackInfo->HiiHandle;
+ *FormId = FORMID_GET_PASSWORD_FORM;
+ CopyGuid (FormSetId, &mPwdCredentialGuid);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Returns bitmap used to describe the credential provider type.
+
+ This optional function returns a bitmap that is less than or equal to the number
+ of pixels specified by Width and Height. If no such bitmap exists, then EFI_NOT_FOUND
+ is returned.
+
+ @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.
+ @param[in, out] Width On entry, points to the desired bitmap width. If NULL then no
+ bitmap information will be returned. On exit, points to the
+ width of the bitmap returned.
+ @param[in, out] Height On entry, points to the desired bitmap height. If NULL then no
+ bitmap information will be returned. On exit, points to the
+ height of the bitmap returned
+ @param[out] Hii On return, holds the HII database handle.
+ @param[out] Image On return, holds the HII image identifier.
+
+ @retval EFI_SUCCESS Image identifier returned successfully.
+ @retval EFI_NOT_FOUND Image identifier not returned.
+ @retval EFI_INVALID_PARAMETER Hii is NULL or Image is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+CredentialTile (
+ IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This,
+ IN OUT UINTN *Width,
+ IN OUT UINTN *Height,
+ OUT EFI_HII_HANDLE *Hii,
+ OUT EFI_IMAGE_ID *Image
+ )
+{
+ if ((This == NULL) || (Hii == NULL) || (Image == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ Returns string used to describe the credential provider type.
+
+ This function returns a string which describes the credential provider. If no
+ such string exists, then EFI_NOT_FOUND is returned.
+
+ @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.
+ @param[out] Hii On return, holds the HII database handle.
+ @param[out] String On return, holds the HII string identifier.
+
+ @retval EFI_SUCCESS String identifier returned successfully.
+ @retval EFI_NOT_FOUND String identifier not returned.
+ @retval EFI_INVALID_PARAMETER Hii is NULL or String is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+CredentialTitle (
+ IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This,
+ OUT EFI_HII_HANDLE *Hii,
+ OUT EFI_STRING_ID *String
+ )
+{
+ if ((This == NULL) || (Hii == NULL) || (String == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Set Hii handle and String ID.
+ //
+ *Hii = mCallbackInfo->HiiHandle;
+ *String = STRING_TOKEN (STR_CREDENTIAL_TITLE);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Return the user identifier associated with the currently authenticated user.
+
+ This function returns the user identifier of the user authenticated by this credential
+ provider. This function is called after the credential-related information has been
+ submitted on a form, OR after a call to Default() has returned that this credential is
+ ready to log on.
+
+ @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.
+ @param[in] User The user profile handle of the user profile currently being
+ considered by the user identity manager. If NULL, then no user
+ profile is currently under consideration.
+ @param[out] Identifier On return, points to the user identifier.
+
+ @retval EFI_SUCCESS User identifier returned successfully.
+ @retval EFI_NOT_READY No user identifier can be returned.
+ @retval EFI_ACCESS_DENIED The user has been locked out of this user credential.
+ @retval EFI_INVALID_PARAMETER This is NULL, or Identifier is NULL.
+ @retval EFI_NOT_FOUND User is not NULL, and the specified user handle can't be
+ found in user profile database
+
+**/
+EFI_STATUS
+EFIAPI
+CredentialUser (
+ IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This,
+ IN EFI_USER_PROFILE_HANDLE User,
+ OUT EFI_USER_INFO_IDENTIFIER *Identifier
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ EFI_USER_INFO *UserInfo;
+ UINT8 *UserId;
+ UINT8 *NewUserId;
+ CHAR8 *Pwd;
+ CHAR8 *NewPwd;
+
+ if ((This == NULL) || (Identifier == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (mPwdTable->ValidIndex == 0) {
+ //
+ // No password input, or the input password doesn't match
+ // anyone in PwdTable.
+ //
+ return EFI_NOT_READY;
+ }
+
+ if (User == NULL) {
+ //
+ // Return the user ID whose password matches the input password.
+ //
+ CopyMem (
+ Identifier,
+ &mPwdTable->UserInfo[mPwdTable->ValidIndex - 1].UserId,
+ sizeof (EFI_USER_INFO_IDENTIFIER)
+ );
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Get the User's ID.
+ //
+ Status = FindUserInfoByType (
+ User,
+ EFI_USER_INFO_IDENTIFIER_RECORD,
+ &UserInfo
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Check whether the input password matches one in PwdTable.
+ //
+ for (Index = 0; Index < mPwdTable->Count; Index++) {
+ UserId = (UINT8 *) &mPwdTable->UserInfo[Index].UserId;
+ NewUserId = (UINT8 *) (UserInfo + 1);
+ if (CompareMem (UserId, NewUserId, sizeof (EFI_USER_INFO_IDENTIFIER)) == 0) {
+ Pwd = mPwdTable->UserInfo[Index].Password;
+ NewPwd = mPwdTable->UserInfo[mPwdTable->ValidIndex - 1].Password;
+ if (CompareMem (Pwd, NewPwd, CREDENTIAL_LEN) == 0) {
+ CopyMem (Identifier, UserId, sizeof (EFI_USER_INFO_IDENTIFIER));
+ FreePool (UserInfo);
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ //
+ // The User's password doesn't match the input password.
+ // Return the user ID whose password matches the input password.
+ //
+ CopyMem (
+ Identifier,
+ &mPwdTable->UserInfo[mPwdTable->ValidIndex - 1].UserId,
+ sizeof (EFI_USER_INFO_IDENTIFIER)
+ );
+ FreePool (UserInfo);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Indicate that user interface interaction has begun for the specified credential.
+
+ This function is called when a credential provider is selected by the user. If
+ AutoLogon returns FALSE, then the user interface will be constructed by the User
+ Identity Manager.
+
+ @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.
+ @param[out] AutoLogon On return, points to the credential provider's capabilities
+ after the credential provider has been selected by the user.
+
+ @retval EFI_SUCCESS Credential provider successfully selected.
+ @retval EFI_INVALID_PARAMETER AutoLogon is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+CredentialSelect (
+ IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This,
+ OUT EFI_CREDENTIAL_LOGON_FLAGS *AutoLogon
+ )
+{
+ if ((This == NULL) || (AutoLogon == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ *AutoLogon = 0;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Indicate that user interface interaction has ended for the specified credential.
+
+ This function is called when a credential provider is deselected by the user.
+
+ @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.
+
+ @retval EFI_SUCCESS Credential provider successfully deselected.
+
+**/
+EFI_STATUS
+EFIAPI
+CredentialDeselect (
+ IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This
+ )
+{
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Return the default logon behavior for this user credential.
+
+ This function reports the default login behavior regarding this credential provider.
+
+ @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.
+ @param[out] AutoLogon On return, holds whether the credential provider should be used
+ by default to automatically log on the user.
+
+ @retval EFI_SUCCESS Default information successfully returned.
+ @retval EFI_INVALID_PARAMETER AutoLogon is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+CredentialDefault (
+ IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This,
+ OUT EFI_CREDENTIAL_LOGON_FLAGS *AutoLogon
+ )
+{
+ if ((This == NULL) || (AutoLogon == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ *AutoLogon = 0;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Return information attached to the credential provider.
+
+ This function returns user information.
+
+ @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.
+ @param[in] UserInfo Handle of the user information data record.
+ @param[out] Info On entry, points to a buffer of at least *InfoSize bytes. On
+ exit, holds the user information. If the buffer is too small
+ to hold the information, then EFI_BUFFER_TOO_SMALL is returned
+ and InfoSize is updated to contain the number of bytes actually
+ required.
+ @param[in, out] InfoSize On entry, points to the size of Info. On return, points to the
+ size of the user information.
+
+ @retval EFI_SUCCESS Information returned successfully.
+ @retval EFI_BUFFER_TOO_SMALL The size specified by InfoSize is too small to hold all of the
+ user information. The size required is returned in *InfoSize.
+ @retval EFI_INVALID_PARAMETER Info is NULL or InfoSize is NULL.
+ @retval EFI_NOT_FOUND The specified UserInfo does not refer to a valid user info handle.
+
+**/
+EFI_STATUS
+EFIAPI
+CredentialGetInfo (
+ IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This,
+ IN EFI_USER_INFO_HANDLE UserInfo,
+ OUT EFI_USER_INFO *Info,
+ IN OUT UINTN *InfoSize
+ )
+{
+ EFI_USER_INFO *CredentialInfo;
+ UINTN Index;
+
+ if ((This == NULL) || (InfoSize == NULL) || (Info == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((UserInfo == NULL) || (mPwdInfoHandle == NULL)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Find information handle in credential info table.
+ //
+ for (Index = 0; Index < mPwdInfoHandle->Count; Index++) {
+ CredentialInfo = mPwdInfoHandle->Info[Index];
+ if (UserInfo == (EFI_USER_INFO_HANDLE)CredentialInfo) {
+ //
+ // The handle is found, copy the user info.
+ //
+ if (CredentialInfo->InfoSize > *InfoSize) {
+ *InfoSize = CredentialInfo->InfoSize;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+ CopyMem (Info, CredentialInfo, CredentialInfo->InfoSize);
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ Enumerate all of the user informations on the credential provider.
+
+ This function returns the next user information record. To retrieve the first user
+ information record handle, point UserInfo at a NULL. Each subsequent call will retrieve
+ another user information record handle until there are no more, at which point UserInfo
+ will point to NULL.
+
+ @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.
+ @param[in, out] UserInfo On entry, points to the previous user information handle or NULL
+ to start enumeration. On exit, points to the next user information
+ handle or NULL if there is no more user information.
+
+ @retval EFI_SUCCESS User information returned.
+ @retval EFI_NOT_FOUND No more user information found.
+ @retval EFI_INVALID_PARAMETER UserInfo is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+CredentialGetNextInfo (
+ IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This,
+ IN OUT EFI_USER_INFO_HANDLE *UserInfo
+ )
+{
+ EFI_USER_INFO *Info;
+ CHAR16 *ProvNameStr;
+ UINTN InfoLen;
+ UINTN Index;
+ UINTN ProvStrLen;
+
+ if ((This == NULL) || (UserInfo == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (mPwdInfoHandle == NULL) {
+ //
+ // Initilized user info table. There are 4 user info records in the table.
+ //
+ InfoLen = sizeof (PASSWORD_CREDENTIAL_INFO) + (4 - 1) * sizeof (EFI_USER_INFO *);
+ mPwdInfoHandle = AllocateZeroPool (InfoLen);
+ if (mPwdInfoHandle == NULL) {
+ *UserInfo = NULL;
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // The first information, Credential Provider info.
+ //
+ InfoLen = sizeof (EFI_USER_INFO) + sizeof (EFI_GUID);
+ Info = AllocateZeroPool (InfoLen);
+ ASSERT (Info != NULL);
+
+ Info->InfoType = EFI_USER_INFO_CREDENTIAL_PROVIDER_RECORD;
+ Info->InfoSize = (UINT32) InfoLen;
+ Info->InfoAttribs = EFI_USER_INFO_PROTECTED;
+ CopyGuid (&Info->Credential, &mPwdCredentialGuid);
+ CopyGuid ((EFI_GUID *)(Info + 1), &mPwdCredentialGuid);
+
+ mPwdInfoHandle->Info[0] = Info;
+ mPwdInfoHandle->Count++;
+
+ //
+ // The second information, Credential Provider name info.
+ //
+ ProvNameStr = GetStringById (STRING_TOKEN (STR_PROVIDER_NAME));
+ ProvStrLen = StrSize (ProvNameStr);
+ InfoLen = sizeof (EFI_USER_INFO) + ProvStrLen;
+ Info = AllocateZeroPool (InfoLen);
+ ASSERT (Info != NULL);
+
+ Info->InfoType = EFI_USER_INFO_CREDENTIAL_PROVIDER_NAME_RECORD;
+ Info->InfoSize = (UINT32) InfoLen;
+ Info->InfoAttribs = EFI_USER_INFO_PROTECTED;
+ CopyGuid (&Info->Credential, &mPwdCredentialGuid);
+ CopyMem ((UINT8*)(Info + 1), ProvNameStr, ProvStrLen);
+ FreePool (ProvNameStr);
+
+ mPwdInfoHandle->Info[1] = Info;
+ mPwdInfoHandle->Count++;
+
+ //
+ // The third information, Credential Provider type info.
+ //
+ InfoLen = sizeof (EFI_USER_INFO) + sizeof (EFI_GUID);
+ Info = AllocateZeroPool (InfoLen);
+ ASSERT (Info != NULL);
+
+ Info->InfoType = EFI_USER_INFO_CREDENTIAL_TYPE_RECORD;
+ Info->InfoSize = (UINT32) InfoLen;
+ Info->InfoAttribs = EFI_USER_INFO_PROTECTED;
+ CopyGuid (&Info->Credential, &mPwdCredentialGuid);
+ CopyGuid ((EFI_GUID *)(Info + 1), &gEfiUserCredentialClassPasswordGuid);
+
+ mPwdInfoHandle->Info[2] = Info;
+ mPwdInfoHandle->Count++;
+
+ //
+ // The fourth information, Credential Provider type name info.
+ //
+ ProvNameStr = GetStringById (STRING_TOKEN (STR_PROVIDER_TYPE_NAME));
+ ProvStrLen = StrSize (ProvNameStr);
+ InfoLen = sizeof (EFI_USER_INFO) + ProvStrLen;
+ Info = AllocateZeroPool (InfoLen);
+ ASSERT (Info != NULL);
+
+ Info->InfoType = EFI_USER_INFO_CREDENTIAL_PROVIDER_NAME_RECORD;
+ Info->InfoSize = (UINT32) InfoLen;
+ Info->InfoAttribs = EFI_USER_INFO_PROTECTED;
+ CopyGuid (&Info->Credential, &mPwdCredentialGuid);
+ CopyMem ((UINT8*)(Info + 1), ProvNameStr, ProvStrLen);
+ FreePool (ProvNameStr);
+
+ mPwdInfoHandle->Info[3] = Info;
+ mPwdInfoHandle->Count++;
+ }
+
+ if (*UserInfo == NULL) {
+ //
+ // Return the first info handle.
+ //
+ *UserInfo = (EFI_USER_INFO_HANDLE) mPwdInfoHandle->Info[0];
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Find information handle in credential info table.
+ //
+ for (Index = 0; Index < mPwdInfoHandle->Count; Index++) {
+ Info = mPwdInfoHandle->Info[Index];
+ if (*UserInfo == (EFI_USER_INFO_HANDLE)Info) {
+ //
+ // The handle is found, get the next one.
+ //
+ if (Index == mPwdInfoHandle->Count - 1) {
+ //
+ // Already last one.
+ //
+ *UserInfo = NULL;
+ return EFI_NOT_FOUND;
+ }
+
+ Index++;
+ *UserInfo = (EFI_USER_INFO_HANDLE)mPwdInfoHandle->Info[Index];
+ return EFI_SUCCESS;
+ }
+ }
+
+ *UserInfo = NULL;
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ Main entry for this driver.
+
+ @param ImageHandle Image handle this driver.
+ @param SystemTable Pointer to SystemTable.
+
+ @retval EFI_SUCESS This function always complete successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+PasswordProviderInit (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Init credential table.
+ //
+ Status = InitCredentialTable ();
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Init Form Browser.
+ //
+ Status = InitFormBrowser ();
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Install protocol interfaces for the password credential provider.
+ //
+ Status = gBS->InstallProtocolInterface (
+ &mCallbackInfo->DriverHandle,
+ &gEfiUserCredentialProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &gPwdCredentialProviderDriver
+ );
+ return Status;
+}
diff --git a/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProvider.h b/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProvider.h
new file mode 100644
index 0000000000..9b5e7768ba
--- /dev/null
+++ b/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProvider.h
@@ -0,0 +1,354 @@
+/** @file
+ Password Credential Provider driver header file.
+
+Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _PASSWORD_CREDENTIAL_PROVIDER_H_
+#define _PASSWORD_CREDENTIAL_PROVIDER_H_
+
+#include
+
+#include
+#include
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "PwdCredentialProviderData.h"
+
+extern UINT8 PwdCredentialProviderStrings[];
+extern UINT8 PwdCredentialProviderVfrBin[];
+
+#define PASSWORD_TABLE_INC 16
+#define CREDENTIAL_LEN 20
+
+//
+// Password credential information.
+//
+typedef struct {
+ EFI_USER_INFO_IDENTIFIER UserId;
+ CHAR8 Password[CREDENTIAL_LEN];
+} PASSWORD_INFO;
+
+//
+// Password credential table.
+//
+typedef struct {
+ UINTN Count;
+ UINTN MaxCount;
+ UINTN ValidIndex;
+ PASSWORD_INFO UserInfo[1];
+} CREDENTIAL_TABLE;
+
+//
+// The user information on the password provider.
+//
+typedef struct {
+ UINTN Count;
+ EFI_USER_INFO *Info[1];
+} PASSWORD_CREDENTIAL_INFO;
+
+///
+/// HII specific Vendor Device Path definition.
+///
+typedef struct {
+ VENDOR_DEVICE_PATH VendorDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} HII_VENDOR_DEVICE_PATH;
+
+#define PWD_PROVIDER_SIGNATURE SIGNATURE_32 ('P', 'W', 'D', 'P')
+
+typedef struct {
+ UINTN Signature;
+ EFI_HANDLE DriverHandle;
+ EFI_HII_HANDLE HiiHandle;
+ //
+ // Produced protocol.
+ //
+ EFI_HII_CONFIG_ACCESS_PROTOCOL ConfigAccess;
+} PWD_PROVIDER_CALLBACK_INFO;
+
+
+/**
+ Enroll a user on a credential provider.
+
+ This function enrolls and deletes a user profile using this credential provider.
+ If a user profile is successfully enrolled, it calls the User Manager Protocol
+ function Notify() to notify the user manager driver that credential information
+ has changed. If an enrolled user does exist, delete the user on the credential
+ provider.
+
+ @param[in] This Points to this instance of EFI_USER_CREDENTIAL_PROTOCOL.
+ @param[in] User The user profile to enroll.
+
+ @retval EFI_SUCCESS User profile was successfully enrolled.
+ @retval EFI_ACCESS_DENIED Current user profile does not permit enrollment on the
+ user profile handle. Either the user profile cannot enroll
+ on any user profile or cannot enroll on a user profile
+ other than the current user profile.
+ @retval EFI_UNSUPPORTED This credential provider does not support enrollment in
+ the pre-OS.
+ @retval EFI_DEVICE_ERROR The new credential could not be created because of a device
+ error.
+ @retval EFI_INVALID_PARAMETER User does not refer to a valid user profile handle.
+
+**/
+EFI_STATUS
+EFIAPI
+CredentialEnroll (
+ IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This,
+ IN EFI_USER_PROFILE_HANDLE User
+ );
+
+/**
+ Returns the user interface information used during user identification.
+
+ This function returns information about the form used when interacting with the
+ user during user identification. The form is the first enabled form in the form-set
+ class EFI_HII_USER_CREDENTIAL_FORMSET_GUID installed on the HII handle HiiHandle. If
+ the user credential provider does not require a form to identify the user, then this
+ function should return EFI_NOT_FOUND.
+
+ @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.
+ @param[out] Hii On return, holds the HII database handle.
+ @param[out] FormSetId On return, holds the identifier of the form set which contains
+ the form used during user identification.
+ @param[out] FormId On return, holds the identifier of the form used during user
+ identification.
+
+ @retval EFI_SUCCESS Form returned successfully.
+ @retval EFI_NOT_FOUND Form not returned.
+ @retval EFI_INVALID_PARAMETER Hii is NULL or FormSetId is NULL or FormId is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+CredentialForm (
+ IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This,
+ OUT EFI_HII_HANDLE *Hii,
+ OUT EFI_GUID *FormSetId,
+ OUT EFI_FORM_ID *FormId
+ );
+
+/**
+ Returns bitmap used to describe the credential provider type.
+
+ This optional function returns a bitmap which is less than or equal to the number
+ of pixels specified by Width and Height. If no such bitmap exists, then EFI_NOT_FOUND
+ is returned.
+
+ @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.
+ @param[in, out] Width On entry, points to the desired bitmap width. If NULL then no
+ bitmap information will be returned. On exit, points to the
+ width of the bitmap returned.
+ @param[in, out] Height On entry, points to the desired bitmap height. If NULL then no
+ bitmap information will be returned. On exit, points to the
+ height of the bitmap returned
+ @param[out] Hii On return, holds the HII database handle.
+ @param[out] Image On return, holds the HII image identifier.
+
+ @retval EFI_SUCCESS Image identifier returned successfully.
+ @retval EFI_NOT_FOUND Image identifier not returned.
+ @retval EFI_INVALID_PARAMETER Hii is NULL or Image is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+CredentialTile (
+ IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This,
+ IN OUT UINTN *Width,
+ IN OUT UINTN *Height,
+ OUT EFI_HII_HANDLE *Hii,
+ OUT EFI_IMAGE_ID *Image
+ );
+
+/**
+ Returns string used to describe the credential provider type.
+
+ This function returns a string which describes the credential provider. If no
+ such string exists, then EFI_NOT_FOUND is returned.
+
+ @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.
+ @param[out] Hii On return, holds the HII database handle.
+ @param[out] String On return, holds the HII string identifier.
+
+ @retval EFI_SUCCESS String identifier returned successfully.
+ @retval EFI_NOT_FOUND String identifier not returned.
+ @retval EFI_INVALID_PARAMETER Hii is NULL or String is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+CredentialTitle (
+ IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This,
+ OUT EFI_HII_HANDLE *Hii,
+ OUT EFI_STRING_ID *String
+ );
+
+/**
+ Return the user identifier associated with the currently authenticated user.
+
+ This function returns the user identifier of the user authenticated by this credential
+ provider. This function is called after the credential-related information has been
+ submitted on a form OR after a call to Default() has returned that this credential is
+ ready to log on.
+
+ @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.
+ @param[in] User The user profile handle of the user profile currently being
+ considered by the user identity manager. If NULL, then no user
+ profile is currently under consideration.
+ @param[out] Identifier On return, points to the user identifier.
+
+ @retval EFI_SUCCESS User identifier returned successfully.
+ @retval EFI_NOT_READY No user identifier can be returned.
+ @retval EFI_ACCESS_DENIED The user has been locked out of this user credential.
+ @retval EFI_INVALID_PARAMETER This is NULL, or Identifier is NULL.
+ @retval EFI_NOT_FOUND User is not NULL, and the specified user handle can't be
+ found in user profile database
+
+**/
+EFI_STATUS
+EFIAPI
+CredentialUser (
+ IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This,
+ IN EFI_USER_PROFILE_HANDLE User,
+ OUT EFI_USER_INFO_IDENTIFIER *Identifier
+ );
+
+/**
+ Indicate that user interface interaction has begun for the specified credential.
+
+ This function is called when a credential provider is selected by the user. If
+ AutoLogon returns FALSE, then the user interface will be constructed by the User
+ Identity Manager.
+
+ @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.
+ @param[out] AutoLogon On return, points to the credential provider's capabilities
+ after the credential provider has been selected by the user.
+
+ @retval EFI_SUCCESS Credential provider successfully selected.
+ @retval EFI_INVALID_PARAMETER AutoLogon is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+CredentialSelect (
+ IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This,
+ OUT EFI_CREDENTIAL_LOGON_FLAGS *AutoLogon
+ );
+
+/**
+ Indicate that user interface interaction has ended for the specified credential.
+
+ This function is called when a credential provider is deselected by the user.
+
+ @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.
+
+ @retval EFI_SUCCESS Credential provider successfully deselected.
+
+**/
+EFI_STATUS
+EFIAPI
+CredentialDeselect (
+ IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This
+ );
+
+/**
+ Return the default logon behavior for this user credential.
+
+ This function reports the default login behavior regarding this credential provider.
+
+ @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.
+ @param[out] AutoLogon On return, holds whether the credential provider should be used
+ by default to automatically log on the user.
+
+ @retval EFI_SUCCESS Default information successfully returned.
+ @retval EFI_INVALID_PARAMETER AutoLogon is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+CredentialDefault (
+ IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This,
+ OUT EFI_CREDENTIAL_LOGON_FLAGS *AutoLogon
+ );
+
+/**
+ Return information attached to the credential provider.
+
+ This function returns user information.
+
+ @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.
+ @param[in] UserInfo Handle of the user information data record.
+ @param[out] Info On entry, points to a buffer of at least *InfoSize bytes. On
+ exit, holds the user information. If the buffer is too small
+ to hold the information, then EFI_BUFFER_TOO_SMALL is returned
+ and InfoSize is updated to contain the number of bytes actually
+ required.
+ @param[in, out] InfoSize On entry, points to the size of Info. On return, points to the
+ size of the user information.
+
+ @retval EFI_SUCCESS Information returned successfully.
+ @retval EFI_BUFFER_TOO_SMALL The size specified by InfoSize is too small to hold all of the
+ user information. The size required is returned in *InfoSize.
+ @retval EFI_INVALID_PARAMETER Info is NULL or InfoSize is NULL.
+ @retval EFI_NOT_FOUND The specified UserInfo does not refer to a valid user info handle.
+
+**/
+EFI_STATUS
+EFIAPI
+CredentialGetInfo (
+ IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This,
+ IN EFI_USER_INFO_HANDLE UserInfo,
+ OUT EFI_USER_INFO *Info,
+ IN OUT UINTN *InfoSize
+ );
+
+
+/**
+ Enumerate all of the user informations on the credential provider.
+
+ This function returns the next user information record. To retrieve the first user
+ information record handle, point UserInfo at a NULL. Each subsequent call will retrieve
+ another user information record handle until there are no more, at which point UserInfo
+ will point to NULL.
+
+ @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.
+ @param[in, out] UserInfo On entry, points to the previous user information handle or NULL
+ to start enumeration. On exit, points to the next user information
+ handle or NULL if there is no more user information.
+
+ @retval EFI_SUCCESS User information returned.
+ @retval EFI_NOT_FOUND No more user information found.
+ @retval EFI_INVALID_PARAMETER UserInfo is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+CredentialGetNextInfo (
+ IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This,
+ IN OUT EFI_USER_INFO_HANDLE *UserInfo
+ );
+
+#endif
diff --git a/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderData.h b/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderData.h
new file mode 100644
index 0000000000..ffe0adea20
--- /dev/null
+++ b/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderData.h
@@ -0,0 +1,33 @@
+/** @file
+ Data structure used by the Password Credential Provider driver.
+
+Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _PWD_CREDENTIAL_PROVIDER_DATA_H_
+#define _PWD_CREDENTIAL_PROVIDER_DATA_H_
+
+#define PWD_CREDENTIAL_PROVIDER_GUID \
+ { \
+ 0x78b9ec8b, 0xc000, 0x46c5, { 0xac, 0x93, 0x24, 0xa0, 0xc1, 0xbb, 0x0, 0xce } \
+ }
+
+//
+// Forms definition
+//
+#define FORMID_GET_PASSWORD_FORM 1
+
+//
+// Key defination
+//
+#define KEY_GET_PASSWORD 0x1000
+
+#endif
diff --git a/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderDxe.inf b/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderDxe.inf
new file mode 100644
index 0000000000..0ffc24e076
--- /dev/null
+++ b/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderDxe.inf
@@ -0,0 +1,53 @@
+## @file
+# Component description file for Password Credential Provider.
+#
+# Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PwdCredentialProvider
+ FILE_GUID = D6C589EA-DD29-49ef-97F6-1A9FE19A04E0
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = PasswordProviderInit
+
+[Sources]
+ PwdCredentialProvider.c
+ PwdCredentialProvider.h
+ PwdCredentialProviderData.h
+ PwdCredentialProviderVfr.Vfr
+ PwdCredentialProviderStrings.uni
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ CryptoPkg/CryptoPkg.dec
+
+[LibraryClasses]
+ UefiRuntimeServicesTableLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ MemoryAllocationLib
+ BaseMemoryLib
+ DebugLib
+ HiiLib
+ UefiLib
+ BaseCryptLib
+
+[Guids]
+ gEfiIfrTianoGuid ## CONSUMES ## Guid
+ gEfiUserCredentialClassPasswordGuid ## CONSUMES ## Guid
+
+[Protocols]
+ gEfiDevicePathProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiHiiConfigAccessProtocolGuid
+ gEfiUserCredentialProtocolGuid
+ gEfiUserManagerProtocolGuid
\ No newline at end of file
diff --git a/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderStrings.uni b/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderStrings.uni
new file mode 100644
index 0000000000..48573b6e8e
Binary files /dev/null and b/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderStrings.uni differ
diff --git a/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderVfr.Vfr b/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderVfr.Vfr
new file mode 100644
index 0000000000..69f4be8c23
--- /dev/null
+++ b/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderVfr.Vfr
@@ -0,0 +1,35 @@
+/** @file
+ Password Credential Provider formset.
+
+Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "PwdCredentialProviderData.h"
+
+formset
+ guid = PWD_CREDENTIAL_PROVIDER_GUID,
+ title = STRING_TOKEN(STR_CREDENTIAL_TITLE),
+ help = STRING_TOKEN(STR_NULL_STRING),
+ classguid = PWD_CREDENTIAL_PROVIDER_GUID,
+
+ form formid = FORMID_GET_PASSWORD_FORM,
+ title = STRING_TOKEN(STR_FORM_TITLE);
+
+ text
+ help = STRING_TOKEN(STR_NULL_STRING),
+ text = STRING_TOKEN(STR_INPUT_PASSWORD),
+ text = STRING_TOKEN(STR_NULL_STRING),
+ flags = INTERACTIVE,
+ key = KEY_GET_PASSWORD;
+
+ endform;
+
+endformset;
\ No newline at end of file
diff --git a/SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProvider.c b/SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProvider.c
new file mode 100644
index 0000000000..6c22bfb2bb
--- /dev/null
+++ b/SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProvider.c
@@ -0,0 +1,1407 @@
+/** @file
+ Usb Credential Provider driver implemenetation.
+
+Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "UsbCredentialProvider.h"
+
+CREDENTIAL_TABLE *mUsbTable = NULL;
+USB_PROVIDER_CALLBACK_INFO *mCallbackInfo = NULL;
+USB_CREDENTIAL_INFO *mUsbInfoHandle = NULL;
+
+//
+// Used for save password credential and form browser
+// And used as provider identifier
+//
+EFI_GUID mUsbCredentialGuid = USB_CREDENTIAL_PROVIDER_GUID;
+
+HII_VENDOR_DEVICE_PATH mHiiVendorDevicePath = {
+ {
+ {
+ HARDWARE_DEVICE_PATH,
+ HW_VENDOR_DP,
+ {
+ (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
+ (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
+ }
+ },
+ { 0x9463f883, 0x48f6, 0x4a7a, { 0x97, 0x2d, 0x9f, 0x8f, 0x38, 0xf2, 0xdd, 0x91 } }
+ },
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ (UINT8) (END_DEVICE_PATH_LENGTH),
+ (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
+ }
+ }
+};
+
+EFI_USER_CREDENTIAL_PROTOCOL gUsbCredentialProviderDriver = {
+ USB_CREDENTIAL_PROVIDER_GUID,
+ EFI_USER_CREDENTIAL_CLASS_SECURE_CARD,
+ CredentialEnroll,
+ CredentialForm,
+ CredentialTile,
+ CredentialTitle,
+ CredentialUser,
+ CredentialSelect,
+ CredentialDeselect,
+ CredentialDefault,
+ CredentialGetInfo,
+ CredentialGetNextInfo
+};
+
+
+/**
+ Get string by string id from HII Interface.
+
+
+ @param[in] Id String ID to get the string from.
+
+ @retval CHAR16 * String from ID.
+ @retval NULL If error occurs.
+
+**/
+CHAR16 *
+GetStringById (
+ IN EFI_STRING_ID Id
+ )
+{
+ //
+ // Get the current string for the current Language
+ //
+ return HiiGetString (mCallbackInfo->HiiHandle, Id, NULL);
+}
+
+
+/**
+ Expand password table size.
+
+**/
+VOID
+ExpandTableSize (
+ VOID
+ )
+{
+ CREDENTIAL_TABLE *NewTable;
+ UINTN Count;
+
+ Count = mUsbTable->MaxCount + USB_TABLE_INC;
+ //
+ // Create new credential table.
+ //
+ NewTable = AllocateZeroPool (
+ sizeof (CREDENTIAL_TABLE) - sizeof (USB_INFO) +
+ Count * sizeof (USB_INFO)
+ );
+ ASSERT (NewTable != NULL);
+
+ NewTable->MaxCount = Count;
+ NewTable->Count = mUsbTable->Count;
+
+ //
+ // Copy old entries.
+ //
+ CopyMem (
+ &NewTable->UserInfo,
+ &mUsbTable->UserInfo,
+ mUsbTable->Count * sizeof (USB_INFO)
+ );
+ FreePool (mUsbTable);
+ mUsbTable = NewTable;
+}
+
+
+/**
+ Add or delete info in table, and sync with NV variable.
+
+ @param[in] Index The index of the password in table. The index begin from 1.
+ If index is found in table, delete the info, else add the
+ into to table.
+ @param[in] Info The new password info to add into table.
+
+ @retval EFI_INVALID_PARAMETER Info is NULL when save the info.
+ @retval EFI_SUCCESS Modify the table successfully.
+ @retval Others Failed to modify the table.
+
+**/
+EFI_STATUS
+ModifyTable (
+ IN UINTN Index,
+ IN USB_INFO * Info OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+
+ if (Index < mUsbTable->Count) {
+ //
+ // Delete the specified entry
+ //
+ mUsbTable->Count--;
+ if (Index != mUsbTable->Count) {
+ CopyMem (
+ &mUsbTable->UserInfo[Index],
+ &mUsbTable->UserInfo[mUsbTable->Count],
+ sizeof (USB_INFO)
+ );
+ }
+ } else {
+ //
+ // Add a new entry
+ //
+ if (Info == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (mUsbTable->Count >= mUsbTable->MaxCount) {
+ ExpandTableSize ();
+ }
+
+ CopyMem (
+ &mUsbTable->UserInfo[mUsbTable->Count],
+ Info,
+ sizeof (USB_INFO)
+ );
+ mUsbTable->Count++;
+ }
+
+ //
+ // Save the credential table.
+ //
+ Status = gRT->SetVariable (
+ L"UsbCredential",
+ &mUsbCredentialGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ mUsbTable->Count * sizeof (USB_INFO),
+ &mUsbTable->UserInfo
+ );
+ return Status;
+}
+
+
+/**
+ Create a credential table
+
+ @retval EFI_SUCCESS Create a credential table successfully.
+ @retval Others Failed to create a password.
+
+**/
+EFI_STATUS
+InitCredentialTable (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *Var;
+ UINTN VarSize;
+
+ //
+ // Get Usb credential data from NV variable.
+ //
+ VarSize = 0;
+ Var = NULL;
+ Status = gRT->GetVariable (
+ L"UsbCredential",
+ &mUsbCredentialGuid,
+ NULL,
+ &VarSize,
+ Var
+ );
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ Var = AllocateZeroPool (VarSize);
+ if (Var == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Status = gRT->GetVariable (
+ L"UsbCredential",
+ &mUsbCredentialGuid,
+ NULL,
+ &VarSize,
+ Var
+ );
+ }
+ if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
+ return Status;
+ }
+
+ //
+ // Init Usb credential table.
+ //
+ mUsbTable = AllocateZeroPool (
+ sizeof (CREDENTIAL_TABLE) - sizeof (USB_INFO) +
+ USB_TABLE_INC * sizeof (USB_INFO) +
+ VarSize
+ );
+ if (mUsbTable == NULL) {
+ FreePool (Var);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ mUsbTable->Count = VarSize / sizeof (USB_INFO);
+ mUsbTable->MaxCount = mUsbTable->Count + USB_TABLE_INC;
+ if (Var != NULL) {
+ CopyMem (mUsbTable->UserInfo, Var, VarSize);
+ FreePool (Var);
+ }
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Read the specified file by FileName in the Usb key and return the file size in BufferSize
+ and file content in Buffer.
+ Note: the caller is responsible to free the buffer memory.
+
+ @param FileName File to read.
+ @param Buffer Returned with data read from the file.
+ @param BufferSize Size of the data buffer.
+
+ @retval EFI_SUCCESS The command completed successfully.
+ @retval EFI_OUT_OF_RESOURCES Resource allocation failed.
+ @retval EFI_NOT_FOUND File not found.
+ @retval EFI_DEVICE_ERROR Device I/O error.
+
+**/
+EFI_STATUS
+GetFileData (
+ IN CHAR16 *FileName,
+ OUT VOID **Buffer,
+ OUT UINTN *BufferSize
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ UINTN HandleCount;
+ UINTN ScratchBufferSize;
+ EFI_HANDLE *HandleBuffer;
+ EFI_FILE *RootFs;
+ EFI_FILE *FileHandle;
+ EFI_FILE_INFO *FileInfo;
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFileSystem;
+ EFI_BLOCK_IO_PROTOCOL *BlkIo;
+
+ FileInfo = NULL;
+ FileHandle = NULL;
+
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiSimpleFileSystemProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Can not Locate SimpleFileSystemProtocol\n"));
+ goto Done;
+ }
+
+ //
+ // Find and open the file in removable media disk.
+ //
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiBlockIoProtocolGuid,
+ (VOID **) &BlkIo
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ if (BlkIo->Media->RemovableMedia) {
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiSimpleFileSystemProtocolGuid,
+ (VOID **) &SimpleFileSystem
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ Status = SimpleFileSystem->OpenVolume (
+ SimpleFileSystem,
+ &RootFs
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ Status = RootFs->Open (
+ RootFs,
+ &FileHandle,
+ FileName,
+ EFI_FILE_MODE_READ,
+ 0
+ );
+ if (!EFI_ERROR (Status)) {
+ break;
+ }
+ }
+ }
+
+ FreePool (HandleBuffer);
+
+ if (Index >= HandleCount) {
+ DEBUG ((DEBUG_ERROR, "Can not found the token file!\n"));
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+
+ //
+ // Figure out how big the file is.
+ //
+ ScratchBufferSize = 0;
+ Status = FileHandle->GetInfo (
+ FileHandle,
+ &gEfiFileInfoGuid,
+ &ScratchBufferSize,
+ NULL
+ );
+ if (EFI_ERROR (Status) && (Status != EFI_BUFFER_TOO_SMALL)) {
+ DEBUG ((DEBUG_ERROR, "Can not obtain file size info!\n"));
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+ FileInfo = AllocateZeroPool (ScratchBufferSize);
+ if (FileInfo == NULL) {
+ DEBUG ((DEBUG_ERROR, "Can not allocate enough memory for the token file!\n"));
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ Status = FileHandle->GetInfo (
+ FileHandle,
+ &gEfiFileInfoGuid,
+ &ScratchBufferSize,
+ FileInfo
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Can not obtain file info from the token file!\n"));
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+ //
+ // Allocate a buffer for the file.
+ //
+ *BufferSize = (UINT32) FileInfo->FileSize;
+ *Buffer = AllocateZeroPool (*BufferSize);
+ if (*Buffer == NULL) {
+ DEBUG ((DEBUG_ERROR, "Can not allocate a buffer for the file!\n"));
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ //
+ // Load file into the allocated memory.
+ //
+ Status = FileHandle->Read (FileHandle, BufferSize, *Buffer);
+ if (EFI_ERROR (Status)) {
+ FreePool (*Buffer);
+ DEBUG ((DEBUG_ERROR, "Can not read the token file!\n"));
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+ //
+ // Close file.
+ //
+ Status = FileHandle->Close (FileHandle);
+ if (EFI_ERROR (Status)) {
+ FreePool (*Buffer);
+ DEBUG ((DEBUG_ERROR, "Can not close the token file !\n"));
+ Status = EFI_DEVICE_ERROR;
+ }
+
+Done:
+
+ if (FileInfo != NULL) {
+ FreePool (FileInfo);
+ }
+
+ return Status;
+}
+
+
+/**
+ Hash the data to get credential.
+
+ @param[in] Buffer Points to the data buffer
+ @param[in] BufferSize The size of data in buffer, in bytes.
+ @param[out] Credential Points to the hashed result
+
+ @retval TRUE Hash the data successfully.
+ @retval FALSE Failed to hash the data.
+
+**/
+BOOLEAN
+GenerateCredential (
+ IN UINT8 *Buffer,
+ IN UINTN BufferSize,
+ OUT UINT8 *Credential
+ )
+{
+ BOOLEAN Status;
+ UINTN HashSize;
+ VOID *Hash;
+
+ HashSize = Sha1GetContextSize ();
+ Hash = AllocatePool (HashSize);
+ ASSERT (Hash != NULL);
+
+ Status = Sha1Init (Hash);
+ if (!Status) {
+ goto Done;
+ }
+
+ Status = Sha1Update (Hash, Buffer, BufferSize);
+ if (!Status) {
+ goto Done;
+ }
+
+ Status = Sha1Final (Hash, Credential);
+
+Done:
+ FreePool (Hash);
+ return Status;
+}
+
+
+/**
+ Read the token file, and default the Token is saved at the begining of the file.
+
+ @param[out] Token Token read from a Token file.
+
+ @retval EFI_SUCCESS Read a Token successfully.
+ @retval Others Fails to read a Token.
+
+**/
+EFI_STATUS
+GetToken (
+ OUT UINT8 *Token
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *Buffer;
+ UINTN BufSize;
+ CHAR16 *TokenFile;
+
+ BufSize = 0;
+ Buffer = NULL;
+ TokenFile = FixedPcdGetPtr (PcdFixedUsbCredentialProviderTokenFileName);
+ Status = GetFileData (TokenFile, (VOID *)&Buffer, &BufSize);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Read file %s from USB error! Status=(%r)\n", TokenFile, Status));
+ return Status;
+ }
+
+ if (!GenerateCredential (Buffer, BufSize, Token)) {
+ DEBUG ((DEBUG_ERROR, "Generate credential from read data failed!\n"));
+ FreePool (Buffer);
+ return EFI_SECURITY_VIOLATION;
+ }
+
+ FreePool (Buffer);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Find a user infomation record by the information record type.
+
+ This function searches all user information records of User from beginning
+ until either the information is found or there are no more user infomation
+ record. A match occurs when a Info.InfoType field matches the user information
+ record type.
+
+ @param[in] User Points to the user profile record to search.
+ @param[in] InfoType The infomation type to be searched.
+ @param[out] Info Points to the user info found, the caller is responsible
+ to free.
+
+ @retval EFI_SUCCESS Find the user information successfully.
+ @retval Others Fail to find the user information.
+
+**/
+EFI_STATUS
+FindUserInfoByType (
+ IN EFI_USER_PROFILE_HANDLE User,
+ IN UINT8 InfoType,
+ OUT EFI_USER_INFO **Info
+ )
+{
+ EFI_STATUS Status;
+ EFI_USER_INFO *UserInfo;
+ UINTN UserInfoSize;
+ EFI_USER_INFO_HANDLE UserInfoHandle;
+ EFI_USER_MANAGER_PROTOCOL *UserManager;
+
+ //
+ // Find user information by information type.
+ //
+ if (Info == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = gBS->LocateProtocol (
+ &gEfiUserManagerProtocolGuid,
+ NULL,
+ (VOID **) &UserManager
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Get each user information.
+ //
+
+ UserInfoHandle = NULL;
+ UserInfo = NULL;
+ UserInfoSize = 0;
+ while (TRUE) {
+ Status = UserManager->GetNextInfo (UserManager, User, &UserInfoHandle);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ //
+ // Get information.
+ //
+ Status = UserManager->GetInfo (
+ UserManager,
+ User,
+ UserInfoHandle,
+ UserInfo,
+ &UserInfoSize
+ );
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ if (UserInfo != NULL) {
+ FreePool (UserInfo);
+ }
+ UserInfo = AllocateZeroPool (UserInfoSize);
+ if (UserInfo == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Status = UserManager->GetInfo (
+ UserManager,
+ User,
+ UserInfoHandle,
+ UserInfo,
+ &UserInfoSize
+ );
+ }
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ ASSERT (UserInfo != NULL);
+ if (UserInfo->InfoType == InfoType) {
+ *Info = UserInfo;
+ return EFI_SUCCESS;
+ }
+ }
+
+ if (UserInfo != NULL) {
+ FreePool (UserInfo);
+ }
+ return Status;
+}
+
+
+/**
+ This function initialize the data mainly used in form browser.
+
+ @retval EFI_SUCCESS Initialize form data successfully.
+ @retval Others Fail to Initialize form data.
+
+**/
+EFI_STATUS
+InitFormBrowser (
+ VOID
+ )
+{
+ USB_PROVIDER_CALLBACK_INFO *CallbackInfo;
+
+ //
+ // Initialize driver private data.
+ //
+ CallbackInfo = AllocateZeroPool (sizeof (USB_PROVIDER_CALLBACK_INFO));
+ if (CallbackInfo == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CallbackInfo->DriverHandle = NULL;
+
+ //
+ // Publish HII data.
+ //
+ CallbackInfo->HiiHandle = HiiAddPackages (
+ &mUsbCredentialGuid,
+ CallbackInfo->DriverHandle,
+ UsbCredentialProviderStrings,
+ NULL
+ );
+ if (CallbackInfo->HiiHandle == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ mCallbackInfo = CallbackInfo;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Enroll a user on a credential provider.
+
+ This function enrolls and deletes a user profile using this credential provider.
+ If a user profile is successfully enrolled, it calls the User Manager Protocol
+ function Notify() to notify the user manager driver that credential information
+ has changed. If an enrolled user does exist, delete the user on the credential
+ provider.
+
+ @param[in] This Points to this instance of EFI_USER_CREDENTIAL_PROTOCOL.
+ @param[in] User The user profile to enroll.
+
+ @retval EFI_SUCCESS User profile was successfully enrolled.
+ @retval EFI_ACCESS_DENIED Current user profile does not permit enrollment on the
+ user profile handle. Either the user profile cannot enroll
+ on any user profile or cannot enroll on a user profile
+ other than the current user profile.
+ @retval EFI_UNSUPPORTED This credential provider does not support enrollment in
+ the pre-OS.
+ @retval EFI_DEVICE_ERROR The new credential could not be created because of a device
+ error.
+ @retval EFI_INVALID_PARAMETER User does not refer to a valid user profile handle.
+
+**/
+EFI_STATUS
+EFIAPI
+CredentialEnroll (
+ IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This,
+ IN EFI_USER_PROFILE_HANDLE User
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ USB_INFO UsbInfo;
+ EFI_USER_INFO *UserInfo;
+ EFI_INPUT_KEY Key;
+ EFI_USER_MANAGER_PROTOCOL *UserManager;
+ UINT8 *UserId;
+ UINT8 *NewUserId;
+ EFI_TPL OldTpl;
+ CHAR16 *QuestionStr;
+ CHAR16 *PromptStr;
+
+ if ((This == NULL) || (User == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = gBS->LocateProtocol (
+ &gEfiUserManagerProtocolGuid,
+ NULL,
+ (VOID **) &UserManager
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Get User Identifier
+ //
+ UserInfo = NULL;
+ Status = FindUserInfoByType (
+ User,
+ EFI_USER_INFO_IDENTIFIER_RECORD,
+ &UserInfo
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // If User exists in mUsbTable, delete User.
+ //
+ for (Index = 0; Index < mUsbTable->Count; Index++) {
+ UserId = (UINT8 *) &mUsbTable->UserInfo[Index].UserId;
+ NewUserId = (UINT8 *) (UserInfo + 1);
+ if (CompareMem (UserId, NewUserId, sizeof (EFI_USER_INFO_IDENTIFIER)) == 0) {
+ //
+ // Delete the exist Token.
+ //
+ FreePool (UserInfo);
+ return ModifyTable (Index, NULL);
+ }
+ }
+
+ //
+ // Get Token and User ID to UsbInfo.
+ //
+ Status = GetToken (UsbInfo.Token);
+ if (EFI_ERROR (Status)) {
+ QuestionStr = GetStringById (STRING_TOKEN (STR_READ_USB_TOKEN_ERROR));
+ PromptStr = GetStringById (STRING_TOKEN (STR_INSERT_USB_TOKEN));
+ OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
+ gBS->RestoreTPL (TPL_APPLICATION);
+ CreatePopUp (
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
+ &Key,
+ QuestionStr,
+ L"",
+ PromptStr,
+ NULL
+ );
+ gBS->RaiseTPL (OldTpl);
+ FreePool (QuestionStr);
+ FreePool (PromptStr);
+ FreePool (UserInfo);
+ return Status;
+ }
+ CopyMem (
+ UsbInfo.UserId,
+ (UINT8 *) (UserInfo + 1),
+ sizeof (EFI_USER_INFO_IDENTIFIER)
+ );
+ FreePool (UserInfo);
+
+ //
+ // Save the new added entry.
+ //
+ Status = ModifyTable (mUsbTable->Count, &UsbInfo);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Notify the user manager driver that credential information has changed.
+ //
+ UserManager->Notify (UserManager, mCallbackInfo->DriverHandle);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Returns the user interface information used during user identification.
+
+ This function returns information about the form used when interacting with the
+ user during user identification. The form is the first enabled form in the form-set
+ class EFI_HII_USER_CREDENTIAL_FORMSET_GUID installed on the HII handle HiiHandle. If
+ the user credential provider does not require a form to identify the user, then this
+ function should return EFI_NOT_FOUND.
+
+ @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.
+ @param[out] Hii On return, holds the HII database handle.
+ @param[out] FormSetId On return, holds the identifier of the form set which contains
+ the form used during user identification.
+ @param[out] FormId On return, holds the identifier of the form used during user
+ identification.
+
+ @retval EFI_SUCCESS Form returned successfully.
+ @retval EFI_NOT_FOUND Form not returned.
+ @retval EFI_INVALID_PARAMETER Hii is NULL or FormSetId is NULL or FormId is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+CredentialForm (
+ IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This,
+ OUT EFI_HII_HANDLE *Hii,
+ OUT EFI_GUID *FormSetId,
+ OUT EFI_FORM_ID *FormId
+ )
+{
+ if ((This == NULL) || (Hii == NULL) ||
+ (FormSetId == NULL) || (FormId == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ Returns bitmap used to describe the credential provider type.
+
+ This optional function returns a bitmap which is less than or equal to the number
+ of pixels specified by Width and Height. If no such bitmap exists, then EFI_NOT_FOUND
+ is returned.
+
+ @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.
+ @param[in, out] Width On entry, points to the desired bitmap width. If NULL then no
+ bitmap information will be returned. On exit, points to the
+ width of the bitmap returned.
+ @param[in, out] Height On entry, points to the desired bitmap height. If NULL then no
+ bitmap information will be returned. On exit, points to the
+ height of the bitmap returned.
+ @param[out] Hii On return, holds the HII database handle.
+ @param[out] Image On return, holds the HII image identifier.
+
+ @retval EFI_SUCCESS Image identifier returned successfully.
+ @retval EFI_NOT_FOUND Image identifier not returned.
+ @retval EFI_INVALID_PARAMETER Hii is NULL or Image is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+CredentialTile (
+ IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This,
+ IN OUT UINTN *Width,
+ IN OUT UINTN *Height,
+ OUT EFI_HII_HANDLE *Hii,
+ OUT EFI_IMAGE_ID *Image
+ )
+{
+ if ((This == NULL) || (Hii == NULL) || (Image == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ Returns string used to describe the credential provider type.
+
+ This function returns a string which describes the credential provider. If no
+ such string exists, then EFI_NOT_FOUND is returned.
+
+ @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.
+ @param[out] Hii On return, holds the HII database handle.
+ @param[out] String On return, holds the HII string identifier.
+
+ @retval EFI_SUCCESS String identifier returned successfully.
+ @retval EFI_NOT_FOUND String identifier not returned.
+ @retval EFI_INVALID_PARAMETER Hii is NULL or String is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+CredentialTitle (
+ IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This,
+ OUT EFI_HII_HANDLE *Hii,
+ OUT EFI_STRING_ID *String
+ )
+{
+ if ((This == NULL) || (Hii == NULL) || (String == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Set Hii handle and String ID.
+ //
+ *Hii = mCallbackInfo->HiiHandle;
+ *String = STRING_TOKEN (STR_CREDENTIAL_TITLE);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Return the user identifier associated with the currently authenticated user.
+
+ This function returns the user identifier of the user authenticated by this credential
+ provider. This function is called after the credential-related information has been
+ submitted on a form OR after a call to Default() has returned that this credential is
+ ready to log on.
+
+ @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.
+ @param[in] User The user profile handle of the user profile currently being
+ considered by the user identity manager. If NULL, then no user
+ profile is currently under consideration.
+ @param[out] Identifier On return, points to the user identifier.
+
+ @retval EFI_SUCCESS User identifier returned successfully.
+ @retval EFI_NOT_READY No user identifier can be returned.
+ @retval EFI_ACCESS_DENIED The user has been locked out of this user credential.
+ @retval EFI_INVALID_PARAMETER This is NULL, or Identifier is NULL.
+ @retval EFI_NOT_FOUND User is not NULL, and the specified user handle can't be
+ found in user profile database.
+
+**/
+EFI_STATUS
+EFIAPI
+CredentialUser (
+ IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This,
+ IN EFI_USER_PROFILE_HANDLE User,
+ OUT EFI_USER_INFO_IDENTIFIER *Identifier
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ EFI_USER_INFO *UserInfo;
+ UINT8 *UserId;
+ UINT8 *NewUserId;
+ UINT8 *UserToken;
+ UINT8 ReadToken[HASHED_CREDENTIAL_LEN];
+ EFI_INPUT_KEY Key;
+ EFI_TPL OldTpl;
+ CHAR16 *QuestionStr;
+ CHAR16 *PromptStr;
+
+ if ((This == NULL) || (Identifier == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (User == NULL) {
+ //
+ // Verify the auto logon user, get user id by matched token.
+ //
+ if (mUsbTable->Count == 0) {
+ return EFI_NOT_READY;
+ }
+
+ //
+ // No user selected, get token first and verify the user existed in user database.
+ //
+ Status = GetToken (ReadToken);
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_READY;
+ }
+
+ for (Index = 0; Index < mUsbTable->Count; Index++) {
+ //
+ // find the specified credential in the Usb credential database.
+ //
+ UserToken = mUsbTable->UserInfo[Index].Token;
+ if (CompareMem (UserToken, ReadToken, HASHED_CREDENTIAL_LEN) == 0) {
+ UserId = (UINT8 *) &mUsbTable->UserInfo[Index].UserId;
+ CopyMem (Identifier, UserId, sizeof (EFI_USER_INFO_IDENTIFIER));
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_NOT_READY;
+ }
+
+ //
+ // User is not NULL here. Read a token, and check whether the token matches with
+ // the selected user's Token. If not, try to find a token in token DB to matches
+ // with read token.
+ //
+
+ Status = GetToken (ReadToken);
+ if (EFI_ERROR (Status)) {
+ QuestionStr = GetStringById (STRING_TOKEN (STR_READ_USB_TOKEN_ERROR));
+ PromptStr = GetStringById (STRING_TOKEN (STR_INSERT_USB_TOKEN));
+ OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
+ gBS->RestoreTPL (TPL_APPLICATION);
+ CreatePopUp (
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
+ &Key,
+ QuestionStr,
+ L"",
+ PromptStr,
+ NULL
+ );
+ gBS->RaiseTPL (OldTpl);
+ FreePool (QuestionStr);
+ FreePool (PromptStr);
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Get the selected user's identifier.
+ //
+ Status = FindUserInfoByType (User, EFI_USER_INFO_IDENTIFIER_RECORD, &UserInfo);
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Check the selected user's Token with the read token.
+ //
+ for (Index = 0; Index < mUsbTable->Count; Index++) {
+ UserId = (UINT8 *) &mUsbTable->UserInfo[Index].UserId;
+ NewUserId = (UINT8 *) (UserInfo + 1);
+ if (CompareMem (UserId, NewUserId, sizeof (EFI_USER_INFO_IDENTIFIER)) == 0) {
+ //
+ // The user's ID is found in the UsbTable.
+ //
+ UserToken = mUsbTable->UserInfo[Index].Token;
+ if (CompareMem (UserToken, ReadToken, HASHED_CREDENTIAL_LEN) == 0) {
+ //
+ // The read token matches with the one in UsbTable.
+ //
+ CopyMem (Identifier, UserId, sizeof (EFI_USER_INFO_IDENTIFIER));
+ FreePool (UserInfo);
+ return EFI_SUCCESS;
+ }
+ }
+ }
+ FreePool (UserInfo);
+
+ //
+ // The read token mismatch with the User's Token.
+ // Only check token.
+ //
+ for (Index = 0; Index < mUsbTable->Count; Index++) {
+ UserToken = mUsbTable->UserInfo[Index].Token;
+ if (CompareMem (UserToken, ReadToken, HASHED_CREDENTIAL_LEN) == 0) {
+ //
+ // The read token matches with the one in UsbTable.
+ //
+ UserId = (UINT8 *) &mUsbTable->UserInfo[Index].UserId;
+ CopyMem (Identifier, UserId, sizeof (EFI_USER_INFO_IDENTIFIER));
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ Indicate that user interface interaction has begun for the specified credential.
+
+ This function is called when a credential provider is selected by the user. If
+ AutoLogon returns FALSE, then the user interface will be constructed by the User
+ Identity Manager.
+
+ @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.
+ @param[out] AutoLogon On return, points to the credential provider's capabilities
+ after the credential provider has been selected by the user.
+
+ @retval EFI_SUCCESS Credential provider successfully selected.
+ @retval EFI_INVALID_PARAMETER AutoLogon is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+CredentialSelect (
+ IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This,
+ OUT EFI_CREDENTIAL_LOGON_FLAGS *AutoLogon
+ )
+{
+ if ((This == NULL) || (AutoLogon == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *AutoLogon = EFI_CREDENTIAL_LOGON_FLAG_DEFAULT | EFI_CREDENTIAL_LOGON_FLAG_AUTO;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Indicate that user interface interaction has ended for the specified credential.
+
+ This function is called when a credential provider is deselected by the user.
+
+ @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.
+
+ @retval EFI_SUCCESS Credential provider successfully deselected.
+
+**/
+EFI_STATUS
+EFIAPI
+CredentialDeselect (
+ IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This
+ )
+{
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Return the default logon behavior for this user credential.
+
+ This function reports the default login behavior regarding this credential provider.
+
+ @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.
+ @param[out] AutoLogon On return, holds whether the credential provider should be used
+ by default to automatically log on the user.
+
+ @retval EFI_SUCCESS Default information successfully returned.
+ @retval EFI_INVALID_PARAMETER AutoLogon is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+CredentialDefault (
+ IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This,
+ OUT EFI_CREDENTIAL_LOGON_FLAGS *AutoLogon
+ )
+{
+ if ((This == NULL) || (AutoLogon == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *AutoLogon = EFI_CREDENTIAL_LOGON_FLAG_DEFAULT | EFI_CREDENTIAL_LOGON_FLAG_AUTO;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Return information attached to the credential provider.
+
+ This function returns user information.
+
+ @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.
+ @param[in] UserInfo Handle of the user information data record.
+ @param[out] Info On entry, points to a buffer of at least *InfoSize bytes. On
+ exit, holds the user information. If the buffer is too small
+ to hold the information, then EFI_BUFFER_TOO_SMALL is returned
+ and InfoSize is updated to contain the number of bytes actually
+ required.
+ @param[in, out] InfoSize On entry, points to the size of Info. On return, points to the
+ size of the user information.
+
+ @retval EFI_SUCCESS Information returned successfully.
+ @retval EFI_BUFFER_TOO_SMALL The size specified by InfoSize is too small to hold all of the
+ user information. The size required is returned in *InfoSize.
+ @retval EFI_INVALID_PARAMETER Info is NULL or InfoSize is NULL.
+ @retval EFI_NOT_FOUND The specified UserInfo does not refer to a valid user info handle.
+
+**/
+EFI_STATUS
+EFIAPI
+CredentialGetInfo (
+ IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This,
+ IN EFI_USER_INFO_HANDLE UserInfo,
+ OUT EFI_USER_INFO *Info,
+ IN OUT UINTN *InfoSize
+ )
+{
+ EFI_USER_INFO *CredentialInfo;
+ UINTN Index;
+
+ if ((This == NULL) || (InfoSize == NULL) || (Info == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((UserInfo == NULL) || (mUsbInfoHandle == NULL)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Find information handle in credential info table.
+ //
+ for (Index = 0; Index < mUsbInfoHandle->Count; Index++) {
+ CredentialInfo = mUsbInfoHandle->Info[Index];
+ if (UserInfo == (EFI_USER_INFO_HANDLE)CredentialInfo) {
+ //
+ // The handle is found, copy the user info.
+ //
+ if (CredentialInfo->InfoSize > *InfoSize) {
+ *InfoSize = CredentialInfo->InfoSize;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ CopyMem (Info, CredentialInfo, CredentialInfo->InfoSize);
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ Enumerate all of the user informations on the credential provider.
+
+ This function returns the next user information record. To retrieve the first user
+ information record handle, point UserInfo at a NULL. Each subsequent call will retrieve
+ another user information record handle until there are no more, at which point UserInfo
+ will point to NULL.
+
+ @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.
+ @param[in, out] UserInfo On entry, points to the previous user information handle or NULL
+ to start enumeration. On exit, points to the next user information
+ handle or NULL if there is no more user information.
+
+ @retval EFI_SUCCESS User information returned.
+ @retval EFI_NOT_FOUND No more user information found.
+ @retval EFI_INVALID_PARAMETER UserInfo is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+CredentialGetNextInfo (
+ IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This,
+ IN OUT EFI_USER_INFO_HANDLE *UserInfo
+ )
+{
+ EFI_USER_INFO *Info;
+ CHAR16 *ProvNameStr;
+ UINTN InfoLen;
+ UINTN Index;
+ UINTN ProvStrLen;
+
+ if ((This == NULL) || (UserInfo == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (mUsbInfoHandle == NULL) {
+ //
+ // Initilized user info table. There are 4 user info records in the table.
+ //
+ InfoLen = sizeof (USB_CREDENTIAL_INFO) + (4 - 1) * sizeof (EFI_USER_INFO *);
+ mUsbInfoHandle = AllocateZeroPool (InfoLen);
+ if (mUsbInfoHandle == NULL) {
+ *UserInfo = NULL;
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // The first information, Credential Provider info.
+ //
+ InfoLen = sizeof (EFI_USER_INFO) + sizeof (EFI_GUID);
+ Info = AllocateZeroPool (InfoLen);
+ ASSERT (Info != NULL);
+
+ Info->InfoType = EFI_USER_INFO_CREDENTIAL_PROVIDER_RECORD;
+ Info->InfoSize = (UINT32) InfoLen;
+ Info->InfoAttribs = EFI_USER_INFO_PROTECTED;
+ CopyGuid (&Info->Credential, &mUsbCredentialGuid);
+ CopyGuid ((EFI_GUID *)(Info + 1), &mUsbCredentialGuid);
+
+ mUsbInfoHandle->Info[0] = Info;
+ mUsbInfoHandle->Count++;
+
+ //
+ // The second information, Credential Provider name info.
+ //
+ ProvNameStr = GetStringById (STRING_TOKEN (STR_PROVIDER_NAME));
+ ProvStrLen = StrSize (ProvNameStr);
+ InfoLen = sizeof (EFI_USER_INFO) + ProvStrLen;
+ Info = AllocateZeroPool (InfoLen);
+ ASSERT (Info != NULL);
+
+ Info->InfoType = EFI_USER_INFO_CREDENTIAL_PROVIDER_NAME_RECORD;
+ Info->InfoSize = (UINT32) InfoLen;
+ Info->InfoAttribs = EFI_USER_INFO_PROTECTED;
+ CopyGuid (&Info->Credential, &mUsbCredentialGuid);
+ CopyMem ((UINT8*)(Info + 1), ProvNameStr, ProvStrLen);
+ FreePool (ProvNameStr);
+
+ mUsbInfoHandle->Info[1] = Info;
+ mUsbInfoHandle->Count++;
+
+ //
+ // The third information, Credential Provider type info.
+ //
+ InfoLen = sizeof (EFI_USER_INFO) + sizeof (EFI_GUID);
+ Info = AllocateZeroPool (InfoLen);
+ ASSERT (Info != NULL);
+
+ Info->InfoType = EFI_USER_INFO_CREDENTIAL_TYPE_RECORD;
+ Info->InfoSize = (UINT32) InfoLen;
+ Info->InfoAttribs = EFI_USER_INFO_PROTECTED;
+ CopyGuid (&Info->Credential, &mUsbCredentialGuid);
+ CopyGuid ((EFI_GUID *)(Info + 1), &gEfiUserCredentialClassSecureCardGuid);
+
+ mUsbInfoHandle->Info[2] = Info;
+ mUsbInfoHandle->Count++;
+
+ //
+ // The fourth information, Credential Provider type name info.
+ //
+ ProvNameStr = GetStringById (STRING_TOKEN (STR_PROVIDER_TYPE_NAME));
+ ProvStrLen = StrSize (ProvNameStr);
+ InfoLen = sizeof (EFI_USER_INFO) + ProvStrLen;
+ Info = AllocateZeroPool (InfoLen);
+ ASSERT (Info != NULL);
+
+ Info->InfoType = EFI_USER_INFO_CREDENTIAL_PROVIDER_NAME_RECORD;
+ Info->InfoSize = (UINT32) InfoLen;
+ Info->InfoAttribs = EFI_USER_INFO_PROTECTED;
+ CopyGuid (&Info->Credential, &mUsbCredentialGuid);
+ CopyMem ((UINT8*)(Info + 1), ProvNameStr, ProvStrLen);
+ FreePool (ProvNameStr);
+
+ mUsbInfoHandle->Info[3] = Info;
+ mUsbInfoHandle->Count++;
+ }
+
+ if (*UserInfo == NULL) {
+ //
+ // Return the first info handle.
+ //
+ *UserInfo = (EFI_USER_INFO_HANDLE) mUsbInfoHandle->Info[0];
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Find information handle in credential info table.
+ //
+ for (Index = 0; Index < mUsbInfoHandle->Count; Index++) {
+ Info = mUsbInfoHandle->Info[Index];
+ if (*UserInfo == (EFI_USER_INFO_HANDLE)Info) {
+ //
+ // The handle is found, get the next one.
+ //
+ if (Index == mUsbInfoHandle->Count - 1) {
+ //
+ // Already last one.
+ //
+ *UserInfo = NULL;
+ return EFI_NOT_FOUND;
+ }
+ Index++;
+ *UserInfo = (EFI_USER_INFO_HANDLE)mUsbInfoHandle->Info[Index];
+ return EFI_SUCCESS;
+ }
+ }
+
+ *UserInfo = NULL;
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ Main entry for this driver.
+
+ @param ImageHandle Image handle this driver.
+ @param SystemTable Pointer to SystemTable.
+
+ @retval EFI_SUCESS This function always complete successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+UsbProviderInit (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Init credential table.
+ //
+ Status = InitCredentialTable ();
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Init Form Browser
+ //
+ Status = InitFormBrowser ();
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Install protocol interfaces for the Usb Credential Provider.
+ //
+ Status = gBS->InstallProtocolInterface (
+ &mCallbackInfo->DriverHandle,
+ &gEfiUserCredentialProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &gUsbCredentialProviderDriver
+ );
+ return Status;
+}
diff --git a/SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProvider.h b/SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProvider.h
new file mode 100644
index 0000000000..1d43e9ac99
--- /dev/null
+++ b/SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProvider.h
@@ -0,0 +1,354 @@
+/** @file
+ Usb Credential Provider driver header file.
+
+Copyright (c) 2009, Intel Corporation. All rights reserved.
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _USB_CREDENTIAL_PROVIDER_H_
+#define _USB_CREDENTIAL_PROVIDER_H_
+
+#include
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+extern UINT8 UsbCredentialProviderStrings[];
+extern UINT8 UsbCredentialProviderVfrBin[];
+
+#define USB_TABLE_INC 16
+#define HASHED_CREDENTIAL_LEN 20
+
+#define USB_CREDENTIAL_PROVIDER_GUID \
+ { \
+ 0xd0849ed1, 0xa88c, 0x4ba6, { 0xb1, 0xd6, 0xab, 0x50, 0xe2, 0x80, 0xb7, 0xa9 }\
+ }
+
+//
+// Save the enroll user credential Information.
+//
+typedef struct {
+ EFI_USER_INFO_IDENTIFIER UserId;
+ UINT8 Token[HASHED_CREDENTIAL_LEN];
+} USB_INFO;
+
+//
+// USB Credential Table.
+//
+typedef struct {
+ UINTN Count;
+ UINTN MaxCount;
+ USB_INFO UserInfo[1];
+} CREDENTIAL_TABLE;
+
+//
+// The user information on the USB provider.
+//
+typedef struct {
+ UINTN Count;
+ EFI_USER_INFO *Info[1];
+} USB_CREDENTIAL_INFO;
+
+///
+/// HII specific Vendor Device Path definition.
+///
+typedef struct {
+ VENDOR_DEVICE_PATH VendorDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} HII_VENDOR_DEVICE_PATH;
+
+#define USB_PROVIDER_SIGNATURE SIGNATURE_32 ('U', 'S', 'B', 'P')
+
+typedef struct {
+ UINTN Signature;
+ EFI_HANDLE DriverHandle;
+ EFI_HII_HANDLE HiiHandle;
+} USB_PROVIDER_CALLBACK_INFO;
+
+/**
+ Enroll a user on a credential provider.
+
+ This function enrolls and deletes a user profile using this credential provider.
+ If a user profile is successfully enrolled, it calls the User Manager Protocol
+ function Notify() to notify the user manager driver that credential information
+ has changed. If an enrolled user does exist, delete the user on the credential
+ provider.
+
+ @param[in] This Points to this instance of EFI_USER_CREDENTIAL_PROTOCOL.
+ @param[in] User The user profile to enroll.
+
+ @retval EFI_SUCCESS User profile was successfully enrolled.
+ @retval EFI_ACCESS_DENIED Current user profile does not permit enrollment on the
+ user profile handle. Either the user profile cannot enroll
+ on any user profile or cannot enroll on a user profile
+ other than the current user profile.
+ @retval EFI_UNSUPPORTED This credential provider does not support enrollment in
+ the pre-OS.
+ @retval EFI_DEVICE_ERROR The new credential could not be created because of a device
+ error.
+ @retval EFI_INVALID_PARAMETER User does not refer to a valid user profile handle.
+
+**/
+EFI_STATUS
+EFIAPI
+CredentialEnroll (
+ IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This,
+ IN EFI_USER_PROFILE_HANDLE User
+ );
+
+/**
+ Returns the user interface information used during user identification.
+
+ This function returns information about the form used when interacting with the
+ user during user identification. The form is the first enabled form in the form-set
+ class EFI_HII_USER_CREDENTIAL_FORMSET_GUID installed on the HII handle HiiHandle. If
+ the user credential provider does not require a form to identify the user, then this
+ function should return EFI_NOT_FOUND.
+
+ @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.
+ @param[out] Hii On return, holds the HII database handle.
+ @param[out] FormSetId On return, holds the identifier of the form set which contains
+ the form used during user identification.
+ @param[out] FormId On return, holds the identifier of the form used during user
+ identification.
+
+ @retval EFI_SUCCESS Form returned successfully.
+ @retval EFI_NOT_FOUND Form not returned.
+ @retval EFI_INVALID_PARAMETER Hii is NULL or FormSetId is NULL or FormId is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+CredentialForm (
+ IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This,
+ OUT EFI_HII_HANDLE *Hii,
+ OUT EFI_GUID *FormSetId,
+ OUT EFI_FORM_ID *FormId
+ );
+
+/**
+ Returns bitmap used to describe the credential provider type.
+
+ This optional function returns a bitmap which is less than or equal to the number
+ of pixels specified by Width and Height. If no such bitmap exists, then EFI_NOT_FOUND
+ is returned.
+
+ @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.
+ @param[in, out] Width On entry, points to the desired bitmap width. If NULL then no
+ bitmap information will be returned. On exit, points to the
+ width of the bitmap returned.
+ @param[in, out] Height On entry, points to the desired bitmap height. If NULL then no
+ bitmap information will be returned. On exit, points to the
+ height of the bitmap returned.
+ @param[out] Hii On return, holds the HII database handle.
+ @param[out] Image On return, holds the HII image identifier.
+
+ @retval EFI_SUCCESS Image identifier returned successfully.
+ @retval EFI_NOT_FOUND Image identifier not returned.
+ @retval EFI_INVALID_PARAMETER Hii is NULL or Image is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+CredentialTile (
+ IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This,
+ IN OUT UINTN *Width,
+ IN OUT UINTN *Height,
+ OUT EFI_HII_HANDLE *Hii,
+ OUT EFI_IMAGE_ID *Image
+ );
+
+/**
+ Returns string used to describe the credential provider type.
+
+ This function returns a string which describes the credential provider. If no
+ such string exists, then EFI_NOT_FOUND is returned.
+
+ @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.
+ @param[out] Hii On return, holds the HII database handle.
+ @param[out] String On return, holds the HII string identifier.
+
+ @retval EFI_SUCCESS String identifier returned successfully.
+ @retval EFI_NOT_FOUND String identifier not returned.
+ @retval EFI_INVALID_PARAMETER Hii is NULL or String is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+CredentialTitle (
+ IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This,
+ OUT EFI_HII_HANDLE *Hii,
+ OUT EFI_STRING_ID *String
+ );
+
+/**
+ Return the user identifier associated with the currently authenticated user.
+
+ This function returns the user identifier of the user authenticated by this credential
+ provider. This function is called after the credential-related information has been
+ submitted on a form OR after a call to Default() has returned that this credential is
+ ready to log on.
+
+ @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.
+ @param[in] User The user profile handle of the user profile currently being
+ considered by the user identity manager. If NULL, then no user
+ profile is currently under consideration.
+ @param[out] Identifier On return, points to the user identifier.
+
+ @retval EFI_SUCCESS User identifier returned successfully.
+ @retval EFI_NOT_READY No user identifier can be returned.
+ @retval EFI_ACCESS_DENIED The user has been locked out of this user credential.
+ @retval EFI_INVALID_PARAMETER This is NULL, or Identifier is NULL.
+ @retval EFI_NOT_FOUND User is not NULL, and the specified user handle can't be
+ found in user profile database.
+
+**/
+EFI_STATUS
+EFIAPI
+CredentialUser (
+ IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This,
+ IN EFI_USER_PROFILE_HANDLE User,
+ OUT EFI_USER_INFO_IDENTIFIER *Identifier
+ );
+
+/**
+ Indicate that user interface interaction has begun for the specified credential.
+
+ This function is called when a credential provider is selected by the user. If
+ AutoLogon returns FALSE, then the user interface will be constructed by the User
+ Identity Manager.
+
+ @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.
+ @param[out] AutoLogon On return, points to the credential provider's capabilities
+ after the credential provider has been selected by the user.
+
+ @retval EFI_SUCCESS Credential provider successfully selected.
+ @retval EFI_INVALID_PARAMETER AutoLogon is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+CredentialSelect (
+ IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This,
+ OUT EFI_CREDENTIAL_LOGON_FLAGS *AutoLogon
+ );
+
+/**
+ Indicate that user interface interaction has ended for the specified credential.
+
+ This function is called when a credential provider is deselected by the user.
+
+ @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.
+
+ @retval EFI_SUCCESS Credential provider successfully deselected.
+
+**/
+EFI_STATUS
+EFIAPI
+CredentialDeselect (
+ IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This
+ );
+
+/**
+ Return the default logon behavior for this user credential.
+
+ This function reports the default login behavior regarding this credential provider.
+
+ @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.
+ @param[out] AutoLogon On return, holds whether the credential provider should be used
+ by default to automatically log on the user.
+
+ @retval EFI_SUCCESS Default information successfully returned.
+ @retval EFI_INVALID_PARAMETER AutoLogon is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+CredentialDefault (
+ IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This,
+ OUT EFI_CREDENTIAL_LOGON_FLAGS *AutoLogon
+ );
+
+/**
+ Return information attached to the credential provider.
+
+ This function returns user information.
+
+ @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.
+ @param[in] UserInfo Handle of the user information data record.
+ @param[out] Info On entry, points to a buffer of at least *InfoSize bytes. On
+ exit, holds the user information. If the buffer is too small
+ to hold the information, then EFI_BUFFER_TOO_SMALL is returned
+ and InfoSize is updated to contain the number of bytes actually
+ required.
+ @param[in, out] InfoSize On entry, points to the size of Info. On return, points to the
+ size of the user information.
+
+ @retval EFI_SUCCESS Information returned successfully.
+ @retval EFI_BUFFER_TOO_SMALL The size specified by InfoSize is too small to hold all of the
+ user information. The size required is returned in *InfoSize.
+ @retval EFI_INVALID_PARAMETER Info is NULL or InfoSize is NULL.
+ @retval EFI_NOT_FOUND The specified UserInfo does not refer to a valid user info handle.
+
+**/
+EFI_STATUS
+EFIAPI
+CredentialGetInfo (
+ IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This,
+ IN EFI_USER_INFO_HANDLE UserInfo,
+ OUT EFI_USER_INFO *Info,
+ IN OUT UINTN *InfoSize
+ );
+
+/**
+ Enumerate all of the user informations on the credential provider.
+
+ This function returns the next user information record. To retrieve the first user
+ information record handle, point UserInfo at a NULL. Each subsequent call will retrieve
+ another user information record handle until there are no more, at which point UserInfo
+ will point to NULL.
+
+ @param[in] This Points to this instance of the EFI_USER_CREDENTIAL_PROTOCOL.
+ @param[in, out] UserInfo On entry, points to the previous user information handle or NULL
+ to start enumeration. On exit, points to the next user information
+ handle or NULL if there is no more user information.
+
+ @retval EFI_SUCCESS User information returned.
+ @retval EFI_NOT_FOUND No more user information found.
+ @retval EFI_INVALID_PARAMETER UserInfo is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+CredentialGetNextInfo (
+ IN CONST EFI_USER_CREDENTIAL_PROTOCOL *This,
+ IN OUT EFI_USER_INFO_HANDLE *UserInfo
+ );
+
+#endif
diff --git a/SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProviderDxe.inf b/SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProviderDxe.inf
new file mode 100644
index 0000000000..2a45763566
--- /dev/null
+++ b/SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProviderDxe.inf
@@ -0,0 +1,58 @@
+## @file
+# Component description file for USB Credential Provider.
+#
+# Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = UsbCredentialProvider
+ FILE_GUID = 672A0C68-2BF0-46f9-93C3-C4E7DC0FA555
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = UsbProviderInit
+
+[Sources]
+ UsbCredentialProvider.c
+ UsbCredentialProvider.h
+ UsbCredentialProviderStrings.uni
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ CryptoPkg/CryptoPkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+ UefiRuntimeServicesTableLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ MemoryAllocationLib
+ BaseMemoryLib
+ DebugLib
+ HiiLib
+ UefiLib
+ BaseCryptLib
+
+[Guids]
+ gEfiIfrTianoGuid ## CONSUMES ## Guid
+ gEfiFileInfoGuid ## CONSUMES ## Guid
+ gEfiUserCredentialClassSecureCardGuid ## CONSUMES ## Guid
+
+[Pcd]
+ gEfiSecurityPkgTokenSpaceGuid.PcdFixedUsbCredentialProviderTokenFileName
+
+[Protocols]
+ gEfiDevicePathProtocolGuid # PROTOCOL ALWAYS_CONSUMED
+ gEfiUserCredentialProtocolGuid
+ gEfiUserManagerProtocolGuid
+ gEfiBlockIoProtocolGuid
+ gEfiSimpleFileSystemProtocolGuid
+
\ No newline at end of file
diff --git a/SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProviderStrings.uni b/SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProviderStrings.uni
new file mode 100644
index 0000000000..7c531f4230
Binary files /dev/null and b/SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProviderStrings.uni differ
diff --git a/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/LoadDeferredImage.c b/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/LoadDeferredImage.c
new file mode 100644
index 0000000000..da1201a5f9
--- /dev/null
+++ b/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/LoadDeferredImage.c
@@ -0,0 +1,148 @@
+/** @file
+ Load the deferred images after user is identified.
+
+Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "UserIdentifyManager.h"
+
+EFI_HANDLE mDeferredImageHandle;
+
+/**
+ The function will load all the deferred images again. If the deferred image is loaded
+ successfully, try to start it.
+
+ @param Event Event whose notification function is being invoked.
+ @param Context Pointer to the notification function's context
+
+**/
+VOID
+EFIAPI
+LoadDeferredImage (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEFERRED_IMAGE_LOAD_PROTOCOL *DeferredImage;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuf;
+ UINTN Index;
+ UINTN DriverIndex;
+ EFI_DEVICE_PATH_PROTOCOL *ImageDevicePath;
+ VOID *DriverImage;
+ UINTN ImageSize;
+ BOOLEAN BootOption;
+ EFI_HANDLE ImageHandle;
+ UINTN ExitDataSize;
+ CHAR16 *ExitData;
+
+ //
+ // Find all the deferred image load protocols.
+ //
+ HandleCount = 0;
+ HandleBuf = NULL;
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiDeferredImageLoadProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuf
+ );
+ if (EFI_ERROR (Status)) {
+ return ;
+ }
+
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->HandleProtocol (
+ HandleBuf[Index],
+ &gEfiDeferredImageLoadProtocolGuid,
+ (VOID **) &DeferredImage
+ );
+ if (EFI_ERROR (Status)) {
+ continue ;
+ }
+
+ DriverIndex = 0;
+ do {
+ //
+ // Load all the deferred images in this protocol instance.
+ //
+ Status = DeferredImage->GetImageInfo(
+ DeferredImage,
+ DriverIndex,
+ &ImageDevicePath,
+ (VOID **) &DriverImage,
+ &ImageSize,
+ &BootOption
+ );
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ //
+ // Load and start the image.
+ //
+ Status = gBS->LoadImage (
+ BootOption,
+ mDeferredImageHandle,
+ ImageDevicePath,
+ NULL,
+ 0,
+ &ImageHandle
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Before calling the image, enable the Watchdog Timer for
+ // a 5 Minute period
+ //
+ gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);
+ Status = gBS->StartImage (ImageHandle, &ExitDataSize, &ExitData);
+
+ //
+ // Clear the Watchdog Timer after the image returns.
+ //
+ gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);
+ }
+ DriverIndex++;
+ } while (TRUE);
+ }
+ FreePool (HandleBuf);
+}
+
+
+/**
+ Register an event notification function for user profile changed.
+
+ @param[in] ImageHandle Image handle this driver.
+
+**/
+VOID
+LoadDeferredImageInit (
+ IN EFI_HANDLE ImageHandle
+ )
+{
+ EFI_STATUS Status;
+ EFI_EVENT Event;
+
+ mDeferredImageHandle = ImageHandle;
+
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ LoadDeferredImage,
+ NULL,
+ &gEfiEventUserProfileChangedGuid,
+ &Event
+ );
+
+ ASSERT (Status == EFI_SUCCESS);
+}
diff --git a/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManager.c b/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManager.c
new file mode 100644
index 0000000000..e105579115
--- /dev/null
+++ b/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManager.c
@@ -0,0 +1,4381 @@
+/** @file
+ This driver manages user information and produces user manager protocol.
+
+Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "UserIdentifyManager.h"
+
+//
+// Guid used in user profile saving and in form browser.
+//
+EFI_GUID mUserManagerGuid = USER_IDENTIFY_MANAGER_GUID;
+
+//
+// Default user name.
+//
+CHAR16 mUserName[] = L"Administrator";
+
+//
+// Points to the user profile database.
+//
+USER_PROFILE_DB *mUserProfileDb = NULL;
+
+//
+// Points to the credential providers found in system.
+//
+CREDENTIAL_PROVIDER_INFO *mProviderDb = NULL;
+
+//
+// Current user shared in multi function.
+//
+EFI_USER_PROFILE_HANDLE mCurrentUser = NULL;
+
+//
+// Flag indicates a user is identified.
+//
+BOOLEAN mIdentified = FALSE;
+USER_MANAGER_CALLBACK_INFO *mCallbackInfo = NULL;
+HII_VENDOR_DEVICE_PATH mHiiVendorDevicePath = {
+ {
+ {
+ HARDWARE_DEVICE_PATH,
+ HW_VENDOR_DP,
+ {
+ (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
+ (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
+ }
+ },
+ //
+ // {ACA7C06F-743C-454f-9C6D-692138482498}
+ //
+ { 0xaca7c06f, 0x743c, 0x454f, { 0x9c, 0x6d, 0x69, 0x21, 0x38, 0x48, 0x24, 0x98 } }
+ },
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ (UINT8) (END_DEVICE_PATH_LENGTH),
+ (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
+ }
+ }
+};
+
+
+EFI_USER_MANAGER_PROTOCOL gUserIdentifyManager = {
+ UserProfileCreate,
+ UserProfileDelete,
+ UserProfileGetNext,
+ UserProfileCurrent,
+ UserProfileIdentify,
+ UserProfileFind,
+ UserProfileNotify,
+ UserProfileGetInfo,
+ UserProfileSetInfo,
+ UserProfileDeleteInfo,
+ UserProfileGetNextInfo,
+};
+
+
+/**
+ Find the specified user in the user database.
+
+ This function searches the specified user from the beginning of the user database.
+ And if NextUser is TRUE, return the next User in the user database.
+
+ @param[in, out] User On entry, points to the user profile entry to search.
+ On return, points to the user profile entry or NULL if not found.
+ @param[in] NextUser If FALSE, find the user in user profile database specifyed by User
+ If TRUE, find the next user in user profile database specifyed
+ by User.
+ @param[out] ProfileIndex A pointer to the index of user profile database that matches the
+ user specifyed by User.
+
+ @retval EFI_NOT_FOUND User was NULL, or User was not found, or the next user was not found.
+ @retval EFI_SUCCESS User or the next user are found in user profile database
+
+**/
+EFI_STATUS
+FindUserProfile (
+ IN OUT USER_PROFILE_ENTRY **User,
+ IN BOOLEAN NextUser,
+ OUT UINTN *ProfileIndex OPTIONAL
+ )
+{
+ UINTN Index;
+
+ //
+ // Check parameters
+ //
+ if ((mUserProfileDb == NULL) || (User == NULL)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Check whether the user profile is in the user profile database.
+ //
+ for (Index = 0; Index < mUserProfileDb->UserProfileNum; Index++) {
+ if (mUserProfileDb->UserProfile[Index] == *User) {
+ if (ProfileIndex != NULL) {
+ *ProfileIndex = Index;
+ }
+ break;
+ }
+ }
+
+ if (NextUser) {
+ //
+ // Find the next user profile.
+ //
+ Index++;
+ if (Index < mUserProfileDb->UserProfileNum) {
+ *User = mUserProfileDb->UserProfile[Index];
+ } else if (Index == mUserProfileDb->UserProfileNum) {
+ *User = NULL;
+ return EFI_NOT_FOUND;
+ } else {
+ if ((mUserProfileDb->UserProfileNum > 0) && (*User == NULL)) {
+ *User = mUserProfileDb->UserProfile[0];
+ } else {
+ *User = NULL;
+ return EFI_NOT_FOUND;
+ }
+ }
+ } else if (Index == mUserProfileDb->UserProfileNum) {
+ return EFI_NOT_FOUND;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Find the specified user information record in the specified User profile.
+
+ This function searches the specified user information record from the beginning of the user
+ profile. And if NextInfo is TRUE, return the next info in the user profile.
+
+ @param[in] User Points to the user profile entry.
+ @param[in, out] Info On entry, points to the user information record or NULL to start
+ searching with the first user information record.
+ On return, points to the user information record or NULL if not found.
+ @param[in] NextInfo If FALSE, find the user information record in profile specifyed by User.
+ If TRUE, find the next user information record in profile specifyed
+ by User.
+ @param[out] Offset A pointer to the offset of the information record in the user profile.
+
+ @retval EFI_INVALID_PARAMETER Info is NULL
+ @retval EFI_NOT_FOUND Info was not found, or the next Info was not found.
+ @retval EFI_SUCCESS Info or the next info are found in user profile.
+
+**/
+EFI_STATUS
+FindUserInfo (
+ IN USER_PROFILE_ENTRY * User,
+ IN OUT EFI_USER_INFO **Info,
+ IN BOOLEAN NextInfo,
+ OUT UINTN *Offset OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_USER_INFO *UserInfo;
+ UINTN InfoLen;
+
+ if (Info == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check user profile entry
+ //
+ Status = FindUserProfile (&User, FALSE, NULL);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Find user information in the specified user record.
+ //
+ InfoLen = 0;
+ while (InfoLen < User->UserProfileSize) {
+ UserInfo = (EFI_USER_INFO *) (User->ProfileInfo + InfoLen);
+ if (UserInfo == *Info) {
+ if (Offset != NULL) {
+ *Offset = InfoLen;
+ }
+ break;
+ }
+ InfoLen += ALIGN_VARIABLE (UserInfo->InfoSize);
+ }
+
+ //
+ // Check whether to find the next user information.
+ //
+ if (NextInfo) {
+ if (InfoLen < User->UserProfileSize) {
+ UserInfo = (EFI_USER_INFO *) (User->ProfileInfo + InfoLen);
+ InfoLen += ALIGN_VARIABLE (UserInfo->InfoSize);
+ if (InfoLen < User->UserProfileSize) {
+ *Info = (EFI_USER_INFO *) (User->ProfileInfo + InfoLen);
+ if (Offset != NULL) {
+ *Offset = InfoLen;
+ }
+ } else if (InfoLen == User->UserProfileSize) {
+ *Info = NULL;
+ return EFI_NOT_FOUND;
+ }
+ } else {
+ if (*Info == NULL) {
+ *Info = (EFI_USER_INFO *) User->ProfileInfo;
+ if (Offset != NULL) {
+ *Offset = 0;
+ }
+ } else {
+ *Info = NULL;
+ return EFI_NOT_FOUND;
+ }
+ }
+ } else if (InfoLen == User->UserProfileSize) {
+ return EFI_NOT_FOUND;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Find a user infomation record by the information record type.
+
+ This function searches all user information records of User. The search starts with the
+ user information record following Info and continues until either the information is found
+ or there are no more user infomation record.
+ A match occurs when a Info.InfoType field matches the user information record type.
+
+ @param[in] User Points to the user profile record to search.
+ @param[in, out] Info On entry, points to the user information record or NULL to start
+ searching with the first user information record.
+ On return, points to the user information record or NULL if not found.
+ @param[in] InfoType The infomation type to be searched.
+
+ @retval EFI_SUCCESS User information was found. Info points to the user information record.
+ @retval EFI_NOT_FOUND User information was not found.
+ @retval EFI_INVALID_PARAMETER User is NULL or Info is NULL.
+
+**/
+EFI_STATUS
+FindUserInfoByType (
+ IN USER_PROFILE_ENTRY *User,
+ IN OUT EFI_USER_INFO **Info,
+ IN UINT8 InfoType
+ )
+{
+ EFI_STATUS Status;
+ EFI_USER_INFO *UserInfo;
+ UINTN InfoLen;
+
+ if (Info == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check whether the user has the specified user information.
+ //
+ InfoLen = 0;
+ if (*Info == NULL) {
+ Status = FindUserProfile (&User, FALSE, NULL);
+ } else {
+ Status = FindUserInfo (User, Info, TRUE, &InfoLen);
+ }
+
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+
+ while (InfoLen < User->UserProfileSize) {
+ UserInfo = (EFI_USER_INFO *) (User->ProfileInfo + InfoLen);
+ if (UserInfo->InfoType == InfoType) {
+ if (UserInfo != *Info) {
+ *Info = UserInfo;
+ return EFI_SUCCESS;
+ }
+ }
+
+ InfoLen += ALIGN_VARIABLE (UserInfo->InfoSize);
+ }
+
+ *Info = NULL;
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Find a user using a user information record.
+
+ This function searches all user profiles for the specified user information record. The
+ search starts with the user information record handle following UserInfo and continues
+ until either the information is found or there are no more user profiles.
+ A match occurs when the Info.InfoType field matches the user information record type and the
+ user information record data matches the portion of Info passed the EFI_USER_INFO header.
+
+ @param[in, out] User On entry, points to the previously returned user profile record,
+ or NULL to start searching with the first user profile.
+ On return, points to the user profile entry, or NULL if not found.
+ @param[in, out] UserInfo On entry, points to the previously returned user information record,
+ or NULL to start searching with the first.
+ On return, points to the user information record, or NULL if not found.
+ @param[in] Info Points to the buffer containing the user information to be compared
+ to the user information record.
+ @param[in] InfoSize The size of Info, in bytes. Same as Info->InfoSize.
+
+ @retval EFI_SUCCESS User information was found. User points to the user profile record,
+ and UserInfo points to the user information record.
+ @retval EFI_NOT_FOUND User information was not found.
+ @retval EFI_INVALID_PARAMETER User is NULL; Info is NULL; or, InfoSize is too small.
+
+**/
+EFI_STATUS
+FindUserProfileByInfo (
+ IN OUT USER_PROFILE_ENTRY **User,
+ IN OUT EFI_USER_INFO **UserInfo, OPTIONAL
+ IN EFI_USER_INFO *Info,
+ IN UINTN InfoSize
+ )
+{
+ EFI_STATUS Status;
+ EFI_USER_INFO *InfoEntry;
+
+
+ if ((User == NULL) || (Info == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (InfoSize < sizeof (EFI_USER_INFO)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (UserInfo != NULL) {
+ InfoEntry = *UserInfo;
+ } else {
+ InfoEntry = NULL;
+ }
+ //
+ // Find user profile according to information.
+ //
+ if (*User == NULL) {
+ *User = mUserProfileDb->UserProfile[0];
+ }
+
+ //
+ // Check user profile handle.
+ //
+ Status = FindUserProfile (User, FALSE, NULL);
+
+ while (!EFI_ERROR (Status)) {
+ //
+ // Find the user information in a user profile.
+ //
+ while (TRUE) {
+ Status = FindUserInfoByType (*User, &InfoEntry, Info->InfoType);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ if (InfoSize == Info->InfoSize) {
+ if (CompareMem ((UINT8 *) (InfoEntry + 1), (UINT8 *) (Info + 1), InfoSize - sizeof (EFI_USER_INFO)) == 0) {
+ //
+ // Found the infomation record.
+ //
+ if (UserInfo != NULL) {
+ *UserInfo = InfoEntry;
+ }
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ //
+ // Get next user profile.
+ //
+ InfoEntry = NULL;
+ Status = FindUserProfile (User, TRUE, NULL);
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Find the credential provider in the specified identity policy.
+
+ @param[in] FindIdentity Point to the user identity policy.
+ @param[in] IdentifyInfo Point to the user information to be searched.
+
+ @retval TRUE The credential provider was found in the identity policy.
+ @retval FALSE The credential provider was not found.
+**/
+BOOLEAN
+FindProvider (
+ IN EFI_USER_INFO_IDENTITY_POLICY *FindIdentity,
+ IN CONST EFI_USER_INFO *IdentifyInfo
+ )
+{
+ UINTN TotalLen;
+ EFI_USER_INFO_IDENTITY_POLICY *Identity;
+
+ //
+ // Found the credential provider.
+ //
+ TotalLen = 0;
+ while (TotalLen < IdentifyInfo->InfoSize - sizeof (EFI_USER_INFO)) {
+ Identity = (EFI_USER_INFO_IDENTITY_POLICY *) ((UINT8 *) (IdentifyInfo + 1) + TotalLen);
+ if ((Identity->Type == FindIdentity->Type) &&
+ (Identity->Length == FindIdentity->Length) &&
+ CompareGuid ((EFI_GUID *) (Identity + 1), (EFI_GUID *) (FindIdentity + 1))
+ ) {
+ return TRUE;
+ }
+
+ TotalLen += Identity->Length;
+ }
+
+ return FALSE;
+}
+
+
+/**
+ Check whether the access policy is valid.
+
+ @param[in] PolicyInfo Point to the access policy.
+ @param[in] InfoLen The policy length.
+
+ @retval TRUE The policy is a valid access policy.
+ @retval FALSE The access policy is not a valid access policy.
+
+**/
+BOOLEAN
+CheckAccessPolicy (
+ IN UINT8 *PolicyInfo,
+ IN UINTN InfoLen
+ )
+{
+ UINTN TotalLen;
+ UINTN ValueLen;
+ UINTN OffSet;
+ EFI_USER_INFO_ACCESS_CONTROL Access;
+ EFI_DEVICE_PATH_PROTOCOL *Path;
+ UINTN PathSize;
+
+ TotalLen = 0;
+ while (TotalLen < InfoLen) {
+ //
+ // Check access policy according to type.
+ //
+ CopyMem (&Access, PolicyInfo + TotalLen, sizeof (Access));
+ ValueLen = Access.Size - sizeof (EFI_USER_INFO_ACCESS_CONTROL);
+ switch (Access.Type) {
+ case EFI_USER_INFO_ACCESS_FORBID_LOAD:
+ case EFI_USER_INFO_ACCESS_PERMIT_LOAD:
+ case EFI_USER_INFO_ACCESS_FORBID_CONNECT:
+ case EFI_USER_INFO_ACCESS_PERMIT_CONNECT:
+ OffSet = 0;
+ while (OffSet < ValueLen) {
+ Path = (EFI_DEVICE_PATH_PROTOCOL *) (PolicyInfo + TotalLen + sizeof (Access) + OffSet);
+ PathSize = GetDevicePathSize (Path);
+ OffSet += PathSize;
+ }
+ if (OffSet != ValueLen) {
+ return FALSE;
+ }
+ break;
+
+ case EFI_USER_INFO_ACCESS_SETUP:
+ if (ValueLen % sizeof (EFI_GUID) != 0) {
+ return FALSE;
+ }
+ break;
+
+ case EFI_USER_INFO_ACCESS_BOOT_ORDER:
+ if (ValueLen % sizeof (EFI_USER_INFO_ACCESS_BOOT_ORDER_HDR) != 0) {
+ return FALSE;
+ }
+ break;
+
+ case EFI_USER_INFO_ACCESS_ENROLL_SELF:
+ case EFI_USER_INFO_ACCESS_ENROLL_OTHERS:
+ case EFI_USER_INFO_ACCESS_MANAGE:
+ if (ValueLen != 0) {
+ return FALSE;
+ }
+ break;
+
+ default:
+ return FALSE;
+ break;
+ }
+
+ TotalLen += Access.Size;
+ }
+
+ if (TotalLen != InfoLen) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/**
+ Check whether the identity policy is valid.
+
+ @param[in] PolicyInfo Point to the identity policy.
+ @param[in] InfoLen The policy length.
+
+ @retval TRUE The policy is a valid identity policy.
+ @retval FALSE The access policy is not a valid identity policy.
+
+**/
+BOOLEAN
+CheckIdentityPolicy (
+ IN UINT8 *PolicyInfo,
+ IN UINTN InfoLen
+ )
+{
+ UINTN TotalLen;
+ UINTN ValueLen;
+ EFI_USER_INFO_IDENTITY_POLICY *Identity;
+
+ TotalLen = 0;
+
+ //
+ // Check each part of policy expression.
+ //
+ while (TotalLen < InfoLen) {
+ //
+ // Check access polisy according to type.
+ //
+ Identity = (EFI_USER_INFO_IDENTITY_POLICY *) (PolicyInfo + TotalLen);
+ ValueLen = Identity->Length - sizeof (EFI_USER_INFO_IDENTITY_POLICY);
+ switch (Identity->Type) {
+ //
+ // Check False option.
+ //
+ case EFI_USER_INFO_IDENTITY_FALSE:
+ if (ValueLen != 0) {
+ return FALSE;
+ }
+ break;
+
+ //
+ // Check True option.
+ //
+ case EFI_USER_INFO_IDENTITY_TRUE:
+ if (ValueLen != 0) {
+ return FALSE;
+ }
+ break;
+
+ //
+ // Check negative operation.
+ //
+ case EFI_USER_INFO_IDENTITY_NOT:
+ if (ValueLen != 0) {
+ return FALSE;
+ }
+ break;
+
+ //
+ // Check and operation.
+ //
+ case EFI_USER_INFO_IDENTITY_AND:
+ if (ValueLen != 0) {
+ return FALSE;
+ }
+ break;
+
+ //
+ // Check or operation.
+ //
+ case EFI_USER_INFO_IDENTITY_OR:
+ if (ValueLen != 0) {
+ return FALSE;
+ }
+ break;
+
+ //
+ // Check credential provider by type.
+ //
+ case EFI_USER_INFO_IDENTITY_CREDENTIAL_TYPE:
+ if (ValueLen != sizeof (EFI_GUID)) {
+ return FALSE;
+ }
+ break;
+
+ //
+ // Check credential provider by ID.
+ //
+ case EFI_USER_INFO_IDENTITY_CREDENTIAL_PROVIDER:
+ if (ValueLen != sizeof (EFI_GUID)) {
+ return FALSE;
+ }
+ break;
+
+ default:
+ return FALSE;
+ break;
+ }
+
+ TotalLen += Identity->Length;
+ }
+
+ if (TotalLen != InfoLen) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/**
+ Check whether the user information is a valid user information record.
+
+ @param[in] Info points to the user information.
+
+ @retval TRUE The info is a valid user information record.
+ @retval FALSE The info is not a valid user information record.
+
+**/
+BOOLEAN
+CheckUserInfo (
+ IN CONST EFI_USER_INFO *Info
+ )
+{
+ UINTN InfoLen;
+
+ if (Info == NULL) {
+ return FALSE;
+ }
+ //
+ // Check user information according to information type.
+ //
+ InfoLen = Info->InfoSize - sizeof (EFI_USER_INFO);
+ switch (Info->InfoType) {
+ case EFI_USER_INFO_EMPTY_RECORD:
+ if (InfoLen != 0) {
+ return FALSE;
+ }
+ break;
+
+ case EFI_USER_INFO_NAME_RECORD:
+ case EFI_USER_INFO_CREDENTIAL_TYPE_NAME_RECORD:
+ case EFI_USER_INFO_CREDENTIAL_PROVIDER_NAME_RECORD:
+ break;
+
+ case EFI_USER_INFO_CREATE_DATE_RECORD:
+ case EFI_USER_INFO_USAGE_DATE_RECORD:
+ if (InfoLen != sizeof (EFI_TIME)) {
+ return FALSE;
+ }
+ break;
+
+ case EFI_USER_INFO_USAGE_COUNT_RECORD:
+ if (InfoLen != sizeof (UINT64)) {
+ return FALSE;
+ }
+ break;
+
+ case EFI_USER_INFO_IDENTIFIER_RECORD:
+ if (InfoLen != 16) {
+ return FALSE;
+ }
+ break;
+
+ case EFI_USER_INFO_CREDENTIAL_TYPE_RECORD:
+ case EFI_USER_INFO_CREDENTIAL_PROVIDER_RECORD:
+ case EFI_USER_INFO_GUID_RECORD:
+ if (InfoLen != sizeof (EFI_GUID)) {
+ return FALSE;
+ }
+ break;
+
+ case EFI_USER_INFO_PKCS11_RECORD:
+ case EFI_USER_INFO_CBEFF_RECORD:
+ break;
+
+ case EFI_USER_INFO_FAR_RECORD:
+ case EFI_USER_INFO_RETRY_RECORD:
+ if (InfoLen != 1) {
+ return FALSE;
+ }
+ break;
+
+ case EFI_USER_INFO_ACCESS_POLICY_RECORD:
+ if(!CheckAccessPolicy ((UINT8 *) (Info + 1), InfoLen)) {
+ return FALSE;
+ }
+ break;
+
+ case EFI_USER_INFO_IDENTITY_POLICY_RECORD:
+ if (!CheckIdentityPolicy ((UINT8 *) (Info + 1), InfoLen)) {
+ return FALSE;
+ }
+ break;
+
+ default:
+ return FALSE;
+ break;
+ }
+
+ return TRUE;
+}
+
+
+/**
+ Check the user profile data format to be added.
+
+ @param[in] UserProfileInfo Points to the user profile data.
+ @param[in] UserProfileSize The length of user profile data.
+
+ @retval TRUE It is a valid user profile.
+ @retval FALSE It is not a valid user profile.
+
+**/
+BOOLEAN
+CheckProfileInfo (
+ IN UINT8 *UserProfileInfo,
+ IN UINTN UserProfileSize
+ )
+{
+ UINTN ChkLen;
+ EFI_USER_INFO *Info;
+
+ if (UserProfileInfo == NULL) {
+ return FALSE;
+ }
+
+ //
+ // Check user profile information length.
+ //
+ ChkLen = 0;
+ while (ChkLen < UserProfileSize) {
+ Info = (EFI_USER_INFO *) (UserProfileInfo + ChkLen);
+ //
+ // Check user information format.
+ //
+ if (!CheckUserInfo (Info)) {
+ return FALSE;
+ }
+
+ ChkLen += ALIGN_VARIABLE (Info->InfoSize);
+ }
+
+ if (ChkLen != UserProfileSize) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/**
+ Find the specified RightType in current user profile.
+
+ @param[in] RightType Could be EFI_USER_INFO_ACCESS_MANAGE,
+ EFI_USER_INFO_ACCESS_ENROLL_OTHERS or
+ EFI_USER_INFO_ACCESS_ENROLL_SELF.
+
+ @retval TRUE Find the specified RightType in current user profile.
+ @retval FALSE Can't find the right in the profile.
+
+**/
+BOOLEAN
+CheckCurrentUserAccessRight (
+ IN UINT32 RightType
+ )
+{
+ EFI_STATUS Status;
+ EFI_USER_INFO *Info;
+ UINTN TotalLen;
+ UINTN CheckLen;
+ EFI_USER_INFO_ACCESS_CONTROL Access;
+
+ //
+ // Get user access right information.
+ //
+ Info = NULL;
+ Status = FindUserInfoByType (
+ (USER_PROFILE_ENTRY *) mCurrentUser,
+ &Info,
+ EFI_USER_INFO_ACCESS_POLICY_RECORD
+ );
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ ASSERT (Info != NULL);
+ TotalLen = Info->InfoSize - sizeof (EFI_USER_INFO);
+ CheckLen = 0;
+ while (CheckLen < TotalLen) {
+ //
+ // Check right according to access type.
+ //
+ CopyMem (&Access, (UINT8 *) (Info + 1) + CheckLen, sizeof (Access));
+ if (Access.Type == RightType) {
+ return TRUE;;
+ }
+
+ CheckLen += Access.Size;
+ }
+
+ return FALSE;
+}
+
+
+/**
+ Create a unique user identifier.
+
+ @param[out] Identifier This points to the identifier.
+
+**/
+VOID
+GenerateIdentifier (
+ OUT UINT8 *Identifier
+ )
+{
+ EFI_TIME Time;
+ UINT64 MonotonicCount;
+ UINT32 *MonotonicPointer;
+ UINTN Index;
+
+ //
+ // Create a unique user identifier.
+ //
+ gRT->GetTime (&Time, NULL);
+ CopyMem (Identifier, &Time, sizeof (EFI_TIME));
+ //
+ // Remove zeros.
+ //
+ for (Index = 0; Index < sizeof (EFI_TIME); Index++) {
+ if (Identifier[Index] == 0) {
+ Identifier[Index] = 0x5a;
+ }
+ }
+
+ MonotonicPointer = (UINT32 *) Identifier;
+ gBS->GetNextMonotonicCount (&MonotonicCount);
+ MonotonicPointer[0] += (UINT32) MonotonicCount;
+ MonotonicPointer[1] += (UINT32) MonotonicCount;
+ MonotonicPointer[2] += (UINT32) MonotonicCount;
+ MonotonicPointer[3] += (UINT32) MonotonicCount;
+}
+
+
+/**
+ Generate unique user ID.
+
+ @param[out] UserId Points to the user identifer.
+
+**/
+VOID
+GenerateUserId (
+ OUT UINT8 *UserId
+ )
+{
+ EFI_STATUS Status;
+ USER_PROFILE_ENTRY *UserProfile;
+ EFI_USER_INFO *UserInfo;
+ UINTN Index;
+
+ //
+ // Generate unique user ID
+ //
+ while (TRUE) {
+ GenerateIdentifier (UserId);
+ //
+ // Check whether it's unique in user profile database.
+ //
+ if (mUserProfileDb == NULL) {
+ return ;
+ }
+
+ for (Index = 0; Index < mUserProfileDb->UserProfileNum; Index++) {
+ UserProfile = (USER_PROFILE_ENTRY *) (mUserProfileDb->UserProfile[Index]);
+ UserInfo = NULL;
+ Status = FindUserInfoByType (UserProfile, &UserInfo, EFI_USER_INFO_IDENTIFIER_RECORD);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ if (CompareMem ((UINT8 *) (UserInfo + 1), UserId, sizeof (EFI_USER_INFO_IDENTIFIER)) == 0) {
+ break;
+ }
+ }
+
+ if (Index == mUserProfileDb->UserProfileNum) {
+ return ;
+ }
+ }
+}
+
+
+/**
+ Expand user profile database.
+
+ @retval TRUE Success to expand user profile database.
+ @retval FALSE Fail to expand user profile database.
+
+**/
+BOOLEAN
+ExpandUsermUserProfileDb (
+ VOID
+ )
+{
+ UINTN MaxNum;
+ USER_PROFILE_DB *NewDataBase;
+
+ //
+ // Create new user profile database.
+ //
+ if (mUserProfileDb == NULL) {
+ MaxNum = USER_NUMBER_INC;
+ } else {
+ MaxNum = mUserProfileDb->MaxProfileNum + USER_NUMBER_INC;
+ }
+
+ NewDataBase = AllocateZeroPool (
+ sizeof (USER_PROFILE_DB) - sizeof (EFI_USER_PROFILE_HANDLE) +
+ MaxNum * sizeof (EFI_USER_PROFILE_HANDLE)
+ );
+ if (NewDataBase == NULL) {
+ return FALSE;
+ }
+
+ NewDataBase->MaxProfileNum = MaxNum;
+
+ //
+ // Copy old user profile database value
+ //
+ if (mUserProfileDb == NULL) {
+ NewDataBase->UserProfileNum = 0;
+ } else {
+ NewDataBase->UserProfileNum = mUserProfileDb->UserProfileNum;
+ CopyMem (
+ NewDataBase->UserProfile,
+ mUserProfileDb->UserProfile,
+ NewDataBase->UserProfileNum * sizeof (EFI_USER_PROFILE_HANDLE)
+ );
+ FreePool (mUserProfileDb);
+ }
+
+ mUserProfileDb = NewDataBase;
+ return TRUE;
+}
+
+
+/**
+ Expand user profile
+
+ @param[in] User Points to user profile.
+ @param[in] ExpandSize The size of user profile.
+
+ @retval TRUE Success to expand user profile size.
+ @retval FALSE Fail to expand user profile size.
+
+**/
+BOOLEAN
+ExpandUserProfile (
+ IN USER_PROFILE_ENTRY *User,
+ IN UINTN ExpandSize
+ )
+{
+ UINT8 *Info;
+ UINTN InfoSizeInc;
+
+ //
+ // Allocate new memory.
+ //
+ InfoSizeInc = 128;
+ User->MaxProfileSize += ((ExpandSize + InfoSizeInc - 1) / InfoSizeInc) * InfoSizeInc;
+ Info = AllocateZeroPool (User->MaxProfileSize);
+ if (Info == NULL) {
+ return FALSE;
+ }
+
+ //
+ // Copy exist information.
+ //
+ if (User->UserProfileSize > 0) {
+ CopyMem (Info, User->ProfileInfo, User->UserProfileSize);
+ FreePool (User->ProfileInfo);
+ }
+
+ User->ProfileInfo = Info;
+ return TRUE;
+}
+
+
+/**
+ Add or delete the user's credential record in the provider.
+
+ @param[in] ProviderGuid Point to credential provider guid or class guid.
+ @param[in] ByType If TRUE, Provider is credential class guid.
+ If FALSE, Provider is provider guid.
+ @param[in] User Points to user profile.
+
+ @retval EFI_SUCCESS Add or delete record successfully.
+ @retval Others Fail to add or delete record.
+
+**/
+EFI_STATUS
+ModifyProviderCredential (
+ IN EFI_GUID *Provider,
+ IN BOOLEAN ByType,
+ IN USER_PROFILE_ENTRY *User
+ )
+{
+ UINTN Index;
+ EFI_USER_CREDENTIAL_PROTOCOL *UserCredential;
+
+ if (Provider == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+
+ //
+ // Find the specified credential provider.
+ //
+ for (Index = 0; Index < mProviderDb->Count; Index++) {
+ //
+ // Check credential provider ID.
+ //
+ UserCredential = mProviderDb->Provider[Index];
+ if (CompareGuid (&UserCredential->Identifier, Provider)) {
+ return UserCredential->Enroll (UserCredential, User);
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ Modify user's credential record in the providers.
+
+ Found the providers information in PolicyInfo, and then add or delete the user's credential
+ record in the providers.
+
+ @param User Points to user profile.
+ @param PolicyInfo Point to identification policy to be modified.
+ @param InfoLen The length of PolicyInfo.
+
+ @retval EFI_SUCCESS Modify PolicyInfo successfully.
+ @retval Others Fail to modify PolicyInfo.
+
+**/
+EFI_STATUS
+ModifyCredentialInfo (
+ IN USER_PROFILE_ENTRY *User,
+ IN UINT8 *PolicyInfo,
+ IN UINTN InfoLen
+ )
+{
+ EFI_STATUS Status;
+ UINTN TotalLen;
+ EFI_USER_INFO_IDENTITY_POLICY *Identity;
+
+ //
+ // Modify user's credential.
+ //
+ TotalLen = 0;
+ while (TotalLen < InfoLen) {
+ //
+ // Check identification policy according to type.
+ //
+ Identity = (EFI_USER_INFO_IDENTITY_POLICY *) (PolicyInfo + TotalLen);
+ switch (Identity->Type) {
+ case EFI_USER_INFO_IDENTITY_CREDENTIAL_TYPE:
+ Status = ModifyProviderCredential ((EFI_GUID *) (Identity + 1), TRUE, User);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ break;
+
+ case EFI_USER_INFO_IDENTITY_CREDENTIAL_PROVIDER:
+ Status = ModifyProviderCredential ((EFI_GUID *) (Identity + 1), FALSE, User);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ TotalLen += Identity->Length;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Save the user profile to non-volatile memory, or delete it from non-volatile memory.
+
+ @param[in] User Point to the user profile
+ @param[in] Delete If TRUE, delete the found user profile.
+ If FALSE, save the user profile.
+ @retval EFI_SUCCESS Save or delete user profile successfully.
+ @retval Others Fail to change the profile.
+
+**/
+EFI_STATUS
+SaveNvUserProfile (
+ IN USER_PROFILE_ENTRY *User,
+ IN BOOLEAN Delete
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Check user profile entry.
+ //
+ Status = FindUserProfile (&User, FALSE, NULL);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Save the user profile to non-volatile memory.
+ //
+ Status = gRT->SetVariable (
+ User->UserVarName,
+ &mUserManagerGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ Delete ? 0 : User->UserProfileSize,
+ User->ProfileInfo
+ );
+ return Status;
+}
+
+
+/**
+ Replace the old identity info with NewInfo in NV Flash.
+
+ This function only replace the identity record in the user profile. Don't update
+ the the information on the credential provider.
+
+ @param[in] User Point to the user profile.
+ @param[in] NewInfo Point to the new identity policy info.
+ @param[out] UserInfo Point to the new added identity info.
+
+ @retval EFI_SUCCESS Replace user identity successfully.
+ @retval Others Fail to Replace user identity.
+
+**/
+EFI_STATUS
+SaveUserIpInfo (
+ IN USER_PROFILE_ENTRY * User,
+ IN CONST EFI_USER_INFO * NewInfo,
+ OUT EFI_USER_INFO **UserInfo OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_USER_INFO *OldIpInfo;
+ UINTN Offset;
+ UINTN NextOffset;
+
+ if ((NewInfo == NULL) || (User == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Get user old identify policy information.
+ //
+ OldIpInfo = NULL;
+ Status = FindUserInfoByType (User, &OldIpInfo, EFI_USER_INFO_IDENTITY_POLICY_RECORD);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Get the old identity policy offset.
+ //
+ Status = FindUserInfo (User, &OldIpInfo, FALSE, &Offset);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Delete the old identity policy information.
+ //
+ NextOffset = ALIGN_VARIABLE (OldIpInfo->InfoSize) + Offset;
+ User->UserProfileSize -= ALIGN_VARIABLE (OldIpInfo->InfoSize);
+ if (Offset < User->UserProfileSize) {
+ CopyMem (User->ProfileInfo + Offset, User->ProfileInfo + NextOffset, User->UserProfileSize - Offset);
+ }
+
+ //
+ // Add new user information.
+ //
+ if (User->MaxProfileSize - User->UserProfileSize < ALIGN_VARIABLE (NewInfo->InfoSize)) {
+ if (!ExpandUserProfile (User, ALIGN_VARIABLE (NewInfo->InfoSize))) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ CopyMem (User->ProfileInfo + User->UserProfileSize, (VOID *) NewInfo, NewInfo->InfoSize);
+ if (UserInfo != NULL) {
+ *UserInfo = (EFI_USER_INFO *) (User->ProfileInfo + User->UserProfileSize);
+ }
+
+ User->UserProfileSize += ALIGN_VARIABLE (NewInfo->InfoSize);
+
+ //
+ // Save user profile information.
+ //
+ Status = SaveNvUserProfile (User, FALSE);
+ return Status;
+}
+
+
+/**
+ Remove the provider in FindIdentity from the user identification information record.
+
+ @param[in, out] NewInfo On entry, points to the user information to remove provider.
+ On return, points to the user information the provider is removed.
+ @param[in] FindIdentity Point to the user identity policy.
+
+ @retval TRUE The provider is removed successfully.
+ @retval FALSE Fail to remove the provider.
+
+**/
+BOOLEAN
+RemoveProvider (
+ IN OUT EFI_USER_INFO **NewInfo,
+ IN EFI_USER_INFO_IDENTITY_POLICY *FindIdentity
+ )
+{
+ UINTN TotalLen;
+ EFI_USER_INFO_IDENTITY_POLICY *Identity;
+ EFI_USER_INFO *IdentifyInfo;
+ UINT8 *Buffer;
+
+ IdentifyInfo = *NewInfo;
+ TotalLen = IdentifyInfo->InfoSize - sizeof (EFI_USER_INFO);
+ if (TotalLen == FindIdentity->Length) {
+ //
+ // Only one credential provider in the identification policy.
+ // Set the new policy to be TRUE after removed the provider.
+ //
+ Identity = (EFI_USER_INFO_IDENTITY_POLICY *) (IdentifyInfo + 1);
+ Identity->Type = EFI_USER_INFO_IDENTITY_TRUE;
+ Identity->Length = sizeof (EFI_USER_INFO_IDENTITY_POLICY);
+ IdentifyInfo->InfoSize = sizeof (EFI_USER_INFO) + Identity->Length;
+ return TRUE;
+ }
+
+ //
+ // Found the credential provider.
+ //
+ TotalLen = 0;
+ while (TotalLen < IdentifyInfo->InfoSize - sizeof (EFI_USER_INFO)) {
+ Identity = (EFI_USER_INFO_IDENTITY_POLICY *) ((UINT8 *) (IdentifyInfo + 1) + TotalLen);
+ if ((Identity->Type == FindIdentity->Type) &&
+ (Identity->Length == FindIdentity->Length) &&
+ CompareGuid ((EFI_GUID *) (Identity + 1), (EFI_GUID *) (FindIdentity + 1))
+ ) {
+ //
+ // Found the credential provider to delete
+ //
+ if (Identity == (EFI_USER_INFO_IDENTITY_POLICY *)(IdentifyInfo + 1)) {
+ //
+ // It is the first item in the identification policy, delete it and the connector after it.
+ //
+ Buffer = (UINT8 *) Identity + Identity->Length + sizeof(EFI_USER_INFO_IDENTITY_POLICY);
+ IdentifyInfo->InfoSize -= Identity->Length + sizeof(EFI_USER_INFO_IDENTITY_POLICY);
+ TotalLen = IdentifyInfo->InfoSize - sizeof (EFI_USER_INFO);
+ CopyMem (Identity, Buffer, TotalLen);
+ } else {
+ //
+ // It is not the first item in the identification policy, delete it and the connector before it.
+ //
+ Buffer = (UINT8 *) Identity + Identity->Length;
+ TotalLen = IdentifyInfo->InfoSize - sizeof (EFI_USER_INFO);
+ TotalLen -= (Buffer - (UINT8 *)(IdentifyInfo + 1));
+ IdentifyInfo->InfoSize -= Identity->Length + sizeof(EFI_USER_INFO_IDENTITY_POLICY);
+ CopyMem ((UINT8 *) (Identity - 1), Buffer, TotalLen);
+ }
+ return TRUE;
+ }
+
+ TotalLen += Identity->Length;
+ }
+ return FALSE;
+}
+
+
+/**
+ This function replaces the old identity policy with a new identity policy.
+
+ This function changes user identity policy information.
+ If enroll new credential failed, recover the old identity policy.
+
+ For new policy:
+ a. For each credential, if it is newly added, try to enroll it.
+ If enroll failed, try to delete the newly added ones.
+
+ b. For each credential, if it exists in the old policy, delete old one,
+ and enroll new one. If failed to enroll the new one, removed it from new
+ identification policy.
+
+ For old policy:
+ a. For each credential, if it does not exist in new one, delete it.
+
+ @param[in] User Point to the user profile.
+ @param[in] Info Points to the user identity information.
+ @param[in] InfoSize The size of Info (Not used in this function).
+ @param[out] IpInfo The new identification info after modify.
+
+ @retval EFI_SUCCESS Modify user identity policy successfully.
+ @retval Others Fail to modify user identity policy.
+
+**/
+EFI_STATUS
+ModifyUserIpInfo (
+ IN USER_PROFILE_ENTRY *User,
+ IN CONST EFI_USER_INFO *Info,
+ IN UINTN InfoSize,
+ OUT EFI_USER_INFO **IpInfo
+ )
+{
+ EFI_STATUS Status;
+ EFI_USER_INFO *OldIpInfo;
+ UINTN TotalLen;
+ EFI_USER_INFO_IDENTITY_POLICY *Identity;
+ UINT32 CredentialCount;
+ EFI_USER_INFO *NewIpInfo;
+
+ //
+ // Get user old identify policy information.
+ //
+ OldIpInfo = NULL;
+ Status = FindUserInfoByType (User, &OldIpInfo, EFI_USER_INFO_IDENTITY_POLICY_RECORD);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ ASSERT (OldIpInfo != NULL);
+
+ //
+ // Enroll new added credential provider.
+ //
+ CredentialCount = 0;
+ TotalLen = 0;
+ while (TotalLen < Info->InfoSize - sizeof (EFI_USER_INFO)) {
+ Identity = (EFI_USER_INFO_IDENTITY_POLICY *) ((UINT8 *) (Info + 1) + TotalLen);
+ if (Identity->Type == EFI_USER_INFO_IDENTITY_CREDENTIAL_PROVIDER) {
+ if (!FindProvider (Identity, OldIpInfo)) {
+ //
+ // The credential is NOT found in the old identity policy; add it.
+ //
+ Status = ModifyCredentialInfo (User, (UINT8 *) Identity, Identity->Length);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ CredentialCount++;
+ }
+ }
+
+ TotalLen += Identity->Length;
+ }
+
+ if (EFI_ERROR (Status)) {
+ //
+ // Enroll new credential failed. Delete the newly enrolled credential, and return.
+ //
+ TotalLen = 0;
+ while (TotalLen < Info->InfoSize - sizeof (EFI_USER_INFO)) {
+ Identity = (EFI_USER_INFO_IDENTITY_POLICY *) ((UINT8 *) (Info + 1) + TotalLen);
+ if (Identity->Type == EFI_USER_INFO_IDENTITY_CREDENTIAL_PROVIDER) {
+ if (!FindProvider (Identity, OldIpInfo)) {
+ //
+ // The credential is NOT found in the old identity policy. Delete it.
+ //
+ if (CredentialCount == 0) {
+ break;
+ }
+
+ ModifyCredentialInfo (User, (UINT8 *) Identity, Identity->Length);
+ CredentialCount--;
+ }
+ }
+ TotalLen += Identity->Length;
+ }
+
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Backup new identification policy
+ //
+ NewIpInfo = AllocateCopyPool (Info->InfoSize, Info);
+ ASSERT (NewIpInfo != NULL);
+
+ //
+ // Enroll the credential that existed in the old identity policy.
+ //
+ TotalLen = 0;
+ while (TotalLen < Info->InfoSize - sizeof (EFI_USER_INFO)) {
+ Identity = (EFI_USER_INFO_IDENTITY_POLICY *) ((UINT8 *) (Info + 1) + TotalLen);
+ if (Identity->Type == EFI_USER_INFO_IDENTITY_CREDENTIAL_PROVIDER) {
+ if (FindProvider (Identity, OldIpInfo)) {
+ //
+ // The credential is found in the old identity policy, so delete the old credential first.
+ //
+ Status = ModifyCredentialInfo (User, (UINT8 *) Identity, Identity->Length);
+ if (EFI_ERROR (Status)) {
+ //
+ // Failed to delete old credential.
+ //
+ FreePool (NewIpInfo);
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Add the new credential.
+ //
+ Status = ModifyCredentialInfo (User, (UINT8 *) Identity, Identity->Length);
+ if (EFI_ERROR (Status)) {
+ //
+ // Failed to enroll the user by new identification policy.
+ // So removed the credential provider from the identification policy
+ //
+ RemoveProvider (&NewIpInfo, Identity);
+ }
+ }
+ }
+ TotalLen += Identity->Length;
+ }
+
+ //
+ // Delete old credential that didn't exist in the new identity policy.
+ //
+ TotalLen = 0;
+ while (TotalLen < OldIpInfo->InfoSize - sizeof (EFI_USER_INFO)) {
+ Identity = (EFI_USER_INFO_IDENTITY_POLICY *) ((UINT8 *) (OldIpInfo + 1) + TotalLen);
+ if (Identity->Type == EFI_USER_INFO_IDENTITY_CREDENTIAL_PROVIDER) {
+ if (!FindProvider (Identity, Info)) {
+ //
+ // The credential is NOT found in the new identity policy. Delete the old credential.
+ //
+ ModifyCredentialInfo (User, (UINT8 *) Identity, Identity->Length);
+ }
+ }
+ TotalLen += Identity->Length;
+ }
+
+ *IpInfo = NewIpInfo;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Add one new user info into the user's profile.
+
+ @param[in] User point to the user profile
+ @param[in] Info Points to the user information payload.
+ @param[in] InfoSize The size of the user information payload, in bytes.
+ @param[out] UserInfo Point to the new info in user profile
+ @param[in] Save If TRUE, save the profile to NV flash.
+ If FALSE, don't need to save the profile to NV flash.
+
+ @retval EFI_SUCCESS Add user info to user profile successfully.
+ @retval Others Fail to add user info to user profile.
+
+**/
+EFI_STATUS
+AddUserInfo (
+ IN USER_PROFILE_ENTRY *User,
+ IN UINT8 *Info,
+ IN UINTN InfoSize,
+ OUT EFI_USER_INFO **UserInfo, OPTIONAL
+ IN BOOLEAN Save
+ )
+{
+ EFI_STATUS Status;
+
+ if ((Info == NULL) || (User == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check user profile handle.
+ //
+ Status = FindUserProfile (&User, FALSE, NULL);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Check user information memory size.
+ //
+ if (User->MaxProfileSize - User->UserProfileSize < ALIGN_VARIABLE (InfoSize)) {
+ if (!ExpandUserProfile (User, ALIGN_VARIABLE (InfoSize))) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ //
+ // Add credential.
+ //
+ if (((EFI_USER_INFO *) Info)->InfoType == EFI_USER_INFO_IDENTITY_POLICY_RECORD) {
+ Status = ModifyCredentialInfo (
+ User,
+ (UINT8 *) ((EFI_USER_INFO *) Info + 1),
+ InfoSize - sizeof (EFI_USER_INFO)
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // Add new user information.
+ //
+ CopyMem (User->ProfileInfo + User->UserProfileSize, Info, InfoSize);
+ if (UserInfo != NULL) {
+ *UserInfo = (EFI_USER_INFO *) (User->ProfileInfo + User->UserProfileSize);
+ }
+ User->UserProfileSize += ALIGN_VARIABLE (InfoSize);
+
+ //
+ // Save user profile information.
+ //
+ if (Save) {
+ Status = SaveNvUserProfile (User, FALSE);
+ }
+
+ return Status;
+}
+
+
+/**
+ Get the user info from the specified user info handle.
+
+ @param[in] User Point to the user profile.
+ @param[in] UserInfo Point to the user information record to get.
+ @param[out] Info On entry, points to a buffer of at least *InfoSize bytes.
+ On exit, holds the user information.
+ @param[in, out] InfoSize On entry, points to the size of Info.
+ On return, points to the size of the user information.
+ @param[in] ChkRight If TRUE, check the user info attribute.
+ If FALSE, don't check the user info attribute.
+
+
+ @retval EFI_ACCESS_DENIED The information cannot be accessed by the current user.
+ @retval EFI_INVALID_PARAMETER InfoSize is NULL or UserInfo is NULL.
+ @retval EFI_BUFFER_TOO_SMALL The number of bytes specified by *InfoSize is too small to hold the
+ returned data. The actual size required is returned in *InfoSize.
+ @retval EFI_SUCCESS Information returned successfully.
+
+**/
+EFI_STATUS
+GetUserInfo (
+ IN USER_PROFILE_ENTRY *User,
+ IN EFI_USER_INFO *UserInfo,
+ OUT EFI_USER_INFO *Info,
+ IN OUT UINTN *InfoSize,
+ IN BOOLEAN ChkRight
+ )
+{
+ EFI_STATUS Status;
+
+ if ((InfoSize == NULL) || (UserInfo == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((*InfoSize != 0) && (Info == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Find the user information to get.
+ //
+ Status = FindUserInfo (User, &UserInfo, FALSE, NULL);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Check information attributes.
+ //
+ if (ChkRight) {
+ switch (UserInfo->InfoAttribs & EFI_USER_INFO_ACCESS) {
+ case EFI_USER_INFO_PRIVATE:
+ case EFI_USER_INFO_PROTECTED:
+ if (User != mCurrentUser) {
+ return EFI_ACCESS_DENIED;
+ }
+ break;
+
+ case EFI_USER_INFO_PUBLIC:
+ break;
+
+ default:
+ return EFI_INVALID_PARAMETER;
+ break;
+ }
+ }
+
+ //
+ // Get user information.
+ //
+ if (UserInfo->InfoSize > *InfoSize) {
+ *InfoSize = UserInfo->InfoSize;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ *InfoSize = UserInfo->InfoSize;
+ if (Info != NULL) {
+ CopyMem (Info, UserInfo, *InfoSize);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Delete the specified user information from user profile.
+
+ @param[in] User Point to the user profile.
+ @param[in] Info Point to the user information record to delete.
+ @param[in] Save If TRUE, save the profile to NV flash.
+ If FALSE, don't need to save the profile to NV flash.
+
+ @retval EFI_SUCCESS Delete user info from user profile successfully.
+ @retval Others Fail to delete user info from user profile.
+
+**/
+EFI_STATUS
+DelUserInfo (
+ IN USER_PROFILE_ENTRY *User,
+ IN EFI_USER_INFO *Info,
+ IN BOOLEAN Save
+ )
+{
+ EFI_STATUS Status;
+ UINTN Offset;
+ UINTN NextOffset;
+
+ //
+ // Check user information handle.
+ //
+ Status = FindUserInfo (User, &Info, FALSE, &Offset);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Info->InfoType == EFI_USER_INFO_IDENTIFIER_RECORD) {
+ return EFI_ACCESS_DENIED;
+ } else if (Info->InfoType == EFI_USER_INFO_IDENTITY_POLICY_RECORD) {
+ Status = ModifyCredentialInfo (User, (UINT8 *) (Info + 1), Info->InfoSize - sizeof (EFI_USER_INFO));
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // Delete the specified user information.
+ //
+ NextOffset = Offset + ALIGN_VARIABLE (Info->InfoSize);
+ User->UserProfileSize -= ALIGN_VARIABLE (Info->InfoSize);
+ if (Offset < User->UserProfileSize) {
+ CopyMem (User->ProfileInfo + Offset, User->ProfileInfo + NextOffset, User->UserProfileSize - Offset);
+ }
+
+ if (Save) {
+ Status = SaveNvUserProfile (User, FALSE);
+ }
+
+ return Status;
+}
+
+
+/**
+ Add or update user information.
+
+ @param[in] User Point to the user profile.
+ @param[in, out] UserInfo On entry, points to the user information to modify,
+ or NULL to add a new UserInfo.
+ On return, points to the modified user information.
+ @param[in] Info Points to the new user information.
+ @param[in] InfoSize The size of Info,in bytes.
+
+ @retval EFI_INVALID_PARAMETER UserInfo is NULL or Info is NULL.
+ @retval EFI_ACCESS_DENIED The record is exclusive.
+ @retval EFI_SUCCESS User information was successfully changed/added.
+
+**/
+EFI_STATUS
+ModifyUserInfo (
+ IN USER_PROFILE_ENTRY *User,
+ IN OUT EFI_USER_INFO **UserInfo,
+ IN CONST EFI_USER_INFO *Info,
+ IN UINTN InfoSize
+ )
+{
+ EFI_STATUS Status;
+ UINTN PayloadLen;
+ EFI_USER_INFO *OldInfo;
+ EFI_USER_INFO *IpInfo;
+
+ if ((UserInfo == NULL) || (Info == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (InfoSize < sizeof (EFI_USER_INFO) || InfoSize != Info->InfoSize) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check user information.
+ //
+ if (Info->InfoType == EFI_USER_INFO_IDENTIFIER_RECORD) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ if (!CheckUserInfo (Info)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+
+ if (*UserInfo == NULL) {
+ //
+ // Add new user information.
+ //
+ OldInfo = NULL;
+ do {
+ Status = FindUserInfoByType (User, &OldInfo, Info->InfoType);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ ASSERT (OldInfo != NULL);
+
+ if (((OldInfo->InfoAttribs & EFI_USER_INFO_EXCLUSIVE) != 0) ||
+ ((Info->InfoAttribs & EFI_USER_INFO_EXCLUSIVE) != 0)) {
+ //
+ // Same type can not co-exist for exclusive information.
+ //
+ return EFI_ACCESS_DENIED;
+ }
+
+ //
+ // Check whether it exists in DB.
+ //
+ if (Info->InfoSize != OldInfo->InfoSize) {
+ continue;
+ }
+
+ if (!CompareGuid (&OldInfo->Credential, &Info->Credential)) {
+ continue;
+ }
+
+ PayloadLen = Info->InfoSize - sizeof (EFI_USER_INFO);
+ if (PayloadLen == 0) {
+ continue;
+ }
+
+ if (CompareMem ((UINT8 *)(OldInfo + 1), (UINT8 *)(Info + 1), PayloadLen) != 0) {
+ continue;
+ }
+
+ //
+ // Yes. The new info is as same as the one in profile.
+ //
+ return EFI_SUCCESS;
+ } while (!EFI_ERROR (Status));
+
+ Status = AddUserInfo (User, (UINT8 *) Info, InfoSize, UserInfo, TRUE);
+ return Status;
+ }
+
+ //
+ // Modify existing user information.
+ //
+ OldInfo = *UserInfo;
+ if (OldInfo->InfoType != Info->InfoType) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (((Info->InfoAttribs & EFI_USER_INFO_EXCLUSIVE) != 0) &&
+ (OldInfo->InfoAttribs & EFI_USER_INFO_EXCLUSIVE) == 0) {
+ //
+ // Try to add exclusive attrib in new info.
+ // Check whether there is another information with the same type in profile.
+ //
+ OldInfo = NULL;
+ do {
+ Status = FindUserInfoByType (User, &OldInfo, Info->InfoType);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ if (OldInfo != *UserInfo) {
+ //
+ // There is another information with the same type in profile.
+ // Therefore, can't modify existing user information to add exclusive attribute.
+ //
+ return EFI_ACCESS_DENIED;
+ }
+ } while (TRUE);
+ }
+
+ if (Info->InfoType == EFI_USER_INFO_IDENTITY_POLICY_RECORD) {
+ //
+ // For user identification policy, need to update the info in credential provider.
+ //
+ IpInfo = NULL;
+ Status = ModifyUserIpInfo (User, Info, InfoSize, &IpInfo);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ASSERT (IpInfo != NULL);
+ Status = SaveUserIpInfo (User, IpInfo, UserInfo);
+ if (IpInfo->InfoSize != Info->InfoSize) {
+ Status = EFI_DEVICE_ERROR;
+ }
+ FreePool (IpInfo);
+ return Status;
+ }
+
+ Status = DelUserInfo (User, *UserInfo, FALSE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return AddUserInfo (User, (UINT8 *) Info, InfoSize, UserInfo, TRUE);
+}
+
+
+/**
+ Delete the user profile from non-volatile memory and database.
+
+ @param[in] User Points to the user profile.
+
+ @retval EFI_SUCCESS Delete user from the user profile successfully.
+ @retval Others Fail to delete user from user profile
+
+**/
+EFI_STATUS
+DelUserProfile (
+ IN USER_PROFILE_ENTRY *User
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ EFI_USER_INFO *UserInfo;
+
+ //
+ // Check whether it is in the user profile database.
+ //
+ Status = FindUserProfile (&User, FALSE, &Index);
+ if (EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check whether it is the current user.
+ //
+ if (User == mCurrentUser) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ //
+ // Delete user credential information.
+ //
+ UserInfo = NULL;
+ Status = FindUserInfoByType (User, &UserInfo, EFI_USER_INFO_IDENTITY_POLICY_RECORD);
+ if (Status == EFI_SUCCESS) {
+ Status = DelUserInfo (User, UserInfo, FALSE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // Delete user profile from the non-volatile memory.
+ //
+ Status = SaveNvUserProfile (mUserProfileDb->UserProfile[mUserProfileDb->UserProfileNum - 1], TRUE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ mUserProfileDb->UserProfileNum--;
+
+ //
+ // Modify user profile database.
+ //
+ if (Index != mUserProfileDb->UserProfileNum) {
+ mUserProfileDb->UserProfile[Index] = mUserProfileDb->UserProfile[mUserProfileDb->UserProfileNum];
+ CopyMem (
+ ((USER_PROFILE_ENTRY *) mUserProfileDb->UserProfile[Index])->UserVarName,
+ User->UserVarName,
+ sizeof (User->UserVarName)
+ );
+ Status = SaveNvUserProfile (mUserProfileDb->UserProfile[Index], FALSE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ //
+ // Delete user profile information.
+ //
+ if (User->ProfileInfo != NULL) {
+ FreePool (User->ProfileInfo);
+ }
+
+ FreePool (User);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Add user profile to user profile database.
+
+ @param[out] UserProfile Point to the newly added user profile.
+ @param[in] ProfileSize The size of the user profile.
+ @param[in] ProfileInfo Point to the user profie data.
+ @param[in] Save If TRUE, save the new added profile to NV flash.
+ If FALSE, don't save the profile to NV flash.
+
+ @retval EFI_SUCCESS Add user profile to user profile database successfully.
+ @retval Others Fail to add user profile to user profile database.
+
+**/
+EFI_STATUS
+AddUserProfile (
+ OUT USER_PROFILE_ENTRY **UserProfile, OPTIONAL
+ IN UINTN ProfileSize,
+ IN UINT8 *ProfileInfo,
+ IN BOOLEAN Save
+ )
+{
+ EFI_STATUS Status;
+ USER_PROFILE_ENTRY *User;
+
+ //
+ // Check the data format to be added.
+ //
+ if (!CheckProfileInfo (ProfileInfo, ProfileSize)) {
+ return EFI_SECURITY_VIOLATION;
+ }
+
+ //
+ // Create user profile entry.
+ //
+ User = AllocateZeroPool (sizeof (USER_PROFILE_ENTRY));
+ if (User == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Add the entry to the user profile database.
+ //
+ if (mUserProfileDb->UserProfileNum == mUserProfileDb->MaxProfileNum) {
+ if (!ExpandUsermUserProfileDb ()) {
+ FreePool (User);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ UnicodeSPrint (
+ User->UserVarName,
+ sizeof (User->UserVarName),
+ L"User%04x",
+ mUserProfileDb->UserProfileNum
+ );
+ User->UserProfileSize = 0;
+ User->MaxProfileSize = 0;
+ User->ProfileInfo = NULL;
+ mUserProfileDb->UserProfile[mUserProfileDb->UserProfileNum] = (EFI_USER_PROFILE_HANDLE) User;
+ mUserProfileDb->UserProfileNum++;
+
+ //
+ // Add user profile information.
+ //
+ Status = AddUserInfo (User, ProfileInfo, ProfileSize, NULL, Save);
+ if (EFI_ERROR (Status)) {
+ DelUserProfile (User);
+ return Status;
+ }
+ //
+ // Set new user profile handle.
+ //
+ if (UserProfile != NULL) {
+ *UserProfile = User;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function creates a new user profile with only a new user identifier
+ attached and returns its handle. The user profile is non-volatile, but the
+ handle User can change across reboots.
+
+ @param[out] User Handle of a new user profile.
+
+ @retval EFI_SUCCESS User profile was successfully created.
+ @retval Others Fail to create user profile
+
+**/
+EFI_STATUS
+CreateUserProfile (
+ OUT USER_PROFILE_ENTRY **User
+ )
+{
+ EFI_STATUS Status;
+ EFI_USER_INFO *UserInfo;
+
+ if (User == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Generate user id information.
+ //
+ UserInfo = AllocateZeroPool (sizeof (EFI_USER_INFO) + sizeof (EFI_USER_INFO_IDENTIFIER));
+ if (UserInfo == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ UserInfo->InfoType = EFI_USER_INFO_IDENTIFIER_RECORD;
+ UserInfo->InfoSize = sizeof (EFI_USER_INFO) + sizeof (EFI_USER_INFO_IDENTIFIER);
+ UserInfo->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV | EFI_USER_INFO_PUBLIC | EFI_USER_INFO_EXCLUSIVE;
+ GenerateUserId ((UINT8 *) (UserInfo + 1));
+
+ //
+ // Add user profile to the user profile database.
+ //
+ Status = AddUserProfile (User, UserInfo->InfoSize, (UINT8 *) UserInfo, TRUE);
+ FreePool (UserInfo);
+ return Status;
+}
+
+
+/**
+ Add a default user profile to user profile database.
+
+ @retval EFI_SUCCESS A default user profile is added successfully.
+ @retval Others Fail to add a default user profile
+
+**/
+EFI_STATUS
+AddDefaultUserProfile (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ USER_PROFILE_ENTRY *User;
+ EFI_USER_INFO *Info;
+ EFI_USER_INFO *NewInfo;
+ EFI_USER_INFO_CREATE_DATE CreateDate;
+ EFI_USER_INFO_USAGE_COUNT UsageCount;
+ EFI_USER_INFO_ACCESS_CONTROL *Access;
+ EFI_USER_INFO_IDENTITY_POLICY *Policy;
+
+ //
+ // Create a user profile.
+ //
+ Status = CreateUserProfile (&User);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Allocate a buffer to add all default user information.
+ //
+ Info = AllocateZeroPool (sizeof (EFI_USER_INFO) + INFO_PAYLOAD_SIZE);
+ if (Info == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Add user name.
+ //
+ Info->InfoType = EFI_USER_INFO_NAME_RECORD;
+ Info->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV | EFI_USER_INFO_PUBLIC | EFI_USER_INFO_EXCLUSIVE;
+ Info->InfoSize = sizeof (EFI_USER_INFO) + sizeof (mUserName);
+ CopyMem ((UINT8 *) (Info + 1), mUserName, sizeof (mUserName));
+ NewInfo = NULL;
+ Status = ModifyUserInfo (User, &NewInfo, Info, Info->InfoSize);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Add user profile create date record.
+ //
+ Info->InfoType = EFI_USER_INFO_CREATE_DATE_RECORD;
+ Info->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV | EFI_USER_INFO_PUBLIC | EFI_USER_INFO_EXCLUSIVE;
+ Info->InfoSize = sizeof (EFI_USER_INFO) + sizeof (EFI_USER_INFO_CREATE_DATE);
+ Status = gRT->GetTime (&CreateDate, NULL);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ CopyMem ((UINT8 *) (Info + 1), &CreateDate, sizeof (EFI_USER_INFO_CREATE_DATE));
+ NewInfo = NULL;
+ Status = ModifyUserInfo (User, &NewInfo, Info, Info->InfoSize);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Add user profile usage count record.
+ //
+ Info->InfoType = EFI_USER_INFO_USAGE_COUNT_RECORD;
+ Info->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV | EFI_USER_INFO_PUBLIC | EFI_USER_INFO_EXCLUSIVE;
+ Info->InfoSize = sizeof (EFI_USER_INFO) + sizeof (EFI_USER_INFO_USAGE_COUNT);
+ UsageCount = 0;
+ CopyMem ((UINT8 *) (Info + 1), &UsageCount, sizeof (EFI_USER_INFO_USAGE_COUNT));
+ NewInfo = NULL;
+ Status = ModifyUserInfo (User, &NewInfo, Info, Info->InfoSize);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Add user access right.
+ //
+ Info->InfoType = EFI_USER_INFO_ACCESS_POLICY_RECORD;
+ Info->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV | EFI_USER_INFO_PUBLIC | EFI_USER_INFO_EXCLUSIVE;
+ Access = (EFI_USER_INFO_ACCESS_CONTROL *) (Info + 1);
+ Access->Type = EFI_USER_INFO_ACCESS_MANAGE;
+ Access->Size = sizeof (EFI_USER_INFO_ACCESS_CONTROL);
+ Info->InfoSize = sizeof (EFI_USER_INFO) + Access->Size;
+ NewInfo = NULL;
+ Status = ModifyUserInfo (User, &NewInfo, Info, Info->InfoSize);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Add user identity policy.
+ //
+ Info->InfoType = EFI_USER_INFO_IDENTITY_POLICY_RECORD;
+ Info->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV | EFI_USER_INFO_PRIVATE | EFI_USER_INFO_EXCLUSIVE;
+ Policy = (EFI_USER_INFO_IDENTITY_POLICY *) (Info + 1);
+ Policy->Type = EFI_USER_INFO_IDENTITY_TRUE;
+ Policy->Length = sizeof (EFI_USER_INFO_IDENTITY_POLICY);
+ Info->InfoSize = sizeof (EFI_USER_INFO) + Policy->Length;
+ NewInfo = NULL;
+ Status = ModifyUserInfo (User, &NewInfo, Info, Info->InfoSize);
+
+Done:
+ FreePool (Info);
+ return Status;
+}
+
+
+/**
+ Publish current user information into EFI System Configuration Table.
+
+ By UEFI spec, the User Identity Manager will publish the current user profile
+ into the EFI System Configuration Table. Currently, only the user identifier and user
+ name are published.
+
+ @retval EFI_SUCCESS Current user information is published successfully.
+ @retval Others Fail to publish current user information
+
+**/
+EFI_STATUS
+PublishUserTable (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_CONFIGURATION_TABLE *EfiConfigurationTable;
+ EFI_USER_INFO_TABLE *UserInfoTable;
+ EFI_USER_INFO *IdInfo;
+ EFI_USER_INFO *NameInfo;
+
+ Status = EfiGetSystemConfigurationTable (
+ &gEfiUserManagerProtocolGuid,
+ (VOID **) &EfiConfigurationTable
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // The table existed!
+ //
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Get user ID information.
+ //
+ IdInfo = NULL;
+ Status = FindUserInfoByType (mCurrentUser, &IdInfo, EFI_USER_INFO_IDENTIFIER_RECORD);
+ if (EFI_ERROR (Status)) {
+ return Status;
+
+ }
+ //
+ // Get user name information.
+ //
+ NameInfo = NULL;
+ Status = FindUserInfoByType (mCurrentUser, &NameInfo, EFI_USER_INFO_NAME_RECORD);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Allocate a buffer for user information table.
+ //
+ UserInfoTable = (EFI_USER_INFO_TABLE *) AllocateRuntimePool (
+ sizeof (EFI_USER_INFO_TABLE) +
+ IdInfo->InfoSize +
+ NameInfo->InfoSize
+ );
+ if (UserInfoTable == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ return Status;
+ }
+
+ UserInfoTable->Size = sizeof (EFI_USER_INFO_TABLE);
+
+ //
+ // Append the user information to the user info table
+ //
+ CopyMem ((UINT8 *) UserInfoTable + UserInfoTable->Size, (UINT8 *) IdInfo, IdInfo->InfoSize);
+ UserInfoTable->Size += IdInfo->InfoSize;
+
+ CopyMem ((UINT8 *) UserInfoTable + UserInfoTable->Size, (UINT8 *) NameInfo, NameInfo->InfoSize);
+ UserInfoTable->Size += NameInfo->InfoSize;
+
+ Status = gBS->InstallConfigurationTable (&gEfiUserManagerProtocolGuid, (VOID *) UserInfoTable);
+ return Status;
+}
+
+
+/**
+ Get the user's identity type.
+
+ The identify manager only supports the identity policy in which the credential
+ provider handles are connected by the operator 'AND' or 'OR'.
+
+
+ @param[in] User Handle of a user profile.
+ @param[out] PolicyType Point to the identity type.
+
+ @retval EFI_SUCCESS Get user's identity type successfully.
+ @retval Others Fail to get user's identity type.
+
+**/
+EFI_STATUS
+GetIdentifyType (
+ IN EFI_USER_PROFILE_HANDLE User,
+ OUT UINT8 *PolicyType
+ )
+{
+ EFI_STATUS Status;
+ EFI_USER_INFO *IdentifyInfo;
+ UINTN TotalLen;
+ EFI_USER_INFO_IDENTITY_POLICY *Identity;
+
+ //
+ // Get user identify policy information.
+ //
+ IdentifyInfo = NULL;
+ Status = FindUserInfoByType (User, &IdentifyInfo, EFI_USER_INFO_IDENTITY_POLICY_RECORD);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ ASSERT (IdentifyInfo != NULL);
+
+ //
+ // Search the user identify policy according to type.
+ //
+ TotalLen = 0;
+ *PolicyType = EFI_USER_INFO_IDENTITY_FALSE;
+ while (TotalLen < IdentifyInfo->InfoSize - sizeof (EFI_USER_INFO)) {
+ Identity = (EFI_USER_INFO_IDENTITY_POLICY *) ((UINT8 *) (IdentifyInfo + 1) + TotalLen);
+ if (Identity->Type == EFI_USER_INFO_IDENTITY_AND) {
+ *PolicyType = EFI_USER_INFO_IDENTITY_AND;
+ break;
+ }
+
+ if (Identity->Type == EFI_USER_INFO_IDENTITY_OR) {
+ *PolicyType = EFI_USER_INFO_IDENTITY_OR;
+ break;
+ }
+ TotalLen += Identity->Length;
+ }
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Identify the User by the specfied provider.
+
+ @param[in] User Handle of a user profile.
+ @param[in] Provider Points to the identifir of credential provider.
+
+ @retval EFI_INVALID_PARAMETER Provider is NULL.
+ @retval EFI_NOT_FOUND Fail to identify the specified user.
+ @retval EFI_SUCCESS User is identified successfully.
+
+**/
+EFI_STATUS
+IdentifyByProviderId (
+ IN EFI_USER_PROFILE_HANDLE User,
+ IN EFI_GUID *Provider
+ )
+{
+ EFI_STATUS Status;
+ EFI_USER_INFO_IDENTIFIER UserId;
+ UINTN Index;
+ EFI_CREDENTIAL_LOGON_FLAGS AutoLogon;
+ EFI_HII_HANDLE HiiHandle;
+ EFI_GUID FormSetId;
+ EFI_FORM_ID FormId;
+ EFI_USER_CREDENTIAL_PROTOCOL *UserCredential;
+ EFI_USER_INFO *IdInfo;
+
+ if (Provider == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check the user ID identified by the specified credential provider.
+ //
+ for (Index = 0; Index < mProviderDb->Count; Index++) {
+ //
+ // Check credential provider class.
+ //
+ UserCredential = mProviderDb->Provider[Index];
+ if (CompareGuid (&UserCredential->Identifier, Provider)) {
+ Status = UserCredential->Select (UserCredential, &AutoLogon);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((AutoLogon & EFI_CREDENTIAL_LOGON_FLAG_AUTO) == 0) {
+ //
+ // Get credential provider form.
+ //
+ Status = UserCredential->Form (
+ UserCredential,
+ &HiiHandle,
+ &FormSetId,
+ &FormId
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Send form to get user input.
+ //
+ Status = mCallbackInfo->FormBrowser2->SendForm (
+ mCallbackInfo->FormBrowser2,
+ &HiiHandle,
+ 1,
+ &FormSetId,
+ FormId,
+ NULL,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ }
+
+ Status = UserCredential->User (UserCredential, User, &UserId);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = UserCredential->Deselect (UserCredential);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (User == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Get user ID information.
+ //
+ IdInfo = NULL;
+ Status = FindUserInfoByType (User, &IdInfo, EFI_USER_INFO_IDENTIFIER_RECORD);
+ ASSERT (IdInfo != NULL);
+
+ if (CompareMem ((UINT8 *) (IdInfo + 1), UserId, sizeof (EFI_USER_INFO_IDENTIFIER)) != 0) {
+ //
+ // One user name is selected, but the other's credential is given. Here no user passed.
+ //
+ break;
+ }
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ Update user information when user is logon on successfully.
+
+ @param[in] User Points to user profile.
+
+ @retval EFI_SUCCESS Update user information successfully.
+ @retval Others Fail to update user information.
+
+**/
+EFI_STATUS
+UpdateUserInfo (
+ IN USER_PROFILE_ENTRY *User
+ )
+{
+ EFI_STATUS Status;
+ EFI_USER_INFO *Info;
+ EFI_USER_INFO *NewInfo;
+ EFI_USER_INFO_CREATE_DATE Date;
+ EFI_USER_INFO_USAGE_COUNT UsageCount;
+ UINTN InfoLen;
+
+ //
+ // Allocate a buffer to update user's date record and usage record.
+ //
+ InfoLen = MAX (sizeof (EFI_USER_INFO_CREATE_DATE), sizeof (EFI_USER_INFO_USAGE_COUNT));
+ Info = AllocateZeroPool (sizeof (EFI_USER_INFO) + InfoLen);
+ if (Info == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Check create date record.
+ //
+ NewInfo = NULL;
+ Status = FindUserInfoByType (User, &NewInfo, EFI_USER_INFO_CREATE_DATE_RECORD);
+ if (Status == EFI_NOT_FOUND) {
+ Info->InfoType = EFI_USER_INFO_CREATE_DATE_RECORD;
+ Info->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV | EFI_USER_INFO_PUBLIC | EFI_USER_INFO_EXCLUSIVE;
+ Info->InfoSize = sizeof (EFI_USER_INFO) + sizeof (EFI_USER_INFO_CREATE_DATE);
+ Status = gRT->GetTime (&Date, NULL);
+ if (EFI_ERROR (Status)) {
+ FreePool (Info);
+ return Status;
+ }
+
+ CopyMem ((UINT8 *) (Info + 1), &Date, sizeof (EFI_USER_INFO_CREATE_DATE));
+ NewInfo = NULL;
+ Status = ModifyUserInfo (User, &NewInfo, Info, Info->InfoSize);
+ if (EFI_ERROR (Status)) {
+ FreePool (Info);
+ return Status;
+ }
+ }
+
+ //
+ // Update usage date record.
+ //
+ NewInfo = NULL;
+ Status = FindUserInfoByType (User, &NewInfo, EFI_USER_INFO_USAGE_DATE_RECORD);
+ if ((Status == EFI_SUCCESS) || (Status == EFI_NOT_FOUND)) {
+ Info->InfoType = EFI_USER_INFO_USAGE_DATE_RECORD;
+ Info->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV | EFI_USER_INFO_PUBLIC | EFI_USER_INFO_EXCLUSIVE;
+ Info->InfoSize = sizeof (EFI_USER_INFO) + sizeof (EFI_USER_INFO_USAGE_DATE);
+ Status = gRT->GetTime (&Date, NULL);
+ if (EFI_ERROR (Status)) {
+ FreePool (Info);
+ return Status;
+ }
+
+ CopyMem ((UINT8 *) (Info + 1), &Date, sizeof (EFI_USER_INFO_USAGE_DATE));
+ Status = ModifyUserInfo (User, &NewInfo, Info, Info->InfoSize);
+ if (EFI_ERROR (Status)) {
+ FreePool (Info);
+ return Status;
+ }
+ }
+
+ //
+ // Update usage count record.
+ //
+ UsageCount = 0;
+ NewInfo = NULL;
+ Status = FindUserInfoByType (User, &NewInfo, EFI_USER_INFO_USAGE_COUNT_RECORD);
+ //
+ // Get usage count.
+ //
+ if (Status == EFI_SUCCESS) {
+ CopyMem (&UsageCount, (UINT8 *) (NewInfo + 1), sizeof (EFI_USER_INFO_USAGE_COUNT));
+ }
+
+ UsageCount++;
+ if ((Status == EFI_SUCCESS) || (Status == EFI_NOT_FOUND)) {
+ Info->InfoType = EFI_USER_INFO_USAGE_COUNT_RECORD;
+ Info->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV | EFI_USER_INFO_PUBLIC | EFI_USER_INFO_EXCLUSIVE;
+ Info->InfoSize = sizeof (EFI_USER_INFO) + sizeof (EFI_USER_INFO_USAGE_COUNT);
+ CopyMem ((UINT8 *) (Info + 1), &UsageCount, sizeof (EFI_USER_INFO_USAGE_COUNT));
+ Status = ModifyUserInfo (User, &NewInfo, Info, Info->InfoSize);
+ if (EFI_ERROR (Status)) {
+ FreePool (Info);
+ return Status;
+ }
+ }
+
+ FreePool (Info);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Add a credenetial provider item in form.
+
+ @param[in] ProviderGuid Points to the identifir of credential provider.
+ @param[in] OpCodeHandle Points to container for dynamic created opcodes.
+
+**/
+VOID
+AddProviderSelection (
+ IN EFI_GUID *ProviderGuid,
+ IN VOID *OpCodeHandle
+ )
+{
+ EFI_HII_HANDLE HiiHandle;
+ EFI_STRING_ID ProvID;
+ CHAR16 *ProvStr;
+ UINTN Index;
+ EFI_USER_CREDENTIAL_PROTOCOL *UserCredential;
+
+ for (Index = 0; Index < mProviderDb->Count; Index++) {
+ UserCredential = mProviderDb->Provider[Index];
+ if (CompareGuid (&UserCredential->Identifier, ProviderGuid)) {
+ //
+ // Add credential provider selection.
+ //
+ UserCredential->Title (UserCredential, &HiiHandle, &ProvID);
+ ProvStr = HiiGetString (HiiHandle, ProvID, NULL);
+ if (ProvStr == NULL) {
+ continue ;
+ }
+ ProvID = HiiSetString (mCallbackInfo->HiiHandle, 0, ProvStr, NULL);
+ FreePool (ProvStr);
+ HiiCreateActionOpCode (
+ OpCodeHandle, // Container for dynamic created opcodes
+ (EFI_QUESTION_ID)(LABEL_PROVIDER_NAME + Index), // Question ID
+ ProvID, // Prompt text
+ STRING_TOKEN (STR_NULL_STRING), // Help text
+ EFI_IFR_FLAG_CALLBACK, // Question flag
+ 0 // Action String ID
+ );
+ break;
+ }
+ }
+}
+
+
+/**
+ Add a username item in form.
+
+ @param[in] Index The index of the user in the user name list.
+ @param[in] User Points to the user profile whose username is added.
+ @param[in] OpCodeHandle Points to container for dynamic created opcodes.
+
+ @retval EFI_SUCCESS Add a username successfully.
+ @retval Others Fail to add a username.
+
+**/
+EFI_STATUS
+AddUserSelection (
+ IN UINT16 Index,
+ IN USER_PROFILE_ENTRY *User,
+ IN VOID *OpCodeHandle
+ )
+{
+ EFI_STRING_ID UserName;
+ EFI_STATUS Status;
+ EFI_USER_INFO *UserInfo;
+
+ UserInfo = NULL;
+ Status = FindUserInfoByType (User, &UserInfo, EFI_USER_INFO_NAME_RECORD);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Add user name selection.
+ //
+ UserName = HiiSetString (mCallbackInfo->HiiHandle, 0, (EFI_STRING) (UserInfo + 1), NULL);
+ if (UserName == 0) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ HiiCreateGotoOpCode (
+ OpCodeHandle, // Container for dynamic created opcodes
+ FORMID_PROVIDER_FORM, // Target Form ID
+ UserName, // Prompt text
+ STRING_TOKEN (STR_NULL_STRING), // Help text
+ EFI_IFR_FLAG_CALLBACK, // Question flag
+ (UINT16) Index // Question ID
+ );
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Identify the user whose identity policy does not contain the operator 'OR'.
+
+ @param[in] User Points to the user profile.
+
+ @retval EFI_SUCCESS The specified user is identified successfully.
+ @retval Others Fail to identify the user.
+
+**/
+EFI_STATUS
+IdentifyAndTypeUser (
+ IN USER_PROFILE_ENTRY *User
+ )
+{
+ EFI_STATUS Status;
+ EFI_USER_INFO *IdentifyInfo;
+ BOOLEAN Success;
+ UINTN TotalLen;
+ UINTN ValueLen;
+ EFI_USER_INFO_IDENTITY_POLICY *Identity;
+
+ //
+ // Get user identify policy information.
+ //
+ IdentifyInfo = NULL;
+ Status = FindUserInfoByType (User, &IdentifyInfo, EFI_USER_INFO_IDENTITY_POLICY_RECORD);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ ASSERT (IdentifyInfo != NULL);
+
+ //
+ // Check each part of identification policy expression.
+ //
+ Success = FALSE;
+ TotalLen = 0;
+ while (TotalLen < IdentifyInfo->InfoSize - sizeof (EFI_USER_INFO)) {
+ Identity = (EFI_USER_INFO_IDENTITY_POLICY *) ((UINT8 *) (IdentifyInfo + 1) + TotalLen);
+ ValueLen = Identity->Length - sizeof (EFI_USER_INFO_IDENTITY_POLICY);
+ switch (Identity->Type) {
+
+ case EFI_USER_INFO_IDENTITY_FALSE:
+ //
+ // Check False option.
+ //
+ Success = FALSE;
+ break;
+
+ case EFI_USER_INFO_IDENTITY_TRUE:
+ //
+ // Check True option.
+ //
+ Success = TRUE;
+ break;
+
+ case EFI_USER_INFO_IDENTITY_NOT:
+ //
+ // Check negative operation.
+ //
+ break;
+
+ case EFI_USER_INFO_IDENTITY_AND:
+ //
+ // Check and operation.
+ //
+ if (!Success) {
+ return EFI_NOT_READY;
+ }
+
+ Success = FALSE;
+ break;
+
+ case EFI_USER_INFO_IDENTITY_OR:
+ //
+ // Check or operation.
+ //
+ if (Success) {
+ return EFI_SUCCESS;
+ }
+ break;
+
+ case EFI_USER_INFO_IDENTITY_CREDENTIAL_TYPE:
+ //
+ // Check credential provider by type.
+ //
+ break;
+
+ case EFI_USER_INFO_IDENTITY_CREDENTIAL_PROVIDER:
+ //
+ // Check credential provider by ID.
+ //
+ if (ValueLen != sizeof (EFI_GUID)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = IdentifyByProviderId (User, (EFI_GUID *) (Identity + 1));
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Success = TRUE;
+ break;
+
+ default:
+ return EFI_INVALID_PARAMETER;
+ break;
+ }
+
+ TotalLen += Identity->Length;
+ }
+
+ if (TotalLen != IdentifyInfo->InfoSize - sizeof (EFI_USER_INFO)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!Success) {
+ return EFI_NOT_READY;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Identify the user whose identity policy does not contain the operator 'AND'.
+
+ @param[in] User Points to the user profile.
+
+ @retval EFI_SUCCESS The specified user is identified successfully.
+ @retval Others Fail to identify the user.
+
+**/
+EFI_STATUS
+IdentifyOrTypeUser (
+ IN USER_PROFILE_ENTRY *User
+ )
+{
+ EFI_STATUS Status;
+ EFI_USER_INFO *IdentifyInfo;
+ UINTN TotalLen;
+ UINTN ValueLen;
+ EFI_USER_INFO_IDENTITY_POLICY *Identity;
+ VOID *StartOpCodeHandle;
+ VOID *EndOpCodeHandle;
+ EFI_IFR_GUID_LABEL *StartLabel;
+ EFI_IFR_GUID_LABEL *EndLabel;
+
+ //
+ // Get user identify policy information.
+ //
+ IdentifyInfo = NULL;
+ Status = FindUserInfoByType (User, &IdentifyInfo, EFI_USER_INFO_IDENTITY_POLICY_RECORD);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ ASSERT (IdentifyInfo != NULL);
+
+ //
+ // Initialize the container for dynamic opcodes.
+ //
+ StartOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (StartOpCodeHandle != NULL);
+
+ EndOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (EndOpCodeHandle != NULL);
+
+ //
+ // Create Hii Extend Label OpCode.
+ //
+ StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (
+ StartOpCodeHandle,
+ &gEfiIfrTianoGuid,
+ NULL,
+ sizeof (EFI_IFR_GUID_LABEL)
+ );
+ StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
+ StartLabel->Number = LABEL_PROVIDER_NAME;
+
+ EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (
+ EndOpCodeHandle,
+ &gEfiIfrTianoGuid,
+ NULL,
+ sizeof (EFI_IFR_GUID_LABEL)
+ );
+ EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
+ EndLabel->Number = LABEL_END;
+
+ //
+ // Add the providers that exists in the user's policy.
+ //
+ TotalLen = 0;
+ while (TotalLen < IdentifyInfo->InfoSize - sizeof (EFI_USER_INFO)) {
+ Identity = (EFI_USER_INFO_IDENTITY_POLICY *) ((UINT8 *) (IdentifyInfo + 1) + TotalLen);
+ ValueLen = Identity->Length - sizeof (EFI_USER_INFO_IDENTITY_POLICY);
+ if (Identity->Type == EFI_USER_INFO_IDENTITY_CREDENTIAL_PROVIDER) {
+ AddProviderSelection ((EFI_GUID *) (Identity + 1), StartOpCodeHandle);
+ }
+
+ TotalLen += Identity->Length;
+ }
+
+ HiiUpdateForm (
+ mCallbackInfo->HiiHandle, // HII handle
+ &mUserManagerGuid, // Formset GUID
+ FORMID_PROVIDER_FORM, // Form ID
+ StartOpCodeHandle, // Label for where to insert opcodes
+ EndOpCodeHandle // Replace data
+ );
+
+ HiiFreeOpCodeHandle (StartOpCodeHandle);
+ HiiFreeOpCodeHandle (EndOpCodeHandle);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function processes the results of changes in configuration.
+
+ @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param Action Specifies the type of action taken by the browser.
+ @param QuestionId A unique value which is sent to the original
+ exporting driver so that it can identify the type
+ of data to expect.
+ @param Type The type of value for the question.
+ @param Value A pointer to the data being sent to the original
+ exporting driver.
+ @param ActionRequest On return, points to the action requested by the
+ callback function.
+
+ @retval EFI_SUCCESS The callback successfully handled the action.
+ @retval Others Fail to handle the action.
+
+**/
+EFI_STATUS
+EFIAPI
+UserIdentifyManagerCallback (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN EFI_BROWSER_ACTION Action,
+ IN EFI_QUESTION_ID QuestionId,
+ IN UINT8 Type,
+ IN EFI_IFR_TYPE_VALUE *Value,
+ OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
+ )
+{
+ EFI_STATUS Status;
+ USER_PROFILE_ENTRY *User;
+ UINT8 PolicyType;
+ UINT16 Index;
+ VOID *StartOpCodeHandle;
+ VOID *EndOpCodeHandle;
+ EFI_IFR_GUID_LABEL *StartLabel;
+ EFI_IFR_GUID_LABEL *EndLabel;
+
+ Status = EFI_SUCCESS;
+
+ switch (Action) {
+ case EFI_BROWSER_ACTION_FORM_OPEN:
+ {
+ //
+ // Update user Form when user Form is opened.
+ // This will be done only in FORM_OPEN CallBack of question with FORM_OPEN_QUESTION_ID from user Form.
+ //
+ if (QuestionId != FORM_OPEN_QUESTION_ID) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Initialize the container for dynamic opcodes.
+ //
+ StartOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (StartOpCodeHandle != NULL);
+
+ EndOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (EndOpCodeHandle != NULL);
+
+ //
+ // Create Hii Extend Label OpCode.
+ //
+ StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (
+ StartOpCodeHandle,
+ &gEfiIfrTianoGuid,
+ NULL,
+ sizeof (EFI_IFR_GUID_LABEL)
+ );
+ StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
+ StartLabel->Number = LABEL_USER_NAME;
+
+ EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (
+ EndOpCodeHandle,
+ &gEfiIfrTianoGuid,
+ NULL,
+ sizeof (EFI_IFR_GUID_LABEL)
+ );
+ EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
+ EndLabel->Number = LABEL_END;
+
+ //
+ // Add all the user profile in the user profile database.
+ //
+ for (Index = 0; Index < mUserProfileDb->UserProfileNum; Index++) {
+ User = (USER_PROFILE_ENTRY *) mUserProfileDb->UserProfile[Index];
+ AddUserSelection ((UINT16)(LABEL_USER_NAME + Index), User, StartOpCodeHandle);
+ }
+
+ HiiUpdateForm (
+ mCallbackInfo->HiiHandle, // HII handle
+ &mUserManagerGuid, // Formset GUID
+ FORMID_USER_FORM, // Form ID
+ StartOpCodeHandle, // Label for where to insert opcodes
+ EndOpCodeHandle // Replace data
+ );
+
+ HiiFreeOpCodeHandle (StartOpCodeHandle);
+ HiiFreeOpCodeHandle (EndOpCodeHandle);
+
+ return EFI_SUCCESS;
+ }
+ break;
+
+ case EFI_BROWSER_ACTION_FORM_CLOSE:
+ Status = EFI_SUCCESS;
+ break;
+
+ case EFI_BROWSER_ACTION_CHANGING:
+ {
+ if (QuestionId >= LABEL_PROVIDER_NAME) {
+ //
+ // QuestionId comes from the second Form (Select a Credential Provider if identity
+ // policy is OR type). Identify the user by the selected provider.
+ //
+ Status = IdentifyByProviderId (mCurrentUser, &mProviderDb->Provider[QuestionId & 0xFFF]->Identifier);
+ if (Status == EFI_SUCCESS) {
+ mIdentified = TRUE;
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;
+ }
+ return EFI_SUCCESS;
+ }
+
+ //
+ // QuestionId comes from the first Form (Select a user to identify).
+ //
+ User = (USER_PROFILE_ENTRY *) mUserProfileDb->UserProfile[QuestionId & 0xFFF];
+ Status = GetIdentifyType (User, &PolicyType);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (PolicyType == EFI_USER_INFO_IDENTITY_OR) {
+ //
+ // Identify the user by "OR" logical.
+ //
+ Status = IdentifyOrTypeUser (User);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ mCurrentUser = (EFI_USER_PROFILE_HANDLE) User;
+ } else {
+ //
+ // Identify the user by "AND" logical.
+ //
+ Status = IdentifyAndTypeUser (User);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ mCurrentUser = (EFI_USER_PROFILE_HANDLE) User;
+ mIdentified = TRUE;
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;
+ }
+ }
+ break;
+
+ default:
+ //
+ // All other action return unsupported.
+ //
+ Status = EFI_UNSUPPORTED;
+ break;
+ }
+
+
+ return Status;
+}
+
+
+/**
+ This function construct user profile database from user data saved in the Flash.
+ If no user is found in Flash, add one default user "administrator" in the user
+ profile database.
+
+ @retval EFI_SUCCESS Init user profile database successfully.
+ @retval Others Fail to init user profile database.
+
+**/
+EFI_STATUS
+InitUserProfileDb (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *VarData;
+ UINTN VarSize;
+ UINTN CurVarSize;
+ CHAR16 VarName[10];
+ UINTN Index;
+ UINT32 VarAttr;
+
+ if (mUserProfileDb != NULL) {
+ //
+ // The user profiles had been already initialized.
+ //
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Init user profile database structure.
+ //
+ if (!ExpandUsermUserProfileDb ()) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CurVarSize = DEFAULT_PROFILE_SIZE;
+ VarData = AllocateZeroPool (CurVarSize);
+ if (VarData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Get all user proifle entries.
+ //
+ Index = 0;
+ while (TRUE) {
+ //
+ // Get variable name.
+ //
+ UnicodeSPrint (
+ VarName,
+ sizeof (VarName),
+ L"User%04x",
+ Index
+ );
+ Index++;
+
+ //
+ // Get variable value.
+ //
+ VarSize = CurVarSize;
+ Status = gRT->GetVariable (VarName, &mUserManagerGuid, &VarAttr, &VarSize, VarData);
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ FreePool (VarData);
+ VarData = AllocatePool (VarSize);
+ if (VarData == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ break;
+ }
+
+ CurVarSize = VarSize;
+ Status = gRT->GetVariable (VarName, &mUserManagerGuid, &VarAttr, &VarSize, VarData);
+ }
+
+ if (EFI_ERROR (Status)) {
+ if (Status == EFI_NOT_FOUND) {
+ Status = EFI_SUCCESS;
+ }
+ break;
+ }
+
+ //
+ // Check variable attributes.
+ //
+ if (VarAttr != (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS)) {
+ Status = gRT->SetVariable (VarName, &mUserManagerGuid, VarAttr, 0, NULL);
+ continue;
+ }
+
+ //
+ // Add user profile to the user profile database.
+ //
+ Status = AddUserProfile (NULL, VarSize, VarData, FALSE);
+ if (EFI_ERROR (Status)) {
+ if (Status == EFI_SECURITY_VIOLATION) {
+ //
+ // Delete invalid user profile
+ //
+ gRT->SetVariable (VarName, &mUserManagerGuid, VarAttr, 0, NULL);
+ } else if (Status == EFI_OUT_OF_RESOURCES) {
+ break;
+ }
+ } else {
+ //
+ // Delete and save the profile again if some invalid profiles are deleted.
+ //
+ if (mUserProfileDb->UserProfileNum < Index) {
+ gRT->SetVariable (VarName, &mUserManagerGuid, VarAttr, 0, NULL);
+ SaveNvUserProfile (mUserProfileDb->UserProfile[mUserProfileDb->UserProfileNum - 1], FALSE);
+ }
+ }
+ }
+
+ if (VarData != NULL) {
+ FreePool (VarData);
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Check whether the user profile database is empty.
+ //
+ if (mUserProfileDb->UserProfileNum == 0) {
+ Status = AddDefaultUserProfile ();
+ }
+
+ return Status;
+}
+
+
+/**
+ This function collects all the credential providers and saves to mProviderDb.
+
+ @retval EFI_SUCCESS Collect credential providers successfully.
+ @retval Others Fail to collect credential providers.
+
+**/
+EFI_STATUS
+InitProviderInfo (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuf;
+ UINTN Index;
+
+ if (mProviderDb != NULL) {
+ //
+ // The credential providers had been collected before.
+ //
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Try to find all the user credential provider driver.
+ //
+ HandleCount = 0;
+ HandleBuf = NULL;
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiUserCredentialProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuf
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Get provider infomation.
+ //
+ mProviderDb = AllocateZeroPool (
+ sizeof (CREDENTIAL_PROVIDER_INFO) -
+ sizeof (EFI_USER_CREDENTIAL_PROTOCOL *) +
+ HandleCount * sizeof (EFI_USER_CREDENTIAL_PROTOCOL *)
+ );
+ if (mProviderDb == NULL) {
+ FreePool (HandleBuf);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ mProviderDb->Count = HandleCount;
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->HandleProtocol (
+ HandleBuf[Index],
+ &gEfiUserCredentialProtocolGuid,
+ (VOID **) &mProviderDb->Provider[Index]
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (HandleBuf);
+ FreePool (mProviderDb);
+ mProviderDb = NULL;
+ return Status;
+ }
+ }
+
+ FreePool (HandleBuf);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function allows a caller to extract the current configuration for one
+ or more named elements from the target driver.
+
+
+ @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param Request A null-terminated Unicode string in format.
+ @param Progress On return, points to a character in the Request string.
+ Points to the string's null terminator if request was successful.
+ Points to the most recent '&' before the first failing name/value
+ pair (or the beginning of the string if the failure is in the
+ first name/value pair) if the request was not successful.
+ @param Results A null-terminated Unicode string in format which
+ has all values filled in for the names in the Request string.
+ String to be allocated by the called function.
+
+ @retval EFI_SUCCESS The Results is filled with the requested values.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results.
+ @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name.
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in this driver.
+
+**/
+EFI_STATUS
+EFIAPI
+FakeExtractConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Request,
+ OUT EFI_STRING *Progress,
+ OUT EFI_STRING *Results
+ )
+{
+ if (Progress == NULL || Results == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ *Progress = Request;
+ return EFI_NOT_FOUND;
+}
+
+/**
+ This function processes the results of changes in configuration.
+
+
+ @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param Configuration A null-terminated Unicode string in format.
+ @param Progress A pointer to a string filled in with the offset of the most
+ recent '&' before the first failing name/value pair (or the
+ beginning of the string if the failure is in the first
+ name/value pair) or the terminating NULL if all was successful.
+
+ @retval EFI_SUCCESS The Results is processed successfully.
+ @retval EFI_INVALID_PARAMETER Configuration is NULL.
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in this driver.
+
+**/
+EFI_STATUS
+EFIAPI
+FakeRouteConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Configuration,
+ OUT EFI_STRING *Progress
+ )
+{
+ if (Configuration == NULL || Progress == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ This function initialize the data mainly used in form browser.
+
+ @retval EFI_SUCCESS Initialize form data successfully.
+ @retval Others Fail to Initialize form data.
+
+**/
+EFI_STATUS
+InitFormBrowser (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ USER_MANAGER_CALLBACK_INFO *CallbackInfo;
+ EFI_HII_DATABASE_PROTOCOL *HiiDatabase;
+ EFI_HII_STRING_PROTOCOL *HiiString;
+ EFI_FORM_BROWSER2_PROTOCOL *FormBrowser2;
+
+ //
+ // Initialize driver private data.
+ //
+ CallbackInfo = AllocateZeroPool (sizeof (USER_MANAGER_CALLBACK_INFO));
+ if (CallbackInfo == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CallbackInfo->Signature = USER_MANAGER_SIGNATURE;
+ CallbackInfo->ConfigAccess.ExtractConfig = FakeExtractConfig;
+ CallbackInfo->ConfigAccess.RouteConfig = FakeRouteConfig;
+ CallbackInfo->ConfigAccess.Callback = UserIdentifyManagerCallback;
+
+ //
+ // Locate Hii Database protocol.
+ //
+ Status = gBS->LocateProtocol (&gEfiHiiDatabaseProtocolGuid, NULL, (VOID **) &HiiDatabase);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ CallbackInfo->HiiDatabase = HiiDatabase;
+
+ //
+ // Locate HiiString protocol.
+ //
+ Status = gBS->LocateProtocol (&gEfiHiiStringProtocolGuid, NULL, (VOID **) &HiiString);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ CallbackInfo->HiiString = HiiString;
+
+ //
+ // Locate Formbrowser2 protocol.
+ //
+ Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &FormBrowser2);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ CallbackInfo->FormBrowser2 = FormBrowser2;
+ CallbackInfo->DriverHandle = NULL;
+
+ //
+ // Install Device Path Protocol and Config Access protocol to driver handle.
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &CallbackInfo->DriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mHiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ &CallbackInfo->ConfigAccess,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Publish HII data.
+ //
+ CallbackInfo->HiiHandle = HiiAddPackages (
+ &mUserManagerGuid,
+ CallbackInfo->DriverHandle,
+ UserIdentifyManagerStrings,
+ UserIdentifyManagerVfrBin,
+ NULL
+ );
+ if (CallbackInfo->HiiHandle == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ mCallbackInfo = CallbackInfo;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Identify the user whose identification policy supports auto logon.
+
+ @param[in] ProviderIndex The provider index in the provider list.
+ @param[out] User Points to user user profile if a user is identified successfully.
+
+ @retval EFI_SUCCESS Identify a user with the specified provider successfully.
+ @retval Others Fail to identify a user.
+
+**/
+EFI_STATUS
+IdentifyAutoLogonUser (
+ IN UINTN ProviderIndex,
+ OUT USER_PROFILE_ENTRY **User
+ )
+{
+ EFI_STATUS Status;
+ EFI_USER_INFO *Info;
+ UINT8 PolicyType;
+
+ Info = AllocateZeroPool (sizeof (EFI_USER_INFO) + sizeof (EFI_USER_INFO_IDENTIFIER));
+ if (Info == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Info->InfoType = EFI_USER_INFO_IDENTIFIER_RECORD;
+ Info->InfoSize = sizeof (EFI_USER_INFO) + sizeof (EFI_USER_INFO_IDENTIFIER);
+
+ //
+ // Identify the specified credential provider's auto logon user.
+ //
+ Status = mProviderDb->Provider[ProviderIndex]->User (
+ mProviderDb->Provider[ProviderIndex],
+ NULL,
+ (EFI_USER_INFO_IDENTIFIER *) (Info + 1)
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (Info);
+ return Status;
+ }
+
+ //
+ // Find user with the specified user ID.
+ //
+ *User = NULL;
+ Status = FindUserProfileByInfo (User, NULL, Info, Info->InfoSize);
+ FreePool (Info);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = GetIdentifyType ((EFI_USER_PROFILE_HANDLE) * User, &PolicyType);
+ if (PolicyType == EFI_USER_INFO_IDENTITY_AND) {
+ //
+ // The identified user need also identified by other credential provider.
+ // This can handle through select user.
+ //
+ return EFI_NOT_READY;
+ }
+
+ return Status;
+}
+
+
+/**
+ Check whether the given console is ready.
+
+ @param[in] ProtocolGuid Points to the protocol guid of sonsole .
+
+ @retval TRUE The given console is ready.
+ @retval FALSE The given console is not ready.
+
+**/
+BOOLEAN
+CheckConsole (
+ EFI_GUID *ProtocolGuid
+ )
+{
+ EFI_STATUS Status;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuf;
+ UINTN Index;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+
+ //
+ // Try to find all the handle driver.
+ //
+ HandleCount = 0;
+ HandleBuf = NULL;
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ ProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuf
+ );
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ for (Index = 0; Index < HandleCount; Index++) {
+ DevicePath = DevicePathFromHandle (HandleBuf[Index]);
+ if (DevicePath != NULL) {
+ FreePool (HandleBuf);
+ return TRUE;
+ }
+ }
+ FreePool (HandleBuf);
+ return FALSE;
+}
+
+
+/**
+ Check whether the console is ready.
+
+ @retval TRUE The console is ready.
+ @retval FALSE The console is not ready.
+
+**/
+BOOLEAN
+IsConsoleReady (
+ VOID
+ )
+{
+ if (!CheckConsole (&gEfiSimpleTextOutProtocolGuid)) {
+ return FALSE;
+ }
+
+ if (!CheckConsole (&gEfiSimpleTextInProtocolGuid)) {
+ if (!CheckConsole (&gEfiSimpleTextInputExProtocolGuid)) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+/**
+ Identify a user to logon.
+
+ @param[out] User Points to user user profile if a user is identified successfully.
+
+ @retval EFI_SUCCESS Identify a user successfully.
+
+**/
+EFI_STATUS
+IdentifyUser (
+ OUT USER_PROFILE_ENTRY **User
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ EFI_CREDENTIAL_LOGON_FLAGS AutoLogon;
+ EFI_USER_INFO *IdentifyInfo;
+ EFI_USER_INFO_IDENTITY_POLICY *Identity;
+ EFI_USER_CREDENTIAL_PROTOCOL *UserCredential;
+ USER_PROFILE_ENTRY *UserEntry;
+
+ //
+ // Initialize credential providers.
+ //
+ InitProviderInfo ();
+
+ //
+ // Initialize user profile database.
+ //
+ InitUserProfileDb ();
+
+ //
+ // If only one user in system, and its identify policy is TRUE, then auto logon.
+ //
+ if (mUserProfileDb->UserProfileNum == 1) {
+ UserEntry = (USER_PROFILE_ENTRY *) mUserProfileDb->UserProfile[0];
+ IdentifyInfo = NULL;
+ Status = FindUserInfoByType (UserEntry, &IdentifyInfo, EFI_USER_INFO_IDENTITY_POLICY_RECORD);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ ASSERT (IdentifyInfo != NULL);
+
+ Identity = (EFI_USER_INFO_IDENTITY_POLICY *) ((UINT8 *) (IdentifyInfo + 1));
+ if (Identity->Type == EFI_USER_INFO_IDENTITY_TRUE) {
+ mCurrentUser = (EFI_USER_PROFILE_HANDLE) UserEntry;
+ UpdateUserInfo (UserEntry);
+ *User = UserEntry;
+ return EFI_SUCCESS;
+ }
+ }
+
+ //
+ // Find and login the default & AutoLogon user.
+ //
+ for (Index = 0; Index < mProviderDb->Count; Index++) {
+ UserCredential = mProviderDb->Provider[Index];
+ Status = UserCredential->Default (UserCredential, &AutoLogon);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ if ((AutoLogon & (EFI_CREDENTIAL_LOGON_FLAG_DEFAULT | EFI_CREDENTIAL_LOGON_FLAG_AUTO)) != 0) {
+ Status = IdentifyAutoLogonUser (Index, &UserEntry);
+ if (Status == EFI_SUCCESS) {
+ mCurrentUser = (EFI_USER_PROFILE_HANDLE) UserEntry;
+ UpdateUserInfo (UserEntry);
+ *User = UserEntry;
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ if (!IsConsoleReady ()) {
+ //
+ // The console is still not ready for user selection.
+ //
+ return EFI_ACCESS_DENIED;
+ }
+
+ //
+ // Select a user and identify it.
+ //
+ mCallbackInfo->FormBrowser2->SendForm (
+ mCallbackInfo->FormBrowser2,
+ &mCallbackInfo->HiiHandle,
+ 1,
+ &mUserManagerGuid,
+ 0,
+ NULL,
+ NULL
+ );
+
+ if (mIdentified) {
+ *User = (USER_PROFILE_ENTRY *) mCurrentUser;
+ UpdateUserInfo (*User);
+ return EFI_SUCCESS;
+ }
+
+ return EFI_ACCESS_DENIED;
+}
+
+
+/**
+ An empty function to pass error checking of CreateEventEx ().
+
+ @param Event Event whose notification function is being invoked.
+ @param Context Pointer to the notification function's context,
+ which is implementation-dependent.
+
+**/
+VOID
+EFIAPI
+InternalEmptyFuntion (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+}
+
+
+/**
+ Create, Signal, and Close the User Profile Changed event.
+
+**/
+VOID
+SignalEventUserProfileChanged (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_EVENT Event;
+
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ InternalEmptyFuntion,
+ NULL,
+ &gEfiEventUserProfileChangedGuid,
+ &Event
+ );
+ ASSERT_EFI_ERROR (Status);
+ gBS->SignalEvent (Event);
+ gBS->CloseEvent (Event);
+}
+
+
+/**
+ Create a new user profile.
+
+ This function creates a new user profile with only a new user identifier attached and returns
+ its handle. The user profile is non-volatile, but the handle User can change across reboots.
+
+ @param[in] This Points to this instance of the EFI_USER_MANAGER_PROTOCOL.
+ @param[out] User On return, points to the new user profile handle.
+ The user profile handle is unique only during this boot.
+
+ @retval EFI_SUCCESS User profile was successfully created.
+ @retval EFI_ACCESS_DENIED Current user does not have sufficient permissions to create a
+ user profile.
+ @retval EFI_UNSUPPORTED Creation of new user profiles is not supported.
+ @retval EFI_INVALID_PARAMETER The User parameter is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+UserProfileCreate (
+ IN CONST EFI_USER_MANAGER_PROTOCOL *This,
+ OUT EFI_USER_PROFILE_HANDLE *User
+ )
+{
+ EFI_STATUS Status;
+
+ if ((This == NULL) || (User == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check the right of the current user.
+ //
+ if (!CheckCurrentUserAccessRight (EFI_USER_INFO_ACCESS_MANAGE)) {
+ if (!CheckCurrentUserAccessRight (EFI_USER_INFO_ACCESS_ENROLL_OTHERS)) {
+ return EFI_ACCESS_DENIED;
+ }
+ }
+
+ //
+ // Create new user profile
+ //
+ Status = CreateUserProfile ((USER_PROFILE_ENTRY **) User);
+ if (EFI_ERROR (Status)) {
+ return EFI_ACCESS_DENIED;
+ }
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Delete an existing user profile.
+
+ @param[in] This Points to this instance of the EFI_USER_MANAGER_PROTOCOL.
+ @param[in] User User profile handle.
+
+ @retval EFI_SUCCESS User profile was successfully deleted.
+ @retval EFI_ACCESS_DENIED Current user does not have sufficient permissions to delete a user
+ profile or there is only one user profile.
+ @retval EFI_UNSUPPORTED Deletion of new user profiles is not supported.
+ @retval EFI_INVALID_PARAMETER User does not refer to a valid user profile.
+
+**/
+EFI_STATUS
+EFIAPI
+UserProfileDelete (
+ IN CONST EFI_USER_MANAGER_PROTOCOL *This,
+ IN EFI_USER_PROFILE_HANDLE User
+ )
+{
+ EFI_STATUS Status;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check the right of the current user.
+ //
+ if (!CheckCurrentUserAccessRight (EFI_USER_INFO_ACCESS_MANAGE)) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ //
+ // Delete user profile.
+ //
+ Status = DelUserProfile (User);
+ if (EFI_ERROR (Status)) {
+ if (Status != EFI_INVALID_PARAMETER) {
+ return EFI_ACCESS_DENIED;
+ }
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Enumerate all of the enrolled users on the platform.
+
+ This function returns the next enrolled user profile. To retrieve the first user profile handle,
+ point User at a NULL. Each subsequent call will retrieve another user profile handle until there
+ are no more, at which point User will point to NULL.
+
+ @param[in] This Points to this instance of the EFI_USER_MANAGER_PROTOCOL.
+ @param[in, out] User On entry, points to the previous user profile handle or NULL to
+ start enumeration. On exit, points to the next user profile handle
+ or NULL if there are no more user profiles.
+
+ @retval EFI_SUCCESS Next enrolled user profile successfully returned.
+ @retval EFI_ACCESS_DENIED Next enrolled user profile was not successfully returned.
+ @retval EFI_INVALID_PARAMETER The User parameter is NULL.
+**/
+EFI_STATUS
+EFIAPI
+UserProfileGetNext (
+ IN CONST EFI_USER_MANAGER_PROTOCOL *This,
+ IN OUT EFI_USER_PROFILE_HANDLE *User
+ )
+{
+ EFI_STATUS Status;
+
+ if ((This == NULL) || (User == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = FindUserProfile ((USER_PROFILE_ENTRY **) User, TRUE, NULL);
+ if (EFI_ERROR (Status)) {
+ return EFI_ACCESS_DENIED;
+ }
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Return the current user profile handle.
+
+ @param[in] This Points to this instance of the EFI_USER_MANAGER_PROTOCOL.
+ @param[out] CurrentUser On return, points to the current user profile handle.
+
+ @retval EFI_SUCCESS Current user profile handle returned successfully.
+ @retval EFI_INVALID_PARAMETER The CurrentUser parameter is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+UserProfileCurrent (
+ IN CONST EFI_USER_MANAGER_PROTOCOL *This,
+ OUT EFI_USER_PROFILE_HANDLE *CurrentUser
+ )
+{
+ //
+ // Get current user profile.
+ //
+ if ((This == NULL) || (CurrentUser == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *CurrentUser = mCurrentUser;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Identify a user.
+
+ Identify the user and, if authenticated, returns the user handle and changes the current
+ user profile. All user information marked as private in a previously selected profile
+ is no longer available for inspection.
+ Whenever the current user profile is changed then the an event with the GUID
+ EFI_EVENT_GROUP_USER_PROFILE_CHANGED is signaled.
+
+ @param[in] This Points to this instance of the EFI_USER_MANAGER_PROTOCOL.
+ @param[out] User On return, points to the user profile handle for the current
+ user profile.
+
+ @retval EFI_SUCCESS User was successfully identified.
+ @retval EFI_ACCESS_DENIED User was not successfully identified.
+ @retval EFI_INVALID_PARAMETER The User parameter is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+UserProfileIdentify (
+ IN CONST EFI_USER_MANAGER_PROTOCOL *This,
+ OUT EFI_USER_PROFILE_HANDLE *User
+ )
+{
+ EFI_STATUS Status;
+
+ if ((This == NULL) || (User == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (mCurrentUser != NULL) {
+ *User = mCurrentUser;
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Identify user
+ //
+ Status = IdentifyUser ((USER_PROFILE_ENTRY **) User);
+ if (EFI_ERROR (Status)) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ //
+ // Publish the user info into the EFI system configuration table.
+ //
+ PublishUserTable ();
+
+ //
+ // Signal User Profile Changed event.
+ //
+ SignalEventUserProfileChanged ();
+ return EFI_SUCCESS;
+}
+
+/**
+ Find a user using a user information record.
+
+ This function searches all user profiles for the specified user information record.
+ The search starts with the user information record handle following UserInfo and
+ continues until either the information is found or there are no more user profiles.
+ A match occurs when the Info.InfoType field matches the user information record
+ type and the user information record data matches the portion of Info.
+
+ @param[in] This Points to this instance of the EFI_USER_MANAGER_PROTOCOL.
+ @param[in, out] User On entry, points to the previously returned user profile
+ handle, or NULL to start searching with the first user profile.
+ On return, points to the user profile handle, or NULL if not
+ found.
+ @param[in, out] UserInfo On entry, points to the previously returned user information
+ handle, or NULL to start searching with the first. On return,
+ points to the user information handle of the user information
+ record, or NULL if not found. Can be NULL, in which case only
+ one user information record per user can be returned.
+ @param[in] Info Points to the buffer containing the user information to be
+ compared to the user information record. If the user information
+ record data is empty, then only the user information record type
+ is compared. If InfoSize is 0, then the user information record
+ must be empty.
+
+ @param[in] InfoSize The size of Info, in bytes.
+
+ @retval EFI_SUCCESS User information was found. User points to the user profile
+ handle, and UserInfo points to the user information handle.
+ @retval EFI_NOT_FOUND User information was not found. User points to NULL, and
+ UserInfo points to NULL.
+ @retval EFI_INVALID_PARAMETER User is NULL. Or Info is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+UserProfileFind (
+ IN CONST EFI_USER_MANAGER_PROTOCOL *This,
+ IN OUT EFI_USER_PROFILE_HANDLE *User,
+ IN OUT EFI_USER_INFO_HANDLE *UserInfo OPTIONAL,
+ IN CONST EFI_USER_INFO *Info,
+ IN UINTN InfoSize
+ )
+{
+ EFI_STATUS Status;
+ UINTN Size;
+
+ if ((This == NULL) || (User == NULL) || (Info == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (InfoSize == 0) {
+ //
+ // If InfoSize is 0, then the user information record must be empty.
+ //
+ if (Info->InfoSize != sizeof (EFI_USER_INFO)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ } else {
+ if (InfoSize != Info->InfoSize) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ Size = Info->InfoSize;
+
+ //
+ // Find user profile accdoring to user information.
+ //
+ Status = FindUserProfileByInfo (
+ (USER_PROFILE_ENTRY **) User,
+ (EFI_USER_INFO **) UserInfo,
+ (EFI_USER_INFO *) Info,
+ Size
+ );
+ if (EFI_ERROR (Status)) {
+ *User = NULL;
+ if (UserInfo != NULL) {
+ *UserInfo = NULL;
+ }
+ return EFI_NOT_FOUND;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Return information attached to the user.
+
+ This function returns user information. The format of the information is described in User
+ Information. The function may return EFI_ACCESS_DENIED if the information is marked private
+ and the handle specified by User is not the current user profile. The function may return
+ EFI_ACCESS_DENIED if the information is marked protected and the information is associated
+ with a credential provider for which the user has not been authenticated.
+
+ @param[in] This Points to this instance of the EFI_USER_MANAGER_PROTOCOL.
+ @param[in] User Handle of the user whose profile will be retrieved.
+ @param[in] UserInfo Handle of the user information data record.
+ @param[out] Info On entry, points to a buffer of at least *InfoSize bytes. On exit,
+ holds the user information. If the buffer is too small to hold the
+ information, then EFI_BUFFER_TOO_SMALL is returned and InfoSize is
+ updated to contain the number of bytes actually required.
+ @param[in, out] InfoSize On entry, points to the size of Info. On return, points to the size
+ of the user information.
+
+ @retval EFI_SUCCESS Information returned successfully.
+ @retval EFI_ACCESS_DENIED The information about the specified user cannot be accessed by the
+ current user.
+ @retval EFI_BUFFER_TOO_SMALL The number of bytes specified by *InfoSize is too small to hold the
+ returned data. The actual size required is returned in *InfoSize.
+ @retval EFI_NOT_FOUND User does not refer to a valid user profile or UserInfo does not refer
+ to a valid user info handle.
+ @retval EFI_INVALID_PARAMETER Info is NULL or InfoSize is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+UserProfileGetInfo (
+ IN CONST EFI_USER_MANAGER_PROTOCOL *This,
+ IN EFI_USER_PROFILE_HANDLE User,
+ IN EFI_USER_INFO_HANDLE UserInfo,
+ OUT EFI_USER_INFO *Info,
+ IN OUT UINTN *InfoSize
+ )
+{
+ EFI_STATUS Status;
+
+ if ((This == NULL) || (InfoSize == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((*InfoSize != 0) && (Info == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((User == NULL) || (UserInfo == NULL)) {
+ return EFI_NOT_FOUND;
+ }
+
+ Status = GetUserInfo (User, UserInfo, Info, InfoSize, TRUE);
+ if (EFI_ERROR (Status)) {
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ return EFI_BUFFER_TOO_SMALL;
+ }
+ return EFI_ACCESS_DENIED;
+ }
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Add or update user information.
+
+ This function changes user information. If NULL is pointed to by UserInfo, then a new user
+ information record is created and its handle is returned in UserInfo. Otherwise, the existing
+ one is replaced.
+ If EFI_USER_INFO_EXCLUSIVE is specified in Info and a user information record of the same
+ type already exists in the user profile, then EFI_ACCESS_DENIED will be returned and UserInfo
+ will point to the handle of the existing record.
+
+ @param[in] This Points to this instance of the EFI_USER_MANAGER_PROTOCOL.
+ @param[in] User Handle of the user whose profile will be retrieved.
+ @param[in, out] UserInfo Handle of the user information data record.
+ @param[in] Info On entry, points to a buffer of at least *InfoSize bytes. On exit,
+ holds the user information. If the buffer is too small to hold the
+ information, then EFI_BUFFER_TOO_SMALL is returned and InfoSize is
+ updated to contain the number of bytes actually required.
+ @param[in] InfoSize On entry, points to the size of Info. On return, points to the size
+ of the user information.
+
+ @retval EFI_SUCCESS Information returned successfully.
+ @retval EFI_ACCESS_DENIED The record is exclusive.
+ @retval EFI_SECURITY_VIOLATION The current user does not have permission to change the specified
+ user profile or user information record.
+ @retval EFI_NOT_FOUND User does not refer to a valid user profile or UserInfo does not
+ refer to a valid user info handle.
+ @retval EFI_INVALID_PARAMETER UserInfo is NULL or Info is NULL.
+**/
+EFI_STATUS
+EFIAPI
+UserProfileSetInfo (
+ IN CONST EFI_USER_MANAGER_PROTOCOL *This,
+ IN EFI_USER_PROFILE_HANDLE User,
+ IN OUT EFI_USER_INFO_HANDLE *UserInfo,
+ IN CONST EFI_USER_INFO *Info,
+ IN UINTN InfoSize
+ )
+{
+ EFI_STATUS Status;
+
+ if ((This == NULL) || (User == NULL) || (UserInfo == NULL) || (Info == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check the right of the current user.
+ //
+ if (User != mCurrentUser) {
+ if (!CheckCurrentUserAccessRight (EFI_USER_INFO_ACCESS_MANAGE)) {
+ if (*UserInfo != NULL) {
+ //
+ // Can't update info in other profiles without MANAGE right.
+ //
+ return EFI_SECURITY_VIOLATION;
+ }
+
+ if (!CheckCurrentUserAccessRight (EFI_USER_INFO_ACCESS_ENROLL_OTHERS)) {
+ //
+ // Can't add info into other profiles.
+ //
+ return EFI_SECURITY_VIOLATION;
+ }
+ }
+ }
+
+ if (User == mCurrentUser) {
+ if (CheckCurrentUserAccessRight (EFI_USER_INFO_ACCESS_ENROLL_SELF)) {
+ //
+ // Only identify policy can be added/updated.
+ //
+ if (Info->InfoType != EFI_USER_INFO_IDENTITY_POLICY_RECORD) {
+ return EFI_SECURITY_VIOLATION;
+ }
+ }
+ }
+
+ //
+ // Modify user information.
+ //
+ Status = ModifyUserInfo (User, (EFI_USER_INFO **) UserInfo, Info, InfoSize);
+ if (EFI_ERROR (Status)) {
+ if (Status == EFI_ACCESS_DENIED) {
+ return EFI_ACCESS_DENIED;
+ }
+ return EFI_SECURITY_VIOLATION;
+ }
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Called by credential provider to notify of information change.
+
+ This function allows the credential provider to notify the User Identity Manager when user status
+ has changed while deselected.
+ If the User Identity Manager doesn't support asynchronous changes in credentials, then this function
+ should return EFI_UNSUPPORTED.
+ If the User Identity Manager supports this, it will call User() to get the user identifier and then
+ GetNextInfo() and GetInfo() in the User Credential Protocol to get all of the information from the
+ credential and add it.
+
+ @param[in] This Points to this instance of the EFI_USER_MANAGER_PROTOCOL.
+ @param[in] Changed Handle on which is installed an instance of the EFI_USER_CREDENTIAL_PROTOCOL
+ where the user has changed.
+
+ @retval EFI_SUCCESS The User Identity Manager has handled the notification.
+ @retval EFI_NOT_READY The function was called while the specified credential provider was not selected.
+ @retval EFI_UNSUPPORTED The User Identity Manager doesn't support asynchronous notifications.
+
+**/
+EFI_STATUS
+EFIAPI
+UserProfileNotify (
+ IN CONST EFI_USER_MANAGER_PROTOCOL *This,
+ IN EFI_HANDLE Changed
+ )
+{
+ EFI_STATUS Status;
+ EFI_USER_CREDENTIAL_PROTOCOL *Provider;
+ EFI_USER_INFO_IDENTIFIER UserId;
+ EFI_USER_INFO_HANDLE UserInfo;
+ EFI_USER_INFO_HANDLE UserInfo2;
+ UINTN InfoSize;
+ EFI_USER_INFO *Info;
+ USER_PROFILE_ENTRY *User;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = gBS->HandleProtocol (
+ Changed,
+ &gEfiUserCredentialProtocolGuid,
+ (VOID **) &Provider
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = Provider->User (Provider, NULL, &UserId);
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_READY;
+ }
+
+ //
+ // Find user with the UserId.
+ //
+ User = NULL;
+ while (TRUE) {
+ //
+ // Find next user profile.
+ //
+ Status = FindUserProfile (&User, TRUE, NULL);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Find the user information.
+ //
+ Info = NULL;
+ FindUserInfoByType (User, &Info, EFI_USER_INFO_IDENTIFIER_RECORD);
+ if (CompareMem ((UINT8 *) (Info + 1), UserId, sizeof (UserId)) == 0) {
+ //
+ // Found the infomation record.
+ //
+ break;
+ }
+ }
+
+ UserInfo = NULL;
+ do {
+ //
+ // Get user info handle.
+ //
+ Status = Provider->GetNextInfo(Provider, &UserInfo);
+ if (EFI_ERROR (Status)) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Get the user information from the user info handle.
+ //
+ InfoSize = 0;
+ Status = Provider->GetInfo(Provider, UserInfo, NULL, &InfoSize);
+ if (EFI_ERROR (Status)) {
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ Info = AllocateZeroPool (InfoSize);
+ if (Info == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Status = Provider->GetInfo(Provider, UserInfo, Info, &InfoSize);
+ if (EFI_ERROR (Status)) {
+ FreePool (Info);
+ break;
+ }
+ }
+ break;
+ }
+
+ //
+ // Save the user information.
+ //
+ UserInfo2 = NULL;
+ Status = UserProfileSetInfo (&gUserIdentifyManager, (EFI_USER_PROFILE_HANDLE)User, &UserInfo2, Info, InfoSize);
+ FreePool (Info);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ } while (TRUE);
+
+ return Status;
+}
+
+
+/**
+ Delete user information.
+
+ Delete the user information attached to the user profile specified by the UserInfo.
+
+ @param[in] This Points to this instance of the EFI_USER_MANAGER_PROTOCOL.
+ @param[in] User Handle of the user whose information will be deleted.
+ @param[in] UserInfo Handle of the user information to remove.
+
+ @retval EFI_SUCCESS User information deleted successfully.
+ @retval EFI_NOT_FOUND User information record UserInfo does not exist in the user profile.
+ @retval EFI_ACCESS_DENIED The current user does not have permission to delete this user information.
+
+**/
+EFI_STATUS
+EFIAPI
+UserProfileDeleteInfo (
+ IN CONST EFI_USER_MANAGER_PROTOCOL *This,
+ IN EFI_USER_PROFILE_HANDLE User,
+ IN EFI_USER_INFO_HANDLE UserInfo
+ )
+{
+ EFI_STATUS Status;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check the right of the current user.
+ //
+ if (User != mCurrentUser) {
+ if (!CheckCurrentUserAccessRight (EFI_USER_INFO_ACCESS_MANAGE)) {
+ return EFI_ACCESS_DENIED;
+ }
+ }
+
+ //
+ // Delete user information.
+ //
+ Status = DelUserInfo (User, UserInfo, TRUE);
+ if (EFI_ERROR (Status)) {
+ if (Status == EFI_NOT_FOUND) {
+ return EFI_NOT_FOUND;
+ }
+ return EFI_ACCESS_DENIED;
+ }
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Enumerate user information of all the enrolled users on the platform.
+
+ This function returns the next user information record. To retrieve the first user
+ information record handle, point UserInfo at a NULL. Each subsequent call will retrieve
+ another user information record handle until there are no more, at which point UserInfo
+ will point to NULL.
+
+ @param[in] This Points to this instance of the EFI_USER_MANAGER_PROTOCOL.
+ @param[in] User Handle of the user whose information will be deleted.
+ @param[in, out] UserInfo Handle of the user information to remove.
+
+ @retval EFI_SUCCESS User information returned.
+ @retval EFI_NOT_FOUND No more user information found.
+ @retval EFI_INVALID_PARAMETER UserInfo is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+UserProfileGetNextInfo (
+ IN CONST EFI_USER_MANAGER_PROTOCOL *This,
+ IN EFI_USER_PROFILE_HANDLE User,
+ IN OUT EFI_USER_INFO_HANDLE *UserInfo
+ )
+{
+ if ((This == NULL) || (UserInfo == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Get next user information entry.
+ //
+ return FindUserInfo (User, (EFI_USER_INFO **) UserInfo, TRUE, NULL);
+}
+
+
+/**
+ Main entry for this driver.
+
+ @param[in] ImageHandle Image handle this driver.
+ @param[in] SystemTable Pointer to SystemTable.
+
+ @retval EFI_SUCESS This function always complete successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+UserIdentifyManagerInit (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+
+ EFI_STATUS Status;
+
+ //
+ // Initiate form browser.
+ //
+ InitFormBrowser ();
+
+ //
+ // Install protocol interfaces for the User Identity Manager.
+ //
+ Status = gBS->InstallProtocolInterface (
+ &mCallbackInfo->DriverHandle,
+ &gEfiUserManagerProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &gUserIdentifyManager
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ LoadDeferredImageInit (ImageHandle);
+ return EFI_SUCCESS;
+}
+
+
diff --git a/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManager.h b/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManager.h
new file mode 100644
index 0000000000..b1e078a03e
--- /dev/null
+++ b/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManager.h
@@ -0,0 +1,413 @@
+/** @file
+ The header file for User identify Manager driver.
+
+Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _USER_IDENTIFY_MANAGER_H_
+#define _USER_IDENTIFY_MANAGER_H_
+
+#include
+
+#include
+#include