summaryrefslogtreecommitdiff
path: root/Core
diff options
context:
space:
mode:
Diffstat (limited to 'Core')
-rw-r--r--Core/SecurityPkg/Application/RngTest/RngTest.c234
-rw-r--r--Core/SecurityPkg/Application/RngTest/RngTest.inf57
-rw-r--r--Core/SecurityPkg/Application/RngTest/RngTest.uni23
-rw-r--r--Core/SecurityPkg/Application/RngTest/RngTestExtra.uni18
-rw-r--r--Core/SecurityPkg/Contributions.txt218
-rw-r--r--Core/SecurityPkg/Hash2DxeCrypto/Driver.c242
-rw-r--r--Core/SecurityPkg/Hash2DxeCrypto/Driver.h132
-rw-r--r--Core/SecurityPkg/Hash2DxeCrypto/Hash2DxeCrypto.c618
-rw-r--r--Core/SecurityPkg/Hash2DxeCrypto/Hash2DxeCrypto.inf64
-rw-r--r--Core/SecurityPkg/Hash2DxeCrypto/Hash2DxeCrypto.uni22
-rw-r--r--Core/SecurityPkg/Hash2DxeCrypto/Hash2DxeCryptoExtra.uni19
-rw-r--r--Core/SecurityPkg/Include/Guid/AuthenticatedVariableFormat.h75
-rw-r--r--Core/SecurityPkg/Include/Guid/MeasuredFvHob.h36
-rw-r--r--Core/SecurityPkg/Include/Guid/OpalPasswordExtraInfoVariable.h27
-rw-r--r--Core/SecurityPkg/Include/Guid/PhysicalPresenceData.h81
-rw-r--r--Core/SecurityPkg/Include/Guid/PwdCredentialProviderHii.h29
-rw-r--r--Core/SecurityPkg/Include/Guid/SecureBootConfigHii.h26
-rw-r--r--Core/SecurityPkg/Include/Guid/SecurityPkgTokenSpace.h25
-rw-r--r--Core/SecurityPkg/Include/Guid/Tcg2ConfigHii.h25
-rw-r--r--Core/SecurityPkg/Include/Guid/Tcg2PhysicalPresenceData.h47
-rw-r--r--Core/SecurityPkg/Include/Guid/TcgConfigHii.h25
-rw-r--r--Core/SecurityPkg/Include/Guid/TcgEventHob.h58
-rw-r--r--Core/SecurityPkg/Include/Guid/TpmInstance.h38
-rw-r--r--Core/SecurityPkg/Include/Guid/TrEEConfigHii.h25
-rw-r--r--Core/SecurityPkg/Include/Guid/TrEEPhysicalPresenceData.h67
-rw-r--r--Core/SecurityPkg/Include/Guid/UsbCredentialProviderHii.h29
-rw-r--r--Core/SecurityPkg/Include/Guid/UserIdentifyManagerHii.h25
-rw-r--r--Core/SecurityPkg/Include/Guid/UserProfileManagerHii.h25
-rw-r--r--Core/SecurityPkg/Include/Library/HashLib.h169
-rw-r--r--Core/SecurityPkg/Include/Library/OpalPasswordSupportLib.h289
-rw-r--r--Core/SecurityPkg/Include/Library/PlatformSecureLib.h42
-rw-r--r--Core/SecurityPkg/Include/Library/Tcg2PhysicalPresenceLib.h187
-rw-r--r--Core/SecurityPkg/Include/Library/Tcg2PpVendorLib.h129
-rw-r--r--Core/SecurityPkg/Include/Library/TcgPhysicalPresenceLib.h54
-rw-r--r--Core/SecurityPkg/Include/Library/TcgPpVendorLib.h159
-rw-r--r--Core/SecurityPkg/Include/Library/TcgStorageCoreLib.h1310
-rw-r--r--Core/SecurityPkg/Include/Library/TcgStorageOpalLib.h837
-rw-r--r--Core/SecurityPkg/Include/Library/Tpm12CommandLib.h225
-rw-r--r--Core/SecurityPkg/Include/Library/Tpm12DeviceLib.h54
-rw-r--r--Core/SecurityPkg/Include/Library/Tpm2CommandLib.h1106
-rw-r--r--Core/SecurityPkg/Include/Library/Tpm2DeviceLib.h109
-rw-r--r--Core/SecurityPkg/Include/Library/TpmCommLib.h287
-rw-r--r--Core/SecurityPkg/Include/Library/TrEEPhysicalPresenceLib.h57
-rw-r--r--Core/SecurityPkg/Include/Library/TrEEPpVendorLib.h164
-rw-r--r--Core/SecurityPkg/Include/Ppi/FirmwareVolumeInfoMeasurementExcluded.h37
-rw-r--r--Core/SecurityPkg/Include/Ppi/LockPhysicalPresence.h60
-rw-r--r--Core/SecurityPkg/Include/Ppi/TpmInitialized.h40
-rw-r--r--Core/SecurityPkg/Library/AuthVariableLib/AuthService.c2626
-rw-r--r--Core/SecurityPkg/Library/AuthVariableLib/AuthServiceInternal.h436
-rw-r--r--Core/SecurityPkg/Library/AuthVariableLib/AuthVariableLib.c492
-rw-r--r--Core/SecurityPkg/Library/AuthVariableLib/AuthVariableLib.inf92
-rw-r--r--Core/SecurityPkg/Library/AuthVariableLib/AuthVariableLib.uni21
-rw-r--r--Core/SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.c933
-rw-r--r--Core/SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.h105
-rw-r--r--Core/SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.inf68
-rw-r--r--Core/SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.uni23
-rw-r--r--Core/SecurityPkg/Library/DxeImageAuthenticationStatusLib/DxeImageAuthenticationStatusLib.c76
-rw-r--r--Core/SecurityPkg/Library/DxeImageAuthenticationStatusLib/DxeImageAuthenticationStatusLib.inf40
-rw-r--r--Core/SecurityPkg/Library/DxeImageAuthenticationStatusLib/DxeImageAuthenticationStatusLib.uni21
-rw-r--r--Core/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c1999
-rw-r--r--Core/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.h207
-rw-r--r--Core/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.inf100
-rw-r--r--Core/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.uni26
-rw-r--r--Core/SecurityPkg/Library/DxeImageVerificationLib/Measurement.c321
-rw-r--r--Core/SecurityPkg/Library/DxeRsa2048Sha256GuidedSectionExtractLib/DxeRsa2048Sha256GuidedSectionExtractLib.c402
-rw-r--r--Core/SecurityPkg/Library/DxeRsa2048Sha256GuidedSectionExtractLib/DxeRsa2048Sha256GuidedSectionExtractLib.inf62
-rw-r--r--Core/SecurityPkg/Library/DxeRsa2048Sha256GuidedSectionExtractLib/DxeRsa2048Sha256GuidedSectionExtractLib.uni24
-rw-r--r--Core/SecurityPkg/Library/DxeTcg2PhysicalPresenceLib/DxeTcg2PhysicalPresenceLib.c1228
-rw-r--r--Core/SecurityPkg/Library/DxeTcg2PhysicalPresenceLib/DxeTcg2PhysicalPresenceLib.inf72
-rw-r--r--Core/SecurityPkg/Library/DxeTcg2PhysicalPresenceLib/DxeTcg2PhysicalPresenceLib.uni27
-rw-r--r--Core/SecurityPkg/Library/DxeTcg2PhysicalPresenceLib/PhysicalPresenceStrings.uni61
-rw-r--r--Core/SecurityPkg/Library/DxeTcgPhysicalPresenceLib/DxeTcgPhysicalPresenceLib.c1393
-rw-r--r--Core/SecurityPkg/Library/DxeTcgPhysicalPresenceLib/DxeTcgPhysicalPresenceLib.inf69
-rw-r--r--Core/SecurityPkg/Library/DxeTcgPhysicalPresenceLib/DxeTcgPhysicalPresenceLib.uni27
-rw-r--r--Core/SecurityPkg/Library/DxeTcgPhysicalPresenceLib/PhysicalPresenceStrings.uni52
-rw-r--r--Core/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c702
-rw-r--r--Core/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.inf67
-rw-r--r--Core/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.uni27
-rw-r--r--Core/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c1011
-rw-r--r--Core/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.inf67
-rw-r--r--Core/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.uni27
-rw-r--r--Core/SecurityPkg/Library/DxeTpmMeasurementLib/DxeTpmMeasurementLib.c212
-rw-r--r--Core/SecurityPkg/Library/DxeTpmMeasurementLib/DxeTpmMeasurementLib.inf49
-rw-r--r--Core/SecurityPkg/Library/DxeTpmMeasurementLib/DxeTpmMeasurementLib.uni22
-rw-r--r--Core/SecurityPkg/Library/DxeTrEEPhysicalPresenceLib/DxeTrEEPhysicalPresenceLib.c743
-rw-r--r--Core/SecurityPkg/Library/DxeTrEEPhysicalPresenceLib/DxeTrEEPhysicalPresenceLib.inf69
-rw-r--r--Core/SecurityPkg/Library/DxeTrEEPhysicalPresenceLib/DxeTrEEPhysicalPresenceLib.uni27
-rw-r--r--Core/SecurityPkg/Library/DxeTrEEPhysicalPresenceLib/PhysicalPresenceStrings.uni29
-rw-r--r--Core/SecurityPkg/Library/FmpAuthenticationLibPkcs7/FmpAuthenticationLibPkcs7.c222
-rw-r--r--Core/SecurityPkg/Library/FmpAuthenticationLibPkcs7/FmpAuthenticationLibPkcs7.inf49
-rw-r--r--Core/SecurityPkg/Library/FmpAuthenticationLibPkcs7/FmpAuthenticationLibPkcs7.uni26
-rw-r--r--Core/SecurityPkg/Library/FmpAuthenticationLibRsa2048Sha256/FmpAuthenticationLibRsa2048Sha256.c360
-rw-r--r--Core/SecurityPkg/Library/FmpAuthenticationLibRsa2048Sha256/FmpAuthenticationLibRsa2048Sha256.inf53
-rw-r--r--Core/SecurityPkg/Library/FmpAuthenticationLibRsa2048Sha256/FmpAuthenticationLibRsa2048Sha256.uni26
-rw-r--r--Core/SecurityPkg/Library/HashInstanceLibSha1/HashInstanceLibSha1.c155
-rw-r--r--Core/SecurityPkg/Library/HashInstanceLibSha1/HashInstanceLibSha1.inf46
-rw-r--r--Core/SecurityPkg/Library/HashInstanceLibSha1/HashInstanceLibSha1.uni21
-rw-r--r--Core/SecurityPkg/Library/HashInstanceLibSha256/HashInstanceLibSha256.c155
-rw-r--r--Core/SecurityPkg/Library/HashInstanceLibSha256/HashInstanceLibSha256.inf46
-rw-r--r--Core/SecurityPkg/Library/HashInstanceLibSha256/HashInstanceLibSha256.uni21
-rw-r--r--Core/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterCommon.c77
-rw-r--r--Core/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterCommon.h44
-rw-r--r--Core/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterDxe.c306
-rw-r--r--Core/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterDxe.inf56
-rw-r--r--Core/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterDxe.uni23
-rw-r--r--Core/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterPei.c437
-rw-r--r--Core/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterPei.inf62
-rw-r--r--Core/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterPei.uni23
-rw-r--r--Core/SecurityPkg/Library/HashLibTpm2/HashLibTpm2.c342
-rw-r--r--Core/SecurityPkg/Library/HashLibTpm2/HashLibTpm2.inf49
-rw-r--r--Core/SecurityPkg/Library/HashLibTpm2/HashLibTpm2.uni22
-rw-r--r--Core/SecurityPkg/Library/OpalPasswordSupportLib/OpalPasswordSupportLib.c781
-rw-r--r--Core/SecurityPkg/Library/OpalPasswordSupportLib/OpalPasswordSupportLib.inf55
-rw-r--r--Core/SecurityPkg/Library/OpalPasswordSupportLib/OpalPasswordSupportNotify.h56
-rw-r--r--Core/SecurityPkg/Library/PeiRsa2048Sha256GuidedSectionExtractLib/PeiRsa2048Sha256GuidedSectionExtractLib.c387
-rw-r--r--Core/SecurityPkg/Library/PeiRsa2048Sha256GuidedSectionExtractLib/PeiRsa2048Sha256GuidedSectionExtractLib.inf58
-rw-r--r--Core/SecurityPkg/Library/PeiRsa2048Sha256GuidedSectionExtractLib/PeiRsa2048Sha256GuidedSectionExtractLib.uni24
-rw-r--r--Core/SecurityPkg/Library/PeiTcg2PhysicalPresenceLib/PeiTcg2PhysicalPresenceLib.c59
-rw-r--r--Core/SecurityPkg/Library/PeiTcg2PhysicalPresenceLib/PeiTcg2PhysicalPresenceLib.inf52
-rw-r--r--Core/SecurityPkg/Library/PeiTcg2PhysicalPresenceLib/PeiTcg2PhysicalPresenceLib.uni21
-rw-r--r--Core/SecurityPkg/Library/PlatformSecureLibNull/PlatformSecureLibNull.c67
-rw-r--r--Core/SecurityPkg/Library/PlatformSecureLibNull/PlatformSecureLibNull.inf44
-rw-r--r--Core/SecurityPkg/Library/PlatformSecureLibNull/PlatformSecureLibNull.uni24
-rw-r--r--Core/SecurityPkg/Library/SmmTcg2PhysicalPresenceLib/SmmTcg2PhysicalPresenceLib.c387
-rw-r--r--Core/SecurityPkg/Library/SmmTcg2PhysicalPresenceLib/SmmTcg2PhysicalPresenceLib.inf57
-rw-r--r--Core/SecurityPkg/Library/SmmTcg2PhysicalPresenceLib/SmmTcg2PhysicalPresenceLib.uni26
-rw-r--r--Core/SecurityPkg/Library/Tcg2PpVendorLibNull/Tcg2PpVendorLibNull.c133
-rw-r--r--Core/SecurityPkg/Library/Tcg2PpVendorLibNull/Tcg2PpVendorLibNull.inf37
-rw-r--r--Core/SecurityPkg/Library/Tcg2PpVendorLibNull/Tcg2PpVendorLibNull.uni18
-rw-r--r--Core/SecurityPkg/Library/TcgPpVendorLibNull/TcgPpVendorLibNull.c129
-rw-r--r--Core/SecurityPkg/Library/TcgPpVendorLibNull/TcgPpVendorLibNull.inf37
-rw-r--r--Core/SecurityPkg/Library/TcgPpVendorLibNull/TcgPpVendorLibNull.uni18
-rw-r--r--Core/SecurityPkg/Library/TcgStorageCoreLib/TcgStorageCore.c1652
-rw-r--r--Core/SecurityPkg/Library/TcgStorageCoreLib/TcgStorageCoreLib.inf38
-rw-r--r--Core/SecurityPkg/Library/TcgStorageCoreLib/TcgStorageUtil.c907
-rw-r--r--Core/SecurityPkg/Library/TcgStorageOpalLib/TcgStorageOpalCore.c1665
-rw-r--r--Core/SecurityPkg/Library/TcgStorageOpalLib/TcgStorageOpalLib.inf47
-rw-r--r--Core/SecurityPkg/Library/TcgStorageOpalLib/TcgStorageOpalUtil.c914
-rw-r--r--Core/SecurityPkg/Library/Tpm12CommandLib/Tpm12CommandLib.inf50
-rw-r--r--Core/SecurityPkg/Library/Tpm12CommandLib/Tpm12CommandLib.uni21
-rw-r--r--Core/SecurityPkg/Library/Tpm12CommandLib/Tpm12GetCapability.c137
-rw-r--r--Core/SecurityPkg/Library/Tpm12CommandLib/Tpm12NvStorage.c234
-rw-r--r--Core/SecurityPkg/Library/Tpm12CommandLib/Tpm12Ownership.c55
-rw-r--r--Core/SecurityPkg/Library/Tpm12CommandLib/Tpm12Pcr.c87
-rw-r--r--Core/SecurityPkg/Library/Tpm12CommandLib/Tpm12PhysicalPresence.c72
-rw-r--r--Core/SecurityPkg/Library/Tpm12CommandLib/Tpm12SelfTest.c60
-rw-r--r--Core/SecurityPkg/Library/Tpm12CommandLib/Tpm12Startup.c109
-rw-r--r--Core/SecurityPkg/Library/Tpm12DeviceLibDTpm/Tpm12DeviceLibDTpm.inf48
-rw-r--r--Core/SecurityPkg/Library/Tpm12DeviceLibDTpm/Tpm12DeviceLibDTpm.uni23
-rw-r--r--Core/SecurityPkg/Library/Tpm12DeviceLibDTpm/Tpm12Tis.c550
-rw-r--r--Core/SecurityPkg/Library/Tpm12DeviceLibTcg/Tpm12DeviceLibTcg.c108
-rw-r--r--Core/SecurityPkg/Library/Tpm12DeviceLibTcg/Tpm12DeviceLibTcg.inf46
-rw-r--r--Core/SecurityPkg/Library/Tpm12DeviceLibTcg/Tpm12DeviceLibTcg.uni22
-rw-r--r--Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2Capability.c833
-rw-r--r--Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2CommandLib.inf55
-rw-r--r--Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2CommandLib.uni21
-rw-r--r--Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2Context.c86
-rw-r--r--Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2DictionaryAttack.c219
-rw-r--r--Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2EnhancedAuthorization.c385
-rw-r--r--Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2Help.c341
-rw-r--r--Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2Hierarchy.c803
-rw-r--r--Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2Integrity.c671
-rw-r--r--Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2Miscellaneous.c122
-rw-r--r--Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2NVStorage.c1033
-rw-r--r--Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2Object.c346
-rw-r--r--Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2Sequences.c508
-rw-r--r--Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2Session.c169
-rw-r--r--Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2Startup.c127
-rw-r--r--Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2Test.c66
-rw-r--r--Core/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2DeviceLibDTpm.c116
-rw-r--r--Core/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2DeviceLibDTpm.inf51
-rw-r--r--Core/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2DeviceLibDTpm.uni24
-rw-r--r--Core/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2InstanceLibDTpm.c98
-rw-r--r--Core/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2InstanceLibDTpm.inf51
-rw-r--r--Core/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2InstanceLibDTpm.uni23
-rw-r--r--Core/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2Ptp.c537
-rw-r--r--Core/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2Tis.c418
-rw-r--r--Core/SecurityPkg/Library/Tpm2DeviceLibRouter/Tpm2DeviceLibRouterDxe.c98
-rw-r--r--Core/SecurityPkg/Library/Tpm2DeviceLibRouter/Tpm2DeviceLibRouterDxe.inf47
-rw-r--r--Core/SecurityPkg/Library/Tpm2DeviceLibRouter/Tpm2DeviceLibRouterDxe.uni23
-rw-r--r--Core/SecurityPkg/Library/Tpm2DeviceLibRouter/Tpm2DeviceLibRouterPei.c143
-rw-r--r--Core/SecurityPkg/Library/Tpm2DeviceLibRouter/Tpm2DeviceLibRouterPei.inf49
-rw-r--r--Core/SecurityPkg/Library/Tpm2DeviceLibRouter/Tpm2DeviceLibRouterPei.uni23
-rw-r--r--Core/SecurityPkg/Library/Tpm2DeviceLibTcg2/Tpm2DeviceLibTcg2.c125
-rw-r--r--Core/SecurityPkg/Library/Tpm2DeviceLibTcg2/Tpm2DeviceLibTcg2.inf46
-rw-r--r--Core/SecurityPkg/Library/Tpm2DeviceLibTcg2/Tpm2DeviceLibTcg2.uni22
-rw-r--r--Core/SecurityPkg/Library/Tpm2DeviceLibTrEE/Tpm2DeviceLibTrEE.c125
-rw-r--r--Core/SecurityPkg/Library/Tpm2DeviceLibTrEE/Tpm2DeviceLibTrEE.inf46
-rw-r--r--Core/SecurityPkg/Library/Tpm2DeviceLibTrEE/Tpm2DeviceLibTrEE.uni22
-rw-r--r--Core/SecurityPkg/Library/TpmCommLib/CommonHeader.h29
-rw-r--r--Core/SecurityPkg/Library/TpmCommLib/TisPc.c183
-rw-r--r--Core/SecurityPkg/Library/TpmCommLib/TpmComm.c50
-rw-r--r--Core/SecurityPkg/Library/TpmCommLib/TpmCommLib.inf50
-rw-r--r--Core/SecurityPkg/Library/TpmCommLib/TpmCommLib.uni22
-rw-r--r--Core/SecurityPkg/Library/TrEEPpVendorLibNull/TrEEPpVendorLibNull.c131
-rw-r--r--Core/SecurityPkg/Library/TrEEPpVendorLibNull/TrEEPpVendorLibNull.inf37
-rw-r--r--Core/SecurityPkg/Library/TrEEPpVendorLibNull/TrEEPpVendorLibNull.uni18
-rw-r--r--Core/SecurityPkg/License.txt25
-rw-r--r--Core/SecurityPkg/Pkcs7Verify/Pkcs7VerifyDxe/Pkcs7VerifyDxe.c1048
-rw-r--r--Core/SecurityPkg/Pkcs7Verify/Pkcs7VerifyDxe/Pkcs7VerifyDxe.inf70
-rw-r--r--Core/SecurityPkg/Pkcs7Verify/Pkcs7VerifyDxe/Pkcs7VerifyDxe.uni25
-rw-r--r--Core/SecurityPkg/Pkcs7Verify/Pkcs7VerifyDxe/Pkcs7VerifyDxeExtra.uni19
-rw-r--r--Core/SecurityPkg/RandomNumberGenerator/RngDxe/AesCore.c304
-rw-r--r--Core/SecurityPkg/RandomNumberGenerator/RngDxe/AesCore.h37
-rw-r--r--Core/SecurityPkg/RandomNumberGenerator/RngDxe/RdRand.c173
-rw-r--r--Core/SecurityPkg/RandomNumberGenerator/RngDxe/RdRand.h66
-rw-r--r--Core/SecurityPkg/RandomNumberGenerator/RngDxe/RngDxe.c212
-rw-r--r--Core/SecurityPkg/RandomNumberGenerator/RngDxe/RngDxe.inf72
-rw-r--r--Core/SecurityPkg/RandomNumberGenerator/RngDxe/RngDxe.uni27
-rw-r--r--Core/SecurityPkg/RandomNumberGenerator/RngDxe/RngDxeExtra.uni19
-rw-r--r--Core/SecurityPkg/SecurityPkg.dec473
-rw-r--r--Core/SecurityPkg/SecurityPkg.dsc338
-rw-r--r--Core/SecurityPkg/SecurityPkg.uni240
-rw-r--r--Core/SecurityPkg/SecurityPkgExtra.uni19
-rw-r--r--Core/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.c384
-rw-r--r--Core/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.h48
-rw-r--r--Core/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.inf67
-rw-r--r--Core/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.uni21
-rw-r--r--Core/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMorExtra.uni19
-rw-r--r--Core/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLock.c197
-rw-r--r--Core/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLock.h137
-rw-r--r--Core/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLock.uni21
-rw-r--r--Core/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLockExtra.uni19
-rw-r--r--Core/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLockSmm.c158
-rw-r--r--Core/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLockSmm.inf70
-rw-r--r--Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/ComponentName.c398
-rw-r--r--Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalDriver.c1091
-rw-r--r--Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalDriver.h412
-rw-r--r--Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalDriverPrivate.h102
-rw-r--r--Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalHii.c1483
-rw-r--r--Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalHii.h146
-rw-r--r--Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalHiiCallbacks.c221
-rw-r--r--Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalHiiFormStrings.uni103
-rw-r--r--Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalHiiFormValues.h120
-rw-r--r--Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalHiiPrivate.h268
-rw-r--r--Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalPasswordDxe.inf82
-rw-r--r--Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalPasswordForm.vfr350
-rw-r--r--Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalAhciMode.c1295
-rw-r--r--Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalAhciMode.h408
-rw-r--r--Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalIdeMode.c767
-rw-r--r--Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalIdeMode.h173
-rw-r--r--Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalNvmeMode.c2165
-rw-r--r--Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalNvmeMode.h456
-rw-r--r--Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalNvmeReg.h814
-rw-r--r--Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalPasswordSmm.c1139
-rw-r--r--Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalPasswordSmm.h300
-rw-r--r--Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalPasswordSmm.inf77
-rw-r--r--Core/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePei.c134
-rw-r--r--Core/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePei.inf64
-rw-r--r--Core/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePei.uni23
-rw-r--r--Core/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePeiExtra.uni19
-rw-r--r--Core/SecurityPkg/Tcg/Tcg2Config/Tcg2Config.vfr250
-rw-r--r--Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDriver.c461
-rw-r--r--Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDxe.inf91
-rw-r--r--Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDxe.uni22
-rw-r--r--Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDxeExtra.uni19
-rw-r--r--Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigImpl.c1032
-rw-r--r--Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigImpl.h201
-rw-r--r--Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigNvData.h129
-rw-r--r--Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPei.inf77
-rw-r--r--Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPei.uni23
-rw-r--r--Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPeiExtra.uni19
-rw-r--r--Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPeim.c159
-rw-r--r--Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigStrings.uni138
-rw-r--r--Core/SecurityPkg/Tcg/Tcg2Config/TpmDetection.c105
-rw-r--r--Core/SecurityPkg/Tcg/Tcg2Dxe/MeasureBootPeCoff.c427
-rw-r--r--Core/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c2621
-rw-r--r--Core/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.inf112
-rw-r--r--Core/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.uni26
-rw-r--r--Core/SecurityPkg/Tcg/Tcg2Dxe/Tcg2DxeExtra.uni17
-rw-r--r--Core/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.c854
-rw-r--r--Core/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.inf92
-rw-r--r--Core/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.uni21
-rw-r--r--Core/SecurityPkg/Tcg/Tcg2Pei/Tcg2PeiExtra.uni19
-rw-r--r--Core/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.c649
-rw-r--r--Core/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.h105
-rw-r--r--Core/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.inf86
-rw-r--r--Core/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.uni28
-rw-r--r--Core/SecurityPkg/Tcg/Tcg2Smm/Tcg2SmmExtra.uni19
-rw-r--r--Core/SecurityPkg/Tcg/Tcg2Smm/Tpm.asl368
-rw-r--r--Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfig.vfr74
-rw-r--r--Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDriver.c156
-rw-r--r--Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDxe.inf83
-rw-r--r--Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDxe.uni21
-rw-r--r--Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDxeExtra.uni19
-rw-r--r--Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigImpl.c509
-rw-r--r--Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigImpl.h194
-rw-r--r--Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigNvData.h39
-rw-r--r--Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigStrings.uni40
-rw-r--r--Core/SecurityPkg/Tcg/TcgDxe/TcgDxe.c1467
-rw-r--r--Core/SecurityPkg/Tcg/TcgDxe/TcgDxe.inf86
-rw-r--r--Core/SecurityPkg/Tcg/TcgDxe/TcgDxe.uni21
-rw-r--r--Core/SecurityPkg/Tcg/TcgDxe/TcgDxeExtra.uni19
-rw-r--r--Core/SecurityPkg/Tcg/TcgPei/TcgPei.c841
-rw-r--r--Core/SecurityPkg/Tcg/TcgPei/TcgPei.inf93
-rw-r--r--Core/SecurityPkg/Tcg/TcgPei/TcgPei.uni22
-rw-r--r--Core/SecurityPkg/Tcg/TcgPei/TcgPeiExtra.uni19
-rw-r--r--Core/SecurityPkg/Tcg/TcgSmm/TcgSmm.c465
-rw-r--r--Core/SecurityPkg/Tcg/TcgSmm/TcgSmm.h105
-rw-r--r--Core/SecurityPkg/Tcg/TcgSmm/TcgSmm.inf83
-rw-r--r--Core/SecurityPkg/Tcg/TcgSmm/TcgSmm.uni27
-rw-r--r--Core/SecurityPkg/Tcg/TcgSmm/TcgSmmExtra.uni19
-rw-r--r--Core/SecurityPkg/Tcg/TcgSmm/Tpm.asl356
-rw-r--r--Core/SecurityPkg/Tcg/TrEEConfig/TpmDetection.c105
-rw-r--r--Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfig.vfr68
-rw-r--r--Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigDriver.c216
-rw-r--r--Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigDxe.inf88
-rw-r--r--Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigDxe.uni22
-rw-r--r--Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigDxeExtra.uni19
-rw-r--r--Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigImpl.c344
-rw-r--r--Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigImpl.h193
-rw-r--r--Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigNvData.h76
-rw-r--r--Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigPei.inf77
-rw-r--r--Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigPei.uni23
-rw-r--r--Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigPeiExtra.uni19
-rw-r--r--Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigPeim.c159
-rw-r--r--Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigStrings.uni40
-rw-r--r--Core/SecurityPkg/Tcg/TrEEDxe/MeasureBootPeCoff.c427
-rw-r--r--Core/SecurityPkg/Tcg/TrEEDxe/TrEEDxe.c1877
-rw-r--r--Core/SecurityPkg/Tcg/TrEEDxe/TrEEDxe.inf104
-rw-r--r--Core/SecurityPkg/Tcg/TrEEDxe/TrEEDxe.uni26
-rw-r--r--Core/SecurityPkg/Tcg/TrEEDxe/TrEEDxeExtra.uni17
-rw-r--r--Core/SecurityPkg/Tcg/TrEEPei/TrEEPei.c690
-rw-r--r--Core/SecurityPkg/Tcg/TrEEPei/TrEEPei.inf86
-rw-r--r--Core/SecurityPkg/Tcg/TrEEPei/TrEEPei.uni21
-rw-r--r--Core/SecurityPkg/Tcg/TrEEPei/TrEEPeiExtra.uni19
-rw-r--r--Core/SecurityPkg/Tcg/TrEESmm/Tpm.asl354
-rw-r--r--Core/SecurityPkg/Tcg/TrEESmm/TrEESmm.c521
-rw-r--r--Core/SecurityPkg/Tcg/TrEESmm/TrEESmm.h105
-rw-r--r--Core/SecurityPkg/Tcg/TrEESmm/TrEESmm.inf85
-rw-r--r--Core/SecurityPkg/Tcg/TrEESmm/TrEESmm.uni28
-rw-r--r--Core/SecurityPkg/Tcg/TrEESmm/TrEESmmExtra.uni19
-rw-r--r--Core/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProvider.c1461
-rw-r--r--Core/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProvider.h374
-rw-r--r--Core/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProvider.uni21
-rw-r--r--Core/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderData.h30
-rw-r--r--Core/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderDxe.inf65
-rw-r--r--Core/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderExtra.uni19
-rw-r--r--Core/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderStrings.uni38
-rw-r--r--Core/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderVfr.Vfr34
-rw-r--r--Core/SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProvider.c1410
-rw-r--r--Core/SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProvider.h361
-rw-r--r--Core/SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProvider.uni23
-rw-r--r--Core/SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProviderDxe.inf70
-rw-r--r--Core/SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProviderExtra.uni19
-rw-r--r--Core/SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProviderStrings.uni29
-rw-r--r--Core/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/LoadDeferredImage.c148
-rw-r--r--Core/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManager.c3763
-rw-r--r--Core/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManager.h413
-rw-r--r--Core/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManager.uni21
-rw-r--r--Core/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManagerData.h35
-rw-r--r--Core/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManagerDxe.inf79
-rw-r--r--Core/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManagerExtra.uni19
-rw-r--r--Core/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManagerStrings.uni27
-rw-r--r--Core/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManagerVfr.Vfr43
-rw-r--r--Core/SecurityPkg/UserIdentification/UserProfileManagerDxe/ModifyAccessPolicy.c688
-rw-r--r--Core/SecurityPkg/UserIdentification/UserProfileManagerDxe/ModifyIdentityPolicy.c516
-rw-r--r--Core/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileAdd.c372
-rw-r--r--Core/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileDelete.c343
-rw-r--r--Core/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManager.c884
-rw-r--r--Core/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManager.h444
-rw-r--r--Core/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManager.uni22
-rw-r--r--Core/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManagerData.h158
-rw-r--r--Core/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManagerDxe.inf72
-rw-r--r--Core/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManagerExtra.uni19
-rw-r--r--Core/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManagerStrings.uni158
-rw-r--r--Core/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManagerVfr.Vfr244
-rw-r--r--Core/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileModify.c1475
-rw-r--r--Core/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/AuthService.c886
-rw-r--r--Core/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/AuthService.h151
-rw-r--r--Core/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/EsalVariableDxeSal.inf105
-rw-r--r--Core/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/EsalVariableDxeSal.uni22
-rw-r--r--Core/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/EsalVariableDxeSalExtra.uni19
-rw-r--r--Core/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/InitVariable.c247
-rw-r--r--Core/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/Reclaim.c262
-rw-r--r--Core/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/Variable.c3257
-rw-r--r--Core/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/Variable.h505
-rw-r--r--Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfig.vfr570
-rw-r--r--Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDevicePath.c38
-rw-r--r--Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDriver.c133
-rw-r--r--Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxe.inf127
-rw-r--r--Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxe.uni21
-rw-r--r--Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxeExtra.uni19
-rw-r--r--Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigFileExplorer.c422
-rw-r--r--Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigImpl.c4080
-rw-r--r--Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigImpl.h567
-rw-r--r--Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigMisc.c195
-rw-r--r--Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigNvData.h133
-rw-r--r--Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigStrings.uni116
389 files changed, 103454 insertions, 0 deletions
diff --git a/Core/SecurityPkg/Application/RngTest/RngTest.c b/Core/SecurityPkg/Application/RngTest/RngTest.c
new file mode 100644
index 0000000000..f501f806e9
--- /dev/null
+++ b/Core/SecurityPkg/Application/RngTest/RngTest.c
@@ -0,0 +1,234 @@
+/** @file
+ UEFI RNG (Random Number Generator) Protocol test application.
+
+Copyright (c) 2013, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Uefi.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiApplicationEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DebugLib.h>
+#include <Protocol/Rng.h>
+
+/**
+ The user Entry Point for Application. The user code starts with this function
+ as the real entry point for the application.
+
+ @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;
+ EFI_RNG_PROTOCOL *Rng;
+ UINTN RngAlgListSize;
+ EFI_RNG_ALGORITHM RngAlgList[10];
+ EFI_RNG_ALGORITHM *PtrRngAlg;
+ UINTN RngAlgCount;
+ UINT8 *Rand;
+ UINTN RandSize;
+ UINTN Index;
+ UINTN Index2;
+
+ Status = EFI_SUCCESS;
+ PtrRngAlg = NULL;
+ Rand = NULL;
+
+ Print (L"UEFI RNG Protocol Testing :\n");
+ Print (L"----------------------------\n");
+
+ //-----------------------------------------
+ // Basic UEFI RNG Protocol Test
+ //-----------------------------------------
+ Print (L" -- Locate UEFI RNG Protocol : ");
+ Status = gBS->LocateProtocol (&gEfiRngProtocolGuid, NULL, (VOID **)&Rng);
+ if (EFI_ERROR (Status)) {
+ Print (L"[Fail - Status = %r]\n", Status);
+ goto Exit;
+ } else {
+ Print (L"[Pass]\n");
+ }
+
+ //-----------------------------------------
+ // Rng->GetInfo() interface test.
+ //-----------------------------------------
+
+ Print (L" -- Call RNG->GetInfo() interface : ");
+ RngAlgListSize = 0;
+ Status = Rng->GetInfo (Rng, &RngAlgListSize, NULL);
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ Print (L"[Fail - Status = %r]\n", Status);
+ }
+ //
+ // Print out the supported RNG algorithm GUIDs
+ //
+ RngAlgCount = RngAlgListSize / sizeof (EFI_RNG_ALGORITHM);
+ Print (L"\n >> Supported RNG Algorithm (Count = %d) : ", RngAlgCount);
+ Status = Rng->GetInfo (Rng, &RngAlgListSize, RngAlgList);
+ for (Index = 0; Index < RngAlgCount; Index++) {
+ PtrRngAlg = (EFI_RNG_ALGORITHM *)(&RngAlgList[Index]);
+ Print (L"\n %d) ", Index);
+ Print (L"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", PtrRngAlg->Data1,
+ PtrRngAlg->Data2, PtrRngAlg->Data3, PtrRngAlg->Data4[0], PtrRngAlg->Data4[1],
+ PtrRngAlg->Data4[2], PtrRngAlg->Data4[3], PtrRngAlg->Data4[4],
+ PtrRngAlg->Data4[5], PtrRngAlg->Data4[6], PtrRngAlg->Data4[7]);
+ }
+
+ //-----------------------------------------
+ // Rng->GetRNG() interface test.
+ //-----------------------------------------
+ Print (L"\n -- Call RNG->GetRNG() interface : ");
+
+ //
+ // Allocate one buffer to store random data.
+ //
+ RandSize = 32;
+ Rand = AllocatePool (RandSize);
+ if (Rand == NULL) {
+ goto Exit;
+ }
+
+ //
+ // RNG with default algorithm
+ //
+ Print (L"\n >> RNG with default algorithm : ");
+ Status = Rng->GetRNG (Rng, NULL, RandSize, Rand);
+ if (EFI_ERROR (Status)) {
+ Print (L"[Fail - Status = %r]", Status);
+ } else {
+ Print (L"[Pass]");
+ }
+
+ //
+ // RNG with SP800-90-HMAC-256
+ //
+ Print (L"\n >> RNG with SP800-90-HMAC-256 : ");
+ Status = Rng->GetRNG (Rng, &gEfiRngAlgorithmSp80090Hmac256Guid, RandSize, Rand);
+ if (EFI_ERROR (Status)) {
+ Print (L"[Fail - Status = %r]", Status);
+ } else {
+ Print (L"[Pass]");
+ }
+
+ //
+ // RNG with SP800-90-HASH-256
+ //
+ Print (L"\n >> RNG with SP800-90-Hash-256 : ");
+ Status = Rng->GetRNG (Rng, &gEfiRngAlgorithmSp80090Hash256Guid, RandSize, Rand);
+ if (EFI_ERROR (Status)) {
+ Print (L"[Fail - Status = %r]", Status);
+ } else {
+ Print (L"[Pass]");
+ }
+
+ //
+ // RNG with SP800-90-CTR-256
+ //
+ Print (L"\n >> RNG with SP800-90-CTR-256 : ");
+ Status = Rng->GetRNG (Rng, &gEfiRngAlgorithmSp80090Ctr256Guid, RandSize, Rand);
+ if (EFI_ERROR (Status)) {
+ Print (L"[Fail - Status = %r]", Status);
+ } else {
+ Print (L"[Pass]");
+ }
+
+ //
+ // RNG with X9.31-3DES
+ //
+ Print (L"\n >> RNG with X9.31-3DES : ");
+ Status = Rng->GetRNG (Rng, &gEfiRngAlgorithmX9313DesGuid, RandSize, Rand);
+ if (EFI_ERROR (Status)) {
+ Print (L"[Fail - Status = %r]", Status);
+ } else {
+ Print (L"[Pass]");
+ }
+
+ //
+ // RNG with X9.31-AES
+ //
+ Print (L"\n >> RNG with X9.31-AES : ");
+ Status = Rng->GetRNG (Rng, &gEfiRngAlgorithmX931AesGuid, RandSize, Rand);
+ if (EFI_ERROR (Status)) {
+ Print (L"[Fail - Status = %r]", Status);
+ } else {
+ Print (L"[Pass]");
+ }
+
+ //
+ // RNG with RAW Entropy
+ //
+ Print (L"\n >> RNG with RAW Entropy : ");
+ Status = Rng->GetRNG (Rng, &gEfiRngAlgorithmRaw, RandSize, Rand);
+ if (EFI_ERROR (Status)) {
+ Print (L"[Fail - Status = %r]", Status);
+ } else {
+ Print (L"[Pass]");
+ }
+
+ //-----------------------------------------
+ // Random Number Generator test.
+ //-----------------------------------------
+ Print (L"\n -- Random Number Generation Test with default RNG Algorithm (20 Rounds): ");
+
+ RandSize = 1;
+ for (Index = 0; Index < 20; Index++) {
+ Status = Rng->GetRNG (Rng, NULL, RandSize, Rand);
+ if (EFI_ERROR (Status)) {
+ Print (L"[Fail - Status = %r]", Status);
+ break;
+ } else {
+ Print (L"\n %02d) - ", Index + 1);
+ for (Index2 = 0; Index2 < RandSize; Index2++) {
+ Print (L"%02x", Rand[Index2]);
+ }
+ }
+
+ RandSize +=1;
+ }
+
+ //-----------------------------------------
+ // Random Number Generator test.
+ //-----------------------------------------
+ Print (L"\n -- RAW Entropy Generation Test (20 Rounds) : ");
+
+ RandSize = 32;
+ for (Index = 0; Index < 20; Index++) {
+ Status = Rng->GetRNG (Rng, &gEfiRngAlgorithmRaw, RandSize, Rand);
+ if (EFI_ERROR (Status)) {
+ Print (L"[Fail - Status = %r]", Status);
+ break;
+ } else {
+ Print (L"\n %02d) - ", Index + 1);
+ for (Index2 = 0; Index2 < RandSize; Index2++) {
+ Print (L"%02x", Rand[Index2]);
+ }
+ }
+ }
+
+ Print (L"\n -- Exit UEFI RNG Protocol Test (Status = %r).\n", Status);
+
+Exit:
+ if (Rand != NULL) {
+ FreePool (Rand);
+ }
+ return Status;
+}
diff --git a/Core/SecurityPkg/Application/RngTest/RngTest.inf b/Core/SecurityPkg/Application/RngTest/RngTest.inf
new file mode 100644
index 0000000000..334cff45b0
--- /dev/null
+++ b/Core/SecurityPkg/Application/RngTest/RngTest.inf
@@ -0,0 +1,57 @@
+## @file
+# UEFI RNG (Random Number Generator) Protocol test application.
+#
+# This application can print out the supported RNG algorithm in UEFI RNG Protocol.
+# And then it will do a generation test on the supported RNG algorithm.
+#
+# Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = RngTest
+ FILE_GUID = B8AC7FB2-4211-4c2b-B62F-504421666C87
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = UefiMain
+ MODULE_UNI_FILE = RngTest.uni
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ RngTest.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+ UefiApplicationEntryPoint
+ UefiLib
+
+[Protocols]
+ gEfiRngProtocolGuid ## CONSUMES
+
+[Guids]
+ gEfiRngAlgorithmSp80090Hash256Guid ## SOMETIMES_CONSUMES ## GUID # Unique ID of the algorithm for RNG
+ gEfiRngAlgorithmSp80090Hmac256Guid ## SOMETIMES_CONSUMES ## GUID # Unique ID of the algorithm for RNG
+ gEfiRngAlgorithmSp80090Ctr256Guid ## SOMETIMES_CONSUMES ## GUID # Unique ID of the algorithm for RNG
+ gEfiRngAlgorithmX9313DesGuid ## SOMETIMES_CONSUMES ## GUID # Unique ID of the algorithm for RNG
+ gEfiRngAlgorithmX931AesGuid ## SOMETIMES_CONSUMES ## GUID # Unique ID of the algorithm for RNG
+ gEfiRngAlgorithmRaw ## SOMETIMES_CONSUMES ## GUID # Unique ID of the algorithm for RNG
+
+ [UserExtensions.TianoCore."ExtraFiles"]
+ RngTestExtra.uni \ No newline at end of file
diff --git a/Core/SecurityPkg/Application/RngTest/RngTest.uni b/Core/SecurityPkg/Application/RngTest/RngTest.uni
new file mode 100644
index 0000000000..2cf82f9a37
--- /dev/null
+++ b/Core/SecurityPkg/Application/RngTest/RngTest.uni
@@ -0,0 +1,23 @@
+// /** @file
+// UEFI RNG (Random Number Generator) Protocol test application.
+//
+// This application can print out the supported RNG algorithm in UEFI RNG Protocol.
+// And then it will do a generation test on the supported RNG algorithm.
+//
+// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+//
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "A shell application that used UEFI RNG (Random Number Generator) Protocol test"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This application can print out the supported RNG algorithm in UEFI RNG Protocol. And then it will do a generation test on the supported RNG algorithm."
+
diff --git a/Core/SecurityPkg/Application/RngTest/RngTestExtra.uni b/Core/SecurityPkg/Application/RngTest/RngTestExtra.uni
new file mode 100644
index 0000000000..9f2a92d1c9
--- /dev/null
+++ b/Core/SecurityPkg/Application/RngTest/RngTestExtra.uni
@@ -0,0 +1,18 @@
+// /** @file
+// RngTest Localized Strings and Content
+//
+// Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"UEFI RNG (Random Number Generator) Protocol Test Application"
+
diff --git a/Core/SecurityPkg/Contributions.txt b/Core/SecurityPkg/Contributions.txt
new file mode 100644
index 0000000000..f87cbd73c6
--- /dev/null
+++ b/Core/SecurityPkg/Contributions.txt
@@ -0,0 +1,218 @@
+
+======================
+= Code Contributions =
+======================
+
+To make a contribution to a TianoCore project, follow these steps.
+1. Create a change description in the format specified below to
+ use in the source control commit log.
+2. Your commit message must include your "Signed-off-by" signature,
+ and "Contributed-under" message.
+3. Your "Contributed-under" message explicitly states that the
+ contribution is made under the terms of the specified
+ contribution agreement. Your "Contributed-under" message
+ must include the name of contribution agreement and version.
+ For example: Contributed-under: TianoCore Contribution Agreement 1.0
+ The "TianoCore Contribution Agreement" is included below in
+ this document.
+4. Submit your code to the TianoCore project using the process
+ that the project documents on its web page. If the process is
+ not documented, then submit the code on development email list
+ for the project.
+5. It is preferred that contributions are submitted using the same
+ copyright license as the base project. When that is not possible,
+ then contributions using the following licenses can be accepted:
+ * BSD (2-clause): http://opensource.org/licenses/BSD-2-Clause
+ * BSD (3-clause): http://opensource.org/licenses/BSD-3-Clause
+ * MIT: http://opensource.org/licenses/MIT
+ * Python-2.0: http://opensource.org/licenses/Python-2.0
+ * Zlib: http://opensource.org/licenses/Zlib
+
+ Contributions of code put into the public domain can also be
+ accepted.
+
+ Contributions using other licenses might be accepted, but further
+ review will be required.
+
+=====================================================
+= Change Description / Commit Message / Patch Email =
+=====================================================
+
+Your change description should use the standard format for a
+commit message, and must include your "Signed-off-by" signature
+and the "Contributed-under" message.
+
+== Sample Change Description / Commit Message =
+
+=== Start of sample patch email message ===
+
+From: Contributor Name <contributor@example.com>
+Subject: [PATCH] CodeModule: Brief-single-line-summary
+
+Full-commit-message
+
+Contributed-under: TianoCore Contribution Agreement 1.0
+Signed-off-by: Contributor Name <contributor@example.com>
+---
+
+An extra message for the patch email which will not be considered part
+of the commit message can be added here.
+
+Patch content inline or attached
+
+=== End of sample patch email message ===
+
+=== Notes for sample patch email ===
+
+* The first line of commit message is taken from the email's subject
+ line following [PATCH]. The remaining portion of the commit message
+ is the email's content until the '---' line.
+* git format-patch is one way to create this format
+
+=== Definitions for sample patch email ===
+
+* "CodeModule" is a short idenfier for the affected code. For
+ example MdePkg, or MdeModulePkg UsbBusDxe.
+* "Brief-single-line-summary" is a short summary of the change.
+* The entire first line should be less than ~70 characters.
+* "Full-commit-message" a verbose multiple line comment describing
+ the change. Each line should be less than ~70 characters.
+* "Contributed-under" explicitely states that the contribution is
+ made under the terms of the contribtion agreement. This
+ agreement is included below in this document.
+* "Signed-off-by" is the contributor's signature identifying them
+ by their real/legal name and their email address.
+
+========================================
+= TianoCore Contribution Agreement 1.0 =
+========================================
+
+INTEL CORPORATION ("INTEL") MAKES AVAILABLE SOFTWARE, DOCUMENTATION,
+INFORMATION AND/OR OTHER MATERIALS FOR USE IN THE TIANOCORE OPEN SOURCE
+PROJECT (COLLECTIVELY "CONTENT"). USE OF THE CONTENT IS GOVERNED BY THE
+TERMS AND CONDITIONS OF THIS AGREEMENT BETWEEN YOU AND INTEL AND/OR THE
+TERMS AND CONDITIONS OF LICENSE AGREEMENTS OR NOTICES INDICATED OR
+REFERENCED BELOW. BY USING THE CONTENT, YOU AGREE THAT YOUR USE OF THE
+CONTENT IS GOVERNED BY THIS AGREEMENT AND/OR THE TERMS AND CONDITIONS
+OF ANY APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED
+BELOW. IF YOU DO NOT AGREE TO THE TERMS AND CONDITIONS OF THIS
+AGREEMENT AND THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE
+AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW, THEN YOU MAY NOT
+USE THE CONTENT.
+
+Unless otherwise indicated, all Content made available on the TianoCore
+site is provided to you under the terms and conditions of the BSD
+License ("BSD"). A copy of the BSD License is available at
+http://opensource.org/licenses/bsd-license.php
+or when applicable, in the associated License.txt file.
+
+Certain other content may be made available under other licenses as
+indicated in or with such Content. (For example, in a License.txt file.)
+
+You accept and agree to the following terms and conditions for Your
+present and future Contributions submitted to TianoCore site. Except
+for the license granted to Intel hereunder, You reserve all right,
+title, and interest in and to Your Contributions.
+
+== SECTION 1: Definitions ==
+* "You" or "Contributor" shall mean the copyright owner or legal
+ entity authorized by the copyright owner that is making a
+ Contribution hereunder. All other entities that control, are
+ controlled by, or are under common control with that entity are
+ considered to be a single Contributor. For the purposes of this
+ definition, "control" means (i) the power, direct or indirect, to
+ cause the direction or management of such entity, whether by
+ contract or otherwise, or (ii) ownership of fifty percent (50%)
+ or more of the outstanding shares, or (iii) beneficial ownership
+ of such entity.
+* "Contribution" shall mean any original work of authorship,
+ including any modifications or additions to an existing work,
+ that is intentionally submitted by You to the TinaoCore site for
+ inclusion in, or documentation of, any of the Content. For the
+ purposes of this definition, "submitted" means any form of
+ electronic, verbal, or written communication sent to the
+ TianoCore site or its representatives, including but not limited
+ to communication on electronic mailing lists, source code
+ control systems, and issue tracking systems that are managed by,
+ or on behalf of, the TianoCore site for the purpose of
+ discussing and improving the Content, but excluding
+ communication that is conspicuously marked or otherwise
+ designated in writing by You as "Not a Contribution."
+
+== SECTION 2: License for Contributions ==
+* Contributor hereby agrees that redistribution and use of the
+ Contribution in source and binary forms, with or without
+ modification, are permitted provided that the following
+ conditions are met:
+** Redistributions of source code must retain the Contributor's
+ copyright notice, this list of conditions and the following
+ disclaimer.
+** Redistributions in binary form must reproduce the Contributor's
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+* Disclaimer. None of the names of Contributor, Intel, or the names
+ of their respective contributors may be used to endorse or
+ promote products derived from this software without specific
+ prior written permission.
+* Contributor grants a license (with the right to sublicense) under
+ claims of Contributor's patents that Contributor can license that
+ are infringed by the Contribution (as delivered by Contributor) to
+ make, use, distribute, sell, offer for sale, and import the
+ Contribution and derivative works thereof solely to the minimum
+ extent necessary for licensee to exercise the granted copyright
+ license; this patent license applies solely to those portions of
+ the Contribution that are unmodified. No hardware per se is
+ licensed.
+* EXCEPT AS EXPRESSLY SET FORTH IN SECTION 3 BELOW, THE
+ CONTRIBUTION IS PROVIDED BY THE CONTRIBUTOR "AS IS" AND ANY
+ EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ CONTRIBUTOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
+ CONTRIBUTION, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ DAMAGE.
+
+== SECTION 3: Representations ==
+* You represent that You are legally entitled to grant the above
+ license. If your employer(s) has rights to intellectual property
+ that You create that includes Your Contributions, You represent
+ that You have received permission to make Contributions on behalf
+ of that employer, that Your employer has waived such rights for
+ Your Contributions.
+* You represent that each of Your Contributions is Your original
+ creation (see Section 4 for submissions on behalf of others).
+ You represent that Your Contribution submissions include complete
+ details of any third-party license or other restriction
+ (including, but not limited to, related patents and trademarks)
+ of which You are personally aware and which are associated with
+ any part of Your Contributions.
+
+== SECTION 4: Third Party Contributions ==
+* Should You wish to submit work that is not Your original creation,
+ You may submit it to TianoCore site separately from any
+ Contribution, identifying the complete details of its source
+ and of any license or other restriction (including, but not
+ limited to, related patents, trademarks, and license agreements)
+ of which You are personally aware, and conspicuously marking the
+ work as "Submitted on behalf of a third-party: [named here]".
+
+== SECTION 5: Miscellaneous ==
+* Applicable Laws. Any claims arising under or relating to this
+ Agreement shall be governed by the internal substantive laws of
+ the State of Delaware or federal courts located in Delaware,
+ without regard to principles of conflict of laws.
+* Language. This Agreement is in the English language only, which
+ language shall be controlling in all respects, and all versions
+ of this Agreement in any other language shall be for accommodation
+ only and shall not be binding. All communications and notices made
+ or given pursuant to this Agreement, and all documentation and
+ support to be provided, unless otherwise noted, shall be in the
+ English language.
+
diff --git a/Core/SecurityPkg/Hash2DxeCrypto/Driver.c b/Core/SecurityPkg/Hash2DxeCrypto/Driver.c
new file mode 100644
index 0000000000..d63ca2c209
--- /dev/null
+++ b/Core/SecurityPkg/Hash2DxeCrypto/Driver.c
@@ -0,0 +1,242 @@
+/** @file
+ This is service binding for Hash driver.
+
+Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that 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 "Driver.h"
+
+EFI_SERVICE_BINDING_PROTOCOL mHash2ServiceBindingProtocol = {
+ Hash2ServiceBindingCreateChild,
+ Hash2ServiceBindingDestroyChild
+};
+
+/**
+ Creates a child handle with a set of I/O services.
+
+ @param[in] This Protocol instance pointer.
+ @param[in, out] ChildHandle Pointer to the handle of the child to create. If
+ it is NULL, then a new handle is created. If
+ it is not NULL, then the I/O services are added
+ to the existing child handle.
+
+ @retval EFI_SUCCES The protocol was added to ChildHandle.
+ @retval EFI_INVALID_PARAMETER ChildHandle is NULL.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources available to
+ create the child.
+ @retval Others The child handle was not created.
+
+**/
+EFI_STATUS
+EFIAPI
+Hash2ServiceBindingCreateChild (
+ IN EFI_SERVICE_BINDING_PROTOCOL *This,
+ IN OUT EFI_HANDLE *ChildHandle
+ )
+{
+ EFI_STATUS Status;
+ HASH2_SERVICE_DATA *Hash2ServiceData;
+ HASH2_INSTANCE_DATA *Instance;
+ EFI_TPL OldTpl;
+
+ if ((This == NULL) || (ChildHandle == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Hash2ServiceData = HASH2_SERVICE_DATA_FROM_THIS (This);
+
+ //
+ // Allocate buffer for the new instance.
+ //
+ Instance = AllocateZeroPool (sizeof (HASH2_INSTANCE_DATA));
+ if (Instance == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Init the instance data.
+ //
+ Instance->Signature = HASH2_INSTANCE_DATA_SIGNATURE;
+ CopyMem (&Instance->Hash2Protocol, &mHash2Protocol, sizeof (Instance->Hash2Protocol));
+ Instance->Hash2ServiceData = Hash2ServiceData;
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ ChildHandle,
+ &gEfiHash2ProtocolGuid,
+ &Instance->Hash2Protocol,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (Instance);
+ return Status;
+ }
+
+ Instance->Handle = *ChildHandle;
+
+ //
+ // Add the child instance into ChildrenList.
+ //
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ InsertTailList (&Hash2ServiceData->ChildrenList, &Instance->InstEntry);
+
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
+
+
+/**
+ Destroys a child handle with a set of I/O services.
+
+ The DestroyChild() function does the opposite of CreateChild(). It removes a
+ protocol that was installed by CreateChild() from ChildHandle. If the removed
+ protocol is the last protocol on ChildHandle, then ChildHandle is destroyed.
+
+ @param[in] This Pointer to the EFI_SERVICE_BINDING_PROTOCOL
+ instance.
+ @param[in] ChildHandle Handle of the child to destroy.
+
+ @retval EFI_SUCCES The protocol was removed from ChildHandle.
+ @retval EFI_UNSUPPORTED ChildHandle does not support the protocol that
+ is being removed.
+ @retval EFI_INVALID_PARAMETER ChildHandle is NULL.
+ @retval EFI_ACCESS_DENIED The protocol could not be removed from the
+ ChildHandle because its services are being
+ used.
+ @retval Others The child handle was not destroyed.
+
+**/
+EFI_STATUS
+EFIAPI
+Hash2ServiceBindingDestroyChild (
+ IN EFI_SERVICE_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ChildHandle
+ )
+{
+ EFI_STATUS Status;
+ HASH2_SERVICE_DATA *Hash2ServiceData;
+ EFI_HASH2_PROTOCOL *Hash2Protocol;
+ HASH2_INSTANCE_DATA *Instance;
+ EFI_TPL OldTpl;
+ LIST_ENTRY *Entry;
+
+ if ((This == NULL) || (ChildHandle == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Hash2ServiceData = HASH2_SERVICE_DATA_FROM_THIS (This);
+
+ //
+ // Check if this ChildHandle is valid
+ //
+ Instance = NULL;
+ for(Entry = (&Hash2ServiceData->ChildrenList)->ForwardLink; Entry != (&Hash2ServiceData->ChildrenList); Entry = Entry->ForwardLink) {
+ Instance = HASH2_INSTANCE_DATA_FROM_LINK (Entry);
+ if (Instance->Handle == ChildHandle) {
+ break;
+ } else {
+ Instance = NULL;
+ }
+ }
+ if (Instance == NULL) {
+ DEBUG ((EFI_D_ERROR, "Hash2ServiceBindingDestroyChild - Invalid handle\n"));
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Get HashProtocol
+ //
+ Status = gBS->HandleProtocol (
+ ChildHandle,
+ &gEfiHash2ProtocolGuid,
+ (VOID **)&Hash2Protocol
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ASSERT (Hash2Protocol == &Instance->Hash2Protocol);
+
+ //
+ // Uninstall the Hash protocol.
+ //
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ ChildHandle,
+ &gEfiHash2ProtocolGuid,
+ &Instance->Hash2Protocol,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ //
+ // Remove this instance from the ChildrenList.
+ //
+ RemoveEntryList (&Instance->InstEntry);
+
+ gBS->RestoreTPL (OldTpl);
+
+ FreePool (Instance);
+
+ return Status;
+}
+
+/**
+ The entry point for Hash driver which installs the service binding protocol.
+
+ @param[in] ImageHandle The image handle of the driver.
+ @param[in] SystemTable The system table.
+
+ @retval EFI_SUCCES The service binding protocols is successfully installed.
+ @retval Others Other errors as indicated.
+
+**/
+EFI_STATUS
+EFIAPI
+Hash2DriverEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ HASH2_SERVICE_DATA *Hash2ServiceData;
+
+ //
+ // Initialize the Hash Service Data.
+ //
+ Hash2ServiceData = AllocateZeroPool (sizeof (HASH2_SERVICE_DATA));
+ if (Hash2ServiceData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Hash2ServiceData->Signature = HASH2_SERVICE_DATA_SIGNATURE;
+ CopyMem (&Hash2ServiceData->ServiceBinding, &mHash2ServiceBindingProtocol, sizeof (EFI_SERVICE_BINDING_PROTOCOL));
+ InitializeListHead (&Hash2ServiceData->ChildrenList);
+
+ //
+ // Install the HASH Service Binding Protocol
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Hash2ServiceData->ServiceHandle,
+ &gEfiHash2ServiceBindingProtocolGuid,
+ &Hash2ServiceData->ServiceBinding,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (Hash2ServiceData);
+ }
+
+ return Status;
+} \ No newline at end of file
diff --git a/Core/SecurityPkg/Hash2DxeCrypto/Driver.h b/Core/SecurityPkg/Hash2DxeCrypto/Driver.h
new file mode 100644
index 0000000000..9a1cd587da
--- /dev/null
+++ b/Core/SecurityPkg/Hash2DxeCrypto/Driver.h
@@ -0,0 +1,132 @@
+/** @file
+ This is definition for service binding for Hash driver.
+
+Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that 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 _HASH2_DRIVER_H_
+#define _HASH2_DRIVER_H_
+
+#include <Uefi.h>
+
+#include <Protocol/ServiceBinding.h>
+#include <Protocol/Hash2.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/UefiLib.h>
+
+#define HASH2_SERVICE_DATA_SIGNATURE SIGNATURE_32 ('H', 'S', '2', 'S')
+
+typedef struct {
+ UINT32 Signature;
+ EFI_HANDLE ServiceHandle;
+ EFI_SERVICE_BINDING_PROTOCOL ServiceBinding;
+
+ LIST_ENTRY ChildrenList;
+} HASH2_SERVICE_DATA;
+
+#define HASH2_SERVICE_DATA_FROM_THIS(a) \
+ CR ( \
+ (a), \
+ HASH2_SERVICE_DATA, \
+ ServiceBinding, \
+ HASH2_SERVICE_DATA_SIGNATURE \
+ )
+
+#define HASH2_INSTANCE_DATA_SIGNATURE SIGNATURE_32 ('H', 's', '2', 'I')
+
+typedef struct {
+ UINT32 Signature;
+ HASH2_SERVICE_DATA *Hash2ServiceData;
+ EFI_HANDLE Handle;
+ LIST_ENTRY InstEntry;
+ EFI_HASH2_PROTOCOL Hash2Protocol;
+ VOID *HashContext;
+ VOID *HashInfoContext;
+ BOOLEAN Updated;
+} HASH2_INSTANCE_DATA;
+
+#define HASH2_INSTANCE_DATA_FROM_THIS(a) \
+ CR ( \
+ (a), \
+ HASH2_INSTANCE_DATA, \
+ Hash2Protocol, \
+ HASH2_INSTANCE_DATA_SIGNATURE \
+ )
+
+#define HASH2_INSTANCE_DATA_FROM_LINK(a) \
+ CR ( \
+ (a), \
+ HASH2_INSTANCE_DATA, \
+ InstEntry, \
+ HASH2_INSTANCE_DATA_SIGNATURE \
+ )
+
+/**
+ Creates a child handle with a set of I/O services.
+
+ @param[in] This Protocol instance pointer.
+ @param[in, out] ChildHandle Pointer to the handle of the child to create. If
+ it is NULL, then a new handle is created. If
+ it is not NULL, then the I/O services are added
+ to the existing child handle.
+
+ @retval EFI_SUCCES The protocol was added to ChildHandle.
+ @retval EFI_INVALID_PARAMETER ChildHandle is NULL.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources available to
+ create the child.
+ @retval Others The child handle was not created.
+
+**/
+EFI_STATUS
+EFIAPI
+Hash2ServiceBindingCreateChild (
+ IN EFI_SERVICE_BINDING_PROTOCOL *This,
+ IN OUT EFI_HANDLE *ChildHandle
+ );
+
+/**
+ Destroys a child handle with a set of I/O services.
+
+ The DestroyChild() function does the opposite of CreateChild(). It removes a
+ protocol that was installed by CreateChild() from ChildHandle. If the removed
+ protocol is the last protocol on ChildHandle, then ChildHandle is destroyed.
+
+ @param[in] This Pointer to the EFI_SERVICE_BINDING_PROTOCOL
+ instance.
+ @param[in] ChildHandle Handle of the child to destroy.
+
+ @retval EFI_SUCCES The protocol was removed from ChildHandle.
+ @retval EFI_UNSUPPORTED ChildHandle does not support the protocol that
+ is being removed.
+ @retval EFI_INVALID_PARAMETER ChildHandle is NULL.
+ @retval EFI_ACCESS_DENIED The protocol could not be removed from the
+ ChildHandle because its services are being
+ used.
+ @retval Others The child handle was not destroyed.
+
+**/
+EFI_STATUS
+EFIAPI
+Hash2ServiceBindingDestroyChild (
+ IN EFI_SERVICE_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ChildHandle
+ );
+
+extern EFI_HASH2_PROTOCOL mHash2Protocol;
+
+#endif
diff --git a/Core/SecurityPkg/Hash2DxeCrypto/Hash2DxeCrypto.c b/Core/SecurityPkg/Hash2DxeCrypto/Hash2DxeCrypto.c
new file mode 100644
index 0000000000..93e3273916
--- /dev/null
+++ b/Core/SecurityPkg/Hash2DxeCrypto/Hash2DxeCrypto.c
@@ -0,0 +1,618 @@
+/** @file
+ This module implements Hash2 Protocol.
+
+(C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that 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 <Uefi.h>
+#include <Protocol/Hash2.h>
+#include <Library/BaseLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseCryptLib.h>
+
+#include "Driver.h"
+
+/**
+ Retrieves the size, in bytes, of the context buffer required for hash operations.
+
+ If this interface is not supported, then return zero.
+
+ @return The size, in bytes, of the context buffer required for hash operations.
+ @retval 0 This interface is not supported.
+
+**/
+typedef
+UINTN
+(EFIAPI *EFI_HASH_GET_CONTEXT_SIZE) (
+ VOID
+ );
+
+/**
+ Initializes user-supplied memory pointed by Sha1Context as hash context for
+ subsequent use.
+
+ If HashContext is NULL, then return FALSE.
+ If this interface is not supported, then return FALSE.
+
+ @param[out] HashContext Pointer to Hashcontext being initialized.
+
+ @retval TRUE Hash context initialization succeeded.
+ @retval FALSE Hash context initialization failed.
+ @retval FALSE This interface is not supported.
+
+**/
+typedef
+BOOLEAN
+(EFIAPI *EFI_HASH_INIT) (
+ OUT VOID *HashContext
+ );
+
+/**
+ Digests the input data and updates Hash context.
+
+ This function performs Hash digest on a data buffer of the specified size.
+ It can be called multiple times to compute the digest of long or discontinuous data streams.
+ Hash context should be already correctly initialized by HashInit(), and should not be finalized
+ by HashFinal(). Behavior with invalid context is undefined.
+
+ If HashContext is NULL, then return FALSE.
+ If this interface is not supported, then return FALSE.
+
+ @param[in, out] HashContext Pointer to the Hash context.
+ @param[in] Data Pointer to the buffer containing the data to be hashed.
+ @param[in] DataSize Size of Data buffer in bytes.
+
+ @retval TRUE SHA-1 data digest succeeded.
+ @retval FALSE SHA-1 data digest failed.
+ @retval FALSE This interface is not supported.
+
+**/
+typedef
+BOOLEAN
+(EFIAPI *EFI_HASH_UPDATE) (
+ IN OUT VOID *HashContext,
+ IN CONST VOID *Data,
+ IN UINTN DataSize
+ );
+
+/**
+ Completes computation of the Hash digest value.
+
+ This function completes hash computation and retrieves the digest value into
+ the specified memory. After this function has been called, the Hash context cannot
+ be used again.
+ Hash context should be already correctly intialized by HashInit(), and should not be
+ finalized by HashFinal(). Behavior with invalid Hash context is undefined.
+
+ If HashContext is NULL, then return FALSE.
+ If HashValue is NULL, then return FALSE.
+ If this interface is not supported, then return FALSE.
+
+ @param[in, out] HashContext Pointer to the Hash 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.
+ @retval FALSE This interface is not supported.
+
+**/
+typedef
+BOOLEAN
+(EFIAPI *EFI_HASH_FINAL) (
+ IN OUT VOID *HashContext,
+ OUT UINT8 *HashValue
+ );
+
+typedef struct {
+ EFI_GUID *Guid;
+ UINT32 HashSize;
+ EFI_HASH_GET_CONTEXT_SIZE GetContextSize;
+ EFI_HASH_INIT Init;
+ EFI_HASH_UPDATE Update;
+ EFI_HASH_FINAL Final;
+} EFI_HASH_INFO;
+
+EFI_HASH_INFO mHashInfo[] = {
+ {&gEfiHashAlgorithmMD5Guid, sizeof(EFI_MD5_HASH2), Md5GetContextSize, Md5Init, Md5Update, Md5Final },
+ {&gEfiHashAlgorithmSha1Guid, sizeof(EFI_SHA1_HASH2), Sha1GetContextSize, Sha1Init, Sha1Update, Sha1Final },
+ {&gEfiHashAlgorithmSha256Guid, sizeof(EFI_SHA256_HASH2), Sha256GetContextSize, Sha256Init, Sha256Update, Sha256Final },
+ {&gEfiHashAlgorithmSha384Guid, sizeof(EFI_SHA384_HASH2), Sha384GetContextSize, Sha384Init, Sha384Update, Sha384Final },
+ {&gEfiHashAlgorithmSha512Guid, sizeof(EFI_SHA512_HASH2), Sha512GetContextSize, Sha512Init, Sha512Update, Sha512Final },
+};
+
+/**
+ Returns the size of the hash which results from a specific algorithm.
+
+ @param[in] This Points to this instance of EFI_HASH2_PROTOCOL.
+ @param[in] HashAlgorithm Points to the EFI_GUID which identifies the algorithm to use.
+ @param[out] HashSize Holds the returned size of the algorithm's hash.
+
+ @retval EFI_SUCCESS Hash size returned successfully.
+ @retval EFI_INVALID_PARAMETER This or HashSize is NULL.
+ @retval EFI_UNSUPPORTED The algorithm specified by HashAlgorithm is not supported by this driver
+ or HashAlgorithm is null.
+
+**/
+EFI_STATUS
+EFIAPI
+BaseCrypto2GetHashSize (
+ IN CONST EFI_HASH2_PROTOCOL *This,
+ IN CONST EFI_GUID *HashAlgorithm,
+ OUT UINTN *HashSize
+ );
+
+/**
+ Creates a hash for the specified message text. The hash is not extendable.
+ The output is final with any algorithm-required padding added by the function.
+
+ @param[in] This Points to this instance of EFI_HASH2_PROTOCOL.
+ @param[in] HashAlgorithm Points to the EFI_GUID which identifies the algorithm to use.
+ @param[in] Message Points to the start of the message.
+ @param[in] MessageSize The size of Message, in bytes.
+ @param[in,out] Hash On input, points to a caller-allocated buffer of the size
+ returned by GetHashSize() for the specified HashAlgorithm.
+ On output, the buffer holds the resulting hash computed from the message.
+
+ @retval EFI_SUCCESS Hash returned successfully.
+ @retval EFI_INVALID_PARAMETER This or Hash is NULL.
+ @retval EFI_UNSUPPORTED The algorithm specified by HashAlgorithm is not supported by this driver
+ or HashAlgorithm is Null.
+ @retval EFI_OUT_OF_RESOURCES Some resource required by the function is not available
+ or MessageSize is greater than platform maximum.
+
+**/
+EFI_STATUS
+EFIAPI
+BaseCrypto2Hash (
+ IN CONST EFI_HASH2_PROTOCOL *This,
+ IN CONST EFI_GUID *HashAlgorithm,
+ IN CONST UINT8 *Message,
+ IN UINTN MessageSize,
+ IN OUT EFI_HASH2_OUTPUT *Hash
+ );
+
+/**
+ This function must be called to initialize a digest calculation to be subsequently performed using the
+ EFI_HASH2_PROTOCOL functions HashUpdate() and HashFinal().
+
+ @param[in] This Points to this instance of EFI_HASH2_PROTOCOL.
+ @param[in] HashAlgorithm Points to the EFI_GUID which identifies the algorithm to use.
+
+ @retval EFI_SUCCESS Initialized successfully.
+ @retval EFI_INVALID_PARAMETER This is NULL.
+ @retval EFI_UNSUPPORTED The algorithm specified by HashAlgorithm is not supported by this driver
+ or HashAlgorithm is Null.
+ @retval EFI_OUT_OF_RESOURCES Process failed due to lack of required resource.
+ @retval EFI_ALREADY_STARTED This function is called when the operation in progress is still in processing Hash(),
+ or HashInit() is already called before and not terminated by HashFinal() yet on the same instance.
+
+**/
+EFI_STATUS
+EFIAPI
+BaseCrypto2HashInit (
+ IN CONST EFI_HASH2_PROTOCOL *This,
+ IN CONST EFI_GUID *HashAlgorithm
+ );
+
+/**
+ Updates the hash of a computation in progress by adding a message text.
+
+ @param[in] This Points to this instance of EFI_HASH2_PROTOCOL.
+ @param[in] Message Points to the start of the message.
+ @param[in] MessageSize The size of Message, in bytes.
+
+ @retval EFI_SUCCESS Digest in progress updated successfully.
+ @retval EFI_INVALID_PARAMETER This or Hash is NULL.
+ @retval EFI_OUT_OF_RESOURCES Some resource required by the function is not available
+ or MessageSize is greater than platform maximum.
+ @retval EFI_NOT_READY This call was not preceded by a valid call to HashInit(),
+ or the operation in progress was terminated by a call to Hash() or HashFinal() on the same instance.
+
+**/
+EFI_STATUS
+EFIAPI
+BaseCrypto2HashUpdate (
+ IN CONST EFI_HASH2_PROTOCOL *This,
+ IN CONST UINT8 *Message,
+ IN UINTN MessageSize
+ );
+
+/**
+ Finalizes a hash operation in progress and returns calculation result.
+ The output is final with any necessary padding added by the function.
+ The hash may not be further updated or extended after HashFinal().
+
+ @param[in] This Points to this instance of EFI_HASH2_PROTOCOL.
+ @param[in,out] Hash On input, points to a caller-allocated buffer of the size
+ returned by GetHashSize() for the specified HashAlgorithm specified in preceding HashInit().
+ On output, the buffer holds the resulting hash computed from the message.
+
+ @retval EFI_SUCCESS Hash returned successfully.
+ @retval EFI_INVALID_PARAMETER This or Hash is NULL.
+ @retval EFI_NOT_READY This call was not preceded by a valid call to HashInit() and at least one call to HashUpdate(),
+ or the operation in progress was canceled by a call to Hash() on the same instance.
+
+**/
+EFI_STATUS
+EFIAPI
+BaseCrypto2HashFinal (
+ IN CONST EFI_HASH2_PROTOCOL *This,
+ IN OUT EFI_HASH2_OUTPUT *Hash
+ );
+
+EFI_HASH2_PROTOCOL mHash2Protocol = {
+ BaseCrypto2GetHashSize,
+ BaseCrypto2Hash,
+ BaseCrypto2HashInit,
+ BaseCrypto2HashUpdate,
+ BaseCrypto2HashFinal,
+};
+
+/**
+ Returns hash information.
+
+ @param[in] HashAlgorithm Points to the EFI_GUID which identifies the algorithm to use.
+
+ @return Hash information.
+**/
+EFI_HASH_INFO *
+GetHashInfo (
+ IN CONST EFI_GUID *HashAlgorithm
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < sizeof(mHashInfo)/sizeof(mHashInfo[0]); Index++) {
+ if (CompareGuid (HashAlgorithm, mHashInfo[Index].Guid)) {
+ return &mHashInfo[Index];
+ }
+ }
+ return NULL;
+}
+
+/**
+ Returns the size of the hash which results from a specific algorithm.
+
+ @param[in] This Points to this instance of EFI_HASH2_PROTOCOL.
+ @param[in] HashAlgorithm Points to the EFI_GUID which identifies the algorithm to use.
+ @param[out] HashSize Holds the returned size of the algorithm's hash.
+
+ @retval EFI_SUCCESS Hash size returned successfully.
+ @retval EFI_INVALID_PARAMETER This or HashSize is NULL.
+ @retval EFI_UNSUPPORTED The algorithm specified by HashAlgorithm is not supported by this driver
+ or HashAlgorithm is null.
+
+**/
+EFI_STATUS
+EFIAPI
+BaseCrypto2GetHashSize (
+ IN CONST EFI_HASH2_PROTOCOL *This,
+ IN CONST EFI_GUID *HashAlgorithm,
+ OUT UINTN *HashSize
+ )
+{
+ EFI_HASH_INFO *HashInfo;
+
+ if ((This == NULL) || (HashSize == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (HashAlgorithm == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ HashInfo = GetHashInfo (HashAlgorithm);
+ if (HashInfo == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ *HashSize = HashInfo->HashSize;
+ return EFI_SUCCESS;
+}
+
+/**
+ Creates a hash for the specified message text. The hash is not extendable.
+ The output is final with any algorithm-required padding added by the function.
+
+ @param[in] This Points to this instance of EFI_HASH2_PROTOCOL.
+ @param[in] HashAlgorithm Points to the EFI_GUID which identifies the algorithm to use.
+ @param[in] Message Points to the start of the message.
+ @param[in] MessageSize The size of Message, in bytes.
+ @param[in,out] Hash On input, points to a caller-allocated buffer of the size
+ returned by GetHashSize() for the specified HashAlgorithm.
+ On output, the buffer holds the resulting hash computed from the message.
+
+ @retval EFI_SUCCESS Hash returned successfully.
+ @retval EFI_INVALID_PARAMETER This or Hash is NULL.
+ @retval EFI_UNSUPPORTED The algorithm specified by HashAlgorithm is not supported by this driver
+ or HashAlgorithm is Null.
+ @retval EFI_OUT_OF_RESOURCES Some resource required by the function is not available
+ or MessageSize is greater than platform maximum.
+
+**/
+EFI_STATUS
+EFIAPI
+BaseCrypto2Hash (
+ IN CONST EFI_HASH2_PROTOCOL *This,
+ IN CONST EFI_GUID *HashAlgorithm,
+ IN CONST UINT8 *Message,
+ IN UINTN MessageSize,
+ IN OUT EFI_HASH2_OUTPUT *Hash
+ )
+{
+ EFI_HASH_INFO *HashInfo;
+ VOID *HashCtx;
+ UINTN CtxSize;
+ BOOLEAN Ret;
+ EFI_STATUS Status;
+ HASH2_INSTANCE_DATA *Instance;
+
+ Status = EFI_SUCCESS;
+
+ if ((This == NULL) || (Hash == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (HashAlgorithm == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ HashInfo = GetHashInfo (HashAlgorithm);
+ if (HashInfo == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Instance = HASH2_INSTANCE_DATA_FROM_THIS(This);
+ if (Instance->HashContext != NULL) {
+ FreePool (Instance->HashContext);
+ }
+ Instance->HashInfoContext = NULL;
+ Instance->HashContext = NULL;
+
+ //
+ // Start hash sequence
+ //
+ CtxSize = HashInfo->GetContextSize ();
+ if (CtxSize == 0) {
+ return EFI_UNSUPPORTED;
+ }
+ HashCtx = AllocatePool (CtxSize);
+ if (HashCtx == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Ret = HashInfo->Init (HashCtx);
+ if (!Ret) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ //
+ // Setup the context
+ //
+ Instance->HashContext = HashCtx;
+ Instance->HashInfoContext = HashInfo;
+
+ Ret = HashInfo->Update (HashCtx, Message, MessageSize);
+ if (!Ret) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ Ret = HashInfo->Final (HashCtx, (UINT8 *)Hash->Sha1Hash);
+ if (!Ret) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+Done:
+ //
+ // Cleanup the context
+ //
+ FreePool (HashCtx);
+ Instance->HashInfoContext = NULL;
+ Instance->HashContext = NULL;
+ return Status;
+}
+
+/**
+ This function must be called to initialize a digest calculation to be subsequently performed using the
+ EFI_HASH2_PROTOCOL functions HashUpdate() and HashFinal().
+
+ @param[in] This Points to this instance of EFI_HASH2_PROTOCOL.
+ @param[in] HashAlgorithm Points to the EFI_GUID which identifies the algorithm to use.
+
+ @retval EFI_SUCCESS Initialized successfully.
+ @retval EFI_INVALID_PARAMETER This is NULL.
+ @retval EFI_UNSUPPORTED The algorithm specified by HashAlgorithm is not supported by this driver
+ or HashAlgorithm is Null.
+ @retval EFI_OUT_OF_RESOURCES Process failed due to lack of required resource.
+ @retval EFI_ALREADY_STARTED This function is called when the operation in progress is still in processing Hash(),
+ or HashInit() is already called before and not terminated by HashFinal() yet on the same instance.
+
+**/
+EFI_STATUS
+EFIAPI
+BaseCrypto2HashInit (
+ IN CONST EFI_HASH2_PROTOCOL *This,
+ IN CONST EFI_GUID *HashAlgorithm
+ )
+{
+ EFI_HASH_INFO *HashInfo;
+ VOID *HashCtx;
+ UINTN CtxSize;
+ BOOLEAN Ret;
+ HASH2_INSTANCE_DATA *Instance;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (HashAlgorithm == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ HashInfo = GetHashInfo (HashAlgorithm);
+ if (HashInfo == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Consistency Check
+ //
+ Instance = HASH2_INSTANCE_DATA_FROM_THIS(This);
+ if ((Instance->HashContext != NULL) || (Instance->HashInfoContext != NULL)) {
+ return EFI_ALREADY_STARTED;
+ }
+
+ //
+ // Start hash sequence
+ //
+ CtxSize = HashInfo->GetContextSize ();
+ if (CtxSize == 0) {
+ return EFI_UNSUPPORTED;
+ }
+ HashCtx = AllocatePool (CtxSize);
+ if (HashCtx == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Ret = HashInfo->Init (HashCtx);
+ if (!Ret) {
+ FreePool (HashCtx);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Setup the context
+ //
+ Instance->HashContext = HashCtx;
+ Instance->HashInfoContext = HashInfo;
+ Instance->Updated = FALSE;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Updates the hash of a computation in progress by adding a message text.
+
+ @param[in] This Points to this instance of EFI_HASH2_PROTOCOL.
+ @param[in] Message Points to the start of the message.
+ @param[in] MessageSize The size of Message, in bytes.
+
+ @retval EFI_SUCCESS Digest in progress updated successfully.
+ @retval EFI_INVALID_PARAMETER This or Hash is NULL.
+ @retval EFI_OUT_OF_RESOURCES Some resource required by the function is not available
+ or MessageSize is greater than platform maximum.
+ @retval EFI_NOT_READY This call was not preceded by a valid call to HashInit(),
+ or the operation in progress was terminated by a call to Hash() or HashFinal() on the same instance.
+
+**/
+EFI_STATUS
+EFIAPI
+BaseCrypto2HashUpdate (
+ IN CONST EFI_HASH2_PROTOCOL *This,
+ IN CONST UINT8 *Message,
+ IN UINTN MessageSize
+ )
+{
+ EFI_HASH_INFO *HashInfo;
+ VOID *HashCtx;
+ BOOLEAN Ret;
+ HASH2_INSTANCE_DATA *Instance;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Consistency Check
+ //
+ Instance = HASH2_INSTANCE_DATA_FROM_THIS(This);
+ if ((Instance->HashContext == NULL) || (Instance->HashInfoContext == NULL)) {
+ return EFI_NOT_READY;
+ }
+ HashInfo = Instance->HashInfoContext;
+ HashCtx = Instance->HashContext;
+
+ Ret = HashInfo->Update (HashCtx, Message, MessageSize);
+ if (!Ret) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Instance->Updated = TRUE;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Finalizes a hash operation in progress and returns calculation result.
+ The output is final with any necessary padding added by the function.
+ The hash may not be further updated or extended after HashFinal().
+
+ @param[in] This Points to this instance of EFI_HASH2_PROTOCOL.
+ @param[in,out] Hash On input, points to a caller-allocated buffer of the size
+ returned by GetHashSize() for the specified HashAlgorithm specified in preceding HashInit().
+ On output, the buffer holds the resulting hash computed from the message.
+
+ @retval EFI_SUCCESS Hash returned successfully.
+ @retval EFI_INVALID_PARAMETER This or Hash is NULL.
+ @retval EFI_NOT_READY This call was not preceded by a valid call to HashInit() and at least one call to HashUpdate(),
+ or the operation in progress was canceled by a call to Hash() on the same instance.
+
+**/
+EFI_STATUS
+EFIAPI
+BaseCrypto2HashFinal (
+ IN CONST EFI_HASH2_PROTOCOL *This,
+ IN OUT EFI_HASH2_OUTPUT *Hash
+ )
+{
+ EFI_HASH_INFO *HashInfo;
+ VOID *HashCtx;
+ BOOLEAN Ret;
+ HASH2_INSTANCE_DATA *Instance;
+
+ if ((This == NULL) || (Hash == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Consistency Check
+ //
+ Instance = HASH2_INSTANCE_DATA_FROM_THIS(This);
+ if ((Instance->HashContext == NULL) || (Instance->HashInfoContext == NULL) ||
+ (!Instance->Updated)) {
+ return EFI_NOT_READY;
+ }
+ HashInfo = Instance->HashInfoContext;
+ HashCtx = Instance->HashContext;
+
+ Ret = HashInfo->Final (HashCtx, (UINT8 *)Hash->Sha1Hash);
+
+ //
+ // Cleanup the context
+ //
+ FreePool (HashCtx);
+ Instance->HashInfoContext = NULL;
+ Instance->HashContext = NULL;
+ Instance->Updated = FALSE;
+
+ if (!Ret) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Core/SecurityPkg/Hash2DxeCrypto/Hash2DxeCrypto.inf b/Core/SecurityPkg/Hash2DxeCrypto/Hash2DxeCrypto.inf
new file mode 100644
index 0000000000..557dedbbea
--- /dev/null
+++ b/Core/SecurityPkg/Hash2DxeCrypto/Hash2DxeCrypto.inf
@@ -0,0 +1,64 @@
+## @file
+# Produces the UEFI HASH2 protocol
+#
+# This module will use EDKII crypto libary to HASH2 protocol.
+#
+# (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>
+# Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = Hash2DxeCrypto
+ FILE_GUID = 63E3BDCF-2AC7-4ac0-9B92-03A7541422FF
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = Hash2DriverEntryPoint
+ MODULE_UNI_FILE = Hash2DxeCrypto.uni
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF
+#
+
+[Sources.common]
+ Hash2DxeCrypto.c
+ Driver.h
+ Driver.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ CryptoPkg/CryptoPkg.dec
+
+[LibraryClasses]
+ UefiBootServicesTableLib
+ BaseLib
+ BaseMemoryLib
+ BaseCryptLib
+ MemoryAllocationLib
+ UefiDriverEntryPoint
+ DebugLib
+ UefiLib
+
+[Guids]
+ gEfiHashAlgorithmMD5Guid ## CONSUMES ## GUID
+ gEfiHashAlgorithmSha1Guid ## CONSUMES ## GUID
+ gEfiHashAlgorithmSha256Guid ## CONSUMES ## GUID
+ gEfiHashAlgorithmSha384Guid ## CONSUMES ## GUID
+ gEfiHashAlgorithmSha512Guid ## CONSUMES ## GUID
+
+[Protocols]
+ gEfiHash2ProtocolGuid ## PRODUCES
+ gEfiHash2ServiceBindingProtocolGuid ## PRODUCES
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ Hash2DxeCryptoExtra.uni \ No newline at end of file
diff --git a/Core/SecurityPkg/Hash2DxeCrypto/Hash2DxeCrypto.uni b/Core/SecurityPkg/Hash2DxeCrypto/Hash2DxeCrypto.uni
new file mode 100644
index 0000000000..1253087443
--- /dev/null
+++ b/Core/SecurityPkg/Hash2DxeCrypto/Hash2DxeCrypto.uni
@@ -0,0 +1,22 @@
+// /** @file
+// Produces the UEFI HASH2 protocol
+//
+// This module will use EDKII crypto libary to HASH2 protocol.
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+//
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Produces UEFI HASH2 protocol"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This module will use EDKII crypto libary to HASH2 protocol."
+
diff --git a/Core/SecurityPkg/Hash2DxeCrypto/Hash2DxeCryptoExtra.uni b/Core/SecurityPkg/Hash2DxeCrypto/Hash2DxeCryptoExtra.uni
new file mode 100644
index 0000000000..f70b8baa6b
--- /dev/null
+++ b/Core/SecurityPkg/Hash2DxeCrypto/Hash2DxeCryptoExtra.uni
@@ -0,0 +1,19 @@
+// /** @file
+// Hash2DxeCrypto Localized Strings and Content
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"UEFI Random Number Generator DXE"
+
+
diff --git a/Core/SecurityPkg/Include/Guid/AuthenticatedVariableFormat.h b/Core/SecurityPkg/Include/Guid/AuthenticatedVariableFormat.h
new file mode 100644
index 0000000000..55fd92a322
--- /dev/null
+++ b/Core/SecurityPkg/Include/Guid/AuthenticatedVariableFormat.h
@@ -0,0 +1,75 @@
+/** @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 that has been moved to
+ VariableFormat.h.
+
+Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __AUTHENTICATED_VARIABLE_FORMAT_H__
+#define __AUTHENTICATED_VARIABLE_FORMAT_H__
+
+#include <Guid/VariableFormat.h>
+
+#define EFI_SECURE_BOOT_ENABLE_DISABLE \
+ { 0xf0a30bc7, 0xaf08, 0x4556, { 0x99, 0xc4, 0x0, 0x10, 0x9, 0xc9, 0x3a, 0x44 } }
+
+extern EFI_GUID gEfiSecureBootEnableDisableGuid;
+extern EFI_GUID gEfiCertDbGuid;
+extern EFI_GUID gEfiCustomModeEnableGuid;
+extern EFI_GUID gEfiVendorKeysNvGuid;
+
+///
+/// "SecureBootEnable" variable for the Secure Boot feature enable/disable.
+/// This variable is used for allowing a physically present user to disable
+/// Secure Boot via firmware setup without the possession of PKpriv.
+///
+/// GUID: gEfiSecureBootEnableDisableGuid
+///
+/// Format: UINT8
+///
+#define EFI_SECURE_BOOT_ENABLE_NAME L"SecureBootEnable"
+#define SECURE_BOOT_ENABLE 1
+#define SECURE_BOOT_DISABLE 0
+
+///
+/// "CustomMode" variable for two Secure Boot modes feature: "Custom" and "Standard".
+/// Standard Secure Boot mode is the default mode as UEFI Spec's description.
+/// Custom Secure Boot mode allows for more flexibility as specified in the following:
+/// Can enroll or delete PK without existing PK's private key.
+/// Can enroll or delete KEK without existing PK's private key.
+/// Can enroll or delete signature from DB/DBX without KEK's private key.
+///
+/// GUID: gEfiCustomModeEnableGuid
+///
+/// Format: UINT8
+///
+#define EFI_CUSTOM_MODE_NAME L"CustomMode"
+#define CUSTOM_SECURE_BOOT_MODE 1
+#define STANDARD_SECURE_BOOT_MODE 0
+
+///
+/// "VendorKeysNv" variable to record the out of band secure boot keys modification.
+/// This variable is a read-only NV varaible that indicates whether someone other than
+/// the platform vendor has used a mechanism not defined by the UEFI Specification to
+/// transition the system to setup mode or to update secure boot keys.
+///
+/// GUID: gEfiVendorKeysNvGuid
+///
+/// Format: UINT8
+///
+#define EFI_VENDOR_KEYS_NV_VARIABLE_NAME L"VendorKeysNv"
+#define VENDOR_KEYS_VALID 1
+#define VENDOR_KEYS_MODIFIED 0
+
+#endif // __AUTHENTICATED_VARIABLE_FORMAT_H__
diff --git a/Core/SecurityPkg/Include/Guid/MeasuredFvHob.h b/Core/SecurityPkg/Include/Guid/MeasuredFvHob.h
new file mode 100644
index 0000000000..a2e6922335
--- /dev/null
+++ b/Core/SecurityPkg/Include/Guid/MeasuredFvHob.h
@@ -0,0 +1,36 @@
+/** @file
+ Defines the HOB GUID used to pass all PEI measured FV info to
+ DXE Driver.
+
+Copyright (c) 2012, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _MEASURED_FV_HOB_H_
+#define _MEASURED_FV_HOB_H_
+
+#include <IndustryStandard/UefiTcgPlatform.h>
+
+///
+/// The Global ID of a GUIDed HOB used to pass all PEI measured FV info to DXE Driver.
+///
+#define EFI_MEASURED_FV_HOB_GUID \
+ { \
+ 0xb2360b42, 0x7173, 0x420a, { 0x86, 0x96, 0x46, 0xca, 0x6b, 0xab, 0x10, 0x60 } \
+ }
+
+extern EFI_GUID gMeasuredFvHobGuid;
+
+typedef struct {
+ UINT32 Num;
+ EFI_PLATFORM_FIRMWARE_BLOB MeasuredFvBuf[1];
+} MEASURED_HOB_DATA;
+
+#endif
diff --git a/Core/SecurityPkg/Include/Guid/OpalPasswordExtraInfoVariable.h b/Core/SecurityPkg/Include/Guid/OpalPasswordExtraInfoVariable.h
new file mode 100644
index 0000000000..f16d0a4ac3
--- /dev/null
+++ b/Core/SecurityPkg/Include/Guid/OpalPasswordExtraInfoVariable.h
@@ -0,0 +1,27 @@
+/** @file
+ Defines Name GUIDs to represent an Opal device variable guid for Opal Security Feature.
+
+Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _OPAL_PASSWORD_EXTRA_INFO_VARIABLE_H_
+#define _OPAL_PASSWORD_EXTRA_INFO_VARIABLE_H_
+
+#define OPAL_EXTRA_INFO_VAR_NAME L"OpalExtraInfo"
+
+typedef struct {
+ UINT8 EnableBlockSid;
+} OPAL_EXTRA_INFO_VAR;
+
+extern EFI_GUID gOpalExtraInfoVariableGuid;
+
+#endif // _OPAL_PASSWORD_SECURITY_VARIABLE_H_
+
diff --git a/Core/SecurityPkg/Include/Guid/PhysicalPresenceData.h b/Core/SecurityPkg/Include/Guid/PhysicalPresenceData.h
new file mode 100644
index 0000000000..165b4647c0
--- /dev/null
+++ b/Core/SecurityPkg/Include/Guid/PhysicalPresenceData.h
@@ -0,0 +1,81 @@
+/** @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 - 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __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;
+} EFI_PHYSICAL_PRESENCE;
+
+//
+// The definition of physical presence operation actions
+//
+#define PHYSICAL_PRESENCE_NO_ACTION 0
+#define PHYSICAL_PRESENCE_ENABLE 1
+#define PHYSICAL_PRESENCE_DISABLE 2
+#define PHYSICAL_PRESENCE_ACTIVATE 3
+#define PHYSICAL_PRESENCE_DEACTIVATE 4
+#define PHYSICAL_PRESENCE_CLEAR 5
+#define PHYSICAL_PRESENCE_ENABLE_ACTIVATE 6
+#define PHYSICAL_PRESENCE_DEACTIVATE_DISABLE 7
+#define PHYSICAL_PRESENCE_SET_OWNER_INSTALL_TRUE 8
+#define PHYSICAL_PRESENCE_SET_OWNER_INSTALL_FALSE 9
+#define PHYSICAL_PRESENCE_ENABLE_ACTIVATE_OWNER_TRUE 10
+#define PHYSICAL_PRESENCE_DEACTIVATE_DISABLE_OWNER_FALSE 11
+#define PHYSICAL_PRESENCE_DEFERRED_PP_UNOWNERED_FIELD_UPGRADE 12
+#define PHYSICAL_PRESENCE_SET_OPERATOR_AUTH 13
+#define PHYSICAL_PRESENCE_CLEAR_ENABLE_ACTIVATE 14
+#define PHYSICAL_PRESENCE_SET_NO_PPI_PROVISION_FALSE 15
+#define PHYSICAL_PRESENCE_SET_NO_PPI_PROVISION_TRUE 16
+#define PHYSICAL_PRESENCE_SET_NO_PPI_CLEAR_FALSE 17
+#define PHYSICAL_PRESENCE_SET_NO_PPI_CLEAR_TRUE 18
+#define PHYSICAL_PRESENCE_SET_NO_PPI_MAINTENANCE_FALSE 19
+#define PHYSICAL_PRESENCE_SET_NO_PPI_MAINTENANCE_TRUE 20
+#define PHYSICAL_PRESENCE_ENABLE_ACTIVATE_CLEAR 21
+#define PHYSICAL_PRESENCE_ENABLE_ACTIVATE_CLEAR_ENABLE_ACTIVATE 22
+
+//
+// This variable is used to save TPM Management Flags and corresponding operations.
+// It should be protected from malicious software (e.g. Set it as read-only variable).
+//
+#define PHYSICAL_PRESENCE_FLAGS_VARIABLE L"PhysicalPresenceFlags"
+typedef struct {
+ UINT8 PPFlags;
+} EFI_PHYSICAL_PRESENCE_FLAGS;
+
+//
+// The definition bit of the TPM Management Flags
+//
+#define FLAG_NO_PPI_PROVISION BIT0
+#define FLAG_NO_PPI_CLEAR BIT1
+#define FLAG_NO_PPI_MAINTENANCE BIT2
+#define FLAG_RESET_TRACK BIT3
+
+extern EFI_GUID gEfiPhysicalPresenceGuid;
+
+#endif
+
diff --git a/Core/SecurityPkg/Include/Guid/PwdCredentialProviderHii.h b/Core/SecurityPkg/Include/Guid/PwdCredentialProviderHii.h
new file mode 100644
index 0000000000..007144abfd
--- /dev/null
+++ b/Core/SecurityPkg/Include/Guid/PwdCredentialProviderHii.h
@@ -0,0 +1,29 @@
+/** @file
+ GUID used as HII FormSet and HII Package list GUID in PwdCredentialProviderDxe driver.
+
+Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __PWD_CREDENTIAL_PROVIDER_HII_H__
+#define __PWD_CREDENTIAL_PROVIDER_HII_H__
+
+//
+// Used for save password credential and form browser.
+// Also used as provider identifier.
+//
+#define PWD_CREDENTIAL_PROVIDER_GUID \
+ { \
+ 0x78b9ec8b, 0xc000, 0x46c5, { 0xac, 0x93, 0x24, 0xa0, 0xc1, 0xbb, 0x0, 0xce } \
+ }
+
+extern EFI_GUID gPwdCredentialProviderGuid;
+
+#endif
diff --git a/Core/SecurityPkg/Include/Guid/SecureBootConfigHii.h b/Core/SecurityPkg/Include/Guid/SecureBootConfigHii.h
new file mode 100644
index 0000000000..5f162486f4
--- /dev/null
+++ b/Core/SecurityPkg/Include/Guid/SecureBootConfigHii.h
@@ -0,0 +1,26 @@
+/** @file
+ GUIDs used as HII FormSet and HII Package list GUID in SecureBootConfigDxe driver.
+
+Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that 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 __SECUREBOOT_CONFIG_HII_GUID_H__
+#define __SECUREBOOT_CONFIG_HII_GUID_H__
+
+#define SECUREBOOT_CONFIG_FORM_SET_GUID \
+ { \
+ 0x5daf50a5, 0xea81, 0x4de2, {0x8f, 0x9b, 0xca, 0xbd, 0xa9, 0xcf, 0x5c, 0x14} \
+ }
+
+
+extern EFI_GUID gSecureBootConfigFormSetGuid;
+
+#endif
diff --git a/Core/SecurityPkg/Include/Guid/SecurityPkgTokenSpace.h b/Core/SecurityPkg/Include/Guid/SecurityPkgTokenSpace.h
new file mode 100644
index 0000000000..b1b7666f18
--- /dev/null
+++ b/Core/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.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _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/Core/SecurityPkg/Include/Guid/Tcg2ConfigHii.h b/Core/SecurityPkg/Include/Guid/Tcg2ConfigHii.h
new file mode 100644
index 0000000000..28e31e3475
--- /dev/null
+++ b/Core/SecurityPkg/Include/Guid/Tcg2ConfigHii.h
@@ -0,0 +1,25 @@
+/** @file
+ GUIDs used as HII FormSet and HII Package list GUID in Tcg2Config driver.
+
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that 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 __TCG2_CONFIG_HII_GUID_H__
+#define __TCG2_CONFIG_HII_GUID_H__
+
+#define TCG2_CONFIG_FORM_SET_GUID \
+ { \
+ 0x6339d487, 0x26ba, 0x424b, { 0x9a, 0x5d, 0x68, 0x7e, 0x25, 0xd7, 0x40, 0xbc } \
+ }
+
+extern EFI_GUID gTcg2ConfigFormSetGuid;
+
+#endif
diff --git a/Core/SecurityPkg/Include/Guid/Tcg2PhysicalPresenceData.h b/Core/SecurityPkg/Include/Guid/Tcg2PhysicalPresenceData.h
new file mode 100644
index 0000000000..df43fd9c80
--- /dev/null
+++ b/Core/SecurityPkg/Include/Guid/Tcg2PhysicalPresenceData.h
@@ -0,0 +1,47 @@
+/** @file
+ Define the variable data structures used for TCG2 physical presence.
+ The TPM2 request from firmware or OS is saved to variable. And it is
+ cleared after it is processed in the next boot cycle. The TPM2 response
+ is saved to variable.
+
+Copyright (c) 2015, Intel Corporation. All rights reserved. <BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __TCG2_PHYSICAL_PRESENCE_DATA_GUID_H__
+#define __TCG2_PHYSICAL_PRESENCE_DATA_GUID_H__
+
+#define EFI_TCG2_PHYSICAL_PRESENCE_DATA_GUID \
+ { \
+ 0xaeb9c5c1, 0x94f1, 0x4d02, { 0xbf, 0xd9, 0x46, 0x2, 0xdb, 0x2d, 0x3c, 0x54 } \
+ }
+
+#define TCG2_PHYSICAL_PRESENCE_VARIABLE L"Tcg2PhysicalPresence"
+
+typedef struct {
+ UINT8 PPRequest; ///< Physical Presence request command.
+ UINT32 PPRequestParameter; ///< Physical Presence request Parameter.
+ UINT8 LastPPRequest;
+ UINT32 PPResponse;
+} EFI_TCG2_PHYSICAL_PRESENCE;
+
+//
+// This variable is used to save TCG2 Management Flags and corresponding operations.
+// It should be protected from malicious software (e.g. Set it as read-only variable).
+//
+#define TCG2_PHYSICAL_PRESENCE_FLAGS_VARIABLE L"Tcg2PhysicalPresenceFlags"
+typedef struct {
+ UINT32 PPFlags;
+} EFI_TCG2_PHYSICAL_PRESENCE_FLAGS;
+
+extern EFI_GUID gEfiTcg2PhysicalPresenceGuid;
+
+#endif
+
diff --git a/Core/SecurityPkg/Include/Guid/TcgConfigHii.h b/Core/SecurityPkg/Include/Guid/TcgConfigHii.h
new file mode 100644
index 0000000000..d316299f8f
--- /dev/null
+++ b/Core/SecurityPkg/Include/Guid/TcgConfigHii.h
@@ -0,0 +1,25 @@
+/** @file
+ GUIDs used as HII FormSet and HII Package list GUID in TcgConfig driver.
+
+Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that 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_HII_GUID_H__
+#define __TCG_CONFIG_HII_GUID_H__
+
+#define TCG_CONFIG_FORM_SET_GUID \
+ { \
+ 0xb0f901e4, 0xc424, 0x45de, {0x90, 0x81, 0x95, 0xe2, 0xb, 0xde, 0x6f, 0xb5 } \
+ }
+
+extern EFI_GUID gTcgConfigFormSetGuid;
+
+#endif
diff --git a/Core/SecurityPkg/Include/Guid/TcgEventHob.h b/Core/SecurityPkg/Include/Guid/TcgEventHob.h
new file mode 100644
index 0000000000..943a7c601c
--- /dev/null
+++ b/Core/SecurityPkg/Include/Guid/TcgEventHob.h
@@ -0,0 +1,58 @@
+/** @file
+ Defines the HOB GUID used to pass a TCG_PCR_EVENT or TCG_PCR_EVENT2 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 - 2017, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _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 \
+ { \
+ 0x2b9ffb52, 0x1b13, 0x416f, { 0xa8, 0x7b, 0xbc, 0x93, 0xd, 0xef, 0x92, 0xa8 } \
+ }
+
+extern EFI_GUID gTcgEventEntryHobGuid;
+
+#define EFI_TCG_EVENT2_HOB_GUID \
+ { \
+ 0xd26c221e, 0x2430, 0x4c8a, { 0x91, 0x70, 0x3f, 0xcb, 0x45, 0x0, 0x41, 0x3f } \
+ }
+
+extern EFI_GUID gTcgEvent2EntryHobGuid;
+
+///
+/// The Global ID of a GUIDed HOB used to record TPM device error.
+///
+#define EFI_TPM_ERROR_GUID \
+ { \
+ 0xef598499, 0xb25e, 0x473a, { 0xbf, 0xaf, 0xe7, 0xe5, 0x7d, 0xce, 0x82, 0xc4 } \
+ }
+
+extern EFI_GUID gTpmErrorHobGuid;
+
+///
+/// The Global ID of a GUIDed HOB used to record TPM2 Startup Locality.
+/// HOB payload is UINT8 according to Startup Locality Event.
+///
+#define EFI_TPM2_STARTUP_LOCALITY_HOB_GUID \
+ { \
+ 0xef598499, 0xb25e, 0x473a, { 0xbf, 0xaf, 0xe7, 0xe5, 0x7d, 0xce, 0x82, 0xc4 } \
+ }
+
+extern EFI_GUID gTpm2StartupLocalityHobGuid;
+
+#endif
diff --git a/Core/SecurityPkg/Include/Guid/TpmInstance.h b/Core/SecurityPkg/Include/Guid/TpmInstance.h
new file mode 100644
index 0000000000..27c727bafd
--- /dev/null
+++ b/Core/SecurityPkg/Include/Guid/TpmInstance.h
@@ -0,0 +1,38 @@
+/** @file
+ TPM instance guid, used for PcdTpmInstanceGuid.
+
+Copyright (c) 2013, Intel Corporation. All rights reserved. <BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __TPM_INSTANCE_GUID_H__
+#define __TPM_INSTANCE_GUID_H__
+
+#define TPM_DEVICE_INTERFACE_NONE \
+ { 0x00000000, 0x0000, 0x0000, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }
+
+#define TPM_DEVICE_INTERFACE_TPM12 \
+ { 0x8b01e5b6, 0x4f19, 0x46e8, { 0xab, 0x93, 0x1c, 0x53, 0x67, 0x1b, 0x90, 0xcc } }
+
+#define TPM_DEVICE_INTERFACE_TPM20_DTPM \
+ { 0x286bf25a, 0xc2c3, 0x408c, { 0xb3, 0xb4, 0x25, 0xe6, 0x75, 0x8b, 0x73, 0x17 } }
+
+extern EFI_GUID gEfiTpmDeviceInstanceNoneGuid;
+extern EFI_GUID gEfiTpmDeviceInstanceTpm12Guid;
+extern EFI_GUID gEfiTpmDeviceInstanceTpm20DtpmGuid;
+
+
+#define TPM_DEVICE_SELECTED_GUID \
+ { 0x7f4158d3, 0x74d, 0x456d, { 0x8c, 0xb2, 0x1, 0xf9, 0xc8, 0xf7, 0x9d, 0xaa } }
+
+extern EFI_GUID gEfiTpmDeviceSelectedGuid;
+
+#endif
+
diff --git a/Core/SecurityPkg/Include/Guid/TrEEConfigHii.h b/Core/SecurityPkg/Include/Guid/TrEEConfigHii.h
new file mode 100644
index 0000000000..b5d1de746a
--- /dev/null
+++ b/Core/SecurityPkg/Include/Guid/TrEEConfigHii.h
@@ -0,0 +1,25 @@
+/** @file
+ GUIDs used as HII FormSet and HII Package list GUID in TrEEConfig driver.
+
+Copyright (c) 2013, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that 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 __TREE_CONFIG_HII_GUID_H__
+#define __TREE_CONFIG_HII_GUID_H__
+
+#define TREE_CONFIG_FORM_SET_GUID \
+ { \
+ 0xc54b425f, 0xaa79, 0x48b4, { 0x98, 0x1f, 0x99, 0x8b, 0x3c, 0x4b, 0x64, 0x1c } \
+ }
+
+extern EFI_GUID gTrEEConfigFormSetGuid;
+
+#endif
diff --git a/Core/SecurityPkg/Include/Guid/TrEEPhysicalPresenceData.h b/Core/SecurityPkg/Include/Guid/TrEEPhysicalPresenceData.h
new file mode 100644
index 0000000000..0e2f8d1096
--- /dev/null
+++ b/Core/SecurityPkg/Include/Guid/TrEEPhysicalPresenceData.h
@@ -0,0 +1,67 @@
+/** @file
+ Define the variable data structures used for TrEE physical presence.
+ The TPM2 request from firmware or OS is saved to variable. And it is
+ cleared after it is processed in the next boot cycle. The TPM2 response
+ is saved to variable.
+
+Copyright (c) 2013 - 2015, Intel Corporation. All rights reserved. <BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __TREE_PHYSICAL_PRESENCE_DATA_GUID_H__
+#define __TREE_PHYSICAL_PRESENCE_DATA_GUID_H__
+
+#define EFI_TREE_PHYSICAL_PRESENCE_DATA_GUID \
+ { \
+ 0xf24643c2, 0xc622, 0x494e, { 0x8a, 0xd, 0x46, 0x32, 0x57, 0x9c, 0x2d, 0x5b }\
+ }
+
+#define TREE_PHYSICAL_PRESENCE_VARIABLE L"TrEEPhysicalPresence"
+
+typedef struct {
+ UINT8 PPRequest; ///< Physical Presence request command.
+ UINT8 LastPPRequest;
+ UINT32 PPResponse;
+} EFI_TREE_PHYSICAL_PRESENCE;
+
+//
+// The definition bit of the flags
+//
+// BIT0 is reserved
+#define TREE_FLAG_NO_PPI_CLEAR BIT1
+// BIT2 is reserved
+#define TREE_FLAG_RESET_TRACK BIT3
+
+//
+// This variable is used to save TPM Management Flags and corresponding operations.
+// It should be protected from malicious software (e.g. Set it as read-only variable).
+//
+#define TREE_PHYSICAL_PRESENCE_FLAGS_VARIABLE L"TrEEPhysicalPresenceFlags"
+typedef struct {
+ UINT8 PPFlags;
+} EFI_TREE_PHYSICAL_PRESENCE_FLAGS;
+
+//
+// The definition of physical presence operation actions
+//
+#define TREE_PHYSICAL_PRESENCE_NO_ACTION 0
+#define TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR 5
+#define TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_2 14
+#define TREE_PHYSICAL_PRESENCE_SET_NO_PPI_CLEAR_FALSE 17
+#define TREE_PHYSICAL_PRESENCE_SET_NO_PPI_CLEAR_TRUE 18
+#define TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_3 21
+#define TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_4 22
+
+#define TREE_PHYSICAL_PRESENCE_NO_ACTION_MAX 22
+
+extern EFI_GUID gEfiTrEEPhysicalPresenceGuid;
+
+#endif
+
diff --git a/Core/SecurityPkg/Include/Guid/UsbCredentialProviderHii.h b/Core/SecurityPkg/Include/Guid/UsbCredentialProviderHii.h
new file mode 100644
index 0000000000..217aef6567
--- /dev/null
+++ b/Core/SecurityPkg/Include/Guid/UsbCredentialProviderHii.h
@@ -0,0 +1,29 @@
+/** @file
+ GUID used as HII Package list GUID in UsbCredentialProviderDxe driver.
+
+Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __USB_CREDENTIAL_PROVIDER_HII_H__
+#define __USB_CREDENTIAL_PROVIDER_HII_H__
+
+//
+// Used for save password credential and form browser
+// And used as provider identifier
+//
+#define USB_CREDENTIAL_PROVIDER_GUID \
+ { \
+ 0xd0849ed1, 0xa88c, 0x4ba6, { 0xb1, 0xd6, 0xab, 0x50, 0xe2, 0x80, 0xb7, 0xa9 }\
+ }
+
+extern EFI_GUID gUsbCredentialProviderGuid;
+
+#endif
diff --git a/Core/SecurityPkg/Include/Guid/UserIdentifyManagerHii.h b/Core/SecurityPkg/Include/Guid/UserIdentifyManagerHii.h
new file mode 100644
index 0000000000..11d215c5dd
--- /dev/null
+++ b/Core/SecurityPkg/Include/Guid/UserIdentifyManagerHii.h
@@ -0,0 +1,25 @@
+/** @file
+ GUID used as HII FormSet and HII Package list GUID in UserIdentifyManagerDxe driver.
+
+Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __USER_IDENTIFY_MANAGER_HII_H__
+#define __USER_IDENTIFY_MANAGER_HII_H__
+
+#define USER_IDENTIFY_MANAGER_GUID \
+ { \
+ 0x3ccd3dd8, 0x8d45, 0x4fed, { 0x96, 0x2d, 0x2b, 0x38, 0xcd, 0x82, 0xb3, 0xc4 } \
+ }
+
+extern EFI_GUID gUserIdentifyManagerGuid;
+
+#endif
diff --git a/Core/SecurityPkg/Include/Guid/UserProfileManagerHii.h b/Core/SecurityPkg/Include/Guid/UserProfileManagerHii.h
new file mode 100644
index 0000000000..e53e5a13e6
--- /dev/null
+++ b/Core/SecurityPkg/Include/Guid/UserProfileManagerHii.h
@@ -0,0 +1,25 @@
+/** @file
+ GUID used as HII FormSet and HII Package list GUID in UserProfileManagerDxe driver.
+
+Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __USER_PROFILE_MANAGER_HII_H__
+#define __USER_PROFILE_MANAGER_HII_H__
+
+#define USER_PROFILE_MANAGER_GUID \
+ { \
+ 0xc35f272c, 0x97c2, 0x465a, { 0xa2, 0x16, 0x69, 0x6b, 0x66, 0x8a, 0x8c, 0xfe } \
+ }
+
+extern EFI_GUID gUserProfileManagerGuid;
+
+#endif \ No newline at end of file
diff --git a/Core/SecurityPkg/Include/Library/HashLib.h b/Core/SecurityPkg/Include/Library/HashLib.h
new file mode 100644
index 0000000000..8be8b9c59c
--- /dev/null
+++ b/Core/SecurityPkg/Include/Library/HashLib.h
@@ -0,0 +1,169 @@
+/** @file
+ This library abstract TPM2 hash calculation.
+ The platform can choose multiply hash, while caller just need invoke these API.
+ Then all hash value will be returned and/or extended.
+
+Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved. <BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _HASH_LIB_H_
+#define _HASH_LIB_H_
+
+#include <Uefi.h>
+#include <Protocol/Hash.h>
+
+typedef UINTN HASH_HANDLE;
+
+/**
+ Start hash sequence.
+
+ @param HashHandle Hash handle.
+
+ @retval EFI_SUCCESS Hash sequence start and HandleHandle returned.
+ @retval EFI_OUT_OF_RESOURCES No enough resource to start hash.
+**/
+EFI_STATUS
+EFIAPI
+HashStart (
+ OUT HASH_HANDLE *HashHandle
+ );
+
+/**
+ Update hash sequence data.
+
+ @param HashHandle Hash handle.
+ @param DataToHash Data to be hashed.
+ @param DataToHashLen Data size.
+
+ @retval EFI_SUCCESS Hash sequence updated.
+**/
+EFI_STATUS
+EFIAPI
+HashUpdate (
+ IN HASH_HANDLE HashHandle,
+ IN VOID *DataToHash,
+ IN UINTN DataToHashLen
+ );
+
+/**
+ Hash sequence complete and extend to PCR.
+
+ @param HashHandle Hash handle.
+ @param PcrIndex PCR to be extended.
+ @param DataToHash Data to be hashed.
+ @param DataToHashLen Data size.
+ @param DigestList Digest list.
+
+ @retval EFI_SUCCESS Hash sequence complete and DigestList is returned.
+**/
+EFI_STATUS
+EFIAPI
+HashCompleteAndExtend (
+ IN HASH_HANDLE HashHandle,
+ IN TPMI_DH_PCR PcrIndex,
+ IN VOID *DataToHash,
+ IN UINTN DataToHashLen,
+ OUT TPML_DIGEST_VALUES *DigestList
+ );
+
+/**
+ Hash data and extend to PCR.
+
+ @param PcrIndex PCR to be extended.
+ @param DataToHash Data to be hashed.
+ @param DataToHashLen Data size.
+ @param DigestList Digest list.
+
+ @retval EFI_SUCCESS Hash data and DigestList is returned.
+**/
+EFI_STATUS
+EFIAPI
+HashAndExtend (
+ IN TPMI_DH_PCR PcrIndex,
+ IN VOID *DataToHash,
+ IN UINTN DataToHashLen,
+ OUT TPML_DIGEST_VALUES *DigestList
+ );
+
+/**
+ Start hash sequence.
+
+ @param HashHandle Hash handle.
+
+ @retval EFI_SUCCESS Hash sequence start and HandleHandle returned.
+ @retval EFI_OUT_OF_RESOURCES No enough resource to start hash.
+**/
+typedef
+EFI_STATUS
+(EFIAPI *HASH_INIT) (
+ OUT HASH_HANDLE *HashHandle
+ );
+
+/**
+ Update hash sequence data.
+
+ @param HashHandle Hash handle.
+ @param DataToHash Data to be hashed.
+ @param DataToHashLen Data size.
+
+ @retval EFI_SUCCESS Hash sequence updated.
+**/
+typedef
+EFI_STATUS
+(EFIAPI *HASH_UPDATE) (
+ IN HASH_HANDLE HashHandle,
+ IN VOID *DataToHash,
+ IN UINTN DataToHashLen
+ );
+
+/**
+ Complete hash sequence complete.
+
+ @param HashHandle Hash handle.
+ @param DigestList Digest list.
+
+ @retval EFI_SUCCESS Hash sequence complete and DigestList is returned.
+**/
+typedef
+EFI_STATUS
+(EFIAPI *HASH_FINAL) (
+ IN HASH_HANDLE HashHandle,
+ OUT TPML_DIGEST_VALUES *DigestList
+ );
+
+#define HASH_ALGORITHM_SHA1_GUID EFI_HASH_ALGORITHM_SHA1_GUID
+#define HASH_ALGORITHM_SHA256_GUID EFI_HASH_ALGORITHM_SHA256_GUID
+#define HASH_ALGORITHM_SHA384_GUID EFI_HASH_ALGORITHM_SHA384_GUID
+#define HASH_ALGORITHM_SHA512_GUID EFI_HASH_ALGORITHM_SHA512_GUID
+
+typedef struct {
+ EFI_GUID HashGuid;
+ HASH_INIT HashInit;
+ HASH_UPDATE HashUpdate;
+ HASH_FINAL HashFinal;
+} HASH_INTERFACE;
+
+/**
+ This service register Hash.
+
+ @param HashInterface Hash interface
+
+ @retval EFI_SUCCESS This hash interface is registered successfully.
+ @retval EFI_UNSUPPORTED System does not support register this interface.
+ @retval EFI_ALREADY_STARTED System already register this interface.
+**/
+EFI_STATUS
+EFIAPI
+RegisterHashInterfaceLib (
+ IN HASH_INTERFACE *HashInterface
+ );
+
+#endif
diff --git a/Core/SecurityPkg/Include/Library/OpalPasswordSupportLib.h b/Core/SecurityPkg/Include/Library/OpalPasswordSupportLib.h
new file mode 100644
index 0000000000..e616c763f0
--- /dev/null
+++ b/Core/SecurityPkg/Include/Library/OpalPasswordSupportLib.h
@@ -0,0 +1,289 @@
+/** @file
+ Header file of Opal password support library.
+
+Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+
+#ifndef _OPAL_PASSWORD_SUPPORT_LIB_H_
+#define _OPAL_PASSWORD_SUPPORT_LIB_H_
+
+#include <Protocol/DevicePath.h>
+#include <Library/TcgStorageOpalLib.h>
+
+
+#pragma pack(1)
+
+//
+// Structure that is used to represent the available actions for an OpalDisk.
+// The data can then be utilized to expose/hide certain actions available to an end user
+// by the consumer of this library.
+//
+typedef struct {
+ //
+ // Indicates if the disk can support PSID Revert action. should verify disk supports PSID authority
+ //
+ UINT16 PsidRevert : 1;
+
+ //
+ // Indicates if the disk can support Revert action
+ //
+ UINT16 Revert : 1;
+
+ //
+ // Indicates if the user must keep data for revert action. It is true if no media encryption is supported.
+ //
+ UINT16 RevertKeepDataForced : 1;
+
+ //
+ // Indicates if the disk can support set Admin password
+ //
+ UINT16 AdminPass : 1;
+
+ //
+ // Indicates if the disk can support set User password. This action requires that a user
+ // password is first enabled.
+ //
+ UINT16 UserPass : 1;
+
+ //
+ // Indicates if unlock action is available. Requires disk to be currently locked.
+ //
+ UINT16 Unlock : 1;
+
+ //
+ // Indicates if Secure Erase action is available. Action requires admin credentials and media encryption support.
+ //
+ UINT16 SecureErase : 1;
+
+ //
+ // Indicates if Disable User action is available. Action requires admin credentials.
+ //
+ UINT16 DisableUser : 1;
+} OPAL_DISK_ACTIONS;
+
+//
+// Structure that is used to represent the Opal device with password info.
+//
+typedef struct {
+ LIST_ENTRY Link;
+
+ UINT8 Password[32];
+ UINT8 PasswordLength;
+
+ EFI_DEVICE_PATH_PROTOCOL OpalDevicePath;
+} OPAL_DISK_AND_PASSWORD_INFO;
+
+#pragma pack()
+
+/**
+
+ The function performs determines the available actions for the OPAL_DISK provided.
+
+ @param[in] SupportedAttributes The support attribute for the device.
+ @param[in] LockingFeature The locking status for the device.
+ @param[in] OwnerShip The ownership for the device.
+ @param[out] AvalDiskActions Pointer to fill-out with appropriate disk actions.
+
+**/
+TCG_RESULT
+EFIAPI
+OpalSupportGetAvailableActions(
+ IN OPAL_DISK_SUPPORT_ATTRIBUTE *SupportedAttributes,
+ IN TCG_LOCKING_FEATURE_DESCRIPTOR *LockingFeature,
+ IN UINT16 OwnerShip,
+ OUT OPAL_DISK_ACTIONS *AvalDiskActions
+ );
+
+/**
+ Enable Opal Feature for the input device.
+
+ @param[in] Session The opal session for the opal device.
+ @param[in] Msid Msid
+ @param[in] MsidLength Msid Length
+ @param[in] Password Admin password
+ @param[in] PassLength Length of password in bytes
+ @param[in] DevicePath The device path for the opal devcie.
+
+**/
+TCG_RESULT
+EFIAPI
+OpalSupportEnableOpalFeature(
+ IN OPAL_SESSION *Session,
+ IN VOID *Msid,
+ IN UINT32 MsidLength,
+ IN VOID *Password,
+ IN UINT32 PassLength,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ );
+
+/**
+ Creates a session with OPAL_UID_ADMIN_SP as OPAL_ADMIN_SP_PSID_AUTHORITY, then reverts device using Admin SP Revert method.
+
+ @param[in] Session The opal session for the opal device.
+ @param[in] Psid PSID of device to revert.
+ @param[in] PsidLength Length of PSID in bytes.
+ @param[in] DevicePath The device path for the opal devcie.
+
+**/
+TCG_RESULT
+EFIAPI
+OpalSupportPsidRevert(
+ IN OPAL_SESSION *Session,
+ IN VOID *Psid,
+ IN UINT32 PsidLength,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ );
+
+/**
+ Opens a session with OPAL_UID_ADMIN_SP as OPAL_ADMIN_SP_PSID_AUTHORITY, then reverts the device using the RevertSP method.
+
+ @param[in] Session The opal session for the opal device.
+ @param[in] KeepUserData TRUE to keep existing Data on the disk, or FALSE to erase it
+ @param[in] Password Admin password
+ @param[in] PasswordLength Length of password in bytes
+ @param[in] Msid Msid
+ @param[in] MsidLength Msid Length
+ @param[out] PasswordFailed indicates if password failed (start session didn't work)
+ @param[in] DevicePath The device path for the opal devcie.
+
+**/
+TCG_RESULT
+EFIAPI
+OpalSupportRevert(
+ IN OPAL_SESSION *Session,
+ IN BOOLEAN KeepUserData,
+ IN VOID *Password,
+ IN UINT32 PasswordLength,
+ IN VOID *Msid,
+ IN UINT32 MsidLength,
+ OUT BOOLEAN *PasswordFailed,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ );
+
+/**
+ Set new password.
+
+ @param[in] Session The opal session for the opal device.
+ @param[in] OldPassword Current admin password
+ @param[in] OldPasswordLength Length of current admin password in bytes
+ @param[in] NewPassword New admin password to set
+ @param[in] NewPasswordLength Length of new password in bytes
+ @param[in] DevicePath The device path for the opal devcie.
+ @param[in] SetAdmin Whether set admin password or user password.
+ TRUE for admin, FALSE for user.
+
+**/
+TCG_RESULT
+EFIAPI
+OpalSupportSetPassword(
+ IN OPAL_SESSION *Session,
+ IN VOID *OldPassword,
+ IN UINT32 OldPasswordLength,
+ IN VOID *NewPassword,
+ IN UINT32 NewPasswordLength,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ IN BOOLEAN SetAdmin
+ );
+
+/**
+ Starts a session with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_ADMIN1_AUTHORITY and disables the User1 authority.
+
+ @param[in] Session The opal session for the opal device.
+ @param[in] Password Admin password
+ @param[in] PasswordLength Length of password in bytes
+ @param[out] PasswordFailed Indicates if password failed (start session didn't work)
+ @param[in] DevicePath The device path for the opal devcie.
+
+**/
+TCG_RESULT
+EFIAPI
+OpalSupportDisableUser(
+ IN OPAL_SESSION *Session,
+ IN VOID *Password,
+ IN UINT32 PasswordLength,
+ OUT BOOLEAN *PasswordFailed,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ );
+
+/**
+ Starts a session with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_USER1_AUTHORITY or OPAL_LOCKING_SP_ADMIN1_AUTHORITY
+ and updates the global locking range ReadLocked and WriteLocked columns to FALSE.
+
+ @param[in] Session The opal session for the opal device.
+ @param[in] Password Admin or user password
+ @param[in] PasswordLength Length of password in bytes
+ @param[in] DevicePath The device path for the opal devcie.
+
+**/
+TCG_RESULT
+EFIAPI
+OpalSupportUnlock(
+ IN OPAL_SESSION *Session,
+ IN VOID *Password,
+ IN UINT32 PasswordLength,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ );
+
+/**
+ Starts a session with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_USER1_AUTHORITY or OPAL_LOCKING_SP_ADMIN1_AUTHORITY
+ and updates the global locking range ReadLocked and WriteLocked columns to TRUE.
+
+ @param[in] Session The opal session for the opal device.
+ @param[in] Password Admin or user password
+ @param[in] PasswordLength Length of password in bytes
+ @param[in] DevicePath The device path for the opal devcie.
+
+**/
+TCG_RESULT
+EFIAPI
+OpalSupportLock(
+ IN OPAL_SESSION *Session,
+ IN VOID *Password,
+ IN UINT32 PasswordLength,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ );
+
+/**
+ Check if the password is full zero.
+
+ @param[in] Password Points to the Data Buffer
+
+ @retval TRUE This password string is full zero.
+ @retval FALSE This password string is not full zero.
+
+**/
+LIST_ENTRY *
+EFIAPI
+OpalSupportGetOpalDeviceList (
+ VOID
+ );
+
+/**
+ Transfer the password to the smm driver.
+
+ @param[in] DevicePath The device path for the opal devcie.
+ @param PasswordLen The input password length.
+ @param Password Input password buffer.
+
+ @retval EFI_SUCCESS Do the required action success.
+ @retval Others Error occured.
+
+**/
+EFI_STATUS
+EFIAPI
+OpalSupportSendPasword(
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ UINTN PasswordLen,
+ VOID *Password
+ );
+
+#endif // _OPAL_CORE_H_
diff --git a/Core/SecurityPkg/Include/Library/PlatformSecureLib.h b/Core/SecurityPkg/Include/Library/PlatformSecureLib.h
new file mode 100644
index 0000000000..6a4cb147a6
--- /dev/null
+++ b/Core/SecurityPkg/Include/Library/PlatformSecureLib.h
@@ -0,0 +1,42 @@
+/** @file
+ Provides a secure platform-specific method to detect physically present user.
+
+Copyright (c) 2011 - 2012, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __PLATFORM_SECURE_LIB_H__
+#define __PLATFORM_SECURE_LIB_H__
+
+
+/**
+
+ This function provides a platform-specific method to detect whether the platform
+ is operating by a physically present user.
+
+ Programmatic changing of platform security policy (such as disable Secure Boot,
+ or switch between Standard/Custom Secure Boot mode) MUST NOT be possible during
+ Boot Services or after exiting EFI Boot Services. Only a physically present user
+ is allowed to perform these operations.
+
+ 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 is operated by a physically present user.
+ @retval FALSE The platform is NOT operated by a physically present user.
+
+**/
+BOOLEAN
+EFIAPI
+UserPhysicalPresent (
+ VOID
+ );
+
+#endif
diff --git a/Core/SecurityPkg/Include/Library/Tcg2PhysicalPresenceLib.h b/Core/SecurityPkg/Include/Library/Tcg2PhysicalPresenceLib.h
new file mode 100644
index 0000000000..3e446acab2
--- /dev/null
+++ b/Core/SecurityPkg/Include/Library/Tcg2PhysicalPresenceLib.h
@@ -0,0 +1,187 @@
+/** @file
+ This library is intended to be used by BDS modules.
+ This library will execute TPM2 request.
+
+Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _TCG2_PHYSICAL_PRESENCE_LIB_H_
+#define _TCG2_PHYSICAL_PRESENCE_LIB_H_
+
+#include <IndustryStandard/Tpm20.h>
+#include <IndustryStandard/TcgPhysicalPresence.h>
+#include <Protocol/Tcg2Protocol.h>
+
+//
+// UEFI TCG2 library definition bit of the BIOS TPM Management Flags
+//
+// BIT0 is reserved
+#define TCG2_BIOS_TPM_MANAGEMENT_FLAG_PP_REQUIRED_FOR_CLEAR BIT1
+// BIT2 is reserved
+#define TCG2_LIB_PP_FLAG_RESET_TRACK BIT3
+#define TCG2_BIOS_TPM_MANAGEMENT_FLAG_PP_REQUIRED_FOR_TURN_ON BIT4
+#define TCG2_BIOS_TPM_MANAGEMENT_FLAG_PP_REQUIRED_FOR_TURN_OFF BIT5
+#define TCG2_BIOS_TPM_MANAGEMENT_FLAG_PP_REQUIRED_FOR_CHANGE_EPS BIT6
+#define TCG2_BIOS_TPM_MANAGEMENT_FLAG_PP_REQUIRED_FOR_CHANGE_PCRS BIT7
+
+//
+// UEFI TCG2 library definition bit of the BIOS Information Flags
+//
+#define TCG2_BIOS_INFORMATION_FLAG_HIERACHY_CONTROL_STORAGE_DISABLE BIT8
+#define TCG2_BIOS_INFORMATION_FLAG_HIERACHY_CONTROL_ENDORSEMENT_DISABLE BIT9
+
+//
+// UEFI TCG2 library definition bit of the BIOS Storage Management Flags
+//
+#define TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_PP_REQUIRED_FOR_ENABLE_BLOCK_SID BIT16
+#define TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_PP_REQUIRED_FOR_DISABLE_BLOCK_SID BIT17
+#define TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_ENABLE_BLOCK_SID BIT18
+
+//
+// Default value
+//
+#define TCG2_BIOS_TPM_MANAGEMENT_FLAG_DEFAULT (TCG2_BIOS_TPM_MANAGEMENT_FLAG_PP_REQUIRED_FOR_TURN_OFF | \
+ TCG2_BIOS_TPM_MANAGEMENT_FLAG_PP_REQUIRED_FOR_CLEAR | \
+ TCG2_BIOS_TPM_MANAGEMENT_FLAG_PP_REQUIRED_FOR_CHANGE_EPS | \
+ TCG2_BIOS_TPM_MANAGEMENT_FLAG_PP_REQUIRED_FOR_CHANGE_PCRS)
+
+//
+// Default value
+//
+#define TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_DEFAULT (TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_PP_REQUIRED_FOR_ENABLE_BLOCK_SID | \
+ TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_PP_REQUIRED_FOR_DISABLE_BLOCK_SID)
+
+/**
+ Check and execute the pending TPM request.
+
+ The TPM request may come from OS or BIOS. This API will display request information and wait
+ for user confirmation if TPM request exists. The TPM request will be sent to TPM device after
+ the TPM request is confirmed, and one or more reset may be required to make TPM request to
+ take effect.
+
+ This API should be invoked after console in and console out are all ready as they are required
+ to display request information and get user input to confirm the request.
+
+ @param PlatformAuth platform auth value. NULL means no platform auth change.
+**/
+VOID
+EFIAPI
+Tcg2PhysicalPresenceLibProcessRequest (
+ IN TPM2B_AUTH *PlatformAuth OPTIONAL
+ );
+
+/**
+ Check if the pending TPM request needs user input to confirm.
+
+ The TPM request may come from OS. This API will check if TPM request exists and need user
+ input to confirmation.
+
+ @retval TRUE TPM needs input to confirm user physical presence.
+ @retval FALSE TPM doesn't need input to confirm user physical presence.
+
+**/
+BOOLEAN
+EFIAPI
+Tcg2PhysicalPresenceLibNeedUserConfirm (
+ VOID
+ );
+
+/**
+ Return TPM2 ManagementFlags set by PP interface.
+
+ @retval ManagementFlags TPM2 Management Flags.
+**/
+UINT32
+EFIAPI
+Tcg2PhysicalPresenceLibGetManagementFlags (
+ VOID
+ );
+
+/**
+ The handler for TPM physical presence function:
+ Return TPM Operation Response to OS Environment.
+
+ This API should be invoked in OS runtime phase to interface with ACPI method.
+
+ @param[out] MostRecentRequest Most recent operation request.
+ @param[out] Response Response to the most recent operation request.
+
+ @return Return Code for Return TPM Operation Response to OS Environment.
+**/
+UINT32
+EFIAPI
+Tcg2PhysicalPresenceLibReturnOperationResponseToOsFunction (
+ OUT UINT32 *MostRecentRequest,
+ OUT UINT32 *Response
+ );
+
+/**
+ The handler for TPM physical presence function:
+ Submit TPM Operation Request to Pre-OS Environment and
+ Submit TPM Operation Request to Pre-OS Environment 2.
+
+ This API should be invoked in OS runtime phase to interface with ACPI method.
+
+ Caution: This function may receive untrusted input.
+
+ @param[in, out] Pointer to OperationRequest TPM physical presence operation request.
+ @param[in, out] Pointer to RequestParameter TPM physical presence operation request parameter.
+
+ @return Return Code for Submit TPM Operation Request to Pre-OS Environment and
+ Submit TPM Operation Request to Pre-OS Environment 2.
+ **/
+UINT32
+Tcg2PhysicalPresenceLibSubmitRequestToPreOSFunctionEx (
+ IN OUT UINT32 *OperationRequest,
+ IN OUT UINT32 *RequestParameter
+ );
+
+/**
+ The handler for TPM physical presence function:
+ Submit TPM Operation Request to Pre-OS Environment and
+ Submit TPM Operation Request to Pre-OS Environment 2.
+
+ This API should be invoked in OS runtime phase to interface with ACPI method.
+
+ Caution: This function may receive untrusted input.
+
+ @param[in] OperationRequest TPM physical presence operation request.
+ @param[in] RequestParameter TPM physical presence operation request parameter.
+
+ @return Return Code for Submit TPM Operation Request to Pre-OS Environment and
+ Submit TPM Operation Request to Pre-OS Environment 2.
+**/
+UINT32
+EFIAPI
+Tcg2PhysicalPresenceLibSubmitRequestToPreOSFunction (
+ IN UINT32 OperationRequest,
+ IN UINT32 RequestParameter
+ );
+
+/**
+ The handler for TPM physical presence function:
+ Get User Confirmation Status for Operation.
+
+ This API should be invoked in OS runtime phase to interface with ACPI method.
+
+ Caution: This function may receive untrusted input.
+
+ @param[in] OperationRequest TPM physical presence operation request.
+
+ @return Return Code for Get User Confirmation Status for Operation.
+**/
+UINT32
+EFIAPI
+Tcg2PhysicalPresenceLibGetUserConfirmationStatusFunction (
+ IN UINT32 OperationRequest
+ );
+
+#endif
diff --git a/Core/SecurityPkg/Include/Library/Tcg2PpVendorLib.h b/Core/SecurityPkg/Include/Library/Tcg2PpVendorLib.h
new file mode 100644
index 0000000000..5ae7413273
--- /dev/null
+++ b/Core/SecurityPkg/Include/Library/Tcg2PpVendorLib.h
@@ -0,0 +1,129 @@
+/** @file
+ This library is to support TCG PC Client Platform Physical Presence Interface Specification
+ Family "2.0" part, >= 128 Vendor Specific PPI Operation.
+
+ The Vendor Specific PPI operation may change TPM state, BIOS TPM management
+ flags, and may need additional boot cycle.
+
+ Caution: This function may receive untrusted input.
+
+Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _TCG2_PP_VENDOR_LIB_H_
+#define _TCG2_PP_VENDOR_LIB_H_
+
+#include <IndustryStandard/Tpm20.h>
+#include <Protocol/Tcg2Protocol.h>
+#include <Library/Tcg2PhysicalPresenceLib.h>
+
+/**
+ Check and execute the requested physical presence command.
+
+ This API should be invoked in BIOS boot phase to process pending request.
+
+ Caution: This function may receive untrusted input.
+
+ If OperationRequest < 128, then ASSERT().
+
+ @param[in] PlatformAuth platform auth value. NULL means no platform auth change.
+ @param[in] OperationRequest TPM physical presence operation request.
+ @param[in, out] ManagementFlags BIOS TPM Management Flags.
+ @param[out] ResetRequired If reset is required to vendor settings in effect.
+ True, it indicates the reset is required.
+ False, it indicates the reset is not required.
+
+ @return TPM Operation Response to OS Environment.
+**/
+UINT32
+EFIAPI
+Tcg2PpVendorLibExecutePendingRequest (
+ IN TPM2B_AUTH *PlatformAuth, OPTIONAL
+ IN UINT32 OperationRequest,
+ IN OUT UINT32 *ManagementFlags,
+ OUT BOOLEAN *ResetRequired
+ );
+
+/**
+ Check if there is a valid physical presence command request.
+
+ This API should be invoked in BIOS boot phase to process pending request.
+
+ Caution: This function may receive untrusted input.
+
+ If OperationRequest < 128, then ASSERT().
+
+ @param[in] OperationRequest TPM physical presence operation request.
+ @param[in] ManagementFlags BIOS TPM Management Flags.
+ @param[out] RequestConfirmed If the physical presence operation command required user confirm from UI.
+ True, it indicates the command doesn't require user confirm.
+ False, it indicates the command need user confirm from UI.
+
+ @retval TRUE Physical Presence operation command is valid.
+ @retval FALSE Physical Presence operation command is invalid.
+**/
+BOOLEAN
+EFIAPI
+Tcg2PpVendorLibHasValidRequest (
+ IN UINT32 OperationRequest,
+ IN UINT32 ManagementFlags,
+ OUT BOOLEAN *RequestConfirmed
+ );
+
+/**
+ The callback for TPM vendor specific physical presence which is called for
+ Submit TPM Operation Request to Pre-OS Environment and
+ Submit TPM Operation Request to Pre-OS Environment 2.
+
+ This API should be invoked in OS runtime phase to interface with ACPI method.
+
+ Caution: This function may receive untrusted input.
+
+ If OperationRequest < 128, then ASSERT().
+
+ @param[in] OperationRequest TPM physical presence operation request.
+ @param[in] ManagementFlags BIOS TPM Management Flags.
+ @param[in] RequestParameter Extra parameter from the passed package.
+
+ @return Return Code for Submit TPM Operation Request to Pre-OS Environment and
+ Submit TPM Operation Request to Pre-OS Environment 2.
+**/
+UINT32
+EFIAPI
+Tcg2PpVendorLibSubmitRequestToPreOSFunction (
+ IN UINT32 OperationRequest,
+ IN UINT32 ManagementFlags,
+ IN UINT32 RequestParameter
+ );
+
+/**
+ The callback for TPM vendor specific physical presence which is called for
+ Get User Confirmation Status for Operation.
+
+ This API should be invoked in OS runtime phase to interface with ACPI method.
+
+ Caution: This function may receive untrusted input.
+
+ If OperationRequest < 128, then ASSERT().
+
+ @param[in] OperationRequest TPM physical presence operation request.
+ @param[in] ManagementFlags BIOS TPM Management Flags.
+
+ @return Return Code for Get User Confirmation Status for Operation.
+**/
+UINT32
+EFIAPI
+Tcg2PpVendorLibGetUserConfirmationStatusFunction (
+ IN UINT32 OperationRequest,
+ IN UINT32 ManagementFlags
+ );
+
+#endif
diff --git a/Core/SecurityPkg/Include/Library/TcgPhysicalPresenceLib.h b/Core/SecurityPkg/Include/Library/TcgPhysicalPresenceLib.h
new file mode 100644
index 0000000000..b451823bdf
--- /dev/null
+++ b/Core/SecurityPkg/Include/Library/TcgPhysicalPresenceLib.h
@@ -0,0 +1,54 @@
+/** @file
+ This library is intended to be used by BDS modules.
+ This library will lock TPM after executing TPM request.
+
+Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _TCG_PHYSICAL_PRESENCE_LIB_H_
+#define _TCG_PHYSICAL_PRESENCE_LIB_H_
+
+/**
+ Check and execute the pending TPM request and Lock TPM.
+
+ The TPM request may come from OS or BIOS. This API will display request information and wait
+ for user confirmation if TPM request exists. The TPM request will be sent to TPM device after
+ the TPM request is confirmed, and one or more reset may be required to make TPM request to
+ take effect. At last, it will lock TPM to prevent TPM state change by malware.
+
+ This API should be invoked after console in and console out are all ready as they are required
+ to display request information and get user input to confirm the request. This API should also
+ be invoked as early as possible as TPM is locked in this function.
+
+**/
+VOID
+EFIAPI
+TcgPhysicalPresenceLibProcessRequest (
+ VOID
+ );
+
+/**
+ Check if the pending TPM request needs user input to confirm.
+
+ The TPM request may come from OS. This API will check if TPM request exists and need user
+ input to confirmation.
+
+ @retval TRUE TPM needs input to confirm user physical presence.
+ @retval FALSE TPM doesn't need input to confirm user physical presence.
+
+**/
+BOOLEAN
+EFIAPI
+TcgPhysicalPresenceLibNeedUserConfirm(
+ VOID
+ );
+
+#endif
diff --git a/Core/SecurityPkg/Include/Library/TcgPpVendorLib.h b/Core/SecurityPkg/Include/Library/TcgPpVendorLib.h
new file mode 100644
index 0000000000..284aa9ed72
--- /dev/null
+++ b/Core/SecurityPkg/Include/Library/TcgPpVendorLib.h
@@ -0,0 +1,159 @@
+/** @file
+ This library is to support TCG Physical Presence Interface (PPI) specification
+ >= 128 Vendor Specific PPI Operation.
+
+ The Vendor Specific PPI operation may change TPM state, BIOS TPM management
+ flags, and may need additional boot cycle.
+
+ Caution: This function may receive untrusted input.
+
+Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _TCG_PP_VENDOR_LIB_H_
+#define _TCG_PP_VENDOR_LIB_H_
+
+//
+// The definition of physical presence operation actions
+//
+#define TCG_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION 128
+
+//
+// The definition bit of the BIOS TPM Management Flags
+//
+#define TCG_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_PROVISION BIT0
+#define TCG_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_CLEAR BIT1
+#define TCG_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_MAINTENANCE BIT2
+#define TCG_VENDOR_LIB_FLAG_RESET_TRACK BIT3
+
+//
+// The definition for TPM Operation Response to OS Environment
+//
+#define TCG_PP_OPERATION_RESPONSE_SUCCESS 0x0
+#define TCG_PP_OPERATION_RESPONSE_USER_ABORT 0xFFFFFFF0
+#define TCG_PP_OPERATION_RESPONSE_BIOS_FAILURE 0xFFFFFFF1
+
+//
+// The return code for Submit TPM Request to Pre-OS Environment
+// and Submit TPM Request to Pre-OS Environment 2
+//
+#define TCG_PP_SUBMIT_REQUEST_TO_PREOS_SUCCESS 0
+#define TCG_PP_SUBMIT_REQUEST_TO_PREOS_NOT_IMPLEMENTED 1
+#define TCG_PP_SUBMIT_REQUEST_TO_PREOS_GENERAL_FAILURE 2
+#define TCG_PP_SUBMIT_REQUEST_TO_PREOS_BLOCKED_BY_BIOS_SETTINGS 3
+
+//
+// The return code for Get User Confirmation Status for Operation
+//
+#define TCG_PP_GET_USER_CONFIRMATION_NOT_IMPLEMENTED 0
+#define TCG_PP_GET_USER_CONFIRMATION_BIOS_ONLY 1
+#define TCG_PP_GET_USER_CONFIRMATION_BLOCKED_BY_BIOS_CONFIGURATION 2
+#define TCG_PP_GET_USER_CONFIRMATION_ALLOWED_AND_PPUSER_REQUIRED 3
+#define TCG_PP_GET_USER_CONFIRMATION_ALLOWED_AND_PPUSER_NOT_REQUIRED 4
+
+/**
+ Check and execute the requested physical presence command.
+
+ This API should be invoked in BIOS boot phase to process pending request.
+
+ Caution: This function may receive untrusted input.
+
+ If OperationRequest < 128, then ASSERT().
+
+ @param[in] OperationRequest TPM physical presence operation request.
+ @param[in, out] ManagementFlags BIOS TPM Management Flags.
+ @param[out] ResetRequired If reset is required to vendor settings in effect.
+ True, it indicates the reset is required.
+ False, it indicates the reset is not required.
+
+ @return TPM Operation Response to OS Environment.
+**/
+UINT32
+EFIAPI
+TcgPpVendorLibExecutePendingRequest (
+ IN UINT32 OperationRequest,
+ IN OUT UINT32 *ManagementFlags,
+ OUT BOOLEAN *ResetRequired
+ );
+
+/**
+ Check if there is a valid physical presence command request.
+
+ This API should be invoked in BIOS boot phase to process pending request.
+
+ Caution: This function may receive untrusted input.
+
+ If OperationRequest < 128, then ASSERT().
+
+ @param[in] OperationRequest TPM physical presence operation request.
+ @param[in] ManagementFlags BIOS TPM Management Flags.
+ @param[out] RequestConfirmed If the physical presence operation command required user confirm from UI.
+ True, it indicates the command doesn't require user confirm.
+ False, it indicates the command need user confirm from UI.
+
+ @retval TRUE Physical Presence operation command is valid.
+ @retval FALSE Physical Presence operation command is invalid.
+**/
+BOOLEAN
+EFIAPI
+TcgPpVendorLibHasValidRequest (
+ IN UINT32 OperationRequest,
+ IN UINT32 ManagementFlags,
+ OUT BOOLEAN *RequestConfirmed
+ );
+
+/**
+ The callback for TPM vendor specific physical presence which is called for
+ Submit TPM Operation Request to Pre-OS Environment and
+ Submit TPM Operation Request to Pre-OS Environment 2.
+
+ This API should be invoked in OS runtime phase to interface with ACPI method.
+
+ Caution: This function may receive untrusted input.
+
+ If OperationRequest < 128, then ASSERT().
+
+ @param[in] OperationRequest TPM physical presence operation request.
+ @param[in] ManagementFlags BIOS TPM Management Flags.
+
+ @return Return Code for Submit TPM Operation Request to Pre-OS Environment and
+ Submit TPM Operation Request to Pre-OS Environment 2.
+**/
+UINT32
+EFIAPI
+TcgPpVendorLibSubmitRequestToPreOSFunction (
+ IN UINT32 OperationRequest,
+ IN UINT32 ManagementFlags
+ );
+
+/**
+ The callback for TPM vendor specific physical presence which is called for
+ Get User Confirmation Status for Operation.
+
+ This API should be invoked in OS runtime phase to interface with ACPI method.
+
+ Caution: This function may receive untrusted input.
+
+ If OperationRequest < 128, then ASSERT().
+
+ @param[in] OperationRequest TPM physical presence operation request.
+ @param[in] ManagementFlags BIOS TPM Management Flags.
+
+ @return Return Code for Get User Confirmation Status for Operation.
+**/
+UINT32
+EFIAPI
+TcgPpVendorLibGetUserConfirmationStatusFunction (
+ IN UINT32 OperationRequest,
+ IN UINT32 ManagementFlags
+ );
+
+#endif
diff --git a/Core/SecurityPkg/Include/Library/TcgStorageCoreLib.h b/Core/SecurityPkg/Include/Library/TcgStorageCoreLib.h
new file mode 100644
index 0000000000..67ccf22892
--- /dev/null
+++ b/Core/SecurityPkg/Include/Library/TcgStorageCoreLib.h
@@ -0,0 +1,1310 @@
+/** @file
+ Public API for the Tcg Core library to perform the lowest level TCG Data encoding.
+
+Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _TCG_CORE_H_
+#define _TCG_CORE_H_
+
+#include <IndustryStandard/TcgStorageCore.h>
+
+#define ERROR_CHECK(arg) \
+ { \
+ TCG_RESULT ret = (arg); \
+ if (ret != TcgResultSuccess) { \
+ DEBUG ((DEBUG_INFO, "ERROR_CHECK failed at %s:%u\n", __FILE__, __LINE__)); \
+ return ret; \
+ } \
+ }
+
+#define METHOD_STATUS_ERROR_CHECK(arg, failRet) \
+ if ((arg) != TCG_METHOD_STATUS_CODE_SUCCESS) { \
+ DEBUG ((DEBUG_INFO, "Method Status error: 0x%02X (%s)\n", arg, TcgMethodStatusString(arg))); \
+ return (failRet); \
+ }
+
+#define NULL_CHECK(arg) \
+ do { \
+ if ((arg) == NULL) { \
+ DEBUG ((DEBUG_INFO, "NULL_CHECK(%s) failed at %s:%u\n", #arg, __FILE__, __LINE__)); \
+ return TcgResultFailureNullPointer; \
+ } \
+ } while (0)
+
+#pragma pack(1)
+
+/**
+Tcg result codes.
+
+The result code indicates if the Tcg function call was successful or not
+**/
+typedef enum {
+ //
+ // This is the return result upon successful completion of a Tcg function call
+ //
+ TcgResultSuccess,
+
+ //
+ // This is the return "catchall" result for the failure of a Tcg function call
+ //
+ TcgResultFailure,
+
+ //
+ // This is the return result if a required parameter was Null for a Tcg function call
+ //
+ TcgResultFailureNullPointer,
+
+ //
+ // This is the return result if a required buffersize was 0 for a Tcg function call
+ //
+ TcgResultFailureZeroSize,
+
+ //
+ // This is the return result if a Tcg function call was executed out of order.
+ // For instance, starting a Tcg subpacket before starting its Tcg packet.
+ //
+ TcgResultFailureInvalidAction,
+
+ //
+ // This is the return result if the buffersize provided is not big enough to add a requested Tcg encoded item.
+ //
+ TcgResultFailureBufferTooSmall,
+
+ //
+ // This is the return result for a Tcg parse function if the end of the parsed Buffer is reached, yet Data is still attempted to be retrieved.
+ // For instance, attempting to retrieve another Tcg token from the Buffer after it has reached the end of the Tcg subpacket payload.
+ //
+ TcgResultFailureEndBuffer,
+
+ //
+ // This is the return result for a Tcg parse function if the Tcg Token item requested is not the expected type.
+ // For instance, the caller requested to receive an integer and the Tcg token was a byte sequence.
+ //
+ TcgResultFailureInvalidType,
+} TCG_RESULT;
+
+//
+// Structure that is used to build the Tcg ComPacket. It contains the start Buffer pointer and the current position of the
+// Tcg ComPacket, current Tcg Packet and Tcg SubPacket. This structure must be initialized
+// by calling tcgInitTcgCreateStruct before it is used as parameter to any other Tcg function.
+// This structure should NOT be directly modified by the client of this library.
+//
+// NOTE: WE MAY MAKE THIS AN ABSTRACT STRUCTURE WITH A DEFINED SIZE AND KEEP THE VARIABLES
+// INTERNAL AND ONLY KNOWN TO THE TCG LIBRARY
+//
+// tcgInitTcgCreateStruct
+//
+typedef struct {
+ //
+ // Buffer allocated and freed by the client of the Tcg library.
+ // This is the Buffer that shall contain the final Tcg encoded compacket.
+ //
+ VOID *Buffer;
+
+ //
+ // Size of the Buffer provided.
+ //
+ UINT32 BufferSize;
+
+ //
+ //Pointer to the start of the Tcg ComPacket. It should point to a location within Buffer.
+ //
+ TCG_COM_PACKET *ComPacket;
+
+ //
+ // Current Tcg Packet that is being created. It should point to a location within Buffer.
+ //
+ TCG_PACKET *CurPacket;
+
+ //
+ // Current Tcg SubPacket that is being created. It should point to a location within Buffer.
+ //
+ TCG_SUB_PACKET *CurSubPacket;
+
+ //
+ // Flag used to indicate if the Buffer of the structure should be filled out.
+ // This is intended to be used to support a use-case where the client of library
+ // can perform all the desired tcg calls to determine what the actual Size of the final compacket will be.
+ // Then the client can allocate the required Buffer Size and re-run the tcg calls.
+ // THIS MAY NOT BE IMPLEMENTED... REQUIRES MORE THOUGHT BECAUSE YOU CANNOT SOLVE ISSUE FOR RECEIVE
+ //
+ BOOLEAN DryRun;
+} TCG_CREATE_STRUCT;
+
+//
+// Structure that is used to parse the Tcg response received. It contains the response Buffer pointer
+// and the current position of the Tcg ComPacket, current Tcg Packet and Tcg SubPacket being parsed.
+// This structure must be initialized by calling tcgInitTcgParseStruct before it is used as parameter to any other Tcg parse function.
+// This structure should NOT be directly modified by the client of this library.
+//
+// NOTE: WE MAY MAKE THIS AN ABSTRACT STRUCTURE WITH A DEFINED SIZE AND KEEP THE VARIABLES
+// INTERNAL AND ONLY KNOWN TO THE TCG LIBRARY
+//
+// @sa tcgInitTcgParseStruct
+//
+typedef struct {
+ //
+ // Buffer allocated and freed by the client of the Tcg library.
+ // This is the Buffer that contains the Tcg response to decode/parse.
+ //
+ const VOID* Buffer;
+
+ //
+ //Size of the Buffer provided.
+ //
+ UINT32 BufferSize;
+
+ //
+ // Pointer to the start of the Tcg ComPacket. It should point to a location within Buffer.
+ //
+ TCG_COM_PACKET *ComPacket;
+
+ //
+ // Current Tcg Packet that is being created. It should point to a location within Buffer.
+ //
+ TCG_PACKET *CurPacket;
+
+ //
+ // Current Tcg SubPacket that is being created. It should point to a location within Buffer.
+ //
+ TCG_SUB_PACKET *CurSubPacket;
+
+ //
+ // Current pointer within the current subpacket payload.
+ //
+ UINT8 *CurPtr;
+} TCG_PARSE_STRUCT ;
+
+
+//
+// Structure that is used to represent a Tcg Token that is retrieved by Tcg parse functions.
+//
+typedef struct {
+ //
+ // Describes the type of Tcg token the Hdr start points to.
+ //
+ TCG_TOKEN_TYPE Type;
+
+ //
+ // Pointer to the beginning of the Header of the Tcg token
+ //
+ UINT8 *HdrStart;
+} TCG_TOKEN ;
+
+/**
+
+ Required to be called before calling any other Tcg functions with the TCG_CREATE_STRUCT.
+ Initializes the packet variables to NULL. Additionally, the buffer will be memset.
+
+ @param[in/out] CreateStruct Structure to initialize
+ @param[in] Buffer Buffer allocated by client of library. It will contain the Tcg encoded packet. This cannot be null.
+ @param[in] BufferSize Size of buffer provided. It cannot be 0.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgInitTcgCreateStruct(
+ TCG_CREATE_STRUCT *CreateStruct,
+ VOID *Buffer,
+ UINT32 BufferSize
+ );
+
+
+/**
+
+ Encodes the ComPacket header to the data structure.
+
+ @param[in/out] CreateStruct Structure to initialize
+ @param[in] ComId ComID of the Tcg ComPacket.
+ @param[in] ComIdExtension ComID Extension of the Tcg ComPacket.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgStartComPacket(
+ TCG_CREATE_STRUCT *CreateStruct,
+ UINT16 ComId,
+ UINT16 ComIdExtension
+ );
+
+
+/**
+
+ Starts a new ComPacket in the Data structure.
+
+ @param[in/out] CreateStruct Structure used to add Tcg Packet
+ @param[in] Tsn Packet Tper session number
+ @param[in] Hsn Packet Host session number
+ @param[in] SeqNumber Packet Sequence Number
+ @param[in] AckType Packet Acknowledge Type
+ @param[in] Ack Packet Acknowledge
+
+**/
+TCG_RESULT
+EFIAPI
+TcgStartPacket(
+ TCG_CREATE_STRUCT *CreateStruct,
+ UINT32 Tsn,
+ UINT32 Hsn,
+ UINT32 SeqNumber,
+ UINT16 AckType,
+ UINT32 Ack
+ );
+
+/**
+
+ Starts a new SubPacket in the Data structure.
+
+ @param[in/out] CreateStruct Structure used to start Tcg SubPacket
+ @param[in] Kind SubPacket kind
+
+**/
+TCG_RESULT
+EFIAPI
+TcgStartSubPacket(
+ TCG_CREATE_STRUCT *CreateStruct,
+ UINT16 Kind
+ );
+
+
+/**
+
+ Ends the current SubPacket in the Data structure. This function will also perform the 4-byte padding
+ required for Subpackets.
+
+ @param[in/out] CreateStruct Structure used to end the current Tcg SubPacket
+
+**/
+TCG_RESULT
+EFIAPI
+TcgEndSubPacket(
+ TCG_CREATE_STRUCT *CreateStruct
+ );
+
+
+/**
+
+ Ends the current Packet in the Data structure.
+
+ @param[in/out] CreateStruct Structure used to end the current Tcg Packet
+
+**/
+TCG_RESULT
+EFIAPI
+TcgEndPacket(
+ TCG_CREATE_STRUCT *CreateStruct
+ );
+
+
+/**
+
+ Ends the ComPacket in the Data structure and ret
+
+ @param[in/out] CreateStruct Structure used to end the Tcg ComPacket
+ @param[in/out] Size Describes the Size of the entire ComPacket (Header and payload). Filled out by function.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgEndComPacket(
+ TCG_CREATE_STRUCT *CreateStruct,
+ UINT32 *Size
+ );
+
+/**
+ Adds a single raw token byte to the Data structure.
+
+ @param[in/out] CreateStruct Structure used to add the byte
+ @param [in] Byte Byte to add
+
+**/
+TCG_RESULT
+EFIAPI
+TcgAddRawByte(
+ TCG_CREATE_STRUCT *CreateStruct,
+ UINT8 Byte
+ );
+
+
+/**
+
+ Adds the Data parameter as a byte sequence to the Data structure.
+
+ @param [in/out] CreateStruct Structure used to add the byte sequence
+ @param[in] Data Byte sequence that will be encoded and copied into Data structure
+ @param[in] DataSize Length of Data provided
+ @param[in] Continued TRUE if byte sequence is continued or
+ FALSE if the Data contains the entire byte sequence to be encoded
+
+**/
+TCG_RESULT
+EFIAPI
+TcgAddByteSequence(
+ TCG_CREATE_STRUCT *CreateStruct,
+ const VOID *Data,
+ UINT32 DataSize,
+ BOOLEAN Continued
+ );
+
+
+/**
+
+ Adds an arbitrary-Length integer to the Data structure.
+
+ The integer will be encoded using the shortest possible atom.
+
+ @param[in/out] CreateStruct Structure used to add the integer
+ @param[in] Data Integer in host byte order that will be encoded and copied into Data structure
+ @param[in] DataSize Length in bytes of the Data provided
+ @param[in] SignedInteger TRUE if the integer is signed or FALSE if the integer is unsigned
+
+**/
+TCG_RESULT
+EFIAPI
+TcgAddInteger(
+ TCG_CREATE_STRUCT *CreateStruct,
+ const VOID *Data,
+ UINT32 DataSize,
+ BOOLEAN SignedInteger
+ );
+
+
+/**
+ Adds an 8-bit unsigned integer to the Data structure.
+
+ @param[in/out] CreateStruct Structure used to add the integer
+ @param[in] Value Integer Value to add
+
+**/
+TCG_RESULT
+EFIAPI
+TcgAddUINT8(
+ TCG_CREATE_STRUCT *CreateStruct,
+ UINT8 Value
+ );
+
+/**
+
+ Adds a 16-bit unsigned integer to the Data structure.
+
+ @param[in/out] CreateStruct Structure used to add the integer
+ @param[in] Value Integer Value to add
+
+**/
+TCG_RESULT
+EFIAPI
+TcgAddUINT16 (
+ TCG_CREATE_STRUCT *CreateStruct,
+ UINT16 Value
+ );
+
+/**
+
+ Adds a 32-bit unsigned integer to the Data structure.
+
+ @param[in/out] CreateStruct Structure used to add the integer
+ @param[in] Value Integer Value to add
+
+**/
+TCG_RESULT
+EFIAPI
+TcgAddUINT32(
+ TCG_CREATE_STRUCT *CreateStruct,
+ UINT32 Value
+ );
+
+
+/**
+
+ Adds a 64-bit unsigned integer to the Data structure.
+
+ @param[in/out] CreateStruct Structure used to add the integer
+ @param[in] Value Integer Value to add
+
+**/
+TCG_RESULT
+EFIAPI
+TcgAddUINT64(
+ TCG_CREATE_STRUCT *CreateStruct,
+ UINT64 Value
+ );
+
+/**
+ Adds a BOOLEAN to the Data structure.
+
+ @param[in/out] CreateStruct Structure used to add the integer
+ @param[in] Value BOOLEAN Value to add
+
+**/
+TCG_RESULT
+EFIAPI
+TcgAddBOOLEAN(
+ TCG_CREATE_STRUCT *CreateStruct,
+ BOOLEAN Value
+ );
+
+/**
+ Add tcg uid info.
+
+ @param [in/out] CreateStruct Structure used to add the integer
+ @param Uid Input uid info.
+
+ @retval return the action result.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgAddTcgUid(
+ TCG_CREATE_STRUCT *CreateStruct,
+ TCG_UID Uid
+ );
+
+/**
+ Adds a Start List token to the Data structure.
+
+ @param[in/out] CreateStruct Structure used to add the token
+
+**/
+TCG_RESULT
+EFIAPI
+TcgAddStartList(
+ TCG_CREATE_STRUCT *CreateStruct
+ );
+
+
+/**
+
+ Adds an End List token to the Data structure.
+
+ @param [in/out] CreateStruct Structure used to add the token
+
+**/
+TCG_RESULT
+EFIAPI
+TcgAddEndList(
+ TCG_CREATE_STRUCT *CreateStruct
+ );
+
+
+/**
+ Adds a Start Name token to the Data structure.
+
+ @param[in/out] CreateStruct Structure used to add the token
+
+**/
+TCG_RESULT
+EFIAPI
+TcgAddStartName(
+ TCG_CREATE_STRUCT *CreateStruct
+ );
+
+
+/**
+
+ Adds an End Name token to the Data structure.
+
+ @param [in/out] CreateStruct Structure used to add the token
+
+**/
+TCG_RESULT
+EFIAPI
+TcgAddEndName(
+ TCG_CREATE_STRUCT *CreateStruct
+ );
+
+
+/**
+ Adds a Call token to the Data structure.
+
+ @param [in/out] CreateStruct Structure used to add the token
+
+**/
+TCG_RESULT
+EFIAPI
+TcgAddCall(
+ TCG_CREATE_STRUCT *CreateStruct
+ );
+
+
+/**
+
+Adds an End of Data token to the Data structure.
+
+@param[in/out] CreateStruct Structure used to add the token
+
+**/
+TCG_RESULT
+EFIAPI
+TcgAddEndOfData(
+ TCG_CREATE_STRUCT *CreateStruct
+ );
+
+
+/**
+
+Adds an End of Session token to the Data structure.
+
+@param [in/out] CreateStruct Structure used to add the token
+
+**/
+TCG_RESULT
+EFIAPI
+TcgAddEndOfSession(
+ TCG_CREATE_STRUCT *CreateStruct
+ );
+
+
+/**
+ Adds a Start Transaction token to the Data structure.
+
+ @param [in/out] CreateStruct Structure used to add the token
+
+**/
+TCG_RESULT
+EFIAPI
+TcgAddStartTransaction(
+ TCG_CREATE_STRUCT *CreateStruct
+ );
+
+
+/**
+ Adds an End Transaction token to the Data structure.
+
+ @param[in/out] CreateStruct Structure used to add the token
+
+**/
+TCG_RESULT
+EFIAPI
+TcgAddEndTransaction(
+ TCG_CREATE_STRUCT *CreateStruct
+ );
+
+/**
+ Initial the tcg parse stucture.
+
+ @param ParseStruct Input parse structure.
+ @param Buffer Input buffer data.
+ @param BufferSize Input buffer size.
+
+ @retval return the action result.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgInitTcgParseStruct(
+ TCG_PARSE_STRUCT *ParseStruct,
+ const VOID *Buffer,
+ UINT32 BufferSize
+ );
+
+/**
+ Get next token info.
+
+ @param ParseStruct Input parse structure info.
+ @param TcgToken return the tcg token info.
+
+ @retval return the action result.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgGetNextToken(
+ TCG_PARSE_STRUCT *ParseStruct,
+ TCG_TOKEN *TcgToken
+ );
+
+/**
+ Get next token Type.
+
+ @param ParseStruct Input parse structure.
+ @param Type Input the type need to check.
+
+ @retval return the action result.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgGetNextTokenType(
+ TCG_PARSE_STRUCT *ParseStruct,
+ TCG_TOKEN_TYPE Type
+ );
+
+/**
+ Get atom info.
+
+ @param TcgToken Input token info.
+ @param HeaderLength return the header length.
+ @param DataLength return the data length.
+ @param ByteOrInt return the atom Type.
+ @param SignOrCont return the sign or count info.
+
+ @retval return the action result.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgGetAtomInfo(
+ const TCG_TOKEN *TcgToken,
+ UINT32 *HeaderLength,
+ UINT32 *DataLength,
+ UINT8 *ByteOrInt,
+ UINT8 *SignOrCont
+ );
+
+/**
+ Get token byte sequence.
+
+ @param TcgToken Input token info.
+ @param Length Input the length info.
+
+ @retval Return the value data.
+
+**/
+UINT8*
+EFIAPI
+TcgGetTokenByteSequence(
+ const TCG_TOKEN *TcgToken,
+ UINT32 *Length
+ );
+
+/**
+ Get token specified value.
+
+ @param TcgToken Input token info.
+ @param Value return the value.
+
+ @retval return the action result.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgGetTokenUINT64(
+ const TCG_TOKEN *TcgToken,
+ UINT64 *Value
+ );
+
+
+/**
+ Get next specify value.
+
+ @param ParseStruct Input parse structure.
+ @param Value Return vlaue.
+
+ @retval return the action result.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgGetNextUINT8(
+ TCG_PARSE_STRUCT *ParseStruct,
+ UINT8 *Value
+ );
+
+
+/**
+ Get next specify value.
+
+ @param ParseStruct Input parse structure.
+ @param Value Return vlaue.
+
+ @retval return the action result.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgGetNextUINT16(
+ TCG_PARSE_STRUCT *ParseStruct,
+ UINT16 *Value
+ );
+
+/**
+ Get next specify value.
+
+ @param ParseStruct Input parse structure.
+ @param Value Return vlaue.
+
+ @retval return the action result.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgGetNextUINT32(
+ TCG_PARSE_STRUCT *ParseStruct,
+ UINT32 *Value
+ );
+
+/**
+ Get next specify value.
+
+ @param ParseStruct Input parse structure.
+ @param Value Return vlaue.
+
+ @retval return the action result.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgGetNextUINT64(
+ TCG_PARSE_STRUCT *ParseStruct,
+ UINT64 *Value
+ );
+
+/**
+ Get next specify value.
+
+ @param ParseStruct Input parse structure.
+ @param Value Return vlaue.
+
+ @retval return the action result.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgGetNextBOOLEAN(
+ TCG_PARSE_STRUCT *ParseStruct,
+ BOOLEAN *Value
+ );
+
+/**
+ Get next tcg uid info.
+
+ @param ParseStruct Input parse structure.
+ @param Uid Get the uid info.
+
+ @retval return the action result.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgGetNextTcgUid(
+ TCG_PARSE_STRUCT *ParseStruct,
+ TCG_UID *Uid
+ );
+
+/**
+ Get next byte sequence.
+
+ @param ParseStruct Input parse structure.
+ @param Data return the data.
+ @param Length return the length.
+
+ @retval return the action result.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgGetNextByteSequence(
+ TCG_PARSE_STRUCT *ParseStruct,
+ const VOID **Data,
+ UINT32 *Length
+ );
+
+/**
+ Get next start list.
+
+ @param ParseStruct Input parse structure.
+
+ @retval return the action result.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgGetNextStartList(
+ TCG_PARSE_STRUCT *ParseStruct
+ );
+
+/**
+ Get next end list.
+
+ @param ParseStruct Input parse structure.
+
+ @retval return the action result.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgGetNextEndList(
+ TCG_PARSE_STRUCT *ParseStruct
+ );
+
+/**
+ Get next start name.
+
+ @param ParseStruct Input parse structure.
+
+ @retval return the action result.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgGetNextStartName(
+ TCG_PARSE_STRUCT *ParseStruct
+ );
+
+/**
+ Get next end name.
+
+ @param ParseStruct Input parse structure.
+
+ @retval return the action result.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgGetNextEndName(
+ TCG_PARSE_STRUCT *ParseStruct
+ );
+
+/**
+ Get next call.
+
+ @param ParseStruct Input parse structure.
+
+ @retval return the action result.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgGetNextCall(
+ TCG_PARSE_STRUCT *ParseStruct
+ );
+
+/**
+ Get next end data.
+
+ @param ParseStruct Input parse structure.
+
+ @retval return the action result.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgGetNextEndOfData(
+ TCG_PARSE_STRUCT *ParseStruct
+ );
+
+/**
+ Get next end of session.
+
+ @param ParseStruct Input parse structure.
+
+ @retval return the action result.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgGetNextEndOfSession(
+ TCG_PARSE_STRUCT *ParseStruct
+ );
+
+/**
+ Get next start transaction.
+
+ @param ParseStruct Input parse structure.
+
+ @retval return the action result.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgGetNextStartTransaction(
+ TCG_PARSE_STRUCT *ParseStruct
+ );
+
+/**
+ Get next end transaction.
+
+ @param ParseStruct Input parse structure.
+
+ @retval return the action result.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgGetNextEndTransaction(
+ TCG_PARSE_STRUCT *ParseStruct
+ );
+
+// end of parse functions
+
+
+typedef
+BOOLEAN
+(EFIAPI* TCG_LEVEL0_ENUM_CALLBACK) (
+ const TCG_LEVEL0_DISCOVERY_HEADER *DiscoveryHeader,
+ TCG_LEVEL0_FEATURE_DESCRIPTOR_HEADER *Feature,
+ UINTN FeatureSize, // includes header
+ VOID *Context
+);
+
+/**
+ Adds call token and method Header (invoking id, and method id).
+
+ @param CreateStruct The input create structure.
+ @param InvokingId Invoking id.
+ @param MethodId Method id.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgStartMethodCall(
+ TCG_CREATE_STRUCT *CreateStruct,
+ TCG_UID InvokingId,
+ TCG_UID MethodId
+ );
+
+/**
+ Adds START LIST token.
+
+ @param CreateStruct The input create structure.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgStartParameters(
+ TCG_CREATE_STRUCT *CreateStruct
+ );
+
+/**
+ Adds END LIST token.
+
+ @param CreateStruct The input create structure.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgEndParameters(
+ TCG_CREATE_STRUCT *CreateStruct
+ );
+
+/**
+ Adds END Data token and method list.
+
+ @param CreateStruct The input create structure.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgEndMethodCall(
+ TCG_CREATE_STRUCT *CreateStruct
+ );
+
+/**
+
+ Adds Start Session call to the data structure. This creates the entire ComPacket structure and
+ returns the size of the entire compacket in the size parameter.
+
+ @param [in/out] CreateStruct Structure used to add the start session call
+ @param [in/out] Size Describes the size of the entire ComPacket (header and payload). Filled out by function.
+ @param [in] ComId ComID for the ComPacket
+ @param [in] ComIdExtension Extended ComID for the ComPacket
+ @param [in] HostSessionId Host Session ID
+ @param [in] SpId Security Provider to start session with
+ @param [in] Write Write option for start session. TRUE = start session requests write access
+ @param [in] HostChallengeLength Length of the host challenge. Length should be 0 if hostChallenge is NULL
+ @param [in] HostChallenge Host challenge for Host Signing Authority. If NULL, then no Host Challenge shall be sent.
+ @param [in] HostSigningAuthority Host Signing Authority used for start session. If NULL, then no Host Signing Authority shall be sent.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgCreateStartSession(
+ TCG_CREATE_STRUCT *CreateStruct,
+ UINT32 *Size,
+ UINT16 ComId,
+ UINT16 ComIdExtension,
+ UINT32 HostSessionId,
+ TCG_UID SpId,
+ BOOLEAN Write,
+ UINT32 HostChallengeLength,
+ const VOID *HostChallenge,
+ TCG_UID HostSigningAuthority
+ );
+
+/**
+ Creates ComPacket with a Method call that sets the PIN column for the row specified.
+ This assumes a start session has already been opened with the desired SP.
+
+ @param [in/out] CreateStruct Structure used to add method call.
+ @param [in/out] Size Describes the size of the entire ComPacket (header and payload). Filled out by function.
+ @param [in] ComId ComID for the ComPacket
+ @param [in] ComIdExtension Extended ComID for the ComPacket
+ @param [in] TperSession Tper Session ID for the Packet
+ @param [in] HostSession Host Session ID for the Packet
+ @param [in] SidRow UID of row of current SP to set PIN column
+ @param [in] Password value of PIN to set
+ @param [in] PasswordSize Size of PIN
+
+**/
+TCG_RESULT
+EFIAPI
+TcgCreateSetCPin(
+ TCG_CREATE_STRUCT *CreateStruct,
+ UINT32 *Size,
+ UINT16 ComId,
+ UINT16 ComIdExtension,
+ UINT32 TperSession,
+ UINT32 HostSession,
+ TCG_UID SidRow,
+ const VOID *Password,
+ UINT32 PasswordSize
+ );
+
+/**
+ Creates ComPacket with a Method call that sets the "Enabled" column for the row specified using the value specified.
+ This assumes a start session has already been opened with the desired SP.
+
+ @param [in/out] CreateStruct Structure used to add method call
+ @param [in/out] Size Describes the size of the entire ComPacket (header and payload). Filled out by function.
+ @param [in] ComId ComID for the ComPacket
+ @param [in] ComIdExtension Extended ComID for the ComPacket
+ @param [in] TperSession Tper Session ID for the Packet
+ @param [in] HostSession Host Session ID for the Packet
+ @param [in] AuthorityUid Authority UID to modify the "Enabled" column for
+ @param [in] Enabled Value to set the "Enabled" column to
+
+**/
+TCG_RESULT
+EFIAPI
+TcgSetAuthorityEnabled(
+ TCG_CREATE_STRUCT *CreateStruct,
+ UINT32 *Size,
+ UINT16 ComId,
+ UINT16 ComIdExtension,
+ UINT32 TperSession,
+ UINT32 HostSession,
+ TCG_UID AuthorityUid,
+ BOOLEAN Enabled
+ );
+
+/**
+
+ Creates ComPacket with EndSession.
+ This assumes a start session has already been opened.
+
+ @param [in/out] CreateStruct Structure used to add Endsession
+ @param [in/out] Size Describes the size of the entire ComPacket (header and payload). Filled out by function.
+ @param [in] ComId ComID for the ComPacket
+ @param [in] ComIdExtension Extended ComID for the ComPacket
+ @param [in] HostSessionId Host Session ID for the Packet
+ @param [in] TpSessionId Tper Session ID for the Packet
+
+**/
+TCG_RESULT
+EFIAPI
+TcgCreateEndSession(
+ TCG_CREATE_STRUCT *CreateStruct,
+ UINT32 *Size,
+ UINT16 ComId,
+ UINT16 ComIdExtension,
+ UINT32 HostSessionId,
+ UINT32 TpSessionId
+ );
+
+
+/**
+
+ Retrieves human-readable token type name.
+
+ @param[in] Type Token type to retrieve
+
+**/
+CHAR8*
+EFIAPI
+TcgTokenTypeString(
+ TCG_TOKEN_TYPE Type
+ );
+
+/**
+ Returns the method status of the current subpacket. Does not affect the current position
+ in the ComPacket. In other words, it can be called whenever you have a valid SubPacket.
+
+ @param [in/out] ParseStruct Structure used to parse received TCG response
+ @param [in/out] MethodStatus Method status retrieved of the current SubPacket
+
+**/
+TCG_RESULT
+EFIAPI
+TcgGetMethodStatus(
+ const TCG_PARSE_STRUCT *ParseStruct,
+ UINT8 *MethodStatus
+ );
+
+/**
+ Returns a human-readable string representing a method status return code.
+
+ @param[in] MethodStatus Method status to translate to a string
+
+
+ @retval return the string info.
+**/
+CHAR8*
+EFIAPI
+TcgMethodStatusString(
+ UINT8 MethodStatus
+ );
+
+
+/**
+ Retrieves the comID and Extended comID of the ComPacket in the Tcg response.
+ It is intended to be used to confirm the received Tcg response is intended for user that received it.
+
+ @param [in] ParseStruct Structure used to parse received TCG response.
+ @param [in/out] ComId comID retrieved from received ComPacket.
+ @param [in/out] ComIdExtension Extended comID retrieved from received ComPacket
+
+**/
+TCG_RESULT
+EFIAPI
+TcgGetComIds(
+ const TCG_PARSE_STRUCT *ParseStruct,
+ UINT16 *ComId,
+ UINT16 *ComIdExtension
+ );
+
+/**
+ Checks if the ComIDs of the response match the expected values.
+
+ @param[in] ParseStruct Structure used to parse received TCG response
+ @param[in] ExpectedComId Expected comID
+ @param[in] ExpectedComIdExtension Expected extended comID
+
+**/
+TCG_RESULT
+EFIAPI
+TcgCheckComIds(
+ const TCG_PARSE_STRUCT *ParseStruct,
+ UINT16 ExpectedComId,
+ UINT16 ExpectedComIdExtension
+ );
+
+/**
+ Parses the Sync Session response contained in the parseStruct to retrieve Tper session ID. If the Sync Session response
+ parameters do not match the comID, extended ComID and host session ID then a failure is returned.
+
+ @param[in/out] ParseStruct Structure used to parse received TCG response, contains Sync Session response.
+ @param[in] ComId Expected ComID that is compared to actual ComID of response
+ @param[in] ComIdExtension Expected Extended ComID that is compared to actual Extended ComID of response
+ @param[in] HostSessionId Expected Host Session ID that is compared to actual Host Session ID of response
+ @param[in/out] TperSessionId Tper Session ID retrieved from the Sync Session response.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgParseSyncSession(
+ const TCG_PARSE_STRUCT *ParseStruct,
+ UINT16 ComId,
+ UINT16 ComIdExtension,
+ UINT32 HostSessionId,
+ UINT32 *TperSessionId
+ );
+
+/**
+ Create set ace.
+
+ @param CreateStruct Input create structure.
+ @param Size size info.
+ @param ComId ComId info.
+ @param ComIdExtension ComId extension info.
+ @param TperSession Tper session data.
+ @param HostSession Host session data.
+ @param AceRow Ace row info.
+ @param Authority1 Authority 1 info.
+ @param LogicalOperator Logiccal operator info.
+ @param Authority2 Authority 2 info.
+
+ @retval Return the action result.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgCreateSetAce(
+ TCG_CREATE_STRUCT *CreateStruct,
+ UINT32 *Size,
+ UINT16 ComId,
+ UINT16 ComIdExtension,
+ UINT32 TperSession,
+ UINT32 HostSession,
+ TCG_UID AceRow,
+ TCG_UID Authority1,
+ BOOLEAN LogicalOperator,
+ TCG_UID Authority2
+ );
+
+/**
+ Enum level 0 discovery.
+
+ @param DiscoveryHeader Discovery header.
+ @param Callback Callback function.
+ @param Context The context for the function.
+
+ @retval return true if the callback return TRUE, else return FALSE.
+
+**/
+BOOLEAN
+EFIAPI
+TcgEnumLevel0Discovery(
+ const TCG_LEVEL0_DISCOVERY_HEADER *DiscoveryHeader,
+ TCG_LEVEL0_ENUM_CALLBACK Callback,
+ VOID *Context
+ );
+
+/**
+ Get Feature code from the header.
+
+ @param DiscoveryHeader The discovery header.
+ @param FeatureCode reutrn the Feature code.
+ @param FeatureSize return the Feature size.
+
+ @retval return the Feature code data.
+**/
+TCG_LEVEL0_FEATURE_DESCRIPTOR_HEADER*
+EFIAPI
+TcgGetFeature(
+ const TCG_LEVEL0_DISCOVERY_HEADER *DiscoveryHeader,
+ UINT16 FeatureCode,
+ UINTN *FeatureSize
+ );
+
+/**
+ Determines if the protocol provided is part of the provided supported protocol list.
+
+ @param[in] ProtocolList Supported protocol list to investigate
+ @param[in] Protocol Protocol value to determine if supported
+
+ @return TRUE = protocol is supported, FALSE = protocol is not supported
+**/
+BOOLEAN
+EFIAPI
+TcgIsProtocolSupported(
+ const TCG_SUPPORTED_SECURITY_PROTOCOLS *ProtocolList,
+ UINT16 Protocol
+ );
+
+/**
+ Determines if the Locking Feature "Locked" bit is set in the level 0 discovery response.
+
+ @param[in] Discovery Level 0 discovery response
+
+ @return TRUE = Locked is set, FALSE = Locked is false
+
+**/
+BOOLEAN
+EFIAPI
+TcgIsLocked(
+ const TCG_LEVEL0_DISCOVERY_HEADER *Discovery
+ );
+
+#pragma pack()
+
+
+#endif // _TCG_CORE_H_
diff --git a/Core/SecurityPkg/Include/Library/TcgStorageOpalLib.h b/Core/SecurityPkg/Include/Library/TcgStorageOpalLib.h
new file mode 100644
index 0000000000..9b64a8e5cd
--- /dev/null
+++ b/Core/SecurityPkg/Include/Library/TcgStorageOpalLib.h
@@ -0,0 +1,837 @@
+/** @file
+ Public API for Opal Core library.
+
+Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _OPAL_CORE_H_
+#define _OPAL_CORE_H_
+
+#include <IndustryStandard/TcgStorageOpal.h>
+
+#include <Library/TcgStorageCoreLib.h>
+#include <Protocol/StorageSecurityCommand.h>
+
+#pragma pack(1)
+
+typedef struct {
+ //
+ // Opal SSC 1 support (0 - not supported, 1 - supported)
+ //
+ UINT32 OpalSsc1 : 1;
+
+ //
+ // Opal SSC 2support (0 - not supported, 1 - supported)
+ //
+ UINT32 OpalSsc2 : 1;
+
+ //
+ // Opal SSC Lite support (0 - not supported, 1 - supported)
+ //
+ UINT32 OpalSscLite : 1;
+
+ //
+ // Pyrite SSC support (0 - not supported, 1 - supported)
+ //
+ UINT32 PyriteSsc : 1;
+
+ //
+ // Security protocol 1 support (0 - not supported, 1 - supported)
+ //
+ UINT32 Sp1 : 1;
+
+ //
+ // Security protocol 2 support (0 - not supported, 1 - supported)
+ //
+ UINT32 Sp2 : 1;
+
+ //
+ // Security protocol IEEE1667 support (0 - not supported, 1 - supported)
+ //
+ UINT32 SpIeee1667 : 1;
+
+ //
+ // Media encryption supported (0 - not supported, 1 - supported)
+ //
+ UINT32 MediaEncryption : 1;
+
+ //
+ // Initial C_PIN_SID PIN Indicator
+ // 0 - The initial C_PIN_SID PIN value is NOT equal to the C_PIN_MSID PIN value
+ // 1 - The initial C_PIN_SID PIN value is equal to the C_PIN_MSID PIN value
+ //
+ UINT32 InitCpinIndicator : 1;
+
+ //
+ // Behavior of C_PIN_SID PIN upon TPer Revert
+ // 0 - The initial C_PIN_SID PIN value is NOT equal to the C_PIN_MSID PIN value
+ // 1 - The initial C_PIN_SID PIN value is equal to the C_PIN_MSID PIN value
+ //
+ UINT32 CpinUponRevert : 1;
+
+ //
+ // Media encryption supported (0 - not supported, 1 - supported)
+ //
+ UINT32 BlockSid : 1;
+
+} OPAL_DISK_SUPPORT_ATTRIBUTE;
+
+//
+// Opal device ownership type
+// The type indicates who was the determined owner of the device.
+//
+typedef enum {
+ //
+ // Represents the device ownership is unknown because starting a session as the SID authority with the ADMIN SP
+ //was unsuccessful with the provided PIN
+ //
+ OpalOwnershipUnknown,
+
+ //
+ // Represents that the ADMIN SP SID authority contains the same PIN as the MSID PIN
+ //
+ OpalOwnershipNobody,
+} OPAL_OWNER_SHIP;
+
+//
+// Structure that is used to represent an Opal session.
+// The structure must be initialized by calling OpalStartSession before being used as a parameter
+// for any other Opal function.
+// This structure should NOT be directly modified by the client of this library.
+//
+//
+typedef struct {
+ UINT32 HostSessionId;
+ UINT32 TperSessionId;
+ UINT16 ComIdExtension;
+
+ UINT16 OpalBaseComId;
+
+ EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *Sscp;
+ UINT32 MediaId;
+} OPAL_SESSION;
+#pragma pack()
+
+/**
+
+ The function fills in the provided Buffer with the supported protocol list
+ of the device specified.
+
+ @param[in] Session OPAL_SESSION data.
+ @param[in] BufferSize Size of Buffer provided (in bytes)
+ @param[in] BuffAddress Buffer address to fill with security protocol list
+
+**/
+TCG_RESULT
+EFIAPI
+OpalRetrieveSupportedProtocolList(
+ OPAL_SESSION *Session,
+ UINTN BufferSize,
+ VOID *BuffAddress
+ );
+
+/**
+
+ The function fills in the provided Buffer with the level 0 discovery Header
+ of the device specified.
+
+ @param[in] Session OPAL_SESSION data.
+ @param[in] BufferSize Size of Buffer provided (in bytes)
+ @param[in] BuffAddress Buffer address to fill with Level 0 Discovery response
+
+**/
+TCG_RESULT
+EFIAPI
+OpalRetrieveLevel0DiscoveryHeader(
+ OPAL_SESSION *Session,
+ UINTN BufferSize,
+ VOID *BuffAddress
+ );
+
+/**
+ Starts a session with a security provider (SP).
+
+ If a session is started successfully, the caller must end the session with OpalEndSession when finished
+ performing Opal actions.
+
+ @param[in/out] Session OPAL_SESSION to initialize.
+ @param[in] SpId Security provider ID to start the session with.
+ @param[in] Write Whether the session should be read-only (FALSE) or read/write (TRUE).
+ @param[in] HostChallengeLength Length of the host challenge. Length should be 0 if hostChallenge is NULL
+ @param[in] HostChallenge Host challenge for Host Signing Authority. If NULL, then no Host Challenge will be sent.
+ @param[in] HostSigningAuthority Host Signing Authority used for start session. If NULL, then no Host Signing Authority will be sent.
+ @param[in/out] MethodStatus Status of the StartSession method; only valid if TcgResultSuccess is returned.
+
+ @return TcgResultSuccess indicates that the function completed without any internal errors.
+ The caller must inspect the MethodStatus field to determine whether the method completed successfully.
+
+**/
+TCG_RESULT
+EFIAPI
+OpalStartSession(
+ OPAL_SESSION *Session,
+ TCG_UID SpId,
+ BOOLEAN Write,
+ UINT32 HostChallengeLength,
+ const VOID *HostChallenge,
+ TCG_UID HostSigningAuthority,
+ UINT8 *MethodStatus
+ );
+
+/**
+ Close a session opened with OpalStartSession.
+
+ @param[in/out] Session OPAL_SESSION to end.
+
+**/
+TCG_RESULT
+EFIAPI
+OpalEndSession(
+ OPAL_SESSION *Session
+ );
+
+/**
+
+ Reverts device using Admin SP Revert method.
+
+ @param[in] AdminSpSession OPAL_SESSION with OPAL_UID_ADMIN_SP as OPAL_ADMIN_SP_PSID_AUTHORITY to perform PSID revert.
+
+**/
+TCG_RESULT
+EFIAPI
+OpalPsidRevert(
+ OPAL_SESSION *AdminSpSession
+ );
+
+
+/**
+
+ The function retrieves the MSID from the device specified
+
+ @param[in] AdminSpSession OPAL_SESSION with OPAL_UID_ADMIN_SP as OPAL_ADMIN_SP_PSID_AUTHORITY to perform PSID revert.
+ @param[in] MsidBufferSize Allocated buffer size (in bytes) for MSID allocated by caller
+ @param[in] Msid Variable length byte sequence representing MSID of device
+ @param[in] MsidLength Actual length of MSID retrieved from device
+
+**/
+TCG_RESULT
+EFIAPI
+OpalGetMsid(
+ OPAL_SESSION *AdminSpSession,
+ UINT32 MsidBufferSize,
+ UINT8 *Msid,
+ UINT32 *MsidLength
+ );
+
+/**
+
+ The function activates the Locking SP.
+ Once activated, per Opal spec, the ADMIN SP SID PIN is copied over to the ADMIN1 LOCKING SP PIN.
+ If the Locking SP is already enabled, then TcgResultSuccess is returned and no action occurs.
+
+ @param[in] AdminSpSession OPAL_SESSION with OPAL_UID_ADMIN_SP as OPAL_ADMIN_SP_SID_AUTHORITY to activate Locking SP
+ @param[in/out] MethodStatus Method status of last action performed. If action succeeded, it should be TCG_METHOD_STATUS_CODE_SUCCESS.
+
+**/
+TCG_RESULT
+EFIAPI
+OpalActivateLockingSp(
+ OPAL_SESSION *AdminSpSession,
+ UINT8 *MethodStatus
+ );
+
+
+/**
+
+ The function sets the PIN column of the specified cpinRowUid (authority) with the newPin value.
+
+ @param[in/out] Session OPAL_SESSION to set password
+ @param[in] CpinRowUid UID of row (authority) to update PIN column
+ @param[in] NewPin New Pin to set for cpinRowUid specified
+ @param[in] NewPinLength Length in bytes of newPin
+ @param[in/out] MethodStatus Method status of last action performed. If action succeeded, it should be TCG_METHOD_STATUS_CODE_SUCCESS.
+
+**/
+TCG_RESULT
+EFIAPI
+OpalSetPassword(
+ OPAL_SESSION *Session,
+ TCG_UID CpinRowUid,
+ const VOID *NewPin,
+ UINT32 NewPinLength,
+ UINT8 *MethodStatus
+ );
+
+/**
+
+ The function retrieves the active key of the global locking range
+ and calls the GenKey method on the active key retrieved.
+
+ @param[in] LockingSpSession OPAL_SESSION with OPAL_UID_LOCKING_SP to generate key
+ @param[in/out] MethodStatus Method status of last action performed. If action succeeded, it should be TCG_METHOD_STATUS_CODE_SUCCESS.
+
+**/
+TCG_RESULT
+EFIAPI
+OpalGlobalLockingRangeGenKey(
+ OPAL_SESSION *LockingSpSession,
+ UINT8 *MethodStatus
+ );
+
+
+/**
+
+ The function updates the ReadLocked and WriteLocked columns of the Global Locking Range.
+ This function is required for a user1 authority, since a user1 authority shall only have access to ReadLocked and WriteLocked columns
+ (not ReadLockEnabled and WriteLockEnabled columns).
+
+ @param[in] LockingSpSession OPAL_SESSION with OPAL_UID_LOCKING_SP to generate key
+ @param[in] ReadLocked Value to set ReadLocked column for Global Locking Range
+ @param[in] WriteLocked Value to set WriteLocked column for Global Locking Range
+ @param[in/out] MethodStatus Method status of last action performed. If action succeeded, it should be TCG_METHOD_STATUS_CODE_SUCCESS.
+
+**/
+TCG_RESULT
+EFIAPI
+OpalUpdateGlobalLockingRange(
+ OPAL_SESSION *LockingSpSession,
+ BOOLEAN ReadLocked,
+ BOOLEAN WriteLocked,
+ UINT8 *MethodStatus
+ );
+
+
+/**
+
+ The function updates the RangeStart, RangeLength, ReadLockedEnabled, WriteLockedEnabled, ReadLocked and WriteLocked columns
+ of the specified Locking Range. This function requires admin authority of a locking SP session.
+
+ @param[in] LockingSpSession OPAL_SESSION with OPAL_UID_LOCKING_SP to generate key
+ @param[in] LockingRangeUid Locking range UID to set values
+ @param[in] RangeStart Value to set RangeStart column for Locking Range
+ @param[in] RangeLength Value to set RangeLength column for Locking Range
+ @param[in] ReadLockEnabled Value to set readLockEnabled column for Locking Range
+ @param[in] WriteLockEnabled Value to set writeLockEnabled column for Locking Range
+ @param[in] ReadLocked Value to set ReadLocked column for Locking Range
+ @param[in] WriteLocked Value to set WriteLocked column for Locking Range
+ @param[in/out] MethodStatus Method status of last action performed. If action succeeded, it should be TCG_METHOD_STATUS_CODE_SUCCESS.
+
+**/
+TCG_RESULT
+EFIAPI
+OpalSetLockingRange(
+ OPAL_SESSION *LockingSpSession,
+ TCG_UID LockingRangeUid,
+ UINT64 RangeStart,
+ UINT64 RangeLength,
+ BOOLEAN ReadLockEnabled,
+ BOOLEAN WriteLockEnabled,
+ BOOLEAN ReadLocked,
+ BOOLEAN WriteLocked,
+ UINT8 *MethodStatus
+ );
+
+/**
+
+ The function sets the Enabled column to TRUE for the authorityUid provided and updates the PIN column for the cpinRowUid provided
+ using the newPin provided. AuthorityUid and cpinRowUid should describe the same authority.
+
+ @param[in] LockingSpSession OPAL_SESSION with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_ADMIN1_AUTHORITY to update
+ @param[in] CpinRowUid Row UID of C_PIN table of Locking SP to update PIN
+ @param[in] AuthorityUid UID of Locking SP authority to update Pin column with
+ @param[in] NewPin New Password used to set Pin column
+ @param[in] NewPinLength Length in bytes of new password
+ @param[in/out] MethodStatus Method status of last action performed. If action succeeded, it should be TCG_METHOD_STATUS_CODE_SUCCESS.
+
+**/
+TCG_RESULT
+EFIAPI
+OpalSetLockingSpAuthorityEnabledAndPin(
+ OPAL_SESSION *LockingSpSession,
+ TCG_UID CpinRowUid,
+ TCG_UID AuthorityUid,
+ const VOID *NewPin,
+ UINT32 NewPinLength,
+ UINT8 *MethodStatus
+ );
+
+
+/**
+
+ The function sets the Enabled column to FALSE for the USER1 authority.
+
+ @param[in] LockingSpSession OPAL_SESSION with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_ADMIN1_AUTHORITY to disable User1
+ @param[in/out] MethodStatus Method status of last action performed. If action succeeded, it should be TCG_METHOD_STATUS_CODE_SUCCESS.
+
+**/
+TCG_RESULT
+EFIAPI
+OpalDisableUser(
+ OPAL_SESSION *LockingSpSession,
+ UINT8 *MethodStatus
+ );
+
+
+/**
+
+ The function calls the Admin SP RevertSP method on the Locking SP. If KeepUserData is True, then the optional parameter
+ to keep the user data is set to True, otherwise the optional parameter is not provided.
+
+ @param[in] LockingSpSession OPAL_SESSION with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_ADMIN1_AUTHORITY to revertSP
+ @param[in] KeepUserData Specifies whether or not to keep user data when performing RevertSP action. True = keeps user data.
+ @param[in/out] MethodStatus Method status of last action performed. If action succeeded, it should be TCG_METHOD_STATUS_CODE_SUCCESS.
+
+**/
+TCG_RESULT
+EFIAPI
+OpalAdminRevert(
+ OPAL_SESSION *LockingSpSession,
+ BOOLEAN KeepUserData,
+ UINT8 *MethodStatus
+ );
+
+
+/**
+
+ The function retrieves the TryLimit column for the specified rowUid (authority).
+
+ @param[in] LockingSpSession OPAL_SESSION with OPAL_UID_LOCKING_SP to retrieve try limit
+ @param[in] RowUid Row UID of the Locking SP C_PIN table to retrieve TryLimit column
+ @param[in/out] TryLimit Value from TryLimit column
+
+**/
+TCG_RESULT
+EFIAPI
+OpalGetTryLimit(
+ OPAL_SESSION *LockingSpSession,
+ TCG_UID RowUid,
+ UINT32 *TryLimit
+ );
+
+
+/**
+
+ The function populates the CreateStruct with a payload that will retrieve the global locking range active key.
+ It is intended to be called with a session that is already started with a valid credential.
+ The function does not send the payload.
+
+ @param[in] Session OPAL_SESSION to populate command for, needs comId
+ @param[in/out] CreateStruct Structure to populate with encoded TCG command
+ @param[in/out] Size Size in bytes of the command created.
+
+**/
+TCG_RESULT
+EFIAPI
+OpalCreateRetrieveGlobalLockingRangeActiveKey(
+ const OPAL_SESSION *Session,
+ TCG_CREATE_STRUCT *CreateStruct,
+ UINT32 *Size
+ );
+
+
+/**
+
+ The function acquires the activeKey specified for the Global Locking Range from the parseStruct.
+
+ @param[in] ParseStruct Structure that contains the device's response with the activekey
+ @param[in/out] ActiveKey The UID of the active key retrieved
+
+**/
+TCG_RESULT
+EFIAPI
+OpalParseRetrieveGlobalLockingRangeActiveKey(
+ TCG_PARSE_STRUCT *ParseStruct,
+ TCG_UID *ActiveKey
+ );
+
+/**
+
+ Get the support attribute info.
+
+ @param[in] Session OPAL_SESSION with OPAL_UID_LOCKING_SP to retrieve info.
+ @param[in/out] LockingFeature Return the Locking info.
+
+**/
+TCG_RESULT
+EFIAPI
+OpalGetLockingInfo(
+ OPAL_SESSION *Session,
+ TCG_LOCKING_FEATURE_DESCRIPTOR *LockingFeature
+ );
+
+/**
+
+ The function determines whether or not all of the requirements for the Opal Feature (not full specification)
+ are met by the specified device.
+
+ @param[in] SupportedAttributes Opal device attribute.
+
+**/
+BOOLEAN
+EFIAPI
+OpalFeatureSupported(
+ OPAL_DISK_SUPPORT_ATTRIBUTE *SupportedAttributes
+ );
+
+/**
+
+ The function returns whether or not the device is Opal Enabled.
+ TRUE means that the device is partially or fully locked.
+ This will perform a Level 0 Discovery and parse the locking feature descriptor
+
+ @param[in] SupportedAttributes Opal device attribute.
+ @param[in] LockingFeature Opal device locking status.
+
+
+**/
+BOOLEAN
+EFIAPI
+OpalFeatureEnabled(
+ OPAL_DISK_SUPPORT_ATTRIBUTE *SupportedAttributes,
+ TCG_LOCKING_FEATURE_DESCRIPTOR *LockingFeature
+ );
+
+/**
+
+ The function returns whether or not the device is Opal Locked.
+ TRUE means that the device is partially or fully locked.
+ This will perform a Level 0 Discovery and parse the locking feature descriptor
+
+ @param[in] SupportedAttributes Opal device attribute.
+ @param[in] LockingFeature Opal device locking status.
+
+**/
+BOOLEAN
+OpalDeviceLocked(
+ OPAL_DISK_SUPPORT_ATTRIBUTE *SupportedAttributes,
+ TCG_LOCKING_FEATURE_DESCRIPTOR *LockingFeature
+ );
+
+/**
+ Trig the block sid action.
+
+ @param[in] Session OPAL_SESSION to populate command for, needs comId
+ @param[in] HardwareReset Whether need to do hardware reset.
+
+**/
+TCG_RESULT
+EFIAPI
+OpalBlockSid(
+ OPAL_SESSION *Session,
+ BOOLEAN HardwareReset
+ );
+
+/**
+
+ Get the support attribute info.
+
+ @param[in] Session OPAL_SESSION with OPAL_UID_LOCKING_SP to retrieve info.
+ @param[in/out] SupportedAttributes Return the support attribute info.
+ @param[out] OpalBaseComId Return the base com id info.
+
+**/
+TCG_RESULT
+EFIAPI
+OpalGetSupportedAttributesInfo(
+ OPAL_SESSION *Session,
+ OPAL_DISK_SUPPORT_ATTRIBUTE *SupportedAttributes,
+ UINT16 *OpalBaseComId
+ );
+
+/**
+ Creates a session with OPAL_UID_ADMIN_SP as OPAL_ADMIN_SP_PSID_AUTHORITY, then reverts device using Admin SP Revert method.
+
+ @param[in] AdminSpSession OPAL_SESSION to populate command for, needs comId
+ @param[in] Psid PSID of device to revert.
+ @param[in] PsidLength Length of PSID in bytes.
+
+**/
+TCG_RESULT
+EFIAPI
+OpalUtilPsidRevert(
+ OPAL_SESSION *AdminSpSession,
+ const VOID *Psid,
+ UINT32 PsidLength
+ );
+
+/**
+ Opens a session with OPAL_UID_ADMIN_SP as OPAL_ADMIN_SP_SID_AUTHORITY,
+ sets the OPAL_UID_ADMIN_SP_C_PIN_SID column with the new password,
+ and activates the locking SP to copy SID PIN to Admin1 Locking SP PIN.
+
+ @param[in] AdminSpSession OPAL_SESSION to populate command for, needs comId
+ @param[in] GeneratedSid Generated SID of disk
+ @param[in] SidLength Length of generatedSid in bytes
+ @param[in] Password New admin password to set
+ @param[in] PassLength Length of password in bytes
+
+**/
+TCG_RESULT
+EFIAPI
+OpalUtilSetAdminPasswordAsSid(
+ OPAL_SESSION *AdminSpSession,
+ const VOID *GeneratedSid,
+ UINT32 SidLength,
+ const VOID *Password,
+ UINT32 PassLength
+ );
+
+/**
+
+ Opens a session with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_ADMIN1_AUTHORITY,
+ and updates the specified locking range with the provided column values.
+
+ @param[in] LockingSpSession OPAL_SESSION to populate command for, needs comId
+ @param[in] Password New admin password to set
+ @param[in] PassLength Length of password in bytes
+ @param[in] LockingRangeUid Locking range UID to set values
+ @param[in] RangeStart Value to set RangeStart column for Locking Range
+ @param[in] RangeLength Value to set RangeLength column for Locking Range
+ @param[in] ReadLockEnabled Value to set readLockEnabled column for Locking Range
+ @param[in] WriteLockEnabled Value to set writeLockEnabled column for Locking Range
+ @param[in] ReadLocked Value to set ReadLocked column for Locking Range
+ @param[in] WriteLocked Value to set WriteLocked column for Locking Range
+
+**/
+TCG_RESULT
+EFIAPI
+OpalUtilSetOpalLockingRange(
+ OPAL_SESSION *LockingSpSession,
+ const VOID *Password,
+ UINT32 PassLength,
+ TCG_UID LockingRangeUid,
+ UINT64 RangeStart,
+ UINT64 RangeLength,
+ BOOLEAN ReadLockEnabled,
+ BOOLEAN WriteLockEnabled,
+ BOOLEAN ReadLocked,
+ BOOLEAN WriteLocked
+ );
+
+/**
+ Opens a session with OPAL_UID_ADMIN_SP as OPAL_ADMIN_SP_SID_AUTHORITY,
+ sets OPAL_UID_ADMIN_SP_C_PIN_SID with the new password,
+ and sets OPAL_LOCKING_SP_C_PIN_ADMIN1 with the new password.
+
+ @param[in] AdminSpSession OPAL_SESSION to populate command for, needs comId
+ @param[in] OldPassword Current admin password
+ @param[in] OldPasswordLength Length of current admin password in bytes
+ @param[in] NewPassword New admin password to set
+ @param[in] NewPasswordLength Length of new password in bytes
+
+**/
+TCG_RESULT
+EFIAPI
+OpalUtilSetAdminPassword(
+ OPAL_SESSION *AdminSpSession,
+ const VOID *OldPassword,
+ UINT32 OldPasswordLength,
+ const VOID *NewPassword,
+ UINT32 NewPasswordLength
+ );
+
+/**
+ Starts a session with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_USER1_AUTHORITY or OPAL_LOCKING_SP_ADMIN1_AUTHORITY
+ and sets the User1 SP authority to enabled and sets the User1 password.
+
+ @param[in] LockingSpSession OPAL_SESSION to populate command for, needs comId
+ @param[in] OldPassword Current admin password
+ @param[in] OldPasswordLength Length of current admin password in bytes
+ @param[in] NewPassword New admin password to set
+ @param[in] NewPasswordLength Length of new password in bytes
+
+**/
+TCG_RESULT
+EFIAPI
+OpalUtilSetUserPassword(
+ OPAL_SESSION *LockingSpSession,
+ const VOID *OldPassword,
+ UINT32 OldPasswordLength,
+ const VOID *NewPassword,
+ UINT32 NewPasswordLength
+ );
+
+/**
+ Verify whether user input the correct password.
+
+ @param[in] LockingSpSession OPAL_SESSION to populate command for, needs comId
+ @param[in] Password Admin password
+ @param[in] PasswordLength Length of password in bytes
+ @param[in/out] HostSigningAuthority Use the Host signing authority type.
+
+**/
+TCG_RESULT
+EFIAPI
+OpalUtilVerifyPassword (
+ OPAL_SESSION *LockingSpSession,
+ const VOID *Password,
+ UINT32 PasswordLength,
+ TCG_UID HostSigningAuthority
+ );
+
+/**
+ Starts a session with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_USER1_AUTHORITY or OPAL_LOCKING_SP_ADMIN1_AUTHORITY
+ and generates a new global locking range key to erase the Data.
+
+ @param[in] LockingSpSession OPAL_SESSION to populate command for, needs comId
+ @param[in] Password Admin or user password
+ @param[in] PasswordLength Length of password in bytes
+ @param[in/out] PasswordFailed indicates if password failed (start session didn't work)
+
+**/
+TCG_RESULT
+EFIAPI
+OpalUtilSecureErase(
+ OPAL_SESSION *LockingSpSession,
+ const VOID *Password,
+ UINT32 PasswordLength,
+ BOOLEAN *PasswordFailed
+ );
+
+/**
+ Starts a session with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_ADMIN1_AUTHORITY and disables the User1 authority.
+
+ @param[in] LockingSpSession OPAL_SESSION to populate command for, needs comId
+ @param[in] Password Admin password
+ @param[in] PasswordLength Length of password in bytes
+ @param[in/out] PasswordFailed indicates if password failed (start session didn't work)
+
+**/
+TCG_RESULT
+EFIAPI
+OpalUtilDisableUser(
+ OPAL_SESSION *LockingSpSession,
+ const VOID *Password,
+ UINT32 PasswordLength,
+ BOOLEAN *PasswordFailed
+ );
+
+/**
+ Opens a session with OPAL_UID_ADMIN_SP as OPAL_ADMIN_SP_PSID_AUTHORITY, then reverts the device using the RevertSP method.
+
+ @param[in] LockingSpSession OPAL_SESSION to populate command for, needs comId
+ @param[in] KeepUserData TRUE to keep existing Data on the disk, or FALSE to erase it
+ @param[in] Password Admin password
+ @param[in] PasswordLength Length of password in bytes
+ @param[in/out] PasswordFailed indicates if password failed (start session didn't work)
+ @param[in] Msid Input Msid info.
+ @param[in] MsidLength Input Msid info length.
+
+**/
+TCG_RESULT
+EFIAPI
+OpalUtilRevert(
+ OPAL_SESSION *LockingSpSession,
+ BOOLEAN KeepUserData,
+ const VOID *Password,
+ UINT32 PasswordLength,
+ BOOLEAN *PasswordFailed,
+ UINT8 *Msid,
+ UINT32 MsidLength
+ );
+
+/**
+ After revert success, set SID to MSID.
+
+ @param[in] AdminSpSession OPAL_SESSION to populate command for, needs comId
+ @param Password, Input password info.
+ @param PasswordLength, Input password length.
+ @param[in] Msid Input Msid info.
+ @param[in] MsidLength Input Msid info length.
+
+**/
+TCG_RESULT
+EFIAPI
+OpalUtilSetSIDtoMSID (
+ OPAL_SESSION *AdminSpSession,
+ const VOID *Password,
+ UINT32 PasswordLength,
+ UINT8 *Msid,
+ UINT32 MsidLength
+ );
+
+/**
+ Update global locking range.
+
+ @param[in] LockingSpSession OPAL_SESSION to populate command for, needs comId
+ @param Password, Input password info.
+ @param PasswordLength, Input password length.
+ @param ReadLocked, Read lock info.
+ @param WriteLocked write lock info.
+
+**/
+TCG_RESULT
+EFIAPI
+OpalUtilUpdateGlobalLockingRange(
+ OPAL_SESSION *LockingSpSession,
+ const VOID *Password,
+ UINT32 PasswordLength,
+ BOOLEAN ReadLocked,
+ BOOLEAN WriteLocked
+ );
+
+/**
+ Update global locking range.
+
+ @param Session, The session info for one opal device.
+ @param Msid, The data buffer to save Msid info.
+ @param MsidBufferLength, The data buffer length for Msid.
+ @param MsidLength, The actual data length for Msid.
+
+**/
+TCG_RESULT
+EFIAPI
+OpalUtilGetMsid(
+ OPAL_SESSION *Session,
+ UINT8 *Msid,
+ UINT32 MsidBufferLength,
+ UINT32 *MsidLength
+ );
+
+/**
+
+ The function determines who owns the device by attempting to start a session with different credentials.
+ If the SID PIN matches the MSID PIN, the no one owns the device.
+ If the SID PIN matches the ourSidPin, then "Us" owns the device. Otherwise it is unknown.
+
+
+ @param[in] Session The session info for one opal device.
+ @param Msid, The Msid info.
+ @param MsidLength, The data length for Msid.
+
+**/
+OPAL_OWNER_SHIP
+EFIAPI
+OpalUtilDetermineOwnership(
+ OPAL_SESSION *Session,
+ UINT8 *Msid,
+ UINT32 MsidLength
+ );
+
+/**
+
+ The function returns if admin password exists.
+
+ @param[in] OwnerShip The owner ship of the opal device.
+ @param[in] LockingFeature The locking info of the opal device.
+
+ @retval TRUE Admin password existed.
+ @retval FALSE Admin password not existed.
+
+**/
+BOOLEAN
+EFIAPI
+OpalUtilAdminPasswordExists(
+ IN UINT16 OwnerShip,
+ IN TCG_LOCKING_FEATURE_DESCRIPTOR *LockingFeature
+ );
+
+#endif // _OPAL_CORE_H_
diff --git a/Core/SecurityPkg/Include/Library/Tpm12CommandLib.h b/Core/SecurityPkg/Include/Library/Tpm12CommandLib.h
new file mode 100644
index 0000000000..f7c098f283
--- /dev/null
+++ b/Core/SecurityPkg/Include/Library/Tpm12CommandLib.h
@@ -0,0 +1,225 @@
+/** @file
+ This library is used by other modules to send TPM12 command.
+
+Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved. <BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _TPM12_COMMAND_LIB_H_
+#define _TPM12_COMMAND_LIB_H_
+
+#include <IndustryStandard/Tpm12.h>
+
+/**
+ Send Startup command to TPM1.2.
+
+ @param TpmSt Startup Type.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+Tpm12Startup (
+ IN TPM_STARTUP_TYPE TpmSt
+ );
+
+/**
+ Send SaveState command to TPM1.2.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+Tpm12SaveState (
+ VOID
+ );
+
+/**
+ Send ForceClear command to TPM1.2.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+Tpm12ForceClear (
+ VOID
+ );
+
+#pragma pack(1)
+
+typedef struct {
+ UINT16 sizeOfSelect;
+ UINT8 pcrSelect[3];
+} TPM12_PCR_SELECTION;
+
+typedef struct {
+ TPM12_PCR_SELECTION pcrSelection;
+ TPM_LOCALITY_SELECTION localityAtRelease;
+ TPM_COMPOSITE_HASH digestAtRelease;
+} TPM12_PCR_INFO_SHORT;
+
+typedef struct {
+ TPM_STRUCTURE_TAG tag;
+ TPM_NV_INDEX nvIndex;
+ TPM12_PCR_INFO_SHORT pcrInfoRead;
+ TPM12_PCR_INFO_SHORT pcrInfoWrite;
+ TPM_NV_ATTRIBUTES permission;
+ BOOLEAN bReadSTClear;
+ BOOLEAN bWriteSTClear;
+ BOOLEAN bWriteDefine;
+ UINT32 dataSize;
+} TPM12_NV_DATA_PUBLIC;
+
+#pragma pack()
+
+/**
+ Send NV DefineSpace command to TPM1.2.
+
+ @param PubInfo The public parameters of the NV area.
+ @param EncAuth The encrypted AuthData, only valid if the attributes require subsequent authorization.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+Tpm12NvDefineSpace (
+ IN TPM12_NV_DATA_PUBLIC *PubInfo,
+ IN TPM_ENCAUTH *EncAuth
+ );
+
+/**
+ Send NV ReadValue command to TPM1.2.
+
+ @param NvIndex The index of the area to set.
+ @param Offset The offset into the area.
+ @param DataSize The size of the data area.
+ @param Data The data to set the area to.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+Tpm12NvReadValue (
+ IN TPM_NV_INDEX NvIndex,
+ IN UINT32 Offset,
+ IN OUT UINT32 *DataSize,
+ OUT UINT8 *Data
+ );
+
+/**
+ Send NV WriteValue command to TPM1.2.
+
+ @param NvIndex The index of the area to set.
+ @param Offset The offset into the NV Area.
+ @param DataSize The size of the data parameter.
+ @param Data The data to set the area to.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+Tpm12NvWriteValue (
+ IN TPM_NV_INDEX NvIndex,
+ IN UINT32 Offset,
+ IN UINT32 DataSize,
+ IN UINT8 *Data
+ );
+
+/**
+Extend a TPM PCR.
+
+@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
+EFIAPI
+Tpm12Extend (
+ IN TPM_DIGEST *DigestToExtend,
+ IN TPM_PCRINDEX PcrIndex,
+ OUT TPM_DIGEST *NewPcrValue
+ );
+
+/**
+Send TSC_PhysicalPresence command to TPM.
+
+@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
+EFIAPI
+Tpm12PhysicalPresence (
+ IN TPM_PHYSICAL_PRESENCE PhysicalPresence
+ );
+
+/**
+Send TPM_ContinueSelfTest command to TPM.
+
+@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
+EFIAPI
+Tpm12ContinueSelfTest (
+ VOID
+ );
+
+/**
+Get TPM capability permanent flags.
+
+@param[out] TpmPermanentFlags Pointer to the buffer for returned flag structure.
+
+@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
+EFIAPI
+Tpm12GetCapabilityFlagPermanent (
+ OUT TPM_PERMANENT_FLAGS *TpmPermanentFlags
+ );
+
+/**
+Get TPM capability volatile flags.
+
+@param[out] VolatileFlags Pointer to the buffer for returned flag structure.
+
+@retval EFI_SUCCESS Operation completed successfully.
+@retval EFI_DEVICE_ERROR The command was unsuccessful.
+
+**/
+EFI_STATUS
+EFIAPI
+Tpm12GetCapabilityFlagVolatile (
+ OUT TPM_STCLEAR_FLAGS *VolatileFlags
+ );
+#endif
diff --git a/Core/SecurityPkg/Include/Library/Tpm12DeviceLib.h b/Core/SecurityPkg/Include/Library/Tpm12DeviceLib.h
new file mode 100644
index 0000000000..ab1f522ad0
--- /dev/null
+++ b/Core/SecurityPkg/Include/Library/Tpm12DeviceLib.h
@@ -0,0 +1,54 @@
+/** @file
+ This library abstract how to access TPM12 hardware device.
+
+Copyright (c) 2013, Intel Corporation. All rights reserved. <BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _TPM12_DEVICE_LIB_H_
+#define _TPM12_DEVICE_LIB_H_
+
+#include <IndustryStandard/Tpm12.h>
+
+/**
+ This service enables the sending of commands to the TPM12.
+
+ @param[in] InputParameterBlockSize Size of the TPM12 input parameter block.
+ @param[in] InputParameterBlock Pointer to the TPM12 input parameter block.
+ @param[in,out] OutputParameterBlockSize Size of the TPM12 output parameter block.
+ @param[in] OutputParameterBlock Pointer to the TPM12 output parameter block.
+
+ @retval EFI_SUCCESS The command byte stream was successfully sent to the device and a response was successfully received.
+ @retval EFI_DEVICE_ERROR The command was not successfully sent to the device or a response was not successfully received from the device.
+ @retval EFI_BUFFER_TOO_SMALL The output parameter block is too small.
+**/
+EFI_STATUS
+EFIAPI
+Tpm12SubmitCommand (
+ IN UINT32 InputParameterBlockSize,
+ IN UINT8 *InputParameterBlock,
+ IN OUT UINT32 *OutputParameterBlockSize,
+ IN UINT8 *OutputParameterBlock
+ );
+
+/**
+ This service requests use TPM12.
+
+ @retval EFI_SUCCESS Get the control of TPM12 chip.
+ @retval EFI_NOT_FOUND TPM12 not found.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+Tpm12RequestUseTpm (
+ VOID
+ );
+
+#endif
diff --git a/Core/SecurityPkg/Include/Library/Tpm2CommandLib.h b/Core/SecurityPkg/Include/Library/Tpm2CommandLib.h
new file mode 100644
index 0000000000..80ada7397b
--- /dev/null
+++ b/Core/SecurityPkg/Include/Library/Tpm2CommandLib.h
@@ -0,0 +1,1106 @@
+/** @file
+ This library is used by other modules to send TPM2 command.
+
+Copyright (c) 2013 - 2017, Intel Corporation. All rights reserved. <BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _TPM2_COMMAND_LIB_H_
+#define _TPM2_COMMAND_LIB_H_
+
+#include <IndustryStandard/Tpm20.h>
+
+/**
+ This command starts a hash or an Event sequence.
+ If hashAlg is an implemented hash, then a hash sequence is started.
+ If hashAlg is TPM_ALG_NULL, then an Event sequence is started.
+
+ @param[in] HashAlg The hash algorithm to use for the hash sequence
+ An Event sequence starts if this is TPM_ALG_NULL.
+ @param[out] SequenceHandle A handle to reference the sequence
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2HashSequenceStart (
+ IN TPMI_ALG_HASH HashAlg,
+ OUT TPMI_DH_OBJECT *SequenceHandle
+ );
+
+/**
+ This command is used to add data to a hash or HMAC sequence.
+ The amount of data in buffer may be any size up to the limits of the TPM.
+ NOTE: In all TPM, a buffer size of 1,024 octets is allowed.
+
+ @param[in] SequenceHandle Handle for the sequence object
+ @param[in] Buffer Data to be added to hash
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2SequenceUpdate (
+ IN TPMI_DH_OBJECT SequenceHandle,
+ IN TPM2B_MAX_BUFFER *Buffer
+ );
+
+/**
+ This command adds the last part of data, if any, to an Event sequence and returns the result in a digest list.
+ If pcrHandle references a PCR and not TPM_RH_NULL, then the returned digest list is processed in
+ the same manner as the digest list input parameter to TPM2_PCR_Extend() with the pcrHandle in each
+ bank extended with the associated digest value.
+
+ @param[in] PcrHandle PCR to be extended with the Event data
+ @param[in] SequenceHandle Authorization for the sequence
+ @param[in] Buffer Data to be added to the Event
+ @param[out] Results List of digests computed for the PCR
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2EventSequenceComplete (
+ IN TPMI_DH_PCR PcrHandle,
+ IN TPMI_DH_OBJECT SequenceHandle,
+ IN TPM2B_MAX_BUFFER *Buffer,
+ OUT TPML_DIGEST_VALUES *Results
+ );
+
+/**
+ This command adds the last part of data, if any, to a hash/HMAC sequence and returns the result.
+
+ @param[in] SequenceHandle Authorization for the sequence
+ @param[in] Buffer Data to be added to the hash/HMAC
+ @param[out] Result The returned HMAC or digest in a sized buffer
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2SequenceComplete (
+ IN TPMI_DH_OBJECT SequenceHandle,
+ IN TPM2B_MAX_BUFFER *Buffer,
+ OUT TPM2B_DIGEST *Result
+ );
+
+/**
+ Send Startup command to TPM2.
+
+ @param[in] StartupType TPM_SU_CLEAR or TPM_SU_STATE
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2Startup (
+ IN TPM_SU StartupType
+ );
+
+/**
+ Send Shutdown command to TPM2.
+
+ @param[in] ShutdownType TPM_SU_CLEAR or TPM_SU_STATE.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2Shutdown (
+ IN TPM_SU ShutdownType
+ );
+
+/**
+ This command causes the TPM to perform a test of its capabilities.
+ If the fullTest is YES, the TPM will test all functions.
+ If fullTest = NO, the TPM will only test those functions that have not previously been tested.
+
+ @param[in] FullTest YES if full test to be performed
+ NO if only test of untested functions required
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2SelfTest (
+ IN TPMI_YES_NO FullTest
+ );
+
+/**
+ This command allows setting of the authorization policy for the platform hierarchy (platformPolicy), the
+ storage hierarchy (ownerPolicy), and and the endorsement hierarchy (endorsementPolicy).
+
+ @param[in] AuthHandle TPM_RH_ENDORSEMENT, TPM_RH_OWNER or TPM_RH_PLATFORM+{PP} parameters to be validated
+ @param[in] AuthSession Auth Session context
+ @param[in] AuthPolicy An authorization policy hash
+ @param[in] HashAlg The hash algorithm to use for the policy
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2SetPrimaryPolicy (
+ IN TPMI_RH_HIERARCHY_AUTH AuthHandle,
+ IN TPMS_AUTH_COMMAND *AuthSession,
+ IN TPM2B_DIGEST *AuthPolicy,
+ IN TPMI_ALG_HASH HashAlg
+ );
+
+/**
+ This command removes all TPM context associated with a specific Owner.
+
+ @param[in] AuthHandle TPM_RH_LOCKOUT or TPM_RH_PLATFORM+{PP}
+ @param[in] AuthSession Auth Session context
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2Clear (
+ IN TPMI_RH_CLEAR AuthHandle,
+ IN TPMS_AUTH_COMMAND *AuthSession OPTIONAL
+ );
+
+/**
+ Disables and enables the execution of TPM2_Clear().
+
+ @param[in] AuthHandle TPM_RH_LOCKOUT or TPM_RH_PLATFORM+{PP}
+ @param[in] AuthSession Auth Session context
+ @param[in] Disable YES if the disableOwnerClear flag is to be SET,
+ NO if the flag is to be CLEAR.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2ClearControl (
+ IN TPMI_RH_CLEAR AuthHandle,
+ IN TPMS_AUTH_COMMAND *AuthSession, OPTIONAL
+ IN TPMI_YES_NO Disable
+ );
+
+/**
+ This command allows the authorization secret for a hierarchy or lockout to be changed using the current
+ authorization value as the command authorization.
+
+ @param[in] AuthHandle TPM_RH_LOCKOUT, TPM_RH_ENDORSEMENT, TPM_RH_OWNER or TPM_RH_PLATFORM+{PP}
+ @param[in] AuthSession Auth Session context
+ @param[in] NewAuth New authorization secret
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2HierarchyChangeAuth (
+ IN TPMI_RH_HIERARCHY_AUTH AuthHandle,
+ IN TPMS_AUTH_COMMAND *AuthSession,
+ IN TPM2B_AUTH *NewAuth
+ );
+
+/**
+ This replaces the current EPS with a value from the RNG and sets the Endorsement hierarchy controls to
+ their default initialization values.
+
+ @param[in] AuthHandle TPM_RH_PLATFORM+{PP}
+ @param[in] AuthSession Auth Session context
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2ChangeEPS (
+ IN TPMI_RH_PLATFORM AuthHandle,
+ IN TPMS_AUTH_COMMAND *AuthSession
+ );
+
+/**
+ This replaces the current PPS with a value from the RNG and sets platformPolicy to the default
+ initialization value (the Empty Buffer).
+
+ @param[in] AuthHandle TPM_RH_PLATFORM+{PP}
+ @param[in] AuthSession Auth Session context
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2ChangePPS (
+ IN TPMI_RH_PLATFORM AuthHandle,
+ IN TPMS_AUTH_COMMAND *AuthSession
+ );
+
+/**
+ This command enables and disables use of a hierarchy.
+
+ @param[in] AuthHandle TPM_RH_ENDORSEMENT, TPM_RH_OWNER or TPM_RH_PLATFORM+{PP}
+ @param[in] AuthSession Auth Session context
+ @param[in] Hierarchy Hierarchy of the enable being modified
+ @param[in] State YES if the enable should be SET,
+ NO if the enable should be CLEAR
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2HierarchyControl (
+ IN TPMI_RH_HIERARCHY AuthHandle,
+ IN TPMS_AUTH_COMMAND *AuthSession,
+ IN TPMI_RH_HIERARCHY Hierarchy,
+ IN TPMI_YES_NO State
+ );
+
+/**
+ This command cancels the effect of a TPM lockout due to a number of successive authorization failures.
+ If this command is properly authorized, the lockout counter is set to zero.
+
+ @param[in] LockHandle LockHandle
+ @param[in] AuthSession Auth Session context
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2DictionaryAttackLockReset (
+ IN TPMI_RH_LOCKOUT LockHandle,
+ IN TPMS_AUTH_COMMAND *AuthSession
+ );
+
+/**
+ This command cancels the effect of a TPM lockout due to a number of successive authorization failures.
+ If this command is properly authorized, the lockout counter is set to zero.
+
+ @param[in] LockHandle LockHandle
+ @param[in] AuthSession Auth Session context
+ @param[in] NewMaxTries Count of authorization failures before the lockout is imposed
+ @param[in] NewRecoveryTime Time in seconds before the authorization failure count is automatically decremented
+ @param[in] LockoutRecovery Time in seconds after a lockoutAuth failure before use of lockoutAuth is allowed
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2DictionaryAttackParameters (
+ IN TPMI_RH_LOCKOUT LockHandle,
+ IN TPMS_AUTH_COMMAND *AuthSession,
+ IN UINT32 NewMaxTries,
+ IN UINT32 NewRecoveryTime,
+ IN UINT32 LockoutRecovery
+ );
+
+/**
+ This command is used to read the public area and Name of an NV Index.
+
+ @param[in] NvIndex The NV Index.
+ @param[out] NvPublic The public area of the index.
+ @param[out] NvName The Name of the nvIndex.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2NvReadPublic (
+ IN TPMI_RH_NV_INDEX NvIndex,
+ OUT TPM2B_NV_PUBLIC *NvPublic,
+ OUT TPM2B_NAME *NvName
+ );
+
+/**
+ This command defines the attributes of an NV Index and causes the TPM to
+ reserve space to hold the data associated with the index.
+ If a definition already exists at the index, the TPM will return TPM_RC_NV_DEFINED.
+
+ @param[in] AuthHandle TPM_RH_OWNER or TPM_RH_PLATFORM+{PP}.
+ @param[in] AuthSession Auth Session context
+ @param[in] Auth The authorization data.
+ @param[in] NvPublic The public area of the index.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+ @retval EFI_ALREADY_STARTED The command was returned successfully, but NvIndex is already defined.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2NvDefineSpace (
+ IN TPMI_RH_PROVISION AuthHandle,
+ IN TPMS_AUTH_COMMAND *AuthSession, OPTIONAL
+ IN TPM2B_AUTH *Auth,
+ IN TPM2B_NV_PUBLIC *NvPublic
+ );
+
+/**
+ This command removes an index from the TPM.
+
+ @param[in] AuthHandle TPM_RH_OWNER or TPM_RH_PLATFORM+{PP}.
+ @param[in] NvIndex The NV Index.
+ @param[in] AuthSession Auth Session context
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+ @retval EFI_NOT_FOUND The command was returned successfully, but NvIndex is not found.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2NvUndefineSpace (
+ IN TPMI_RH_PROVISION AuthHandle,
+ IN TPMI_RH_NV_INDEX NvIndex,
+ IN TPMS_AUTH_COMMAND *AuthSession OPTIONAL
+ );
+
+/**
+ This command reads a value from an area in NV memory previously defined by TPM2_NV_DefineSpace().
+
+ @param[in] AuthHandle the handle indicating the source of the authorization value.
+ @param[in] NvIndex The index to be read.
+ @param[in] AuthSession Auth Session context
+ @param[in] Size Number of bytes to read.
+ @param[in] Offset Byte offset into the area.
+ @param[in,out] OutData The data read.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+ @retval EFI_NOT_FOUND The command was returned successfully, but NvIndex is not found.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2NvRead (
+ IN TPMI_RH_NV_AUTH AuthHandle,
+ IN TPMI_RH_NV_INDEX NvIndex,
+ IN TPMS_AUTH_COMMAND *AuthSession, OPTIONAL
+ IN UINT16 Size,
+ IN UINT16 Offset,
+ IN OUT TPM2B_MAX_BUFFER *OutData
+ );
+
+/**
+ This command writes a value to an area in NV memory that was previously defined by TPM2_NV_DefineSpace().
+
+ @param[in] AuthHandle the handle indicating the source of the authorization value.
+ @param[in] NvIndex The NV Index of the area to write.
+ @param[in] AuthSession Auth Session context
+ @param[in] InData The data to write.
+ @param[in] Offset The offset into the NV Area.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+ @retval EFI_NOT_FOUND The command was returned successfully, but NvIndex is not found.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2NvWrite (
+ IN TPMI_RH_NV_AUTH AuthHandle,
+ IN TPMI_RH_NV_INDEX NvIndex,
+ IN TPMS_AUTH_COMMAND *AuthSession, OPTIONAL
+ IN TPM2B_MAX_BUFFER *InData,
+ IN UINT16 Offset
+ );
+
+/**
+ This command may be used to prevent further reads of the Index until the next TPM2_Startup (TPM_SU_CLEAR).
+
+ @param[in] AuthHandle the handle indicating the source of the authorization value.
+ @param[in] NvIndex The NV Index of the area to lock.
+ @param[in] AuthSession Auth Session context
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+ @retval EFI_NOT_FOUND The command was returned successfully, but NvIndex is not found.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2NvReadLock (
+ IN TPMI_RH_NV_AUTH AuthHandle,
+ IN TPMI_RH_NV_INDEX NvIndex,
+ IN TPMS_AUTH_COMMAND *AuthSession OPTIONAL
+ );
+
+/**
+ This command may be used to inhibit further writes of the Index.
+
+ @param[in] AuthHandle the handle indicating the source of the authorization value.
+ @param[in] NvIndex The NV Index of the area to lock.
+ @param[in] AuthSession Auth Session context
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+ @retval EFI_NOT_FOUND The command was returned successfully, but NvIndex is not found.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2NvWriteLock (
+ IN TPMI_RH_NV_AUTH AuthHandle,
+ IN TPMI_RH_NV_INDEX NvIndex,
+ IN TPMS_AUTH_COMMAND *AuthSession OPTIONAL
+ );
+
+/**
+ The command will SET TPMA_NV_WRITELOCKED for all indexes that have their TPMA_NV_GLOBALLOCK attribute SET.
+
+ @param[in] AuthHandle TPM_RH_OWNER or TPM_RH_PLATFORM+{PP}.
+ @param[in] AuthSession Auth Session context
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+ @retval EFI_NOT_FOUND The command was returned successfully, but NvIndex is not found.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2NvGlobalWriteLock (
+ IN TPMI_RH_PROVISION AuthHandle,
+ IN TPMS_AUTH_COMMAND *AuthSession OPTIONAL
+ );
+
+/**
+ This command is used to cause an update to the indicated PCR.
+ The digests parameter contains one or more tagged digest value identified by an algorithm ID.
+ For each digest, the PCR associated with pcrHandle is Extended into the bank identified by the tag (hashAlg).
+
+ @param[in] PcrHandle Handle of the PCR
+ @param[in] Digests List of tagged digest values to be extended
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2PcrExtend (
+ IN TPMI_DH_PCR PcrHandle,
+ IN TPML_DIGEST_VALUES *Digests
+ );
+
+/**
+ This command is used to cause an update to the indicated PCR.
+ The data in eventData is hashed using the hash algorithm associated with each bank in which the
+ indicated PCR has been allocated. After the data is hashed, the digests list is returned. If the pcrHandle
+ references an implemented PCR and not TPM_ALG_NULL, digests list is processed as in
+ TPM2_PCR_Extend().
+ A TPM shall support an Event.size of zero through 1,024 inclusive.
+
+ @param[in] PcrHandle Handle of the PCR
+ @param[in] EventData Event data in sized buffer
+ @param[out] Digests List of digest
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2PcrEvent (
+ IN TPMI_DH_PCR PcrHandle,
+ IN TPM2B_EVENT *EventData,
+ OUT TPML_DIGEST_VALUES *Digests
+ );
+
+/**
+ This command returns the values of all PCR specified in pcrSelect.
+
+ @param[in] PcrSelectionIn The selection of PCR to read.
+ @param[out] PcrUpdateCounter The current value of the PCR update counter.
+ @param[out] PcrSelectionOut The PCR in the returned list.
+ @param[out] PcrValues The contents of the PCR indicated in pcrSelect.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2PcrRead (
+ IN TPML_PCR_SELECTION *PcrSelectionIn,
+ OUT UINT32 *PcrUpdateCounter,
+ OUT TPML_PCR_SELECTION *PcrSelectionOut,
+ OUT TPML_DIGEST *PcrValues
+ );
+
+/**
+ This command is used to set the desired PCR allocation of PCR and algorithms.
+
+ @param[in] AuthHandle TPM_RH_PLATFORM+{PP}
+ @param[in] AuthSession Auth Session context
+ @param[in] PcrAllocation The requested allocation
+ @param[out] AllocationSuccess YES if the allocation succeeded
+ @param[out] MaxPCR maximum number of PCR that may be in a bank
+ @param[out] SizeNeeded number of octets required to satisfy the request
+ @param[out] SizeAvailable Number of octets available. Computed before the allocation
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2PcrAllocate (
+ IN TPMI_RH_PLATFORM AuthHandle,
+ IN TPMS_AUTH_COMMAND *AuthSession,
+ IN TPML_PCR_SELECTION *PcrAllocation,
+ OUT TPMI_YES_NO *AllocationSuccess,
+ OUT UINT32 *MaxPCR,
+ OUT UINT32 *SizeNeeded,
+ OUT UINT32 *SizeAvailable
+ );
+
+/**
+ Alloc PCR data.
+
+ @param[in] PlatformAuth platform auth value. NULL means no platform auth change.
+ @param[in] SupportedPCRBanks Supported PCR banks
+ @param[in] PCRBanks PCR banks
+
+ @retval EFI_SUCCESS Operation completed successfully.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2PcrAllocateBanks (
+ IN TPM2B_AUTH *PlatformAuth, OPTIONAL
+ IN UINT32 SupportedPCRBanks,
+ IN UINT32 PCRBanks
+ );
+
+/**
+ This command returns various information regarding the TPM and its current state.
+
+ The capability parameter determines the category of data returned. The property parameter
+ selects the first value of the selected category to be returned. If there is no property
+ that corresponds to the value of property, the next higher value is returned, if it exists.
+ The moreData parameter will have a value of YES if there are more values of the requested
+ type that were not returned.
+ If no next capability exists, the TPM will return a zero-length list and moreData will have
+ a value of NO.
+
+ NOTE:
+ To simplify this function, leave returned CapabilityData for caller to unpack since there are
+ many capability categories and only few categories will be used in firmware. It means the caller
+ need swap the byte order for the feilds in CapabilityData.
+
+ @param[in] Capability Group selection; determines the format of the response.
+ @param[in] Property Further definition of information.
+ @param[in] PropertyCount Number of properties of the indicated type to return.
+ @param[out] MoreData Flag to indicate if there are more values of this type.
+ @param[out] CapabilityData The capability data.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2GetCapability (
+ IN TPM_CAP Capability,
+ IN UINT32 Property,
+ IN UINT32 PropertyCount,
+ OUT TPMI_YES_NO *MoreData,
+ OUT TPMS_CAPABILITY_DATA *CapabilityData
+ );
+
+/**
+ This command returns the information of TPM Family.
+
+ This function parse the value got from TPM2_GetCapability and return the Family.
+
+ @param[out] Family The Family of TPM. (a 4-octet character string)
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2GetCapabilityFamily (
+ OUT CHAR8 *Family
+ );
+
+/**
+ This command returns the information of TPM manufacture ID.
+
+ This function parse the value got from TPM2_GetCapability and return the TPM manufacture ID.
+
+ @param[out] ManufactureId The manufacture ID of TPM.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2GetCapabilityManufactureID (
+ OUT UINT32 *ManufactureId
+ );
+
+/**
+ This command returns the information of TPM FirmwareVersion.
+
+ This function parse the value got from TPM2_GetCapability and return the TPM FirmwareVersion.
+
+ @param[out] FirmwareVersion1 The FirmwareVersion1.
+ @param[out] FirmwareVersion2 The FirmwareVersion2.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2GetCapabilityFirmwareVersion (
+ OUT UINT32 *FirmwareVersion1,
+ OUT UINT32 *FirmwareVersion2
+ );
+
+/**
+ This command returns the information of the maximum value for commandSize and responseSize in a command.
+
+ This function parse the value got from TPM2_GetCapability and return the max command size and response size
+
+ @param[out] MaxCommandSize The maximum value for commandSize in a command.
+ @param[out] MaxResponseSize The maximum value for responseSize in a command.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2GetCapabilityMaxCommandResponseSize (
+ OUT UINT32 *MaxCommandSize,
+ OUT UINT32 *MaxResponseSize
+ );
+
+/**
+ This command returns Returns a list of TPMS_ALG_PROPERTIES. Each entry is an
+ algorithm ID and a set of properties of the algorithm.
+
+ This function parse the value got from TPM2_GetCapability and return the list.
+
+ @param[out] AlgList List of algorithm.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2GetCapabilitySupportedAlg (
+ OUT TPML_ALG_PROPERTY *AlgList
+ );
+
+/**
+ This command returns the information of TPM LockoutCounter.
+
+ This function parse the value got from TPM2_GetCapability and return the LockoutCounter.
+
+ @param[out] LockoutCounter The LockoutCounter of TPM.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2GetCapabilityLockoutCounter (
+ OUT UINT32 *LockoutCounter
+ );
+
+/**
+ This command returns the information of TPM LockoutInterval.
+
+ This function parse the value got from TPM2_GetCapability and return the LockoutInterval.
+
+ @param[out] LockoutInterval The LockoutInterval of TPM.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2GetCapabilityLockoutInterval (
+ OUT UINT32 *LockoutInterval
+ );
+
+/**
+ This command returns the information of TPM InputBufferSize.
+
+ This function parse the value got from TPM2_GetCapability and return the InputBufferSize.
+
+ @param[out] InputBufferSize The InputBufferSize of TPM.
+ the maximum size of a parameter (typically, a TPM2B_MAX_BUFFER)
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2GetCapabilityInputBufferSize (
+ OUT UINT32 *InputBufferSize
+ );
+
+/**
+ This command returns the information of TPM PCRs.
+
+ This function parse the value got from TPM2_GetCapability and return the PcrSelection.
+
+ @param[out] Pcrs The Pcr Selection
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2GetCapabilityPcrs (
+ OUT TPML_PCR_SELECTION *Pcrs
+ );
+
+/**
+ This function will query the TPM to determine which hashing algorithms
+ are supported and which PCR banks are currently active.
+
+ @param[out] TpmHashAlgorithmBitmap A bitmask containing the algorithms supported by the TPM.
+ @param[out] ActivePcrBanks A bitmask containing the PCRs currently allocated.
+
+ @retval EFI_SUCCESS TPM was successfully queried and return values can be trusted.
+ @retval Others An error occurred, likely in communication with the TPM.
+
+**/
+EFI_STATUS
+EFIAPI
+Tpm2GetCapabilitySupportedAndActivePcrs(
+ OUT UINT32 *TpmHashAlgorithmBitmap,
+ OUT UINT32 *ActivePcrBanks
+ );
+
+/**
+ This command returns the information of TPM AlgorithmSet.
+
+ This function parse the value got from TPM2_GetCapability and return the AlgorithmSet.
+
+ @param[out] AlgorithmSet The AlgorithmSet of TPM.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2GetCapabilityAlgorithmSet (
+ OUT UINT32 *AlgorithmSet
+ );
+
+/**
+ This command is used to check to see if specific combinations of algorithm parameters are supported.
+
+ @param[in] Parameters Algorithm parameters to be validated
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2TestParms (
+ IN TPMT_PUBLIC_PARMS *Parameters
+ );
+
+/**
+ This command allows the platform to change the set of algorithms that are used by the TPM.
+ The algorithmSet setting is a vendor-dependent value.
+
+ @param[in] AuthHandle TPM_RH_PLATFORM
+ @param[in] AuthSession Auth Session context
+ @param[in] AlgorithmSet A TPM vendor-dependent value indicating the
+ algorithm set selection
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2SetAlgorithmSet (
+ IN TPMI_RH_PLATFORM AuthHandle,
+ IN TPMS_AUTH_COMMAND *AuthSession,
+ IN UINT32 AlgorithmSet
+ );
+
+/**
+ This command is used to start an authorization session using alternative methods of
+ establishing the session key (sessionKey) that is used for authorization and encrypting value.
+
+ @param[in] TpmKey Handle of a loaded decrypt key used to encrypt salt.
+ @param[in] Bind Entity providing the authValue.
+ @param[in] NonceCaller Initial nonceCaller, sets nonce size for the session.
+ @param[in] Salt Value encrypted according to the type of tpmKey.
+ @param[in] SessionType Indicates the type of the session.
+ @param[in] Symmetric The algorithm and key size for parameter encryption.
+ @param[in] AuthHash Hash algorithm to use for the session.
+ @param[out] SessionHandle Handle for the newly created session.
+ @param[out] NonceTPM The initial nonce from the TPM, used in the computation of the sessionKey.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2StartAuthSession (
+ IN TPMI_DH_OBJECT TpmKey,
+ IN TPMI_DH_ENTITY Bind,
+ IN TPM2B_NONCE *NonceCaller,
+ IN TPM2B_ENCRYPTED_SECRET *Salt,
+ IN TPM_SE SessionType,
+ IN TPMT_SYM_DEF *Symmetric,
+ IN TPMI_ALG_HASH AuthHash,
+ OUT TPMI_SH_AUTH_SESSION *SessionHandle,
+ OUT TPM2B_NONCE *NonceTPM
+ );
+
+/**
+ This command causes all context associated with a loaded object or session to be removed from TPM memory.
+
+ @param[in] FlushHandle The handle of the item to flush.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2FlushContext (
+ IN TPMI_DH_CONTEXT FlushHandle
+ );
+
+/**
+ This command includes a secret-based authorization to a policy.
+ The caller proves knowledge of the secret value using an authorization
+ session using the authValue associated with authHandle.
+
+ @param[in] AuthHandle Handle for an entity providing the authorization
+ @param[in] PolicySession Handle for the policy session being extended.
+ @param[in] AuthSession Auth Session context
+ @param[in] NonceTPM The policy nonce for the session.
+ @param[in] CpHashA Digest of the command parameters to which this authorization is limited.
+ @param[in] PolicyRef A reference to a policy relating to the authorization.
+ @param[in] Expiration Time when authorization will expire, measured in seconds from the time that nonceTPM was generated.
+ @param[out] Timeout Time value used to indicate to the TPM when the ticket expires.
+ @param[out] PolicyTicket A ticket that includes a value indicating when the authorization expires.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2PolicySecret (
+ IN TPMI_DH_ENTITY AuthHandle,
+ IN TPMI_SH_POLICY PolicySession,
+ IN TPMS_AUTH_COMMAND *AuthSession, OPTIONAL
+ IN TPM2B_NONCE *NonceTPM,
+ IN TPM2B_DIGEST *CpHashA,
+ IN TPM2B_NONCE *PolicyRef,
+ IN INT32 Expiration,
+ OUT TPM2B_TIMEOUT *Timeout,
+ OUT TPMT_TK_AUTH *PolicyTicket
+ );
+
+/**
+ This command allows options in authorizations without requiring that the TPM evaluate all of the options.
+ If a policy may be satisfied by different sets of conditions, the TPM need only evaluate one set that
+ satisfies the policy. This command will indicate that one of the required sets of conditions has been
+ satisfied.
+
+ @param[in] PolicySession Handle for the policy session being extended.
+ @param[in] HashList the list of hashes to check for a match.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2PolicyOR (
+ IN TPMI_SH_POLICY PolicySession,
+ IN TPML_DIGEST *HashList
+ );
+
+/**
+ This command indicates that the authorization will be limited to a specific command code.
+
+ @param[in] PolicySession Handle for the policy session being extended.
+ @param[in] Code The allowed commandCode.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2PolicyCommandCode (
+ IN TPMI_SH_POLICY PolicySession,
+ IN TPM_CC Code
+ );
+
+/**
+ This command returns the current policyDigest of the session. This command allows the TPM
+ to be used to perform the actions required to precompute the authPolicy for an object.
+
+ @param[in] PolicySession Handle for the policy session.
+ @param[out] PolicyHash the current value of the policyHash of policySession.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2PolicyGetDigest (
+ IN TPMI_SH_POLICY PolicySession,
+ OUT TPM2B_DIGEST *PolicyHash
+ );
+
+/**
+ This command allows access to the public area of a loaded object.
+
+ @param[in] ObjectHandle TPM handle of an object
+ @param[out] OutPublic Structure containing the public area of an object
+ @param[out] Name Name of the object
+ @param[out] QualifiedName The Qualified Name of the object
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2ReadPublic (
+ IN TPMI_DH_OBJECT ObjectHandle,
+ OUT TPM2B_PUBLIC *OutPublic,
+ OUT TPM2B_NAME *Name,
+ OUT TPM2B_NAME *QualifiedName
+ );
+
+//
+// Help function
+//
+
+/**
+ Copy AuthSessionIn to TPM2 command buffer.
+
+ @param [in] AuthSessionIn Input AuthSession data
+ @param [out] AuthSessionOut Output AuthSession data in TPM2 command buffer
+
+ @return AuthSession size
+**/
+UINT32
+EFIAPI
+CopyAuthSessionCommand (
+ IN TPMS_AUTH_COMMAND *AuthSessionIn, OPTIONAL
+ OUT UINT8 *AuthSessionOut
+ );
+
+/**
+ Copy AuthSessionIn from TPM2 response buffer.
+
+ @param [in] AuthSessionIn Input AuthSession data in TPM2 response buffer
+ @param [out] AuthSessionOut Output AuthSession data
+
+ @return AuthSession size
+**/
+UINT32
+EFIAPI
+CopyAuthSessionResponse (
+ IN UINT8 *AuthSessionIn,
+ OUT TPMS_AUTH_RESPONSE *AuthSessionOut OPTIONAL
+ );
+
+/**
+ Return size of digest.
+
+ @param[in] HashAlgo Hash algorithm
+
+ @return size of digest
+**/
+UINT16
+EFIAPI
+GetHashSizeFromAlgo (
+ IN TPMI_ALG_HASH HashAlgo
+ );
+
+/**
+ Get hash mask from algorithm.
+
+ @param[in] HashAlgo Hash algorithm
+
+ @return Hash mask
+**/
+UINT32
+EFIAPI
+GetHashMaskFromAlgo (
+ IN TPMI_ALG_HASH HashAlgo
+ );
+
+/**
+ Return if hash alg is supported in HashAlgorithmMask.
+
+ @param HashAlg Hash algorithm to be checked.
+ @param HashAlgorithmMask Bitfield of allowed hash algorithms.
+
+ @retval TRUE Hash algorithm is supported.
+ @retval FALSE Hash algorithm is not supported.
+**/
+BOOLEAN
+EFIAPI
+IsHashAlgSupportedInHashAlgorithmMask(
+ IN TPMI_ALG_HASH HashAlg,
+ IN UINT32 HashAlgorithmMask
+ );
+
+/**
+ Copy TPML_DIGEST_VALUES into a buffer
+
+ @param[in,out] Buffer Buffer to hold copied TPML_DIGEST_VALUES compact binary.
+ @param[in] DigestList TPML_DIGEST_VALUES to be copied.
+ @param[in] HashAlgorithmMask HASH bits corresponding to the desired digests to copy.
+
+ @return The end of buffer to hold TPML_DIGEST_VALUES.
+**/
+VOID *
+EFIAPI
+CopyDigestListToBuffer(
+ IN OUT VOID *Buffer,
+ IN TPML_DIGEST_VALUES *DigestList,
+ IN UINT32 HashAlgorithmMask
+ );
+
+/**
+ Get TPML_DIGEST_VALUES data size.
+
+ @param[in] DigestList TPML_DIGEST_VALUES data.
+
+ @return TPML_DIGEST_VALUES data size.
+**/
+UINT32
+EFIAPI
+GetDigestListSize(
+ IN TPML_DIGEST_VALUES *DigestList
+ );
+
+/**
+ This function get digest from digest list.
+
+ @param[in] HashAlg Digest algorithm
+ @param[in] DigestList Digest list
+ @param[out] Digest Digest
+
+ @retval EFI_SUCCESS Digest is found and returned.
+ @retval EFI_NOT_FOUND Digest is not found.
+**/
+EFI_STATUS
+EFIAPI
+GetDigestFromDigestList(
+ IN TPMI_ALG_HASH HashAlg,
+ IN TPML_DIGEST_VALUES *DigestList,
+ OUT VOID *Digest
+ );
+
+#endif
diff --git a/Core/SecurityPkg/Include/Library/Tpm2DeviceLib.h b/Core/SecurityPkg/Include/Library/Tpm2DeviceLib.h
new file mode 100644
index 0000000000..67f158ef03
--- /dev/null
+++ b/Core/SecurityPkg/Include/Library/Tpm2DeviceLib.h
@@ -0,0 +1,109 @@
+/** @file
+ This library abstract how to access TPM2 hardware device.
+
+Copyright (c) 2013, Intel Corporation. All rights reserved. <BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _TPM2_DEVICE_LIB_H_
+#define _TPM2_DEVICE_LIB_H_
+
+#include <Uefi.h>
+
+/**
+ This service enables the sending of commands to the TPM2.
+
+ @param[in] InputParameterBlockSize Size of the TPM2 input parameter block.
+ @param[in] InputParameterBlock Pointer to the TPM2 input parameter block.
+ @param[in,out] OutputParameterBlockSize Size of the TPM2 output parameter block.
+ @param[in] OutputParameterBlock Pointer to the TPM2 output parameter block.
+
+ @retval EFI_SUCCESS The command byte stream was successfully sent to the device and a response was successfully received.
+ @retval EFI_DEVICE_ERROR The command was not successfully sent to the device or a response was not successfully received from the device.
+ @retval EFI_BUFFER_TOO_SMALL The output parameter block is too small.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2SubmitCommand (
+ IN UINT32 InputParameterBlockSize,
+ IN UINT8 *InputParameterBlock,
+ IN OUT UINT32 *OutputParameterBlockSize,
+ IN UINT8 *OutputParameterBlock
+ );
+
+/**
+ This service requests use TPM2.
+
+ @retval EFI_SUCCESS Get the control of TPM2 chip.
+ @retval EFI_NOT_FOUND TPM2 not found.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2RequestUseTpm (
+ VOID
+ );
+
+/**
+ This service enables the sending of commands to the TPM2.
+
+ @param[in] InputParameterBlockSize Size of the TPM2 input parameter block.
+ @param[in] InputParameterBlock Pointer to the TPM2 input parameter block.
+ @param[in,out] OutputParameterBlockSize Size of the TPM2 output parameter block.
+ @param[in] OutputParameterBlock Pointer to the TPM2 output parameter block.
+
+ @retval EFI_SUCCESS The command byte stream was successfully sent to the device and a response was successfully received.
+ @retval EFI_DEVICE_ERROR The command was not successfully sent to the device or a response was not successfully received from the device.
+ @retval EFI_BUFFER_TOO_SMALL The output parameter block is too small.
+**/
+typedef
+EFI_STATUS
+(EFIAPI *TPM2_SUBMIT_COMMAND) (
+ IN UINT32 InputParameterBlockSize,
+ IN UINT8 *InputParameterBlock,
+ IN OUT UINT32 *OutputParameterBlockSize,
+ IN UINT8 *OutputParameterBlock
+ );
+
+/**
+ This service requests use TPM2.
+
+ @retval EFI_SUCCESS Get the control of TPM2 chip.
+ @retval EFI_NOT_FOUND TPM2 not found.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+typedef
+EFI_STATUS
+(EFIAPI *TPM2_REQUEST_USE_TPM) (
+ VOID
+ );
+
+typedef struct {
+ EFI_GUID ProviderGuid;
+ TPM2_SUBMIT_COMMAND Tpm2SubmitCommand;
+ TPM2_REQUEST_USE_TPM Tpm2RequestUseTpm;
+} TPM2_DEVICE_INTERFACE;
+
+/**
+ This service register TPM2 device.
+
+ @param Tpm2Device TPM2 device
+
+ @retval EFI_SUCCESS This TPM2 device is registered successfully.
+ @retval EFI_UNSUPPORTED System does not support register this TPM2 device.
+ @retval EFI_ALREADY_STARTED System already register this TPM2 device.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2RegisterTpm2DeviceLib (
+ IN TPM2_DEVICE_INTERFACE *Tpm2Device
+ );
+
+#endif
diff --git a/Core/SecurityPkg/Include/Library/TpmCommLib.h b/Core/SecurityPkg/Include/Library/TpmCommLib.h
new file mode 100644
index 0000000000..6c97569c67
--- /dev/null
+++ b/Core/SecurityPkg/Include/Library/TpmCommLib.h
@@ -0,0 +1,287 @@
+/** @file
+ This library is only intended to be used by TPM modules.
+ It provides basic TPM Interface Specification (TIS) and Command functions.
+
+Copyright (c) 2005 - 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _TPM_COMM_LIB_H_
+#define _TPM_COMM_LIB_H_
+
+#include <IndustryStandard/Tpm12.h>
+
+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_A 750 * 1000 // 750ms
+#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/Core/SecurityPkg/Include/Library/TrEEPhysicalPresenceLib.h b/Core/SecurityPkg/Include/Library/TrEEPhysicalPresenceLib.h
new file mode 100644
index 0000000000..ba809b9cf9
--- /dev/null
+++ b/Core/SecurityPkg/Include/Library/TrEEPhysicalPresenceLib.h
@@ -0,0 +1,57 @@
+/** @file
+ This library is intended to be used by BDS modules.
+ This library will execute TPM2 request.
+
+Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _TREE_PHYSICAL_PRESENCE_LIB_H_
+#define _TREE_PHYSICAL_PRESENCE_LIB_H_
+
+#include <IndustryStandard/Tpm20.h>
+#include <Protocol/TrEEProtocol.h>
+
+/**
+ Check and execute the pending TPM request.
+
+ The TPM request may come from OS or BIOS. This API will display request information and wait
+ for user confirmation if TPM request exists. The TPM request will be sent to TPM device after
+ the TPM request is confirmed, and one or more reset may be required to make TPM request to
+ take effect.
+
+ This API should be invoked after console in and console out are all ready as they are required
+ to display request information and get user input to confirm the request.
+
+ @param PlatformAuth platform auth value. NULL means no platform auth change.
+**/
+VOID
+EFIAPI
+TrEEPhysicalPresenceLibProcessRequest (
+ IN TPM2B_AUTH *PlatformAuth OPTIONAL
+ );
+
+/**
+ Check if the pending TPM request needs user input to confirm.
+
+ The TPM request may come from OS. This API will check if TPM request exists and need user
+ input to confirmation.
+
+ @retval TRUE TPM needs input to confirm user physical presence.
+ @retval FALSE TPM doesn't need input to confirm user physical presence.
+
+**/
+BOOLEAN
+EFIAPI
+TrEEPhysicalPresenceLibNeedUserConfirm(
+ VOID
+ );
+
+#endif
diff --git a/Core/SecurityPkg/Include/Library/TrEEPpVendorLib.h b/Core/SecurityPkg/Include/Library/TrEEPpVendorLib.h
new file mode 100644
index 0000000000..f0dcfd9967
--- /dev/null
+++ b/Core/SecurityPkg/Include/Library/TrEEPpVendorLib.h
@@ -0,0 +1,164 @@
+/** @file
+ This library is to support Trusted Execution Environment (TrEE) ACPI Profile
+ >= 128 Vendor Specific PPI Operation.
+
+ The Vendor Specific PPI operation may change TPM state, BIOS TPM management
+ flags, and may need additional boot cycle.
+
+ Caution: This function may receive untrusted input.
+
+Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _TREE_PP_VENDOR_LIB_H_
+#define _TREE_PP_VENDOR_LIB_H_
+
+#include <IndustryStandard/Tpm20.h>
+#include <Protocol/TrEEProtocol.h>
+
+//
+// The definition of physical presence operation actions
+//
+#define TREE_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION 128
+
+//
+// The definition bit of the BIOS TPM Management Flags
+//
+// BIT0 is reserved
+#define TREE_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_CLEAR BIT1
+// BIT2 is reserved
+#define TREE_VENDOR_LIB_FLAG_RESET_TRACK BIT3
+
+//
+// The definition for TPM Operation Response to OS Environment
+//
+#define TREE_PP_OPERATION_RESPONSE_SUCCESS 0x0
+#define TREE_PP_OPERATION_RESPONSE_USER_ABORT 0xFFFFFFF0
+#define TREE_PP_OPERATION_RESPONSE_BIOS_FAILURE 0xFFFFFFF1
+
+//
+// The return code for Submit TPM Request to Pre-OS Environment
+// and Submit TPM Request to Pre-OS Environment 2
+//
+#define TREE_PP_SUBMIT_REQUEST_TO_PREOS_SUCCESS 0
+#define TREE_PP_SUBMIT_REQUEST_TO_PREOS_NOT_IMPLEMENTED 1
+#define TREE_PP_SUBMIT_REQUEST_TO_PREOS_GENERAL_FAILURE 2
+#define TREE_PP_SUBMIT_REQUEST_TO_PREOS_BLOCKED_BY_BIOS_SETTINGS 3
+
+//
+// The return code for Get User Confirmation Status for Operation
+//
+#define TREE_PP_GET_USER_CONFIRMATION_NOT_IMPLEMENTED 0
+#define TREE_PP_GET_USER_CONFIRMATION_BIOS_ONLY 1
+#define TREE_PP_GET_USER_CONFIRMATION_BLOCKED_BY_BIOS_CONFIGURATION 2
+#define TREE_PP_GET_USER_CONFIRMATION_ALLOWED_AND_PPUSER_REQUIRED 3
+#define TREE_PP_GET_USER_CONFIRMATION_ALLOWED_AND_PPUSER_NOT_REQUIRED 4
+
+/**
+ Check and execute the requested physical presence command.
+
+ This API should be invoked in BIOS boot phase to process pending request.
+
+ Caution: This function may receive untrusted input.
+
+ If OperationRequest < 128, then ASSERT().
+
+ @param[in] PlatformAuth platform auth value. NULL means no platform auth change.
+ @param[in] OperationRequest TPM physical presence operation request.
+ @param[in, out] ManagementFlags BIOS TPM Management Flags.
+ @param[out] ResetRequired If reset is required to vendor settings in effect.
+ True, it indicates the reset is required.
+ False, it indicates the reset is not required.
+
+ @return TPM Operation Response to OS Environment.
+**/
+UINT32
+EFIAPI
+TrEEPpVendorLibExecutePendingRequest (
+ IN TPM2B_AUTH *PlatformAuth, OPTIONAL
+ IN UINT32 OperationRequest,
+ IN OUT UINT32 *ManagementFlags,
+ OUT BOOLEAN *ResetRequired
+ );
+
+/**
+ Check if there is a valid physical presence command request.
+
+ This API should be invoked in BIOS boot phase to process pending request.
+
+ Caution: This function may receive untrusted input.
+
+ If OperationRequest < 128, then ASSERT().
+
+ @param[in] OperationRequest TPM physical presence operation request.
+ @param[in] ManagementFlags BIOS TPM Management Flags.
+ @param[out] RequestConfirmed If the physical presence operation command required user confirm from UI.
+ True, it indicates the command doesn't require user confirm.
+ False, it indicates the command need user confirm from UI.
+
+ @retval TRUE Physical Presence operation command is valid.
+ @retval FALSE Physical Presence operation command is invalid.
+**/
+BOOLEAN
+EFIAPI
+TrEEPpVendorLibHasValidRequest (
+ IN UINT32 OperationRequest,
+ IN UINT32 ManagementFlags,
+ OUT BOOLEAN *RequestConfirmed
+ );
+
+/**
+ The callback for TPM vendor specific physical presence which is called for
+ Submit TPM Operation Request to Pre-OS Environment and
+ Submit TPM Operation Request to Pre-OS Environment 2.
+
+ This API should be invoked in OS runtime phase to interface with ACPI method.
+
+ Caution: This function may receive untrusted input.
+
+ If OperationRequest < 128, then ASSERT().
+
+ @param[in] OperationRequest TPM physical presence operation request.
+ @param[in] ManagementFlags BIOS TPM Management Flags.
+
+ @return Return Code for Submit TPM Operation Request to Pre-OS Environment and
+ Submit TPM Operation Request to Pre-OS Environment 2.
+**/
+UINT32
+EFIAPI
+TrEEPpVendorLibSubmitRequestToPreOSFunction (
+ IN UINT32 OperationRequest,
+ IN UINT32 ManagementFlags
+ );
+
+/**
+ The callback for TPM vendor specific physical presence which is called for
+ Get User Confirmation Status for Operation.
+
+ This API should be invoked in OS runtime phase to interface with ACPI method.
+
+ Caution: This function may receive untrusted input.
+
+ If OperationRequest < 128, then ASSERT().
+
+ @param[in] OperationRequest TPM physical presence operation request.
+ @param[in] ManagementFlags BIOS TPM Management Flags.
+
+ @return Return Code for Get User Confirmation Status for Operation.
+**/
+UINT32
+EFIAPI
+TrEEPpVendorLibGetUserConfirmationStatusFunction (
+ IN UINT32 OperationRequest,
+ IN UINT32 ManagementFlags
+ );
+
+#endif
diff --git a/Core/SecurityPkg/Include/Ppi/FirmwareVolumeInfoMeasurementExcluded.h b/Core/SecurityPkg/Include/Ppi/FirmwareVolumeInfoMeasurementExcluded.h
new file mode 100644
index 0000000000..d99fc1db38
--- /dev/null
+++ b/Core/SecurityPkg/Include/Ppi/FirmwareVolumeInfoMeasurementExcluded.h
@@ -0,0 +1,37 @@
+/** @file
+ This PPI means a FV does not need to be extended to PCR by TCG modules.
+
+Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __EFI_PEI_FIRMWARE_VOLUME_INFO_MEASUREMENT_EXCLUDED_H__
+#define __EFI_PEI_FIRMWARE_VOLUME_INFO_MEASUREMENT_EXCLUDED_H__
+
+#define EFI_PEI_FIRMWARE_VOLUME_INFO_MEASUREMENT_EXCLUDED_PPI_GUID \
+ { 0x6e056ff9, 0xc695, 0x4364, { 0x9e, 0x2c, 0x61, 0x26, 0xf5, 0xce, 0xea, 0xae } }
+
+typedef struct {
+ EFI_PHYSICAL_ADDRESS FvBase;
+ UINT64 FvLength;
+} EFI_PEI_FIRMWARE_VOLUME_INFO_MEASUREMENT_EXCLUDED_FV;
+
+//
+// This PPI means a FV does not need to be extended to PCR by TCG modules.
+//
+typedef struct {
+ UINT32 Count;
+ EFI_PEI_FIRMWARE_VOLUME_INFO_MEASUREMENT_EXCLUDED_FV Fv[1];
+} EFI_PEI_FIRMWARE_VOLUME_INFO_MEASUREMENT_EXCLUDED_PPI;
+
+extern EFI_GUID gEfiPeiFirmwareVolumeInfoMeasurementExcludedPpiGuid;
+
+#endif
+
diff --git a/Core/SecurityPkg/Include/Ppi/LockPhysicalPresence.h b/Core/SecurityPkg/Include/Ppi/LockPhysicalPresence.h
new file mode 100644
index 0000000000..0ae3b7b0ab
--- /dev/null
+++ b/Core/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.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __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/Core/SecurityPkg/Include/Ppi/TpmInitialized.h b/Core/SecurityPkg/Include/Ppi/TpmInitialized.h
new file mode 100644
index 0000000000..7d458f5e12
--- /dev/null
+++ b/Core/SecurityPkg/Include/Ppi/TpmInitialized.h
@@ -0,0 +1,40 @@
+/** @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 - 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _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;
+
+///
+/// Global ID for the PEI_TPM_INITIALIZATION_DONE_PPI which always uses a NULL interface.
+///
+#define PEI_TPM_INITIALIZATION_DONE_PPI_GUID \
+ { \
+ 0xa030d115, 0x54dd, 0x447b, { 0x90, 0x64, 0xf2, 0x6, 0x88, 0x3d, 0x7c, 0xcc \
+ }
+
+extern EFI_GUID gPeiTpmInitializationDonePpiGuid;
+
+#endif
diff --git a/Core/SecurityPkg/Library/AuthVariableLib/AuthService.c b/Core/SecurityPkg/Library/AuthVariableLib/AuthService.c
new file mode 100644
index 0000000000..a37ec0bd0f
--- /dev/null
+++ b/Core/SecurityPkg/Library/AuthVariableLib/AuthService.c
@@ -0,0 +1,2626 @@
+/** @file
+ Implement authentication services for the authenticated variables.
+
+ Caution: This module requires additional review when modified.
+ This driver will have external input - variable data. It may be input in SMM mode.
+ This external input must be validated carefully to avoid security issue like
+ buffer overflow, integer overflow.
+ Variable attribute should also be checked to avoid authentication bypass.
+ The whole SMM authentication variable design relies on the integrity of flash part and SMM.
+ which is assumed to be protected by platform. All variable code and metadata in flash/SMM Memory
+ may not be modified without authorization. If platform fails to protect these resources,
+ the authentication service provided in this driver will be broken, and the behavior is undefined.
+
+ ProcessVarWithPk(), ProcessVarWithKek() and ProcessVariable() are the function to do
+ variable authentication.
+
+ VerifyTimeBasedPayloadAndUpdate() and VerifyCounterBasedPayload() are sub function to do verification.
+ They will do basic validation for authentication data structure, then call crypto library
+ to verify the signature.
+
+Copyright (c) 2009 - 2017, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "AuthServiceInternal.h"
+
+//
+// Public Exponent of RSA Key.
+//
+CONST UINT8 mRsaE[] = { 0x01, 0x00, 0x01 };
+
+CONST UINT8 mSha256OidValue[] = { 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01 };
+
+//
+// Requirement for different signature type which have been defined in UEFI spec.
+// These data are used to perform SignatureList format check while setting PK/KEK variable.
+//
+EFI_SIGNATURE_ITEM mSupportSigItem[] = {
+//{SigType, SigHeaderSize, SigDataSize }
+ {EFI_CERT_SHA256_GUID, 0, 32 },
+ {EFI_CERT_RSA2048_GUID, 0, 256 },
+ {EFI_CERT_RSA2048_SHA256_GUID, 0, 256 },
+ {EFI_CERT_SHA1_GUID, 0, 20 },
+ {EFI_CERT_RSA2048_SHA1_GUID, 0, 256 },
+ {EFI_CERT_X509_GUID, 0, ((UINT32) ~0)},
+ {EFI_CERT_SHA224_GUID, 0, 28 },
+ {EFI_CERT_SHA384_GUID, 0, 48 },
+ {EFI_CERT_SHA512_GUID, 0, 64 },
+ {EFI_CERT_X509_SHA256_GUID, 0, 48 },
+ {EFI_CERT_X509_SHA384_GUID, 0, 64 },
+ {EFI_CERT_X509_SHA512_GUID, 0, 80 }
+};
+
+/**
+ Finds variable in storage blocks of volatile and non-volatile storage areas.
+
+ This code finds variable in storage blocks of volatile and non-volatile storage areas.
+ If VariableName is an empty string, then we just return the first
+ qualified variable without comparing VariableName and VendorGuid.
+
+ @param[in] VariableName Name of the variable to be found.
+ @param[in] VendorGuid Variable vendor GUID to be found.
+ @param[out] Data Pointer to data address.
+ @param[out] DataSize Pointer to data size.
+
+ @retval EFI_INVALID_PARAMETER If VariableName is not an empty string,
+ while VendorGuid is NULL.
+ @retval EFI_SUCCESS Variable successfully found.
+ @retval EFI_NOT_FOUND Variable not found
+
+**/
+EFI_STATUS
+AuthServiceInternalFindVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ OUT VOID **Data,
+ OUT UINTN *DataSize
+ )
+{
+ EFI_STATUS Status;
+ AUTH_VARIABLE_INFO AuthVariableInfo;
+
+ ZeroMem (&AuthVariableInfo, sizeof (AuthVariableInfo));
+ Status = mAuthVarLibContextIn->FindVariable (
+ VariableName,
+ VendorGuid,
+ &AuthVariableInfo
+ );
+ *Data = AuthVariableInfo.Data;
+ *DataSize = AuthVariableInfo.DataSize;
+ return Status;
+}
+
+/**
+ Update the variable region with Variable information.
+
+ @param[in] VariableName Name of variable.
+ @param[in] VendorGuid Guid of variable.
+ @param[in] Data Data pointer.
+ @param[in] DataSize Size of Data.
+ @param[in] Attributes Attribute value of the variable.
+
+ @retval EFI_SUCCESS The update operation is success.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_WRITE_PROTECTED Variable is write-protected.
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource.
+
+**/
+EFI_STATUS
+AuthServiceInternalUpdateVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN VOID *Data,
+ IN UINTN DataSize,
+ IN UINT32 Attributes
+ )
+{
+ AUTH_VARIABLE_INFO AuthVariableInfo;
+
+ ZeroMem (&AuthVariableInfo, sizeof (AuthVariableInfo));
+ AuthVariableInfo.VariableName = VariableName;
+ AuthVariableInfo.VendorGuid = VendorGuid;
+ AuthVariableInfo.Data = Data;
+ AuthVariableInfo.DataSize = DataSize;
+ AuthVariableInfo.Attributes = Attributes;
+
+ return mAuthVarLibContextIn->UpdateVariable (
+ &AuthVariableInfo
+ );
+}
+
+/**
+ Update the variable region with Variable information.
+
+ @param[in] VariableName Name of variable.
+ @param[in] VendorGuid Guid of variable.
+ @param[in] Data Data pointer.
+ @param[in] DataSize Size of Data.
+ @param[in] Attributes Attribute value of the variable.
+ @param[in] KeyIndex Index of associated public key.
+ @param[in] MonotonicCount Value of associated monotonic count.
+
+ @retval EFI_SUCCESS The update operation is success.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_WRITE_PROTECTED Variable is write-protected.
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource.
+
+**/
+EFI_STATUS
+AuthServiceInternalUpdateVariableWithMonotonicCount (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN VOID *Data,
+ IN UINTN DataSize,
+ IN UINT32 Attributes,
+ IN UINT32 KeyIndex,
+ IN UINT64 MonotonicCount
+ )
+{
+ AUTH_VARIABLE_INFO AuthVariableInfo;
+
+ ZeroMem (&AuthVariableInfo, sizeof (AuthVariableInfo));
+ AuthVariableInfo.VariableName = VariableName;
+ AuthVariableInfo.VendorGuid = VendorGuid;
+ AuthVariableInfo.Data = Data;
+ AuthVariableInfo.DataSize = DataSize;
+ AuthVariableInfo.Attributes = Attributes;
+ AuthVariableInfo.PubKeyIndex = KeyIndex;
+ AuthVariableInfo.MonotonicCount = MonotonicCount;
+
+ return mAuthVarLibContextIn->UpdateVariable (
+ &AuthVariableInfo
+ );
+}
+
+/**
+ Update the variable region with Variable information.
+
+ @param[in] VariableName Name of variable.
+ @param[in] VendorGuid Guid of variable.
+ @param[in] Data Data pointer.
+ @param[in] DataSize Size of Data.
+ @param[in] Attributes Attribute value of the variable.
+ @param[in] TimeStamp Value of associated TimeStamp.
+
+ @retval EFI_SUCCESS The update operation is success.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_WRITE_PROTECTED Variable is write-protected.
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource.
+
+**/
+EFI_STATUS
+AuthServiceInternalUpdateVariableWithTimeStamp (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN VOID *Data,
+ IN UINTN DataSize,
+ IN UINT32 Attributes,
+ IN EFI_TIME *TimeStamp
+ )
+{
+ EFI_STATUS FindStatus;
+ VOID *OrgData;
+ UINTN OrgDataSize;
+ AUTH_VARIABLE_INFO AuthVariableInfo;
+
+ FindStatus = AuthServiceInternalFindVariable (
+ VariableName,
+ VendorGuid,
+ &OrgData,
+ &OrgDataSize
+ );
+
+ //
+ // EFI_VARIABLE_APPEND_WRITE attribute only effects for existing variable
+ //
+ if (!EFI_ERROR (FindStatus) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) != 0)) {
+ if ((CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid) &&
+ ((StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE) == 0) || (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE1) == 0) ||
+ (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE2) == 0))) ||
+ (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_KEY_EXCHANGE_KEY_NAME) == 0))) {
+ //
+ // For variables with formatted as EFI_SIGNATURE_LIST, the driver shall not perform an append of
+ // EFI_SIGNATURE_DATA values that are already part of the existing variable value.
+ //
+ FilterSignatureList (
+ OrgData,
+ OrgDataSize,
+ Data,
+ &DataSize
+ );
+ }
+ }
+
+ ZeroMem (&AuthVariableInfo, sizeof (AuthVariableInfo));
+ AuthVariableInfo.VariableName = VariableName;
+ AuthVariableInfo.VendorGuid = VendorGuid;
+ AuthVariableInfo.Data = Data;
+ AuthVariableInfo.DataSize = DataSize;
+ AuthVariableInfo.Attributes = Attributes;
+ AuthVariableInfo.TimeStamp = TimeStamp;
+ return mAuthVarLibContextIn->UpdateVariable (
+ &AuthVariableInfo
+ );
+}
+
+/**
+ Determine whether this operation needs a physical present user.
+
+ @param[in] VariableName Name of the Variable.
+ @param[in] VendorGuid GUID of the Variable.
+
+ @retval TRUE This variable is protected, only a physical present user could set this variable.
+ @retval FALSE This variable is not protected.
+
+**/
+BOOLEAN
+NeedPhysicallyPresent(
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid
+ )
+{
+ if ((CompareGuid (VendorGuid, &gEfiSecureBootEnableDisableGuid) && (StrCmp (VariableName, EFI_SECURE_BOOT_ENABLE_NAME) == 0))
+ || (CompareGuid (VendorGuid, &gEfiCustomModeEnableGuid) && (StrCmp (VariableName, EFI_CUSTOM_MODE_NAME) == 0))) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Determine whether the platform is operating in Custom Secure Boot mode.
+
+ @retval TRUE The platform is operating in Custom mode.
+ @retval FALSE The platform is operating in Standard mode.
+
+**/
+BOOLEAN
+InCustomMode (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ VOID *Data;
+ UINTN DataSize;
+
+ Status = AuthServiceInternalFindVariable (EFI_CUSTOM_MODE_NAME, &gEfiCustomModeEnableGuid, &Data, &DataSize);
+ if (!EFI_ERROR (Status) && (*(UINT8 *) Data == CUSTOM_SECURE_BOOT_MODE)) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Get available public key index.
+
+ @param[in] PubKey Pointer to Public Key data.
+
+ @return Public key index, 0 if no any public key index available.
+
+**/
+UINT32
+GetAvailableKeyIndex (
+ IN UINT8 *PubKey
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *Data;
+ UINTN DataSize;
+ UINT8 *Ptr;
+ UINT32 Index;
+ BOOLEAN IsFound;
+ EFI_GUID VendorGuid;
+ CHAR16 Name[1];
+ AUTH_VARIABLE_INFO AuthVariableInfo;
+ UINT32 KeyIndex;
+
+ Status = AuthServiceInternalFindVariable (
+ AUTHVAR_KEYDB_NAME,
+ &gEfiAuthenticatedVariableGuid,
+ (VOID **) &Data,
+ &DataSize
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Get public key database variable failure, Status = %r\n", Status));
+ return 0;
+ }
+
+ if (mPubKeyNumber == mMaxKeyNumber) {
+ Name[0] = 0;
+ AuthVariableInfo.VariableName = Name;
+ ZeroMem (&VendorGuid, sizeof (VendorGuid));
+ AuthVariableInfo.VendorGuid = &VendorGuid;
+ mPubKeyNumber = 0;
+ //
+ // Collect valid key data.
+ //
+ do {
+ Status = mAuthVarLibContextIn->FindNextVariable (AuthVariableInfo.VariableName, AuthVariableInfo.VendorGuid, &AuthVariableInfo);
+ if (!EFI_ERROR (Status)) {
+ if (AuthVariableInfo.PubKeyIndex != 0) {
+ for (Ptr = Data; Ptr < (Data + DataSize); Ptr += sizeof (AUTHVAR_KEY_DB_DATA)) {
+ if (ReadUnaligned32 (&(((AUTHVAR_KEY_DB_DATA *) Ptr)->KeyIndex)) == AuthVariableInfo.PubKeyIndex) {
+ //
+ // Check if the key data has been collected.
+ //
+ for (Index = 0; Index < mPubKeyNumber; Index++) {
+ if (ReadUnaligned32 (&(((AUTHVAR_KEY_DB_DATA *) mPubKeyStore + Index)->KeyIndex)) == AuthVariableInfo.PubKeyIndex) {
+ break;
+ }
+ }
+ if (Index == mPubKeyNumber) {
+ //
+ // New key data.
+ //
+ CopyMem ((AUTHVAR_KEY_DB_DATA *) mPubKeyStore + mPubKeyNumber, Ptr, sizeof (AUTHVAR_KEY_DB_DATA));
+ mPubKeyNumber++;
+ }
+ break;
+ }
+ }
+ }
+ }
+ } while (Status != EFI_NOT_FOUND);
+
+ //
+ // No available space to add new public key.
+ //
+ if (mPubKeyNumber == mMaxKeyNumber) {
+ return 0;
+ }
+ }
+
+ //
+ // Find available public key index.
+ //
+ for (KeyIndex = 1; KeyIndex <= mMaxKeyNumber; KeyIndex++) {
+ IsFound = FALSE;
+ for (Ptr = mPubKeyStore; Ptr < (mPubKeyStore + mPubKeyNumber * sizeof (AUTHVAR_KEY_DB_DATA)); Ptr += sizeof (AUTHVAR_KEY_DB_DATA)) {
+ if (ReadUnaligned32 (&(((AUTHVAR_KEY_DB_DATA *) Ptr)->KeyIndex)) == KeyIndex) {
+ IsFound = TRUE;
+ break;
+ }
+ }
+ if (!IsFound) {
+ break;
+ }
+ }
+
+ return KeyIndex;
+}
+
+/**
+ Add public key in store and return its index.
+
+ @param[in] PubKey Input pointer to Public Key data.
+ @param[in] VariableDataEntry The variable data entry.
+
+ @return Index of new added public key.
+
+**/
+UINT32
+AddPubKeyInStore (
+ IN UINT8 *PubKey,
+ IN VARIABLE_ENTRY_CONSISTENCY *VariableDataEntry
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Index;
+ VARIABLE_ENTRY_CONSISTENCY PublicKeyEntry;
+ UINT32 Attributes;
+ UINT32 KeyIndex;
+
+ if (PubKey == NULL) {
+ return 0;
+ }
+
+ //
+ // Check whether the public key entry does exist.
+ //
+ for (Index = 0; Index < mPubKeyNumber; Index++) {
+ if (CompareMem (((AUTHVAR_KEY_DB_DATA *) mPubKeyStore + Index)->KeyData, PubKey, EFI_CERT_TYPE_RSA2048_SIZE) == 0) {
+ return ReadUnaligned32 (&(((AUTHVAR_KEY_DB_DATA *) mPubKeyStore + Index)->KeyIndex));
+ }
+ }
+
+ KeyIndex = GetAvailableKeyIndex (PubKey);
+ if (KeyIndex == 0) {
+ return 0;
+ }
+
+ //
+ // Check the variable space for both public key and variable data.
+ //
+ PublicKeyEntry.VariableSize = (mPubKeyNumber + 1) * sizeof (AUTHVAR_KEY_DB_DATA);
+ PublicKeyEntry.Guid = &gEfiAuthenticatedVariableGuid;
+ PublicKeyEntry.Name = AUTHVAR_KEYDB_NAME;
+ Attributes = VARIABLE_ATTRIBUTE_NV_BS_RT | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;
+
+ if (!mAuthVarLibContextIn->CheckRemainingSpaceForConsistency (Attributes, &PublicKeyEntry, VariableDataEntry, NULL)) {
+ //
+ // No enough variable space.
+ //
+ return 0;
+ }
+
+ WriteUnaligned32 (&(((AUTHVAR_KEY_DB_DATA *) mPubKeyStore + mPubKeyNumber)->KeyIndex), KeyIndex);
+ CopyMem (((AUTHVAR_KEY_DB_DATA *) mPubKeyStore + mPubKeyNumber)->KeyData, PubKey, EFI_CERT_TYPE_RSA2048_SIZE);
+ mPubKeyNumber++;
+
+ //
+ // Update public key database variable.
+ //
+ Status = AuthServiceInternalUpdateVariable (
+ AUTHVAR_KEYDB_NAME,
+ &gEfiAuthenticatedVariableGuid,
+ mPubKeyStore,
+ mPubKeyNumber * sizeof (AUTHVAR_KEY_DB_DATA),
+ Attributes
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Update public key database variable failure, Status = %r\n", Status));
+ return 0;
+ }
+
+ return KeyIndex;
+}
+
+/**
+ Verify data payload with AuthInfo in EFI_CERT_TYPE_RSA2048_SHA256_GUID type.
+ Follow the steps in UEFI2.2.
+
+ Caution: This function may receive untrusted input.
+ This function may be invoked in SMM mode, and datasize and data are external input.
+ This function will do basic validation, before parse the data.
+ This function will parse the authentication carefully to avoid security issues, like
+ buffer overflow, integer overflow.
+
+ @param[in] Data Pointer to data with AuthInfo.
+ @param[in] DataSize Size of Data.
+ @param[in] PubKey Public key used for verification.
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_SECURITY_VIOLATION If authentication failed.
+ @retval EFI_SUCCESS Authentication successful.
+
+**/
+EFI_STATUS
+VerifyCounterBasedPayload (
+ IN UINT8 *Data,
+ IN UINTN DataSize,
+ IN UINT8 *PubKey
+ )
+{
+ BOOLEAN Status;
+ EFI_VARIABLE_AUTHENTICATION *CertData;
+ EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlock;
+ UINT8 Digest[SHA256_DIGEST_SIZE];
+ VOID *Rsa;
+ UINTN PayloadSize;
+
+ PayloadSize = DataSize - AUTHINFO_SIZE;
+ Rsa = NULL;
+ CertData = NULL;
+ CertBlock = NULL;
+
+ if (Data == NULL || PubKey == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CertData = (EFI_VARIABLE_AUTHENTICATION *) Data;
+ CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);
+
+ //
+ // wCertificateType should be WIN_CERT_TYPE_EFI_GUID.
+ // Cert type should be EFI_CERT_TYPE_RSA2048_SHA256_GUID.
+ //
+ if ((CertData->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) ||
+ !CompareGuid (&CertData->AuthInfo.CertType, &gEfiCertTypeRsa2048Sha256Guid)) {
+ //
+ // Invalid AuthInfo type, return EFI_SECURITY_VIOLATION.
+ //
+ return EFI_SECURITY_VIOLATION;
+ }
+ //
+ // Hash data payload with SHA256.
+ //
+ ZeroMem (Digest, SHA256_DIGEST_SIZE);
+ Status = Sha256Init (mHashCtx);
+ if (!Status) {
+ goto Done;
+ }
+ Status = Sha256Update (mHashCtx, Data + AUTHINFO_SIZE, PayloadSize);
+ if (!Status) {
+ goto Done;
+ }
+ //
+ // Hash Size.
+ //
+ Status = Sha256Update (mHashCtx, &PayloadSize, sizeof (UINTN));
+ if (!Status) {
+ goto Done;
+ }
+ //
+ // Hash Monotonic Count.
+ //
+ Status = Sha256Update (mHashCtx, &CertData->MonotonicCount, sizeof (UINT64));
+ if (!Status) {
+ goto Done;
+ }
+ Status = Sha256Final (mHashCtx, Digest);
+ if (!Status) {
+ goto Done;
+ }
+ //
+ // Generate & Initialize RSA Context.
+ //
+ 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, PubKey, 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,
+ Digest,
+ SHA256_DIGEST_SIZE,
+ CertBlock->Signature,
+ EFI_CERT_TYPE_RSA2048_SHA256_SIZE
+ );
+
+Done:
+ if (Rsa != NULL) {
+ RsaFree (Rsa);
+ }
+ if (Status) {
+ return EFI_SUCCESS;
+ } else {
+ return EFI_SECURITY_VIOLATION;
+ }
+}
+
+/**
+ Update platform mode.
+
+ @param[in] Mode SETUP_MODE or USER_MODE.
+
+ @return EFI_INVALID_PARAMETER Invalid parameter.
+ @return EFI_SUCCESS Update platform mode successfully.
+
+**/
+EFI_STATUS
+UpdatePlatformMode (
+ IN UINT32 Mode
+ )
+{
+ EFI_STATUS Status;
+ VOID *Data;
+ UINTN DataSize;
+ UINT8 SecureBootMode;
+ UINT8 SecureBootEnable;
+ UINTN VariableDataSize;
+
+ Status = AuthServiceInternalFindVariable (
+ EFI_SETUP_MODE_NAME,
+ &gEfiGlobalVariableGuid,
+ &Data,
+ &DataSize
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Update the value of SetupMode variable by a simple mem copy, this could avoid possible
+ // variable storage reclaim at runtime.
+ //
+ mPlatformMode = (UINT8) Mode;
+ CopyMem (Data, &mPlatformMode, sizeof(UINT8));
+
+ if (mAuthVarLibContextIn->AtRuntime ()) {
+ //
+ // SecureBoot Variable indicates whether the platform firmware is operating
+ // in Secure boot mode (1) or not (0), so we should not change SecureBoot
+ // Variable in runtime.
+ //
+ return Status;
+ }
+
+ //
+ // Check "SecureBoot" variable's existence.
+ // If it doesn't exist, firmware has no capability to perform driver signing verification,
+ // then set "SecureBoot" to 0.
+ //
+ Status = AuthServiceInternalFindVariable (
+ EFI_SECURE_BOOT_MODE_NAME,
+ &gEfiGlobalVariableGuid,
+ &Data,
+ &DataSize
+ );
+ //
+ // If "SecureBoot" variable exists, then check "SetupMode" variable update.
+ // If "SetupMode" variable is USER_MODE, "SecureBoot" variable is set to 1.
+ // If "SetupMode" variable is SETUP_MODE, "SecureBoot" variable is set to 0.
+ //
+ if (EFI_ERROR (Status)) {
+ SecureBootMode = SECURE_BOOT_MODE_DISABLE;
+ } else {
+ if (mPlatformMode == USER_MODE) {
+ SecureBootMode = SECURE_BOOT_MODE_ENABLE;
+ } else if (mPlatformMode == SETUP_MODE) {
+ SecureBootMode = SECURE_BOOT_MODE_DISABLE;
+ } else {
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ Status = AuthServiceInternalUpdateVariable (
+ EFI_SECURE_BOOT_MODE_NAME,
+ &gEfiGlobalVariableGuid,
+ &SecureBootMode,
+ sizeof(UINT8),
+ EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Check "SecureBootEnable" variable's existence. It can enable/disable secure boot feature.
+ //
+ Status = AuthServiceInternalFindVariable (
+ EFI_SECURE_BOOT_ENABLE_NAME,
+ &gEfiSecureBootEnableDisableGuid,
+ &Data,
+ &DataSize
+ );
+
+ if (SecureBootMode == SECURE_BOOT_MODE_ENABLE) {
+ //
+ // Create the "SecureBootEnable" variable as secure boot is enabled.
+ //
+ SecureBootEnable = SECURE_BOOT_ENABLE;
+ VariableDataSize = sizeof (SecureBootEnable);
+ } else {
+ //
+ // Delete the "SecureBootEnable" variable if this variable exist as "SecureBoot"
+ // variable is not in secure boot state.
+ //
+ if (EFI_ERROR (Status)) {
+ return EFI_SUCCESS;
+ }
+ SecureBootEnable = SECURE_BOOT_DISABLE;
+ VariableDataSize = 0;
+ }
+
+ Status = AuthServiceInternalUpdateVariable (
+ EFI_SECURE_BOOT_ENABLE_NAME,
+ &gEfiSecureBootEnableDisableGuid,
+ &SecureBootEnable,
+ VariableDataSize,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS
+ );
+ return Status;
+}
+
+/**
+ Check input data form to make sure it is a valid EFI_SIGNATURE_LIST for PK/KEK/db/dbx/dbt variable.
+
+ @param[in] VariableName Name of Variable to be check.
+ @param[in] VendorGuid Variable vendor GUID.
+ @param[in] Data Point to the variable data to be checked.
+ @param[in] DataSize Size of Data.
+
+ @return EFI_INVALID_PARAMETER Invalid signature list format.
+ @return EFI_SUCCESS Passed signature list format check successfully.
+
+**/
+EFI_STATUS
+CheckSignatureListFormat(
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN VOID *Data,
+ IN UINTN DataSize
+ )
+{
+ EFI_SIGNATURE_LIST *SigList;
+ UINTN SigDataSize;
+ UINT32 Index;
+ UINT32 SigCount;
+ BOOLEAN IsPk;
+ VOID *RsaContext;
+ EFI_SIGNATURE_DATA *CertData;
+ UINTN CertLen;
+
+ if (DataSize == 0) {
+ return EFI_SUCCESS;
+ }
+
+ ASSERT (VariableName != NULL && VendorGuid != NULL && Data != NULL);
+
+ if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_PLATFORM_KEY_NAME) == 0)){
+ IsPk = TRUE;
+ } else if ((CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_KEY_EXCHANGE_KEY_NAME) == 0)) ||
+ (CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid) &&
+ ((StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE) == 0) || (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE1) == 0) ||
+ (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE2) == 0)))) {
+ IsPk = FALSE;
+ } else {
+ return EFI_SUCCESS;
+ }
+
+ SigCount = 0;
+ SigList = (EFI_SIGNATURE_LIST *) Data;
+ SigDataSize = DataSize;
+ RsaContext = NULL;
+
+ //
+ // Walk throuth the input signature list and check the data format.
+ // If any signature is incorrectly formed, the whole check will fail.
+ //
+ while ((SigDataSize > 0) && (SigDataSize >= SigList->SignatureListSize)) {
+ for (Index = 0; Index < (sizeof (mSupportSigItem) / sizeof (EFI_SIGNATURE_ITEM)); Index++ ) {
+ if (CompareGuid (&SigList->SignatureType, &mSupportSigItem[Index].SigType)) {
+ //
+ // The value of SignatureSize should always be 16 (size of SignatureOwner
+ // component) add the data length according to signature type.
+ //
+ if (mSupportSigItem[Index].SigDataSize != ((UINT32) ~0) &&
+ (SigList->SignatureSize - sizeof (EFI_GUID)) != mSupportSigItem[Index].SigDataSize) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (mSupportSigItem[Index].SigHeaderSize != ((UINT32) ~0) &&
+ SigList->SignatureHeaderSize != mSupportSigItem[Index].SigHeaderSize) {
+ return EFI_INVALID_PARAMETER;
+ }
+ break;
+ }
+ }
+
+ if (Index == (sizeof (mSupportSigItem) / sizeof (EFI_SIGNATURE_ITEM))) {
+ //
+ // Undefined signature type.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (CompareGuid (&SigList->SignatureType, &gEfiCertX509Guid)) {
+ //
+ // Try to retrieve the RSA public key from the X.509 certificate.
+ // If this operation fails, it's not a valid certificate.
+ //
+ RsaContext = RsaNew ();
+ if (RsaContext == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ CertData = (EFI_SIGNATURE_DATA *) ((UINT8 *) SigList + sizeof (EFI_SIGNATURE_LIST) + SigList->SignatureHeaderSize);
+ CertLen = SigList->SignatureSize - sizeof (EFI_GUID);
+ if (!RsaGetPublicKeyFromX509 (CertData->SignatureData, CertLen, &RsaContext)) {
+ RsaFree (RsaContext);
+ return EFI_INVALID_PARAMETER;
+ }
+ RsaFree (RsaContext);
+ }
+
+ if ((SigList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - SigList->SignatureHeaderSize) % SigList->SignatureSize != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+ SigCount += (SigList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - SigList->SignatureHeaderSize) / SigList->SignatureSize;
+
+ SigDataSize -= SigList->SignatureListSize;
+ SigList = (EFI_SIGNATURE_LIST *) ((UINT8 *) SigList + SigList->SignatureListSize);
+ }
+
+ if (((UINTN) SigList - (UINTN) Data) != DataSize) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (IsPk && SigCount > 1) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Update "VendorKeys" variable to record the out of band secure boot key modification.
+
+ @return EFI_SUCCESS Variable is updated successfully.
+ @return Others Failed to update variable.
+
+**/
+EFI_STATUS
+VendorKeyIsModified (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+
+ if (mVendorKeyState == VENDOR_KEYS_MODIFIED) {
+ return EFI_SUCCESS;
+ }
+ mVendorKeyState = VENDOR_KEYS_MODIFIED;
+
+ Status = AuthServiceInternalUpdateVariable (
+ EFI_VENDOR_KEYS_NV_VARIABLE_NAME,
+ &gEfiVendorKeysNvGuid,
+ &mVendorKeyState,
+ sizeof (UINT8),
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return AuthServiceInternalUpdateVariable (
+ EFI_VENDOR_KEYS_VARIABLE_NAME,
+ &gEfiGlobalVariableGuid,
+ &mVendorKeyState,
+ sizeof (UINT8),
+ EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS
+ );
+}
+
+/**
+ Process variable with platform key for verification.
+
+ Caution: This function may receive untrusted input.
+ This function may be invoked in SMM mode, and datasize and data are external input.
+ This function will do basic validation, before parse the data.
+ This function will parse the authentication carefully to avoid security issues, like
+ buffer overflow, integer overflow.
+ This function will check attribute carefully to avoid authentication bypass.
+
+ @param[in] VariableName Name of Variable to be found.
+ @param[in] VendorGuid Variable vendor GUID.
+ @param[in] Data Data pointer.
+ @param[in] DataSize Size of Data found. If size is less than the
+ data, this value contains the required size.
+ @param[in] Attributes Attribute value of the variable
+ @param[in] IsPk Indicate whether it is to process pk.
+
+ @return EFI_INVALID_PARAMETER Invalid parameter.
+ @return EFI_SECURITY_VIOLATION The variable does NOT pass the validation.
+ check carried out by the firmware.
+ @return EFI_SUCCESS Variable passed validation successfully.
+
+**/
+EFI_STATUS
+ProcessVarWithPk (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN VOID *Data,
+ IN UINTN DataSize,
+ IN UINT32 Attributes OPTIONAL,
+ IN BOOLEAN IsPk
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN Del;
+ UINT8 *Payload;
+ UINTN PayloadSize;
+
+ if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0 ||
+ (Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == 0) {
+ //
+ // PK, KEK and db/dbx/dbt should set EFI_VARIABLE_NON_VOLATILE attribute and should be a time-based
+ // authenticated variable.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Init state of Del. State may change due to secure check
+ //
+ Del = FALSE;
+ if ((InCustomMode() && UserPhysicalPresent()) || (mPlatformMode == SETUP_MODE && !IsPk)) {
+ Payload = (UINT8 *) Data + AUTHINFO2_SIZE (Data);
+ PayloadSize = DataSize - AUTHINFO2_SIZE (Data);
+ if (PayloadSize == 0) {
+ Del = TRUE;
+ }
+
+ Status = CheckSignatureListFormat(VariableName, VendorGuid, Payload, PayloadSize);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = AuthServiceInternalUpdateVariableWithTimeStamp (
+ VariableName,
+ VendorGuid,
+ Payload,
+ PayloadSize,
+ Attributes,
+ &((EFI_VARIABLE_AUTHENTICATION_2 *) Data)->TimeStamp
+ );
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ if ((mPlatformMode != SETUP_MODE) || IsPk) {
+ Status = VendorKeyIsModified ();
+ }
+ } else if (mPlatformMode == USER_MODE) {
+ //
+ // Verify against X509 Cert in PK database.
+ //
+ Status = VerifyTimeBasedPayloadAndUpdate (
+ VariableName,
+ VendorGuid,
+ Data,
+ DataSize,
+ Attributes,
+ AuthVarTypePk,
+ &Del
+ );
+ } else {
+ //
+ // Verify against the certificate in data payload.
+ //
+ Status = VerifyTimeBasedPayloadAndUpdate (
+ VariableName,
+ VendorGuid,
+ Data,
+ DataSize,
+ Attributes,
+ AuthVarTypePayload,
+ &Del
+ );
+ }
+
+ if (!EFI_ERROR(Status) && IsPk) {
+ if (mPlatformMode == SETUP_MODE && !Del) {
+ //
+ // If enroll PK in setup mode, need change to user mode.
+ //
+ Status = UpdatePlatformMode (USER_MODE);
+ } else if (mPlatformMode == USER_MODE && Del){
+ //
+ // If delete PK in user mode, need change to setup mode.
+ //
+ Status = UpdatePlatformMode (SETUP_MODE);
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Process variable with key exchange key for verification.
+
+ Caution: This function may receive untrusted input.
+ This function may be invoked in SMM mode, and datasize and data are external input.
+ This function will do basic validation, before parse the data.
+ This function will parse the authentication carefully to avoid security issues, like
+ buffer overflow, integer overflow.
+ This function will check attribute carefully to avoid authentication bypass.
+
+ @param[in] VariableName Name of Variable to be found.
+ @param[in] VendorGuid Variable vendor GUID.
+ @param[in] Data Data pointer.
+ @param[in] DataSize Size of Data found. If size is less than the
+ data, this value contains the required size.
+ @param[in] Attributes Attribute value of the variable.
+
+ @return EFI_INVALID_PARAMETER Invalid parameter.
+ @return EFI_SECURITY_VIOLATION The variable does NOT pass the validation
+ check carried out by the firmware.
+ @return EFI_SUCCESS Variable pass validation successfully.
+
+**/
+EFI_STATUS
+ProcessVarWithKek (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN VOID *Data,
+ IN UINTN DataSize,
+ IN UINT32 Attributes OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *Payload;
+ UINTN PayloadSize;
+
+ if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0 ||
+ (Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == 0) {
+ //
+ // DB, DBX and DBT should set EFI_VARIABLE_NON_VOLATILE attribute and should be a time-based
+ // authenticated variable.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_SUCCESS;
+ if (mPlatformMode == USER_MODE && !(InCustomMode() && UserPhysicalPresent())) {
+ //
+ // Time-based, verify against X509 Cert KEK.
+ //
+ return VerifyTimeBasedPayloadAndUpdate (
+ VariableName,
+ VendorGuid,
+ Data,
+ DataSize,
+ Attributes,
+ AuthVarTypeKek,
+ NULL
+ );
+ } else {
+ //
+ // If in setup mode or custom secure boot mode, no authentication needed.
+ //
+ Payload = (UINT8 *) Data + AUTHINFO2_SIZE (Data);
+ PayloadSize = DataSize - AUTHINFO2_SIZE (Data);
+
+ Status = CheckSignatureListFormat(VariableName, VendorGuid, Payload, PayloadSize);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = AuthServiceInternalUpdateVariableWithTimeStamp (
+ VariableName,
+ VendorGuid,
+ Payload,
+ PayloadSize,
+ Attributes,
+ &((EFI_VARIABLE_AUTHENTICATION_2 *) Data)->TimeStamp
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (mPlatformMode != SETUP_MODE) {
+ Status = VendorKeyIsModified ();
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Check if it is to delete auth variable.
+
+ @param[in] OrgAttributes Original attribute value of the variable.
+ @param[in] Data Data pointer.
+ @param[in] DataSize Size of Data.
+ @param[in] Attributes Attribute value of the variable.
+
+ @retval TRUE It is to delete auth variable.
+ @retval FALSE It is not to delete auth variable.
+
+**/
+BOOLEAN
+IsDeleteAuthVariable (
+ IN UINT32 OrgAttributes,
+ IN VOID *Data,
+ IN UINTN DataSize,
+ IN UINT32 Attributes
+ )
+{
+ BOOLEAN Del;
+ UINTN PayloadSize;
+
+ Del = FALSE;
+
+ //
+ // To delete a variable created with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
+ // or the EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute,
+ // SetVariable must be used with attributes matching the existing variable
+ // and the DataSize set to the size of the AuthInfo descriptor.
+ //
+ if ((Attributes == OrgAttributes) &&
+ ((Attributes & (EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)) != 0)) {
+ if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {
+ PayloadSize = DataSize - AUTHINFO2_SIZE (Data);
+ if (PayloadSize == 0) {
+ Del = TRUE;
+ }
+ } else {
+ PayloadSize = DataSize - AUTHINFO_SIZE;
+ if (PayloadSize == 0) {
+ Del = TRUE;
+ }
+ }
+ }
+
+ return Del;
+}
+
+/**
+ Process variable with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS/EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set
+
+ Caution: This function may receive untrusted input.
+ This function may be invoked in SMM mode, and datasize and data are external input.
+ This function will do basic validation, before parse the data.
+ This function will parse the authentication carefully to avoid security issues, like
+ buffer overflow, integer overflow.
+ This function will check attribute carefully to avoid authentication bypass.
+
+ @param[in] VariableName Name of the variable.
+ @param[in] VendorGuid Variable vendor GUID.
+ @param[in] Data Data pointer.
+ @param[in] DataSize Size of Data.
+ @param[in] Attributes Attribute value of the variable.
+
+ @return EFI_INVALID_PARAMETER Invalid parameter.
+ @return EFI_WRITE_PROTECTED Variable is write-protected and needs authentication with
+ EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
+ @return EFI_OUT_OF_RESOURCES The Database to save the public key is full.
+ @return EFI_SECURITY_VIOLATION The variable is with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
+ set, but the AuthInfo does NOT pass the validation
+ check carried out by the firmware.
+ @return EFI_SUCCESS Variable is not write-protected or pass validation successfully.
+
+**/
+EFI_STATUS
+ProcessVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN VOID *Data,
+ IN UINTN DataSize,
+ IN UINT32 Attributes
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN IsDeletion;
+ BOOLEAN IsFirstTime;
+ UINT8 *PubKey;
+ EFI_VARIABLE_AUTHENTICATION *CertData;
+ EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlock;
+ UINT32 KeyIndex;
+ UINT64 MonotonicCount;
+ VARIABLE_ENTRY_CONSISTENCY VariableDataEntry;
+ UINT32 Index;
+ AUTH_VARIABLE_INFO OrgVariableInfo;
+
+ KeyIndex = 0;
+ CertData = NULL;
+ CertBlock = NULL;
+ PubKey = NULL;
+ IsDeletion = FALSE;
+ Status = EFI_SUCCESS;
+
+ ZeroMem (&OrgVariableInfo, sizeof (OrgVariableInfo));
+ Status = mAuthVarLibContextIn->FindVariable (
+ VariableName,
+ VendorGuid,
+ &OrgVariableInfo
+ );
+
+ if ((!EFI_ERROR (Status)) && IsDeleteAuthVariable (OrgVariableInfo.Attributes, Data, DataSize, Attributes) && UserPhysicalPresent()) {
+ //
+ // Allow the delete operation of common authenticated variable at user physical presence.
+ //
+ Status = AuthServiceInternalUpdateVariable (
+ VariableName,
+ VendorGuid,
+ NULL,
+ 0,
+ 0
+ );
+ if (!EFI_ERROR (Status) && ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0)) {
+ Status = DeleteCertsFromDb (VariableName, VendorGuid, Attributes);
+ }
+
+ return Status;
+ }
+
+ if (NeedPhysicallyPresent (VariableName, VendorGuid) && !UserPhysicalPresent()) {
+ //
+ // This variable is protected, only physical present user could modify its value.
+ //
+ return EFI_SECURITY_VIOLATION;
+ }
+
+ //
+ // A time-based authenticated variable and a count-based authenticated variable
+ // can't be updated by each other.
+ //
+ if (OrgVariableInfo.Data != NULL) {
+ if (((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) &&
+ ((OrgVariableInfo.Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0)) {
+ return EFI_SECURITY_VIOLATION;
+ }
+
+ if (((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) &&
+ ((OrgVariableInfo.Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0)) {
+ return EFI_SECURITY_VIOLATION;
+ }
+ }
+
+ //
+ // Process Time-based Authenticated variable.
+ //
+ if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {
+ return VerifyTimeBasedPayloadAndUpdate (
+ VariableName,
+ VendorGuid,
+ Data,
+ DataSize,
+ Attributes,
+ AuthVarTypePriv,
+ NULL
+ );
+ }
+
+ //
+ // Determine if first time SetVariable with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS.
+ //
+ if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {
+ //
+ // Determine current operation type.
+ //
+ if (DataSize == AUTHINFO_SIZE) {
+ IsDeletion = TRUE;
+ }
+ //
+ // Determine whether this is the first time with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
+ //
+ if (OrgVariableInfo.Data == NULL) {
+ IsFirstTime = TRUE;
+ } else if ((OrgVariableInfo.Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == 0) {
+ IsFirstTime = TRUE;
+ } else {
+ KeyIndex = OrgVariableInfo.PubKeyIndex;
+ IsFirstTime = FALSE;
+ }
+ } else if ((OrgVariableInfo.Data != NULL) &&
+ ((OrgVariableInfo.Attributes & (EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)) != 0)
+ ) {
+ //
+ // If the variable is already write-protected, it always needs authentication before update.
+ //
+ return EFI_WRITE_PROTECTED;
+ } else {
+ //
+ // If without EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, set and attributes collision.
+ // That means it is not authenticated variable, just update variable as usual.
+ //
+ Status = AuthServiceInternalUpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes);
+ return Status;
+ }
+
+ //
+ // Get PubKey and check Monotonic Count value corresponding to the variable.
+ //
+ CertData = (EFI_VARIABLE_AUTHENTICATION *) Data;
+ CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);
+ PubKey = CertBlock->PublicKey;
+
+ //
+ // Update Monotonic Count value.
+ //
+ MonotonicCount = CertData->MonotonicCount;
+
+ if (!IsFirstTime) {
+ //
+ // 2 cases need to check here
+ // 1. Internal PubKey variable. PubKeyIndex is always 0
+ // 2. Other counter-based AuthVariable. Check input PubKey.
+ //
+ if (KeyIndex == 0) {
+ return EFI_SECURITY_VIOLATION;
+ }
+ for (Index = 0; Index < mPubKeyNumber; Index++) {
+ if (ReadUnaligned32 (&(((AUTHVAR_KEY_DB_DATA *) mPubKeyStore + Index)->KeyIndex)) == KeyIndex) {
+ if (CompareMem (((AUTHVAR_KEY_DB_DATA *) mPubKeyStore + Index)->KeyData, PubKey, EFI_CERT_TYPE_RSA2048_SIZE) == 0) {
+ break;
+ } else {
+ return EFI_SECURITY_VIOLATION;
+ }
+ }
+ }
+ if (Index == mPubKeyNumber) {
+ return EFI_SECURITY_VIOLATION;
+ }
+
+ //
+ // Compare the current monotonic count and ensure that it is greater than the last SetVariable
+ // operation with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute set.
+ //
+ if (MonotonicCount <= OrgVariableInfo.MonotonicCount) {
+ //
+ // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.
+ //
+ return EFI_SECURITY_VIOLATION;
+ }
+ }
+ //
+ // Verify the certificate in Data payload.
+ //
+ Status = VerifyCounterBasedPayload (Data, DataSize, PubKey);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Now, the signature has been verified!
+ //
+ if (IsFirstTime && !IsDeletion) {
+ VariableDataEntry.VariableSize = DataSize - AUTHINFO_SIZE;
+ VariableDataEntry.Guid = VendorGuid;
+ VariableDataEntry.Name = VariableName;
+
+ //
+ // Update public key database variable if need.
+ //
+ KeyIndex = AddPubKeyInStore (PubKey, &VariableDataEntry);
+ if (KeyIndex == 0) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ //
+ // Verification pass.
+ //
+ return AuthServiceInternalUpdateVariableWithMonotonicCount (VariableName, VendorGuid, (UINT8*)Data + AUTHINFO_SIZE, DataSize - AUTHINFO_SIZE, Attributes, KeyIndex, MonotonicCount);
+}
+
+/**
+ Filter out the duplicated EFI_SIGNATURE_DATA from the new data by comparing to the original data.
+
+ @param[in] Data Pointer to original EFI_SIGNATURE_LIST.
+ @param[in] DataSize Size of Data buffer.
+ @param[in, out] NewData Pointer to new EFI_SIGNATURE_LIST.
+ @param[in, out] NewDataSize Size of NewData buffer.
+
+**/
+EFI_STATUS
+FilterSignatureList (
+ IN VOID *Data,
+ IN UINTN DataSize,
+ IN OUT VOID *NewData,
+ IN OUT UINTN *NewDataSize
+ )
+{
+ EFI_SIGNATURE_LIST *CertList;
+ EFI_SIGNATURE_DATA *Cert;
+ UINTN CertCount;
+ EFI_SIGNATURE_LIST *NewCertList;
+ EFI_SIGNATURE_DATA *NewCert;
+ UINTN NewCertCount;
+ UINTN Index;
+ UINTN Index2;
+ UINTN Size;
+ UINT8 *Tail;
+ UINTN CopiedCount;
+ UINTN SignatureListSize;
+ BOOLEAN IsNewCert;
+ UINT8 *TempData;
+ UINTN TempDataSize;
+ EFI_STATUS Status;
+
+ if (*NewDataSize == 0) {
+ return EFI_SUCCESS;
+ }
+
+ TempDataSize = *NewDataSize;
+ Status = mAuthVarLibContextIn->GetScratchBuffer (&TempDataSize, (VOID **) &TempData);
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Tail = TempData;
+
+ NewCertList = (EFI_SIGNATURE_LIST *) NewData;
+ while ((*NewDataSize > 0) && (*NewDataSize >= NewCertList->SignatureListSize)) {
+ NewCert = (EFI_SIGNATURE_DATA *) ((UINT8 *) NewCertList + sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize);
+ NewCertCount = (NewCertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - NewCertList->SignatureHeaderSize) / NewCertList->SignatureSize;
+
+ CopiedCount = 0;
+ for (Index = 0; Index < NewCertCount; Index++) {
+ IsNewCert = TRUE;
+
+ Size = DataSize;
+ CertList = (EFI_SIGNATURE_LIST *) Data;
+ while ((Size > 0) && (Size >= CertList->SignatureListSize)) {
+ if (CompareGuid (&CertList->SignatureType, &NewCertList->SignatureType) &&
+ (CertList->SignatureSize == NewCertList->SignatureSize)) {
+ Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
+ CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
+ for (Index2 = 0; Index2 < CertCount; Index2++) {
+ //
+ // Iterate each Signature Data in this Signature List.
+ //
+ if (CompareMem (NewCert, Cert, CertList->SignatureSize) == 0) {
+ IsNewCert = FALSE;
+ break;
+ }
+ Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);
+ }
+ }
+
+ if (!IsNewCert) {
+ break;
+ }
+ Size -= CertList->SignatureListSize;
+ CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
+ }
+
+ if (IsNewCert) {
+ //
+ // New EFI_SIGNATURE_DATA, keep it.
+ //
+ if (CopiedCount == 0) {
+ //
+ // Copy EFI_SIGNATURE_LIST header for only once.
+ //
+ CopyMem (Tail, NewCertList, sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize);
+ Tail = Tail + sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize;
+ }
+
+ CopyMem (Tail, NewCert, NewCertList->SignatureSize);
+ Tail += NewCertList->SignatureSize;
+ CopiedCount++;
+ }
+
+ NewCert = (EFI_SIGNATURE_DATA *) ((UINT8 *) NewCert + NewCertList->SignatureSize);
+ }
+
+ //
+ // Update SignatureListSize in the kept EFI_SIGNATURE_LIST.
+ //
+ if (CopiedCount != 0) {
+ SignatureListSize = sizeof (EFI_SIGNATURE_LIST) + NewCertList->SignatureHeaderSize + (CopiedCount * NewCertList->SignatureSize);
+ CertList = (EFI_SIGNATURE_LIST *) (Tail - SignatureListSize);
+ CertList->SignatureListSize = (UINT32) SignatureListSize;
+ }
+
+ *NewDataSize -= NewCertList->SignatureListSize;
+ NewCertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) NewCertList + NewCertList->SignatureListSize);
+ }
+
+ TempDataSize = (Tail - (UINT8 *) TempData);
+
+ CopyMem (NewData, TempData, TempDataSize);
+ *NewDataSize = TempDataSize;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Compare two EFI_TIME data.
+
+
+ @param FirstTime A pointer to the first EFI_TIME data.
+ @param SecondTime A pointer to the second EFI_TIME data.
+
+ @retval TRUE The FirstTime is not later than the SecondTime.
+ @retval FALSE The FirstTime is later than the SecondTime.
+
+**/
+BOOLEAN
+AuthServiceInternalCompareTimeStamp (
+ IN EFI_TIME *FirstTime,
+ IN EFI_TIME *SecondTime
+ )
+{
+ if (FirstTime->Year != SecondTime->Year) {
+ return (BOOLEAN) (FirstTime->Year < SecondTime->Year);
+ } else if (FirstTime->Month != SecondTime->Month) {
+ return (BOOLEAN) (FirstTime->Month < SecondTime->Month);
+ } else if (FirstTime->Day != SecondTime->Day) {
+ return (BOOLEAN) (FirstTime->Day < SecondTime->Day);
+ } else if (FirstTime->Hour != SecondTime->Hour) {
+ return (BOOLEAN) (FirstTime->Hour < SecondTime->Hour);
+ } else if (FirstTime->Minute != SecondTime->Minute) {
+ return (BOOLEAN) (FirstTime->Minute < SecondTime->Minute);
+ }
+
+ return (BOOLEAN) (FirstTime->Second <= SecondTime->Second);
+}
+
+/**
+ Find matching signer's certificates for common authenticated variable
+ by corresponding VariableName and VendorGuid from "certdb" or "certdbv".
+
+ The data format of "certdb" or "certdbv":
+ //
+ // UINT32 CertDbListSize;
+ // /// AUTH_CERT_DB_DATA Certs1[];
+ // /// AUTH_CERT_DB_DATA Certs2[];
+ // /// ...
+ // /// AUTH_CERT_DB_DATA Certsn[];
+ //
+
+ @param[in] VariableName Name of authenticated Variable.
+ @param[in] VendorGuid Vendor GUID of authenticated Variable.
+ @param[in] Data Pointer to variable "certdb" or "certdbv".
+ @param[in] DataSize Size of variable "certdb" or "certdbv".
+ @param[out] CertOffset Offset of matching CertData, from starting of Data.
+ @param[out] CertDataSize Length of CertData in bytes.
+ @param[out] CertNodeOffset Offset of matching AUTH_CERT_DB_DATA , from
+ starting of Data.
+ @param[out] CertNodeSize Length of AUTH_CERT_DB_DATA in bytes.
+
+ @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
+ @retval EFI_NOT_FOUND Fail to find matching certs.
+ @retval EFI_SUCCESS Find matching certs and output parameters.
+
+**/
+EFI_STATUS
+FindCertsFromDb (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT8 *Data,
+ IN UINTN DataSize,
+ OUT UINT32 *CertOffset, OPTIONAL
+ OUT UINT32 *CertDataSize, OPTIONAL
+ OUT UINT32 *CertNodeOffset,OPTIONAL
+ OUT UINT32 *CertNodeSize OPTIONAL
+ )
+{
+ UINT32 Offset;
+ AUTH_CERT_DB_DATA *Ptr;
+ UINT32 CertSize;
+ UINT32 NameSize;
+ UINT32 NodeSize;
+ UINT32 CertDbListSize;
+
+ if ((VariableName == NULL) || (VendorGuid == NULL) || (Data == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check whether DataSize matches recorded CertDbListSize.
+ //
+ if (DataSize < sizeof (UINT32)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CertDbListSize = ReadUnaligned32 ((UINT32 *) Data);
+
+ if (CertDbListSize != (UINT32) DataSize) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Offset = sizeof (UINT32);
+
+ //
+ // Get corresponding certificates by VendorGuid and VariableName.
+ //
+ while (Offset < (UINT32) DataSize) {
+ Ptr = (AUTH_CERT_DB_DATA *) (Data + Offset);
+ //
+ // Check whether VendorGuid matches.
+ //
+ if (CompareGuid (&Ptr->VendorGuid, VendorGuid)) {
+ NodeSize = ReadUnaligned32 (&Ptr->CertNodeSize);
+ NameSize = ReadUnaligned32 (&Ptr->NameSize);
+ CertSize = ReadUnaligned32 (&Ptr->CertDataSize);
+
+ if (NodeSize != sizeof (EFI_GUID) + sizeof (UINT32) * 3 + CertSize +
+ sizeof (CHAR16) * NameSize) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Offset = Offset + sizeof (EFI_GUID) + sizeof (UINT32) * 3;
+ //
+ // Check whether VariableName matches.
+ //
+ if ((NameSize == StrLen (VariableName)) &&
+ (CompareMem (Data + Offset, VariableName, NameSize * sizeof (CHAR16)) == 0)) {
+ Offset = Offset + NameSize * sizeof (CHAR16);
+
+ if (CertOffset != NULL) {
+ *CertOffset = Offset;
+ }
+
+ if (CertDataSize != NULL) {
+ *CertDataSize = CertSize;
+ }
+
+ if (CertNodeOffset != NULL) {
+ *CertNodeOffset = (UINT32) ((UINT8 *) Ptr - Data);
+ }
+
+ if (CertNodeSize != NULL) {
+ *CertNodeSize = NodeSize;
+ }
+
+ return EFI_SUCCESS;
+ } else {
+ Offset = Offset + NameSize * sizeof (CHAR16) + CertSize;
+ }
+ } else {
+ NodeSize = ReadUnaligned32 (&Ptr->CertNodeSize);
+ Offset = Offset + NodeSize;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Retrieve signer's certificates for common authenticated variable
+ by corresponding VariableName and VendorGuid from "certdb"
+ or "certdbv" according to authenticated variable attributes.
+
+ @param[in] VariableName Name of authenticated Variable.
+ @param[in] VendorGuid Vendor GUID of authenticated Variable.
+ @param[in] Attributes Attributes of authenticated variable.
+ @param[out] CertData Pointer to signer's certificates.
+ @param[out] CertDataSize Length of CertData in bytes.
+
+ @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
+ @retval EFI_NOT_FOUND Fail to find "certdb"/"certdbv" or matching certs.
+ @retval EFI_SUCCESS Get signer's certificates successfully.
+
+**/
+EFI_STATUS
+GetCertsFromDb (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT32 Attributes,
+ OUT UINT8 **CertData,
+ OUT UINT32 *CertDataSize
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *Data;
+ UINTN DataSize;
+ UINT32 CertOffset;
+ CHAR16 *DbName;
+
+ if ((VariableName == NULL) || (VendorGuid == NULL) || (CertData == NULL) || (CertDataSize == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+
+ if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
+ //
+ // Get variable "certdb".
+ //
+ DbName = EFI_CERT_DB_NAME;
+ } else {
+ //
+ // Get variable "certdbv".
+ //
+ DbName = EFI_CERT_DB_VOLATILE_NAME;
+ }
+
+ //
+ // Get variable "certdb" or "certdbv".
+ //
+ Status = AuthServiceInternalFindVariable (
+ DbName,
+ &gEfiCertDbGuid,
+ (VOID **) &Data,
+ &DataSize
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((DataSize == 0) || (Data == NULL)) {
+ ASSERT (FALSE);
+ return EFI_NOT_FOUND;
+ }
+
+ Status = FindCertsFromDb (
+ VariableName,
+ VendorGuid,
+ Data,
+ DataSize,
+ &CertOffset,
+ CertDataSize,
+ NULL,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ *CertData = Data + CertOffset;
+ return EFI_SUCCESS;
+}
+
+/**
+ Delete matching signer's certificates when deleting common authenticated
+ variable by corresponding VariableName and VendorGuid from "certdb" or
+ "certdbv" according to authenticated variable attributes.
+
+ @param[in] VariableName Name of authenticated Variable.
+ @param[in] VendorGuid Vendor GUID of authenticated Variable.
+ @param[in] Attributes Attributes of authenticated variable.
+
+ @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
+ @retval EFI_NOT_FOUND Fail to find "certdb"/"certdbv" or matching certs.
+ @retval EFI_OUT_OF_RESOURCES The operation is failed due to lack of resources.
+ @retval EFI_SUCCESS The operation is completed successfully.
+
+**/
+EFI_STATUS
+DeleteCertsFromDb (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT32 Attributes
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *Data;
+ UINTN DataSize;
+ UINT32 VarAttr;
+ UINT32 CertNodeOffset;
+ UINT32 CertNodeSize;
+ UINT8 *NewCertDb;
+ UINT32 NewCertDbSize;
+ CHAR16 *DbName;
+
+ if ((VariableName == NULL) || (VendorGuid == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
+ //
+ // Get variable "certdb".
+ //
+ DbName = EFI_CERT_DB_NAME;
+ VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
+ } else {
+ //
+ // Get variable "certdbv".
+ //
+ DbName = EFI_CERT_DB_VOLATILE_NAME;
+ VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
+ }
+
+ Status = AuthServiceInternalFindVariable (
+ DbName,
+ &gEfiCertDbGuid,
+ (VOID **) &Data,
+ &DataSize
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((DataSize == 0) || (Data == NULL)) {
+ ASSERT (FALSE);
+ return EFI_NOT_FOUND;
+ }
+
+ if (DataSize == sizeof (UINT32)) {
+ //
+ // There is no certs in "certdb" or "certdbv".
+ //
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Get corresponding cert node from "certdb" or "certdbv".
+ //
+ Status = FindCertsFromDb (
+ VariableName,
+ VendorGuid,
+ Data,
+ DataSize,
+ NULL,
+ NULL,
+ &CertNodeOffset,
+ &CertNodeSize
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (DataSize < (CertNodeOffset + CertNodeSize)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Construct new data content of variable "certdb" or "certdbv".
+ //
+ NewCertDbSize = (UINT32) DataSize - CertNodeSize;
+ NewCertDb = (UINT8*) mCertDbStore;
+
+ //
+ // Copy the DB entries before deleting node.
+ //
+ CopyMem (NewCertDb, Data, CertNodeOffset);
+ //
+ // Update CertDbListSize.
+ //
+ CopyMem (NewCertDb, &NewCertDbSize, sizeof (UINT32));
+ //
+ // Copy the DB entries after deleting node.
+ //
+ if (DataSize > (CertNodeOffset + CertNodeSize)) {
+ CopyMem (
+ NewCertDb + CertNodeOffset,
+ Data + CertNodeOffset + CertNodeSize,
+ DataSize - CertNodeOffset - CertNodeSize
+ );
+ }
+
+ //
+ // Set "certdb" or "certdbv".
+ //
+ Status = AuthServiceInternalUpdateVariable (
+ DbName,
+ &gEfiCertDbGuid,
+ NewCertDb,
+ NewCertDbSize,
+ VarAttr
+ );
+
+ return Status;
+}
+
+/**
+ Insert signer's certificates for common authenticated variable with VariableName
+ and VendorGuid in AUTH_CERT_DB_DATA to "certdb" or "certdbv" according to
+ time based authenticated variable attributes.
+
+ @param[in] VariableName Name of authenticated Variable.
+ @param[in] VendorGuid Vendor GUID of authenticated Variable.
+ @param[in] Attributes Attributes of authenticated variable.
+ @param[in] CertData Pointer to signer's certificates.
+ @param[in] CertDataSize Length of CertData in bytes.
+
+ @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
+ @retval EFI_ACCESS_DENIED An AUTH_CERT_DB_DATA entry with same VariableName
+ and VendorGuid already exists.
+ @retval EFI_OUT_OF_RESOURCES The operation is failed due to lack of resources.
+ @retval EFI_SUCCESS Insert an AUTH_CERT_DB_DATA entry to "certdb" or "certdbv"
+
+**/
+EFI_STATUS
+InsertCertsToDb (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT32 Attributes,
+ IN UINT8 *CertData,
+ IN UINTN CertDataSize
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *Data;
+ UINTN DataSize;
+ UINT32 VarAttr;
+ UINT8 *NewCertDb;
+ UINT32 NewCertDbSize;
+ UINT32 CertNodeSize;
+ UINT32 NameSize;
+ AUTH_CERT_DB_DATA *Ptr;
+ CHAR16 *DbName;
+
+ if ((VariableName == NULL) || (VendorGuid == NULL) || (CertData == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
+ //
+ // Get variable "certdb".
+ //
+ DbName = EFI_CERT_DB_NAME;
+ VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
+ } else {
+ //
+ // Get variable "certdbv".
+ //
+ DbName = EFI_CERT_DB_VOLATILE_NAME;
+ VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
+ }
+
+ //
+ // Get variable "certdb" or "certdbv".
+ //
+ Status = AuthServiceInternalFindVariable (
+ DbName,
+ &gEfiCertDbGuid,
+ (VOID **) &Data,
+ &DataSize
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((DataSize == 0) || (Data == NULL)) {
+ ASSERT (FALSE);
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Find whether matching cert node already exists in "certdb" or "certdbv".
+ // If yes return error.
+ //
+ Status = FindCertsFromDb (
+ VariableName,
+ VendorGuid,
+ Data,
+ DataSize,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+ );
+
+ if (!EFI_ERROR (Status)) {
+ ASSERT (FALSE);
+ return EFI_ACCESS_DENIED;
+ }
+
+ //
+ // Construct new data content of variable "certdb" or "certdbv".
+ //
+ NameSize = (UINT32) StrLen (VariableName);
+ CertNodeSize = sizeof (AUTH_CERT_DB_DATA) + (UINT32) CertDataSize + NameSize * sizeof (CHAR16);
+ NewCertDbSize = (UINT32) DataSize + CertNodeSize;
+ if (NewCertDbSize > mMaxCertDbSize) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ NewCertDb = (UINT8*) mCertDbStore;
+
+ //
+ // Copy the DB entries before inserting node.
+ //
+ CopyMem (NewCertDb, Data, DataSize);
+ //
+ // Update CertDbListSize.
+ //
+ CopyMem (NewCertDb, &NewCertDbSize, sizeof (UINT32));
+ //
+ // Construct new cert node.
+ //
+ Ptr = (AUTH_CERT_DB_DATA *) (NewCertDb + DataSize);
+ CopyGuid (&Ptr->VendorGuid, VendorGuid);
+ CopyMem (&Ptr->CertNodeSize, &CertNodeSize, sizeof (UINT32));
+ CopyMem (&Ptr->NameSize, &NameSize, sizeof (UINT32));
+ CopyMem (&Ptr->CertDataSize, &CertDataSize, sizeof (UINT32));
+
+ CopyMem (
+ (UINT8 *) Ptr + sizeof (AUTH_CERT_DB_DATA),
+ VariableName,
+ NameSize * sizeof (CHAR16)
+ );
+
+ CopyMem (
+ (UINT8 *) Ptr + sizeof (AUTH_CERT_DB_DATA) + NameSize * sizeof (CHAR16),
+ CertData,
+ CertDataSize
+ );
+
+ //
+ // Set "certdb" or "certdbv".
+ //
+ Status = AuthServiceInternalUpdateVariable (
+ DbName,
+ &gEfiCertDbGuid,
+ NewCertDb,
+ NewCertDbSize,
+ VarAttr
+ );
+
+ return Status;
+}
+
+/**
+ Clean up signer's certificates for common authenticated variable
+ by corresponding VariableName and VendorGuid from "certdb".
+ System may break down during Timebased Variable update & certdb update,
+ make them inconsistent, this function is called in AuthVariable Init
+ to ensure consistency.
+
+ @retval EFI_NOT_FOUND Fail to find variable "certdb".
+ @retval EFI_OUT_OF_RESOURCES The operation is failed due to lack of resources.
+ @retval EFI_SUCCESS The operation is completed successfully.
+
+**/
+EFI_STATUS
+CleanCertsFromDb (
+ VOID
+ )
+{
+ UINT32 Offset;
+ AUTH_CERT_DB_DATA *Ptr;
+ UINT32 NameSize;
+ UINT32 NodeSize;
+ CHAR16 *VariableName;
+ EFI_STATUS Status;
+ BOOLEAN CertCleaned;
+ UINT8 *Data;
+ UINTN DataSize;
+ EFI_GUID AuthVarGuid;
+ AUTH_VARIABLE_INFO AuthVariableInfo;
+
+ Status = EFI_SUCCESS;
+
+ //
+ // Get corresponding certificates by VendorGuid and VariableName.
+ //
+ do {
+ CertCleaned = FALSE;
+
+ //
+ // Get latest variable "certdb"
+ //
+ Status = AuthServiceInternalFindVariable (
+ EFI_CERT_DB_NAME,
+ &gEfiCertDbGuid,
+ (VOID **) &Data,
+ &DataSize
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((DataSize == 0) || (Data == NULL)) {
+ ASSERT (FALSE);
+ return EFI_NOT_FOUND;
+ }
+
+ Offset = sizeof (UINT32);
+
+ while (Offset < (UINT32) DataSize) {
+ Ptr = (AUTH_CERT_DB_DATA *) (Data + Offset);
+ NodeSize = ReadUnaligned32 (&Ptr->CertNodeSize);
+ NameSize = ReadUnaligned32 (&Ptr->NameSize);
+
+ //
+ // Get VarName tailed with '\0'
+ //
+ VariableName = AllocateZeroPool((NameSize + 1) * sizeof(CHAR16));
+ if (VariableName == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ CopyMem (VariableName, (UINT8 *) Ptr + sizeof (AUTH_CERT_DB_DATA), NameSize * sizeof(CHAR16));
+ //
+ // Keep VarGuid aligned
+ //
+ CopyMem (&AuthVarGuid, &Ptr->VendorGuid, sizeof(EFI_GUID));
+
+ //
+ // Find corresponding time auth variable
+ //
+ ZeroMem (&AuthVariableInfo, sizeof (AuthVariableInfo));
+ Status = mAuthVarLibContextIn->FindVariable (
+ VariableName,
+ &AuthVarGuid,
+ &AuthVariableInfo
+ );
+
+ if (EFI_ERROR(Status) || (AuthVariableInfo.Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == 0) {
+ Status = DeleteCertsFromDb(
+ VariableName,
+ &AuthVarGuid,
+ AuthVariableInfo.Attributes
+ );
+ CertCleaned = TRUE;
+ DEBUG((EFI_D_INFO, "Recovery!! Cert for Auth Variable %s Guid %g is removed for consistency\n", VariableName, &AuthVarGuid));
+ FreePool(VariableName);
+ break;
+ }
+
+ FreePool(VariableName);
+ Offset = Offset + NodeSize;
+ }
+ } while (CertCleaned);
+
+ return Status;
+}
+
+/**
+ Process variable with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set
+
+ Caution: This function may receive untrusted input.
+ This function may be invoked in SMM mode, and datasize and data are external input.
+ This function will do basic validation, before parse the data.
+ This function will parse the authentication carefully to avoid security issues, like
+ buffer overflow, integer overflow.
+
+ @param[in] VariableName Name of Variable to be found.
+ @param[in] VendorGuid Variable vendor GUID.
+ @param[in] Data Data pointer.
+ @param[in] DataSize Size of Data found. If size is less than the
+ data, this value contains the required size.
+ @param[in] Attributes Attribute value of the variable.
+ @param[in] AuthVarType Verify against PK, KEK database, private database or certificate in data payload.
+ @param[in] OrgTimeStamp Pointer to original time stamp,
+ original variable is not found if NULL.
+ @param[out] VarPayloadPtr Pointer to variable payload address.
+ @param[out] VarPayloadSize Pointer to variable payload size.
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_SECURITY_VIOLATION The variable does NOT pass the validation
+ check carried out by the firmware.
+ @retval EFI_OUT_OF_RESOURCES Failed to process variable due to lack
+ of resources.
+ @retval EFI_SUCCESS Variable pass validation successfully.
+
+**/
+EFI_STATUS
+VerifyTimeBasedPayload (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN VOID *Data,
+ IN UINTN DataSize,
+ IN UINT32 Attributes,
+ IN AUTHVAR_TYPE AuthVarType,
+ IN EFI_TIME *OrgTimeStamp,
+ OUT UINT8 **VarPayloadPtr,
+ OUT UINTN *VarPayloadSize
+ )
+{
+ EFI_VARIABLE_AUTHENTICATION_2 *CertData;
+ UINT8 *SigData;
+ UINT32 SigDataSize;
+ UINT8 *PayloadPtr;
+ UINTN PayloadSize;
+ UINT32 Attr;
+ BOOLEAN VerifyStatus;
+ EFI_STATUS Status;
+ EFI_SIGNATURE_LIST *CertList;
+ EFI_SIGNATURE_DATA *Cert;
+ UINTN Index;
+ UINTN CertCount;
+ UINT32 KekDataSize;
+ UINT8 *NewData;
+ UINTN NewDataSize;
+ UINT8 *Buffer;
+ UINTN Length;
+ UINT8 *RootCert;
+ UINTN RootCertSize;
+ UINT8 *SignerCerts;
+ UINTN CertStackSize;
+ UINT8 *CertsInCertDb;
+ UINT32 CertsSizeinDb;
+
+ VerifyStatus = FALSE;
+ CertData = NULL;
+ NewData = NULL;
+ Attr = Attributes;
+ SignerCerts = NULL;
+ RootCert = NULL;
+ CertsInCertDb = NULL;
+
+ //
+ // When the attribute EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS is
+ // set, then the Data buffer shall begin with an instance of a complete (and serialized)
+ // EFI_VARIABLE_AUTHENTICATION_2 descriptor. The descriptor shall be followed by the new
+ // variable value and DataSize shall reflect the combined size of the descriptor and the new
+ // variable value. The authentication descriptor is not part of the variable data and is not
+ // returned by subsequent calls to GetVariable().
+ //
+ CertData = (EFI_VARIABLE_AUTHENTICATION_2 *) Data;
+
+ //
+ // Verify that Pad1, Nanosecond, TimeZone, Daylight and Pad2 components of the
+ // TimeStamp value are set to zero.
+ //
+ if ((CertData->TimeStamp.Pad1 != 0) ||
+ (CertData->TimeStamp.Nanosecond != 0) ||
+ (CertData->TimeStamp.TimeZone != 0) ||
+ (CertData->TimeStamp.Daylight != 0) ||
+ (CertData->TimeStamp.Pad2 != 0)) {
+ return EFI_SECURITY_VIOLATION;
+ }
+
+ if ((OrgTimeStamp != NULL) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0)) {
+ if (AuthServiceInternalCompareTimeStamp (&CertData->TimeStamp, OrgTimeStamp)) {
+ //
+ // TimeStamp check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.
+ //
+ return EFI_SECURITY_VIOLATION;
+ }
+ }
+
+ //
+ // wCertificateType should be WIN_CERT_TYPE_EFI_GUID.
+ // Cert type should be EFI_CERT_TYPE_PKCS7_GUID.
+ //
+ if ((CertData->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) ||
+ !CompareGuid (&CertData->AuthInfo.CertType, &gEfiCertPkcs7Guid)) {
+ //
+ // Invalid AuthInfo type, return EFI_SECURITY_VIOLATION.
+ //
+ return EFI_SECURITY_VIOLATION;
+ }
+
+ //
+ // Find out Pkcs7 SignedData which follows the EFI_VARIABLE_AUTHENTICATION_2 descriptor.
+ // AuthInfo.Hdr.dwLength is the length of the entire certificate, including the length of the header.
+ //
+ SigData = CertData->AuthInfo.CertData;
+ SigDataSize = CertData->AuthInfo.Hdr.dwLength - (UINT32) (OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData));
+
+ //
+ // SignedData.digestAlgorithms shall contain the digest algorithm used when preparing the
+ // signature. Only a digest algorithm of SHA-256 is accepted.
+ //
+ // According to PKCS#7 Definition:
+ // SignedData ::= SEQUENCE {
+ // version Version,
+ // digestAlgorithms DigestAlgorithmIdentifiers,
+ // contentInfo ContentInfo,
+ // .... }
+ // The DigestAlgorithmIdentifiers can be used to determine the hash algorithm
+ // in VARIABLE_AUTHENTICATION_2 descriptor.
+ // This field has the fixed offset (+13) and be calculated based on two bytes of length encoding.
+ //
+ if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {
+ if (SigDataSize >= (13 + sizeof (mSha256OidValue))) {
+ if (((*(SigData + 1) & TWO_BYTE_ENCODE) != TWO_BYTE_ENCODE) ||
+ (CompareMem (SigData + 13, &mSha256OidValue, sizeof (mSha256OidValue)) != 0)) {
+ return EFI_SECURITY_VIOLATION;
+ }
+ }
+ }
+
+ //
+ // Find out the new data payload which follows Pkcs7 SignedData directly.
+ //
+ PayloadPtr = SigData + SigDataSize;
+ PayloadSize = DataSize - OFFSET_OF_AUTHINFO2_CERT_DATA - (UINTN) SigDataSize;
+
+ //
+ // Construct a serialization buffer of the values of the VariableName, VendorGuid and Attributes
+ // parameters of the SetVariable() call and the TimeStamp component of the
+ // EFI_VARIABLE_AUTHENTICATION_2 descriptor followed by the variable's new value
+ // i.e. (VariableName, VendorGuid, Attributes, TimeStamp, Data)
+ //
+ NewDataSize = PayloadSize + sizeof (EFI_TIME) + sizeof (UINT32) +
+ sizeof (EFI_GUID) + StrSize (VariableName) - sizeof (CHAR16);
+
+ //
+ // Here is to reuse scratch data area(at the end of volatile variable store)
+ // to reduce SMRAM consumption for SMM variable driver.
+ // The scratch buffer is enough to hold the serialized data and safe to use,
+ // because it is only used at here to do verification temporarily first
+ // and then used in UpdateVariable() for a time based auth variable set.
+ //
+ Status = mAuthVarLibContextIn->GetScratchBuffer (&NewDataSize, (VOID **) &NewData);
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Buffer = NewData;
+ Length = StrLen (VariableName) * sizeof (CHAR16);
+ CopyMem (Buffer, VariableName, Length);
+ Buffer += Length;
+
+ Length = sizeof (EFI_GUID);
+ CopyMem (Buffer, VendorGuid, Length);
+ Buffer += Length;
+
+ Length = sizeof (UINT32);
+ CopyMem (Buffer, &Attr, Length);
+ Buffer += Length;
+
+ Length = sizeof (EFI_TIME);
+ CopyMem (Buffer, &CertData->TimeStamp, Length);
+ Buffer += Length;
+
+ CopyMem (Buffer, PayloadPtr, PayloadSize);
+
+ if (AuthVarType == AuthVarTypePk) {
+ //
+ // Verify that the signature has been made with the current Platform Key (no chaining for PK).
+ // First, get signer's certificates from SignedData.
+ //
+ VerifyStatus = Pkcs7GetSigners (
+ SigData,
+ SigDataSize,
+ &SignerCerts,
+ &CertStackSize,
+ &RootCert,
+ &RootCertSize
+ );
+ if (!VerifyStatus) {
+ goto Exit;
+ }
+
+ //
+ // Second, get the current platform key from variable. Check whether it's identical with signer's certificates
+ // in SignedData. If not, return error immediately.
+ //
+ Status = AuthServiceInternalFindVariable (
+ EFI_PLATFORM_KEY_NAME,
+ &gEfiGlobalVariableGuid,
+ &Data,
+ &DataSize
+ );
+ if (EFI_ERROR (Status)) {
+ VerifyStatus = FALSE;
+ goto Exit;
+ }
+ CertList = (EFI_SIGNATURE_LIST *) Data;
+ Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
+ if ((RootCertSize != (CertList->SignatureSize - (sizeof (EFI_SIGNATURE_DATA) - 1))) ||
+ (CompareMem (Cert->SignatureData, RootCert, RootCertSize) != 0)) {
+ VerifyStatus = FALSE;
+ goto Exit;
+ }
+
+ //
+ // Verify Pkcs7 SignedData via Pkcs7Verify library.
+ //
+ VerifyStatus = Pkcs7Verify (
+ SigData,
+ SigDataSize,
+ RootCert,
+ RootCertSize,
+ NewData,
+ NewDataSize
+ );
+
+ } else if (AuthVarType == AuthVarTypeKek) {
+
+ //
+ // Get KEK database from variable.
+ //
+ Status = AuthServiceInternalFindVariable (
+ EFI_KEY_EXCHANGE_KEY_NAME,
+ &gEfiGlobalVariableGuid,
+ &Data,
+ &DataSize
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Ready to verify Pkcs7 SignedData. Go through KEK Signature Database to find out X.509 CertList.
+ //
+ KekDataSize = (UINT32) DataSize;
+ CertList = (EFI_SIGNATURE_LIST *) Data;
+ while ((KekDataSize > 0) && (KekDataSize >= 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 - (sizeof (EFI_SIGNATURE_DATA) - 1);
+
+ //
+ // Verify Pkcs7 SignedData via Pkcs7Verify library.
+ //
+ VerifyStatus = Pkcs7Verify (
+ SigData,
+ SigDataSize,
+ RootCert,
+ RootCertSize,
+ NewData,
+ NewDataSize
+ );
+ if (VerifyStatus) {
+ goto Exit;
+ }
+ Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);
+ }
+ }
+ KekDataSize -= CertList->SignatureListSize;
+ CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
+ }
+ } else if (AuthVarType == AuthVarTypePriv) {
+
+ //
+ // Process common authenticated variable except PK/KEK/DB/DBX/DBT.
+ // Get signer's certificates from SignedData.
+ //
+ VerifyStatus = Pkcs7GetSigners (
+ SigData,
+ SigDataSize,
+ &SignerCerts,
+ &CertStackSize,
+ &RootCert,
+ &RootCertSize
+ );
+ if (!VerifyStatus) {
+ goto Exit;
+ }
+
+ //
+ // Get previously stored signer's certificates from certdb or certdbv for existing
+ // variable. Check whether they are identical with signer's certificates
+ // in SignedData. If not, return error immediately.
+ //
+ if (OrgTimeStamp != NULL) {
+ VerifyStatus = FALSE;
+
+ Status = GetCertsFromDb (VariableName, VendorGuid, Attributes, &CertsInCertDb, &CertsSizeinDb);
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ if ((CertStackSize != CertsSizeinDb) ||
+ (CompareMem (SignerCerts, CertsInCertDb, CertsSizeinDb) != 0)) {
+ goto Exit;
+ }
+ }
+
+ VerifyStatus = Pkcs7Verify (
+ SigData,
+ SigDataSize,
+ RootCert,
+ RootCertSize,
+ NewData,
+ NewDataSize
+ );
+ if (!VerifyStatus) {
+ goto Exit;
+ }
+
+ if ((OrgTimeStamp == NULL) && (PayloadSize != 0)) {
+ //
+ // Insert signer's certificates when adding a new common authenticated variable.
+ //
+ Status = InsertCertsToDb (VariableName, VendorGuid, Attributes, SignerCerts, CertStackSize);
+ if (EFI_ERROR (Status)) {
+ VerifyStatus = FALSE;
+ goto Exit;
+ }
+ }
+ } else if (AuthVarType == AuthVarTypePayload) {
+ CertList = (EFI_SIGNATURE_LIST *) PayloadPtr;
+ Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
+ RootCert = Cert->SignatureData;
+ RootCertSize = CertList->SignatureSize - (sizeof (EFI_SIGNATURE_DATA) - 1);
+ //
+ // Verify Pkcs7 SignedData via Pkcs7Verify library.
+ //
+ VerifyStatus = Pkcs7Verify (
+ SigData,
+ SigDataSize,
+ RootCert,
+ RootCertSize,
+ NewData,
+ NewDataSize
+ );
+ } else {
+ return EFI_SECURITY_VIOLATION;
+ }
+
+Exit:
+
+ if (AuthVarType == AuthVarTypePk || AuthVarType == AuthVarTypePriv) {
+ Pkcs7FreeSigners (RootCert);
+ Pkcs7FreeSigners (SignerCerts);
+ }
+
+ if (!VerifyStatus) {
+ return EFI_SECURITY_VIOLATION;
+ }
+
+ Status = CheckSignatureListFormat(VariableName, VendorGuid, PayloadPtr, PayloadSize);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ *VarPayloadPtr = PayloadPtr;
+ *VarPayloadSize = PayloadSize;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Process variable with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set
+
+ Caution: This function may receive untrusted input.
+ This function may be invoked in SMM mode, and datasize and data are external input.
+ This function will do basic validation, before parse the data.
+ This function will parse the authentication carefully to avoid security issues, like
+ buffer overflow, integer overflow.
+
+ @param[in] VariableName Name of Variable to be found.
+ @param[in] VendorGuid Variable vendor GUID.
+ @param[in] Data Data pointer.
+ @param[in] DataSize Size of Data found. If size is less than the
+ data, this value contains the required size.
+ @param[in] Attributes Attribute value of the variable.
+ @param[in] AuthVarType Verify against PK, KEK database, private database or certificate in data payload.
+ @param[out] VarDel Delete the variable or not.
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_SECURITY_VIOLATION The variable does NOT pass the validation
+ check carried out by the firmware.
+ @retval EFI_OUT_OF_RESOURCES Failed to process variable due to lack
+ of resources.
+ @retval EFI_SUCCESS Variable pass validation successfully.
+
+**/
+EFI_STATUS
+VerifyTimeBasedPayloadAndUpdate (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN VOID *Data,
+ IN UINTN DataSize,
+ IN UINT32 Attributes,
+ IN AUTHVAR_TYPE AuthVarType,
+ OUT BOOLEAN *VarDel
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS FindStatus;
+ UINT8 *PayloadPtr;
+ UINTN PayloadSize;
+ EFI_VARIABLE_AUTHENTICATION_2 *CertData;
+ AUTH_VARIABLE_INFO OrgVariableInfo;
+ BOOLEAN IsDel;
+
+ ZeroMem (&OrgVariableInfo, sizeof (OrgVariableInfo));
+ FindStatus = mAuthVarLibContextIn->FindVariable (
+ VariableName,
+ VendorGuid,
+ &OrgVariableInfo
+ );
+
+ Status = VerifyTimeBasedPayload (
+ VariableName,
+ VendorGuid,
+ Data,
+ DataSize,
+ Attributes,
+ AuthVarType,
+ (!EFI_ERROR (FindStatus)) ? OrgVariableInfo.TimeStamp : NULL,
+ &PayloadPtr,
+ &PayloadSize
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (!EFI_ERROR(FindStatus)
+ && (PayloadSize == 0)
+ && ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0)) {
+ IsDel = TRUE;
+ } else {
+ IsDel = FALSE;
+ }
+
+ CertData = (EFI_VARIABLE_AUTHENTICATION_2 *) Data;
+
+ //
+ // Final step: Update/Append Variable if it pass Pkcs7Verify
+ //
+ Status = AuthServiceInternalUpdateVariableWithTimeStamp (
+ VariableName,
+ VendorGuid,
+ PayloadPtr,
+ PayloadSize,
+ Attributes,
+ &CertData->TimeStamp
+ );
+
+ //
+ // Delete signer's certificates when delete the common authenticated variable.
+ //
+ if (IsDel && AuthVarType == AuthVarTypePriv && !EFI_ERROR(Status) ) {
+ Status = DeleteCertsFromDb (VariableName, VendorGuid, Attributes);
+ }
+
+ if (VarDel != NULL) {
+ if (IsDel && !EFI_ERROR(Status)) {
+ *VarDel = TRUE;
+ } else {
+ *VarDel = FALSE;
+ }
+ }
+
+ return Status;
+}
diff --git a/Core/SecurityPkg/Library/AuthVariableLib/AuthServiceInternal.h b/Core/SecurityPkg/Library/AuthVariableLib/AuthServiceInternal.h
new file mode 100644
index 0000000000..e9b7cf3579
--- /dev/null
+++ b/Core/SecurityPkg/Library/AuthVariableLib/AuthServiceInternal.h
@@ -0,0 +1,436 @@
+/** @file
+ The internal header file includes the common header files, defines
+ internal structure and functions used by AuthService module.
+
+ Caution: This module requires additional review when modified.
+ This driver will have external input - variable data. It may be input in SMM mode.
+ This external input must be validated carefully to avoid security issue like
+ buffer overflow, integer overflow.
+ Variable attribute should also be checked to avoid authentication bypass.
+ The whole SMM authentication variable design relies on the integrity of flash part and SMM.
+ which is assumed to be protected by platform. All variable code and metadata in flash/SMM Memory
+ may not be modified without authorization. If platform fails to protect these resources,
+ the authentication service provided in this driver will be broken, and the behavior is undefined.
+
+Copyright (c) 2009 - 2017, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _AUTHSERVICE_INTERNAL_H_
+#define _AUTHSERVICE_INTERNAL_H_
+
+#include <Library/AuthVariableLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseCryptLib.h>
+#include <Library/PlatformSecureLib.h>
+
+#include <Guid/AuthenticatedVariableFormat.h>
+#include <Guid/ImageAuthentication.h>
+
+#define TWO_BYTE_ENCODE 0x82
+
+///
+/// Struct to record signature requirement defined by UEFI spec.
+/// For SigHeaderSize and SigDataSize, ((UINT32) ~0) means NO exact length requirement for this field.
+///
+typedef struct {
+ EFI_GUID SigType;
+ // Expected SignatureHeader size in Bytes.
+ UINT32 SigHeaderSize;
+ // Expected SignatureData size in Bytes.
+ UINT32 SigDataSize;
+} EFI_SIGNATURE_ITEM;
+
+typedef enum {
+ AuthVarTypePk,
+ AuthVarTypeKek,
+ AuthVarTypePriv,
+ AuthVarTypePayload
+} AUTHVAR_TYPE;
+
+///
+/// "AuthVarKeyDatabase" variable for the Public Key store
+/// of variables with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
+///
+/// GUID: gEfiAuthenticatedVariableGuid
+///
+/// We need maintain atomicity.
+///
+/// Format:
+/// +----------------------------+
+/// | AUTHVAR_KEY_DB_DATA | <-- First AuthVarKey
+/// +----------------------------+
+/// | ...... |
+/// +----------------------------+
+/// | AUTHVAR_KEY_DB_DATA | <-- Last AuthKey
+/// +----------------------------+
+///
+#define AUTHVAR_KEYDB_NAME L"AuthVarKeyDatabase"
+
+#define EFI_CERT_TYPE_RSA2048_SHA256_SIZE 256
+#define EFI_CERT_TYPE_RSA2048_SIZE 256
+
+#pragma pack(1)
+typedef struct {
+ UINT32 KeyIndex;
+ UINT8 KeyData[EFI_CERT_TYPE_RSA2048_SIZE];
+} AUTHVAR_KEY_DB_DATA;
+#pragma pack()
+
+///
+/// "certdb" variable stores the signer's certificates for non PK/KEK/DB/DBX
+/// variables with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS|EFI_VARIABLE_NON_VOLATILE set.
+/// "certdbv" variable stores the signer's certificates for non PK/KEK/DB/DBX
+/// variables with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set
+///
+/// GUID: gEfiCertDbGuid
+///
+/// We need maintain atomicity.
+///
+/// Format:
+/// +----------------------------+
+/// | UINT32 | <-- CertDbListSize, including this UINT32
+/// +----------------------------+
+/// | AUTH_CERT_DB_DATA | <-- First CERT
+/// +----------------------------+
+/// | ........ |
+/// +----------------------------+
+/// | AUTH_CERT_DB_DATA | <-- Last CERT
+/// +----------------------------+
+///
+#define EFI_CERT_DB_NAME L"certdb"
+#define EFI_CERT_DB_VOLATILE_NAME L"certdbv"
+
+#pragma pack(1)
+typedef struct {
+ EFI_GUID VendorGuid;
+ UINT32 CertNodeSize;
+ UINT32 NameSize;
+ UINT32 CertDataSize;
+ /// CHAR16 VariableName[NameSize];
+ /// UINT8 CertData[CertDataSize];
+} AUTH_CERT_DB_DATA;
+#pragma pack()
+
+extern UINT8 *mPubKeyStore;
+extern UINT32 mPubKeyNumber;
+extern UINT32 mMaxKeyNumber;
+extern UINT32 mMaxKeyDbSize;
+extern UINT8 *mCertDbStore;
+extern UINT32 mMaxCertDbSize;
+extern UINT32 mPlatformMode;
+extern UINT8 mVendorKeyState;
+
+extern VOID *mHashCtx;
+
+extern AUTH_VAR_LIB_CONTEXT_IN *mAuthVarLibContextIn;
+
+
+/**
+ Process variable with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set
+
+ Caution: This function may receive untrusted input.
+ This function may be invoked in SMM mode, and datasize and data are external input.
+ This function will do basic validation, before parse the data.
+ This function will parse the authentication carefully to avoid security issues, like
+ buffer overflow, integer overflow.
+
+ @param[in] VariableName Name of Variable to be found.
+ @param[in] VendorGuid Variable vendor GUID.
+ @param[in] Data Data pointer.
+ @param[in] DataSize Size of Data found. If size is less than the
+ data, this value contains the required size.
+ @param[in] Attributes Attribute value of the variable.
+ @param[in] AuthVarType Verify against PK, KEK database, private database or certificate in data payload.
+ @param[out] VarDel Delete the variable or not.
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_SECURITY_VIOLATION The variable does NOT pass the validation
+ check carried out by the firmware.
+ @retval EFI_OUT_OF_RESOURCES Failed to process variable due to lack
+ of resources.
+ @retval EFI_SUCCESS Variable pass validation successfully.
+
+**/
+EFI_STATUS
+VerifyTimeBasedPayloadAndUpdate (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN VOID *Data,
+ IN UINTN DataSize,
+ IN UINT32 Attributes,
+ IN AUTHVAR_TYPE AuthVarType,
+ OUT BOOLEAN *VarDel
+ );
+
+/**
+ Delete matching signer's certificates when deleting common authenticated
+ variable by corresponding VariableName and VendorGuid from "certdb" or
+ "certdbv" according to authenticated variable attributes.
+
+ @param[in] VariableName Name of authenticated Variable.
+ @param[in] VendorGuid Vendor GUID of authenticated Variable.
+ @param[in] Attributes Attributes of authenticated variable.
+
+ @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
+ @retval EFI_NOT_FOUND Fail to find "certdb"/"certdbv" or matching certs.
+ @retval EFI_OUT_OF_RESOURCES The operation is failed due to lack of resources.
+ @retval EFI_SUCCESS The operation is completed successfully.
+
+**/
+EFI_STATUS
+DeleteCertsFromDb (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT32 Attributes
+ );
+
+/**
+ Clean up signer's certificates for common authenticated variable
+ by corresponding VariableName and VendorGuid from "certdb".
+ Sytem may break down during Timebased Variable update & certdb update,
+ make them inconsistent, this function is called in AuthVariable Init to ensure
+ consistency
+
+ @retval EFI_NOT_FOUND Fail to find matching certs.
+ @retval EFI_SUCCESS Find matching certs and output parameters.
+
+**/
+EFI_STATUS
+CleanCertsFromDb (
+ VOID
+ );
+
+/**
+ Filter out the duplicated EFI_SIGNATURE_DATA from the new data by comparing to the original data.
+
+ @param[in] Data Pointer to original EFI_SIGNATURE_LIST.
+ @param[in] DataSize Size of Data buffer.
+ @param[in, out] NewData Pointer to new EFI_SIGNATURE_LIST.
+ @param[in, out] NewDataSize Size of NewData buffer.
+
+**/
+EFI_STATUS
+FilterSignatureList (
+ IN VOID *Data,
+ IN UINTN DataSize,
+ IN OUT VOID *NewData,
+ IN OUT UINTN *NewDataSize
+ );
+
+/**
+ Process variable with platform key for verification.
+
+ Caution: This function may receive untrusted input.
+ This function may be invoked in SMM mode, and datasize and data are external input.
+ This function will do basic validation, before parse the data.
+ This function will parse the authentication carefully to avoid security issues, like
+ buffer overflow, integer overflow.
+ This function will check attribute carefully to avoid authentication bypass.
+
+ @param[in] VariableName Name of Variable to be found.
+ @param[in] VendorGuid Variable vendor GUID.
+ @param[in] Data Data pointer.
+ @param[in] DataSize Size of Data found. If size is less than the
+ data, this value contains the required size.
+ @param[in] Attributes Attribute value of the variable
+ @param[in] IsPk Indicate whether it is to process pk.
+
+ @return EFI_INVALID_PARAMETER Invalid parameter.
+ @return EFI_SECURITY_VIOLATION The variable does NOT pass the validation.
+ check carried out by the firmware.
+ @return EFI_SUCCESS Variable passed validation successfully.
+
+**/
+EFI_STATUS
+ProcessVarWithPk (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN VOID *Data,
+ IN UINTN DataSize,
+ IN UINT32 Attributes OPTIONAL,
+ IN BOOLEAN IsPk
+ );
+
+/**
+ Process variable with key exchange key for verification.
+
+ Caution: This function may receive untrusted input.
+ This function may be invoked in SMM mode, and datasize and data are external input.
+ This function will do basic validation, before parse the data.
+ This function will parse the authentication carefully to avoid security issues, like
+ buffer overflow, integer overflow.
+ This function will check attribute carefully to avoid authentication bypass.
+
+ @param[in] VariableName Name of Variable to be found.
+ @param[in] VendorGuid Variable vendor GUID.
+ @param[in] Data Data pointer.
+ @param[in] DataSize Size of Data found. If size is less than the
+ data, this value contains the required size.
+ @param[in] Attributes Attribute value of the variable.
+
+ @return EFI_INVALID_PARAMETER Invalid parameter.
+ @return EFI_SECURITY_VIOLATION The variable does NOT pass the validation
+ check carried out by the firmware.
+ @return EFI_SUCCESS Variable pass validation successfully.
+
+**/
+EFI_STATUS
+ProcessVarWithKek (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN VOID *Data,
+ IN UINTN DataSize,
+ IN UINT32 Attributes OPTIONAL
+ );
+
+/**
+ Process variable with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS/EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set
+
+ Caution: This function may receive untrusted input.
+ This function may be invoked in SMM mode, and datasize and data are external input.
+ This function will do basic validation, before parse the data.
+ This function will parse the authentication carefully to avoid security issues, like
+ buffer overflow, integer overflow.
+ This function will check attribute carefully to avoid authentication bypass.
+
+ @param[in] VariableName Name of the variable.
+ @param[in] VendorGuid Variable vendor GUID.
+ @param[in] Data Data pointer.
+ @param[in] DataSize Size of Data.
+ @param[in] Attributes Attribute value of the variable.
+
+ @return EFI_INVALID_PARAMETER Invalid parameter.
+ @return EFI_WRITE_PROTECTED Variable is write-protected and needs authentication with
+ EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
+ @return EFI_OUT_OF_RESOURCES The Database to save the public key is full.
+ @return EFI_SECURITY_VIOLATION The variable is with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
+ set, but the AuthInfo does NOT pass the validation
+ check carried out by the firmware.
+ @return EFI_SUCCESS Variable is not write-protected or pass validation successfully.
+
+**/
+EFI_STATUS
+ProcessVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN VOID *Data,
+ IN UINTN DataSize,
+ IN UINT32 Attributes
+ );
+
+/**
+ Finds variable in storage blocks of volatile and non-volatile storage areas.
+
+ This code finds variable in storage blocks of volatile and non-volatile storage areas.
+ If VariableName is an empty string, then we just return the first
+ qualified variable without comparing VariableName and VendorGuid.
+
+ @param[in] VariableName Name of the variable to be found.
+ @param[in] VendorGuid Variable vendor GUID to be found.
+ @param[out] Data Pointer to data address.
+ @param[out] DataSize Pointer to data size.
+
+ @retval EFI_INVALID_PARAMETER If VariableName is not an empty string,
+ while VendorGuid is NULL.
+ @retval EFI_SUCCESS Variable successfully found.
+ @retval EFI_NOT_FOUND Variable not found
+
+**/
+EFI_STATUS
+AuthServiceInternalFindVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ OUT VOID **Data,
+ OUT UINTN *DataSize
+ );
+
+/**
+ Update the variable region with Variable information.
+
+ @param[in] VariableName Name of variable.
+ @param[in] VendorGuid Guid of variable.
+ @param[in] Data Data pointer.
+ @param[in] DataSize Size of Data.
+ @param[in] Attributes Attribute value of the variable.
+
+ @retval EFI_SUCCESS The update operation is success.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_WRITE_PROTECTED Variable is write-protected.
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource.
+
+**/
+EFI_STATUS
+AuthServiceInternalUpdateVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN VOID *Data,
+ IN UINTN DataSize,
+ IN UINT32 Attributes
+ );
+
+/**
+ Update the variable region with Variable information.
+
+ @param[in] VariableName Name of variable.
+ @param[in] VendorGuid Guid of variable.
+ @param[in] Data Data pointer.
+ @param[in] DataSize Size of Data.
+ @param[in] Attributes Attribute value of the variable.
+ @param[in] KeyIndex Index of associated public key.
+ @param[in] MonotonicCount Value of associated monotonic count.
+
+ @retval EFI_SUCCESS The update operation is success.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_WRITE_PROTECTED Variable is write-protected.
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource.
+
+**/
+EFI_STATUS
+AuthServiceInternalUpdateVariableWithMonotonicCount (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN VOID *Data,
+ IN UINTN DataSize,
+ IN UINT32 Attributes,
+ IN UINT32 KeyIndex,
+ IN UINT64 MonotonicCount
+ );
+
+/**
+ Update the variable region with Variable information.
+
+ @param[in] VariableName Name of variable.
+ @param[in] VendorGuid Guid of variable.
+ @param[in] Data Data pointer.
+ @param[in] DataSize Size of Data.
+ @param[in] Attributes Attribute value of the variable.
+ @param[in] TimeStamp Value of associated TimeStamp.
+
+ @retval EFI_SUCCESS The update operation is success.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_WRITE_PROTECTED Variable is write-protected.
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource.
+
+**/
+EFI_STATUS
+AuthServiceInternalUpdateVariableWithTimeStamp (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN VOID *Data,
+ IN UINTN DataSize,
+ IN UINT32 Attributes,
+ IN EFI_TIME *TimeStamp
+ );
+
+#endif
diff --git a/Core/SecurityPkg/Library/AuthVariableLib/AuthVariableLib.c b/Core/SecurityPkg/Library/AuthVariableLib/AuthVariableLib.c
new file mode 100644
index 0000000000..792a1232ae
--- /dev/null
+++ b/Core/SecurityPkg/Library/AuthVariableLib/AuthVariableLib.c
@@ -0,0 +1,492 @@
+/** @file
+ Implement authentication services for the authenticated variables.
+
+ Caution: This module requires additional review when modified.
+ This driver will have external input - variable data. It may be input in SMM mode.
+ This external input must be validated carefully to avoid security issue like
+ buffer overflow, integer overflow.
+ Variable attribute should also be checked to avoid authentication bypass.
+ The whole SMM authentication variable design relies on the integrity of flash part and SMM.
+ which is assumed to be protected by platform. All variable code and metadata in flash/SMM Memory
+ may not be modified without authorization. If platform fails to protect these resources,
+ the authentication service provided in this driver will be broken, and the behavior is undefined.
+
+Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "AuthServiceInternal.h"
+
+///
+/// Global database array for scratch
+///
+UINT8 *mPubKeyStore;
+UINT32 mPubKeyNumber;
+UINT32 mMaxKeyNumber;
+UINT32 mMaxKeyDbSize;
+UINT8 *mCertDbStore;
+UINT32 mMaxCertDbSize;
+UINT32 mPlatformMode;
+UINT8 mVendorKeyState;
+
+EFI_GUID mSignatureSupport[] = {EFI_CERT_SHA1_GUID, EFI_CERT_SHA256_GUID, EFI_CERT_RSA2048_GUID, EFI_CERT_X509_GUID};
+
+//
+// Hash context pointer
+//
+VOID *mHashCtx = NULL;
+
+VARIABLE_ENTRY_PROPERTY mAuthVarEntry[] = {
+ {
+ &gEfiSecureBootEnableDisableGuid,
+ EFI_SECURE_BOOT_ENABLE_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ 0,
+ VARIABLE_ATTRIBUTE_NV_BS,
+ sizeof (UINT8),
+ sizeof (UINT8)
+ }
+ },
+ {
+ &gEfiCustomModeEnableGuid,
+ EFI_CUSTOM_MODE_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ 0,
+ VARIABLE_ATTRIBUTE_NV_BS,
+ sizeof (UINT8),
+ sizeof (UINT8)
+ }
+ },
+ {
+ &gEfiVendorKeysNvGuid,
+ EFI_VENDOR_KEYS_NV_VARIABLE_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY,
+ VARIABLE_ATTRIBUTE_NV_BS_RT_AT,
+ sizeof (UINT8),
+ sizeof (UINT8)
+ }
+ },
+ {
+ &gEfiAuthenticatedVariableGuid,
+ AUTHVAR_KEYDB_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY,
+ VARIABLE_ATTRIBUTE_NV_BS_RT_AW,
+ sizeof (UINT8),
+ MAX_UINTN
+ }
+ },
+ {
+ &gEfiCertDbGuid,
+ EFI_CERT_DB_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY,
+ VARIABLE_ATTRIBUTE_NV_BS_RT_AT,
+ sizeof (UINT32),
+ MAX_UINTN
+ }
+ },
+ {
+ &gEfiCertDbGuid,
+ EFI_CERT_DB_VOLATILE_NAME,
+ {
+ VAR_CHECK_VARIABLE_PROPERTY_REVISION,
+ VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY,
+ VARIABLE_ATTRIBUTE_BS_RT_AT,
+ sizeof (UINT32),
+ MAX_UINTN
+ }
+ },
+};
+
+VOID **mAuthVarAddressPointer[10];
+
+AUTH_VAR_LIB_CONTEXT_IN *mAuthVarLibContextIn = NULL;
+
+/**
+ Initialization for authenticated varibale services.
+ If this initialization returns error status, other APIs will not work
+ and expect to be not called then.
+
+ @param[in] AuthVarLibContextIn Pointer to input auth variable lib context.
+ @param[out] AuthVarLibContextOut Pointer to output auth variable lib context.
+
+ @retval EFI_SUCCESS Function successfully executed.
+ @retval EFI_INVALID_PARAMETER If AuthVarLibContextIn == NULL or AuthVarLibContextOut == NULL.
+ @retval EFI_OUT_OF_RESOURCES Fail to allocate enough resource.
+ @retval EFI_UNSUPPORTED Unsupported to process authenticated variable.
+
+**/
+EFI_STATUS
+EFIAPI
+AuthVariableLibInitialize (
+ IN AUTH_VAR_LIB_CONTEXT_IN *AuthVarLibContextIn,
+ OUT AUTH_VAR_LIB_CONTEXT_OUT *AuthVarLibContextOut
+ )
+{
+ EFI_STATUS Status;
+ UINT8 VarValue;
+ UINT32 VarAttr;
+ UINT8 *Data;
+ UINTN DataSize;
+ UINTN CtxSize;
+ UINT8 SecureBootMode;
+ UINT8 SecureBootEnable;
+ UINT8 CustomMode;
+ UINT32 ListSize;
+
+ if ((AuthVarLibContextIn == NULL) || (AuthVarLibContextOut == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ mAuthVarLibContextIn = AuthVarLibContextIn;
+
+ //
+ // Initialize hash context.
+ //
+ CtxSize = Sha256GetContextSize ();
+ mHashCtx = AllocateRuntimePool (CtxSize);
+ if (mHashCtx == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Reserve runtime buffer for public key database. The size excludes variable header and name size.
+ //
+ mMaxKeyDbSize = (UINT32) (mAuthVarLibContextIn->MaxAuthVariableSize - sizeof (AUTHVAR_KEYDB_NAME));
+ mMaxKeyNumber = mMaxKeyDbSize / sizeof (AUTHVAR_KEY_DB_DATA);
+ mPubKeyStore = AllocateRuntimePool (mMaxKeyDbSize);
+ if (mPubKeyStore == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Reserve runtime buffer for certificate database. The size excludes variable header and name size.
+ // Use EFI_CERT_DB_VOLATILE_NAME size since it is longer.
+ //
+ mMaxCertDbSize = (UINT32) (mAuthVarLibContextIn->MaxAuthVariableSize - sizeof (EFI_CERT_DB_VOLATILE_NAME));
+ mCertDbStore = AllocateRuntimePool (mMaxCertDbSize);
+ if (mCertDbStore == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Check "AuthVarKeyDatabase" variable's existence.
+ // If it doesn't exist, create a new one with initial value of 0 and EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
+ //
+ Status = AuthServiceInternalFindVariable (
+ AUTHVAR_KEYDB_NAME,
+ &gEfiAuthenticatedVariableGuid,
+ (VOID **) &Data,
+ &DataSize
+ );
+ if (EFI_ERROR (Status)) {
+ VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;
+ VarValue = 0;
+ mPubKeyNumber = 0;
+ Status = AuthServiceInternalUpdateVariable (
+ AUTHVAR_KEYDB_NAME,
+ &gEfiAuthenticatedVariableGuid,
+ &VarValue,
+ sizeof(UINT8),
+ VarAttr
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } else {
+ //
+ // Load database in global variable for cache.
+ //
+ ASSERT ((DataSize != 0) && (Data != NULL));
+ //
+ // "AuthVarKeyDatabase" is an internal variable. Its DataSize is always ensured not to exceed mPubKeyStore buffer size(See definition before)
+ // Therefore, there is no memory overflow in underlying CopyMem.
+ //
+ CopyMem (mPubKeyStore, (UINT8 *) Data, DataSize);
+ mPubKeyNumber = (UINT32) (DataSize / sizeof (AUTHVAR_KEY_DB_DATA));
+ }
+
+ Status = AuthServiceInternalFindVariable (EFI_PLATFORM_KEY_NAME, &gEfiGlobalVariableGuid, (VOID **) &Data, &DataSize);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_INFO, "Variable %s does not exist.\n", EFI_PLATFORM_KEY_NAME));
+ } else {
+ DEBUG ((EFI_D_INFO, "Variable %s exists.\n", EFI_PLATFORM_KEY_NAME));
+ }
+
+ //
+ // Create "SetupMode" variable with BS+RT attribute set.
+ //
+ if (EFI_ERROR (Status)) {
+ mPlatformMode = SETUP_MODE;
+ } else {
+ mPlatformMode = USER_MODE;
+ }
+ Status = AuthServiceInternalUpdateVariable (
+ EFI_SETUP_MODE_NAME,
+ &gEfiGlobalVariableGuid,
+ &mPlatformMode,
+ sizeof(UINT8),
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Create "SignatureSupport" variable with BS+RT attribute set.
+ //
+ Status = AuthServiceInternalUpdateVariable (
+ EFI_SIGNATURE_SUPPORT_NAME,
+ &gEfiGlobalVariableGuid,
+ mSignatureSupport,
+ sizeof(mSignatureSupport),
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // If "SecureBootEnable" variable exists, then update "SecureBoot" variable.
+ // If "SecureBootEnable" variable is SECURE_BOOT_ENABLE and in USER_MODE, Set "SecureBoot" variable to SECURE_BOOT_MODE_ENABLE.
+ // If "SecureBootEnable" variable is SECURE_BOOT_DISABLE, Set "SecureBoot" variable to SECURE_BOOT_MODE_DISABLE.
+ //
+ SecureBootEnable = SECURE_BOOT_DISABLE;
+ Status = AuthServiceInternalFindVariable (EFI_SECURE_BOOT_ENABLE_NAME, &gEfiSecureBootEnableDisableGuid, (VOID **) &Data, &DataSize);
+ if (!EFI_ERROR (Status)) {
+ if (mPlatformMode == USER_MODE){
+ SecureBootEnable = *(UINT8 *) Data;
+ }
+ } else if (mPlatformMode == USER_MODE) {
+ //
+ // "SecureBootEnable" not exist, initialize it in USER_MODE.
+ //
+ SecureBootEnable = SECURE_BOOT_ENABLE;
+ Status = AuthServiceInternalUpdateVariable (
+ EFI_SECURE_BOOT_ENABLE_NAME,
+ &gEfiSecureBootEnableDisableGuid,
+ &SecureBootEnable,
+ sizeof (UINT8),
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // Create "SecureBoot" variable with BS+RT attribute set.
+ //
+ if (SecureBootEnable == SECURE_BOOT_ENABLE && mPlatformMode == USER_MODE) {
+ SecureBootMode = SECURE_BOOT_MODE_ENABLE;
+ } else {
+ SecureBootMode = SECURE_BOOT_MODE_DISABLE;
+ }
+ Status = AuthServiceInternalUpdateVariable (
+ EFI_SECURE_BOOT_MODE_NAME,
+ &gEfiGlobalVariableGuid,
+ &SecureBootMode,
+ sizeof (UINT8),
+ EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_SETUP_MODE_NAME, mPlatformMode));
+ DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_SECURE_BOOT_MODE_NAME, SecureBootMode));
+ DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_SECURE_BOOT_ENABLE_NAME, SecureBootEnable));
+
+ //
+ // Initialize "CustomMode" in STANDARD_SECURE_BOOT_MODE state.
+ //
+ CustomMode = STANDARD_SECURE_BOOT_MODE;
+ Status = AuthServiceInternalUpdateVariable (
+ EFI_CUSTOM_MODE_NAME,
+ &gEfiCustomModeEnableGuid,
+ &CustomMode,
+ sizeof (UINT8),
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_CUSTOM_MODE_NAME, CustomMode));
+
+ //
+ // Check "certdb" variable's existence.
+ // If it doesn't exist, then create a new one with
+ // EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set.
+ //
+ Status = AuthServiceInternalFindVariable (
+ EFI_CERT_DB_NAME,
+ &gEfiCertDbGuid,
+ (VOID **) &Data,
+ &DataSize
+ );
+ if (EFI_ERROR (Status)) {
+ VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
+ ListSize = sizeof (UINT32);
+ Status = AuthServiceInternalUpdateVariable (
+ EFI_CERT_DB_NAME,
+ &gEfiCertDbGuid,
+ &ListSize,
+ sizeof (UINT32),
+ VarAttr
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } else {
+ //
+ // Clean up Certs to make certDB & Time based auth variable consistent
+ //
+ Status = CleanCertsFromDb();
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Clean up CertDB fail! Status %x\n", Status));
+ return Status;
+ }
+ }
+
+ //
+ // Create "certdbv" variable with RT+BS+AT set.
+ //
+ VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
+ ListSize = sizeof (UINT32);
+ Status = AuthServiceInternalUpdateVariable (
+ EFI_CERT_DB_VOLATILE_NAME,
+ &gEfiCertDbGuid,
+ &ListSize,
+ sizeof (UINT32),
+ VarAttr
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Check "VendorKeysNv" variable's existence and create "VendorKeys" variable accordingly.
+ //
+ Status = AuthServiceInternalFindVariable (EFI_VENDOR_KEYS_NV_VARIABLE_NAME, &gEfiVendorKeysNvGuid, (VOID **) &Data, &DataSize);
+ if (!EFI_ERROR (Status)) {
+ mVendorKeyState = *(UINT8 *)Data;
+ } else {
+ //
+ // "VendorKeysNv" not exist, initialize it in VENDOR_KEYS_VALID state.
+ //
+ mVendorKeyState = VENDOR_KEYS_VALID;
+ Status = AuthServiceInternalUpdateVariable (
+ EFI_VENDOR_KEYS_NV_VARIABLE_NAME,
+ &gEfiVendorKeysNvGuid,
+ &mVendorKeyState,
+ sizeof (UINT8),
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // Create "VendorKeys" variable with BS+RT attribute set.
+ //
+ Status = AuthServiceInternalUpdateVariable (
+ EFI_VENDOR_KEYS_VARIABLE_NAME,
+ &gEfiGlobalVariableGuid,
+ &mVendorKeyState,
+ sizeof (UINT8),
+ EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ DEBUG ((EFI_D_INFO, "Variable %s is %x\n", EFI_VENDOR_KEYS_VARIABLE_NAME, mVendorKeyState));
+
+ AuthVarLibContextOut->StructVersion = AUTH_VAR_LIB_CONTEXT_OUT_STRUCT_VERSION;
+ AuthVarLibContextOut->StructSize = sizeof (AUTH_VAR_LIB_CONTEXT_OUT);
+ AuthVarLibContextOut->AuthVarEntry = mAuthVarEntry;
+ AuthVarLibContextOut->AuthVarEntryCount = ARRAY_SIZE (mAuthVarEntry);
+ mAuthVarAddressPointer[0] = (VOID **) &mPubKeyStore;
+ mAuthVarAddressPointer[1] = (VOID **) &mCertDbStore;
+ mAuthVarAddressPointer[2] = (VOID **) &mHashCtx;
+ mAuthVarAddressPointer[3] = (VOID **) &mAuthVarLibContextIn;
+ mAuthVarAddressPointer[4] = (VOID **) &(mAuthVarLibContextIn->FindVariable),
+ mAuthVarAddressPointer[5] = (VOID **) &(mAuthVarLibContextIn->FindNextVariable),
+ mAuthVarAddressPointer[6] = (VOID **) &(mAuthVarLibContextIn->UpdateVariable),
+ mAuthVarAddressPointer[7] = (VOID **) &(mAuthVarLibContextIn->GetScratchBuffer),
+ mAuthVarAddressPointer[8] = (VOID **) &(mAuthVarLibContextIn->CheckRemainingSpaceForConsistency),
+ mAuthVarAddressPointer[9] = (VOID **) &(mAuthVarLibContextIn->AtRuntime),
+ AuthVarLibContextOut->AddressPointer = mAuthVarAddressPointer;
+ AuthVarLibContextOut->AddressPointerCount = ARRAY_SIZE (mAuthVarAddressPointer);
+
+ return Status;
+}
+
+/**
+ Process variable with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS/EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS set.
+
+ @param[in] VariableName Name of the variable.
+ @param[in] VendorGuid Variable vendor GUID.
+ @param[in] Data Data pointer.
+ @param[in] DataSize Size of Data.
+ @param[in] Attributes Attribute value of the variable.
+
+ @retval EFI_SUCCESS The firmware has successfully stored the variable and its data as
+ defined by the Attributes.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_WRITE_PROTECTED Variable is write-protected.
+ @retval EFI_OUT_OF_RESOURCES There is not enough resource.
+ @retval EFI_SECURITY_VIOLATION The variable is with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
+ or EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACESS
+ set, but the AuthInfo does NOT pass the validation
+ check carried out by the firmware.
+ @retval EFI_UNSUPPORTED Unsupported to process authenticated variable.
+
+**/
+EFI_STATUS
+EFIAPI
+AuthVariableLibProcessVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN VOID *Data,
+ IN UINTN DataSize,
+ IN UINT32 Attributes
+ )
+{
+ EFI_STATUS Status;
+
+ if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_PLATFORM_KEY_NAME) == 0)){
+ Status = ProcessVarWithPk (VariableName, VendorGuid, Data, DataSize, Attributes, TRUE);
+ } else if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_KEY_EXCHANGE_KEY_NAME) == 0)) {
+ Status = ProcessVarWithPk (VariableName, VendorGuid, Data, DataSize, Attributes, FALSE);
+ } else if (CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid) &&
+ ((StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE) == 0) ||
+ (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE1) == 0) ||
+ (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE2) == 0)
+ )) {
+ Status = ProcessVarWithPk (VariableName, VendorGuid, Data, DataSize, Attributes, FALSE);
+ if (EFI_ERROR (Status)) {
+ Status = ProcessVarWithKek (VariableName, VendorGuid, Data, DataSize, Attributes);
+ }
+ } else {
+ Status = ProcessVariable (VariableName, VendorGuid, Data, DataSize, Attributes);
+ }
+
+ return Status;
+}
diff --git a/Core/SecurityPkg/Library/AuthVariableLib/AuthVariableLib.inf b/Core/SecurityPkg/Library/AuthVariableLib/AuthVariableLib.inf
new file mode 100644
index 0000000000..572ba4e120
--- /dev/null
+++ b/Core/SecurityPkg/Library/AuthVariableLib/AuthVariableLib.inf
@@ -0,0 +1,92 @@
+## @file
+# Provides authenticated variable services.
+#
+# Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions
+# of the BSD License which accompanies this distribution. The
+# full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = AuthVariableLib
+ MODULE_UNI_FILE = AuthVariableLib.uni
+ FILE_GUID = B23CF5FB-6FCC-4422-B145-D855DBC05457
+ MODULE_TYPE = DXE_RUNTIME_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = AuthVariableLib|DXE_RUNTIME_DRIVER DXE_SMM_DRIVER
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ AuthVariableLib.c
+ AuthService.c
+ AuthServiceInternal.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ SecurityPkg/SecurityPkg.dec
+ CryptoPkg/CryptoPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ MemoryAllocationLib
+ BaseCryptLib
+ PlatformSecureLib
+
+[Guids]
+ ## CONSUMES ## Variable:L"SetupMode"
+ ## PRODUCES ## Variable:L"SetupMode"
+ ## SOMETIMES_CONSUMES ## Variable:L"PK"
+ ## SOMETIMES_CONSUMES ## Variable:L"KEK"
+ ## CONSUMES ## Variable:L"SecureBoot"
+ ## PRODUCES ## Variable:L"SecureBoot"
+ ## CONSUMES ## Variable:L"SignatureSupport"
+ ## PRODUCES ## Variable:L"SignatureSupport"
+ ## PRODUCES ## Variable:L"VendorKeys"
+ gEfiGlobalVariableGuid
+
+ ## SOMETIMES_CONSUMES ## Variable:L"DB"
+ ## SOMETIMES_CONSUMES ## Variable:L"DBX"
+ ## SOMETIMES_CONSUMES ## Variable:L"DBT"
+ gEfiImageSecurityDatabaseGuid
+
+ ## CONSUMES ## Variable:L"SecureBootEnable"
+ ## PRODUCES ## Variable:L"SecureBootEnable"
+ gEfiSecureBootEnableDisableGuid
+
+ ## CONSUMES ## Variable:L"CustomMode"
+ ## PRODUCES ## Variable:L"CustomMode"
+ gEfiCustomModeEnableGuid
+
+ ## CONSUMES ## Variable:L"certdb"
+ ## CONSUMES ## Variable:L"certdbv"
+ ## PRODUCES ## Variable:L"certdb"
+ ## PRODUCES ## Variable:L"certdbv"
+ gEfiCertDbGuid
+
+ ## CONSUMES ## Variable:L"VendorKeysNv"
+ ## PRODUCES ## Variable:L"VendorKeysNv"
+ gEfiVendorKeysNvGuid
+
+ ## CONSUMES ## Variable:L"AuthVarKeyDatabase"
+ ## PRODUCES ## Variable:L"AuthVarKeyDatabase"
+ gEfiAuthenticatedVariableGuid
+
+ gEfiCertTypeRsa2048Sha256Guid ## SOMETIMES_CONSUMES ## GUID # Unique ID for the type of the certificate.
+ gEfiCertPkcs7Guid ## SOMETIMES_CONSUMES ## GUID # Unique ID for the type of the certificate.
+ gEfiCertX509Guid ## SOMETIMES_CONSUMES ## GUID # Unique ID for the type of the signature.
diff --git a/Core/SecurityPkg/Library/AuthVariableLib/AuthVariableLib.uni b/Core/SecurityPkg/Library/AuthVariableLib/AuthVariableLib.uni
new file mode 100644
index 0000000000..59e5b64c4b
--- /dev/null
+++ b/Core/SecurityPkg/Library/AuthVariableLib/AuthVariableLib.uni
@@ -0,0 +1,21 @@
+// /** @file
+// Provides authenticated variable services.
+//
+// Provides authenticated variable services.
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides authenticated variable services"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Provides authenticated variable services."
+
diff --git a/Core/SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.c b/Core/SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.c
new file mode 100644
index 0000000000..02a87f9077
--- /dev/null
+++ b/Core/SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.c
@@ -0,0 +1,933 @@
+/** @file
+ Implement defer image load services for user identification in UEFI2.2.
+
+Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "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;
+}
+
+/**
+ Get file name from device path.
+
+ The file name may contain one or more device path node. Save the file name in a
+ buffer if file name is found. The caller is responsible to free the buffer.
+
+ @param[in] DevicePath A pointer to a device path.
+ @param[out] FileName The callee allocated buffer to save the file name if file name is found.
+ @param[out] FileNameOffset The offset of file name in device path if file name is found.
+
+ @retval UINTN The file name length. 0 means file name is not found.
+
+**/
+UINTN
+GetFileName (
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ OUT UINT8 **FileName,
+ OUT UINTN *FileNameOffset
+ )
+{
+ UINTN Length;
+ EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *RootDevicePath;
+ CHAR8 *NodeStr;
+ UINTN NodeStrLength;
+ CHAR16 LastNodeChar;
+ CHAR16 FirstNodeChar;
+
+ //
+ // Get the length of DevicePath before file name.
+ //
+ Length = 0;
+ RootDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)DevicePath;
+ while (!IsDevicePathEnd (RootDevicePath)) {
+ if ((DevicePathType(RootDevicePath) == MEDIA_DEVICE_PATH) && (DevicePathSubType(RootDevicePath) == MEDIA_FILEPATH_DP)) {
+ break;
+ }
+ Length += DevicePathNodeLength (RootDevicePath);
+ RootDevicePath = NextDevicePathNode (RootDevicePath);
+ }
+
+ *FileNameOffset = Length;
+ if (Length == 0) {
+ return 0;
+ }
+
+ //
+ // Get the file name length.
+ //
+ Length = 0;
+ TmpDevicePath = RootDevicePath;
+ while (!IsDevicePathEnd (TmpDevicePath)) {
+ if ((DevicePathType(TmpDevicePath) != MEDIA_DEVICE_PATH) || (DevicePathSubType(TmpDevicePath) != MEDIA_FILEPATH_DP)) {
+ break;
+ }
+ Length += DevicePathNodeLength (TmpDevicePath) - sizeof (EFI_DEVICE_PATH_PROTOCOL);
+ TmpDevicePath = NextDevicePathNode (TmpDevicePath);
+ }
+ if (Length == 0) {
+ return 0;
+ }
+
+ *FileName = AllocateZeroPool (Length);
+ ASSERT (*FileName != NULL);
+
+ //
+ // Copy the file name to the buffer.
+ //
+ Length = 0;
+ LastNodeChar = '\\';
+ TmpDevicePath = RootDevicePath;
+ while (!IsDevicePathEnd (TmpDevicePath)) {
+ if ((DevicePathType(TmpDevicePath) != MEDIA_DEVICE_PATH) || (DevicePathSubType(TmpDevicePath) != MEDIA_FILEPATH_DP)) {
+ break;
+ }
+
+ FirstNodeChar = (CHAR16) ReadUnaligned16 ((UINT16 *)((UINT8 *)TmpDevicePath + sizeof (EFI_DEVICE_PATH_PROTOCOL)));
+ NodeStr = (CHAR8 *)TmpDevicePath + sizeof (EFI_DEVICE_PATH_PROTOCOL);
+ NodeStrLength = DevicePathNodeLength (TmpDevicePath) - sizeof (EFI_DEVICE_PATH_PROTOCOL) - sizeof(CHAR16);
+
+ if ((FirstNodeChar == '\\') && (LastNodeChar == '\\')) {
+ //
+ // Skip separator "\" when there are two separators.
+ //
+ NodeStr += sizeof (CHAR16);
+ NodeStrLength -= sizeof (CHAR16);
+ } else if ((FirstNodeChar != '\\') && (LastNodeChar != '\\')) {
+ //
+ // Add separator "\" when there is no separator.
+ //
+ WriteUnaligned16 ((UINT16 *)(*FileName + Length), '\\');
+ Length += sizeof (CHAR16);
+ }
+ CopyMem (*FileName + Length, NodeStr, NodeStrLength);
+ Length += NodeStrLength;
+
+ LastNodeChar = (CHAR16) ReadUnaligned16 ((UINT16 *) (NodeStr + NodeStrLength - sizeof(CHAR16)));
+ TmpDevicePath = NextDevicePathNode (TmpDevicePath);
+ }
+
+ return Length;
+}
+
+
+/**
+ 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
+ )
+{
+ UINTN DevicePathSize;
+ UINTN FileNameSize1;
+ UINTN FileNameSize2;
+ UINT8 *FileName1;
+ UINT8 *FileName2;
+ UINTN FileNameOffset1;
+ UINTN FileNameOffset2;
+ BOOLEAN DevicePathEqual;
+
+ FileName1 = NULL;
+ FileName2 = NULL;
+ DevicePathEqual = TRUE;
+
+ ASSERT (DevicePath1 != NULL);
+ ASSERT (DevicePath2 != NULL);
+ if (IsDevicePathEnd (DevicePath1)) {
+ return FALSE;
+ }
+
+ //
+ // The file name may contain one or more device path node.
+ // To compare the file name, copy file name to a buffer and compare the buffer.
+ //
+ FileNameSize1 = GetFileName (DevicePath1, &FileName1, &FileNameOffset1);
+ if (FileNameSize1 != 0) {
+ FileNameSize2 = GetFileName (DevicePath2, &FileName2, &FileNameOffset2);
+ if (FileNameOffset1 != FileNameOffset2) {
+ DevicePathEqual = FALSE;
+ goto Done;
+ }
+ if (CompareMem (DevicePath1, DevicePath2, FileNameOffset1) != 0) {
+ DevicePathEqual = FALSE;
+ goto Done;
+ }
+ if (FileNameSize1 > FileNameSize2) {
+ DevicePathEqual = FALSE;
+ goto Done;
+ }
+ if (CompareMem (FileName1, FileName2, FileNameSize1) != 0) {
+ DevicePathEqual = FALSE;
+ goto Done;
+ }
+ DevicePathEqual = TRUE;
+ goto Done;
+ }
+
+ DevicePathSize = GetDevicePathSize (DevicePath1);
+ if (DevicePathSize > GetDevicePathSize (DevicePath2)) {
+ return FALSE;
+ }
+
+ //
+ // Exclude the end of device path node.
+ //
+ DevicePathSize -= sizeof (EFI_DEVICE_PATH_PROTOCOL);
+ if (CompareMem (DevicePath1, DevicePath2, DevicePathSize) != 0) {
+ DevicePathEqual = FALSE;
+ }
+
+Done:
+ if (FileName1 != NULL) {
+ FreePool (FileName1);
+ }
+ if (FileName2 != NULL) {
+ FreePool (FileName2);
+ }
+ 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 TRUE 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 TRUE 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 TRUE 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);
+ GetEfiGlobalVariable2 (StrTemp, (VOID**)&OptionBuffer, NULL);
+ 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.
+ @param[in] BootPolicy A boot policy that was used to call LoadImage() UEFI service.
+
+ @retval EFI_SUCCESS FileBuffer is NULL and current user has permission to start
+ UEFI device drivers on the device path specified by DevicePath.
+ @retval EFI_SUCCESS The file specified by DevicePath and non-NULL
+ FileBuffer did authenticate, and the platform policy dictates
+ that the DXE Foundation may use the file.
+ @retval EFI_SECURITY_VIOLATION FileBuffer is NULL and the user has no
+ permission to start UEFI device drivers on the device path specified
+ by DevicePath.
+ @retval EFI_SECURITY_VIOLATION FileBuffer is not NULL and the user has no permission to load
+ drivers from the device path specified by DevicePath. The
+ image has been added into the list of the deferred images.
+ @retval EFI_ACCESS_DENIED The file specified by File and FileBuffer did not
+ authenticate, and the platform policy dictates that the DXE
+ Foundation many not use File.
+
+**/
+EFI_STATUS
+EFIAPI
+DxeDeferImageLoadHandler (
+ IN UINT32 AuthenticationStatus,
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *File,
+ IN VOID *FileBuffer,
+ IN UINTN FileSize,
+ IN BOOLEAN BootPolicy
+ )
+{
+ EFI_STATUS Status;
+ EFI_USER_PROFILE_HANDLE CurrentUser;
+ UINT32 Policy;
+ UINT32 FileType;
+
+ //
+ // Ignore if File is NULL.
+ //
+ if (File == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // 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_SECURITY_VIOLATION;
+ }
+ 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_INFO, "[Security] No user identified, the image is deferred to load!\n"));
+ PutDefferedImageInfo (File, FileBuffer, FileSize);
+
+ //
+ // 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 RegisterSecurity2Handler (
+ DxeDeferImageLoadHandler,
+ EFI_AUTH_OPERATION_DEFER_IMAGE_LOAD
+ );
+}
+
+
diff --git a/Core/SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.h b/Core/SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.h
new file mode 100644
index 0000000000..fd750be512
--- /dev/null
+++ b/Core/SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.h
@@ -0,0 +1,105 @@
+/** @file
+ The internal header file includes the common header files, defines
+ internal structure and functions used by DeferImageLoadLib.
+
+Copyright (c) 2009 - 2013, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __DEFER_IMAGE_LOAD_LIB_H__
+#define __DEFER_IMAGE_LOAD_LIB_H__
+
+#include <PiDxe.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/SecurityManagementLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PrintLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+#include <Library/PcdLib.h>
+
+#include <Protocol/FirmwareVolume2.h>
+#include <Protocol/BlockIo.h>
+#include <Protocol/SimpleFileSystem.h>
+#include <Protocol/DeferredImageLoad.h>
+#include <Protocol/UserCredential.h>
+#include <Protocol/UserManager.h>
+
+#include <Guid/GlobalVariable.h>
+
+//
+// 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/Core/SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.inf b/Core/SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.inf
new file mode 100644
index 0000000000..8297230bed
--- /dev/null
+++ b/Core/SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.inf
@@ -0,0 +1,68 @@
+## @file
+# Provides security service of deferred image load
+#
+# The platform may need to defer the execution of an image because of security
+# considerations. These deferred images will be recorded and then reported by
+# installing an instance of the EFI_DEFERRED_IMAGE_LOAD_PROTOCOL.
+#
+# Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeDeferImageLoadLib
+ MODULE_UNI_FILE = DxeDeferImageLoadLib.uni
+ 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 ## SOMETIMES_CONSUMES
+ gEfiBlockIoProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiSimpleFileSystemProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiDeferredImageLoadProtocolGuid ## SOMETIMES_PRODUCES
+ ## SOMETIMES_CONSUMES
+ ## NOTIFY
+ gEfiUserManagerProtocolGuid
+
+[Guids]
+ gEfiGlobalVariableGuid ## SOMETIMES_CONSUMES ## Variable:L"BootOrder"
+
+[Pcd]
+ gEfiSecurityPkgTokenSpaceGuid.PcdDeferImageLoadPolicy ## SOMETIMES_CONSUMES
diff --git a/Core/SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.uni b/Core/SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.uni
new file mode 100644
index 0000000000..fd49a032ea
--- /dev/null
+++ b/Core/SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.uni
@@ -0,0 +1,23 @@
+// /** @file
+// Provides security service of deferred image load
+//
+// The platform may need to defer the execution of an image because of security
+// considerations. These deferred images will be recorded and then reported by
+// installing an instance of the EFI_DEFERRED_IMAGE_LOAD_PROTOCOL.
+//
+// Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides security service of deferred image load"
+
+#string STR_MODULE_DESCRIPTION #language en-US "The platform may need to defer the execution of an image because of security considerations. These deferred images will be recorded and then reported by installing an instance of the EFI_DEFERRED_IMAGE_LOAD_PROTOCOL."
+
diff --git a/Core/SecurityPkg/Library/DxeImageAuthenticationStatusLib/DxeImageAuthenticationStatusLib.c b/Core/SecurityPkg/Library/DxeImageAuthenticationStatusLib/DxeImageAuthenticationStatusLib.c
new file mode 100644
index 0000000000..bc1acd1fed
--- /dev/null
+++ b/Core/SecurityPkg/Library/DxeImageAuthenticationStatusLib/DxeImageAuthenticationStatusLib.c
@@ -0,0 +1,76 @@
+/** @file
+ Implement image authentication status check in UEFI2.3.1.
+
+Copyright (c) 2012, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiDxe.h>
+#include <Library/SecurityManagementLib.h>
+
+
+/**
+ Check image authentication status returned from Section Extraction Protocol
+
+ @param[in] AuthenticationStatus This is the authentication status returned from
+ the Section Extraction Protocol when reading 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.
+ @param[in] BootPolicy A boot policy that was used to call LoadImage() UEFI service.
+
+ @retval EFI_SUCCESS The input file specified by File did authenticate, and the
+ platform policy dictates that the DXE Core may use File.
+ @retval EFI_ACCESS_DENIED The file specified by File and FileBuffer did not
+ authenticate, and the platform policy dictates that the DXE
+ Foundation many not use File.
+
+**/
+EFI_STATUS
+EFIAPI
+DxeImageAuthenticationStatusHandler (
+ IN UINT32 AuthenticationStatus,
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *File,
+ IN VOID *FileBuffer,
+ IN UINTN FileSize,
+ IN BOOLEAN BootPolicy
+ )
+{
+ if ((AuthenticationStatus & EFI_AUTH_STATUS_IMAGE_SIGNED) != 0) {
+ if ((AuthenticationStatus & (EFI_AUTH_STATUS_TEST_FAILED | EFI_AUTH_STATUS_NOT_TESTED)) != 0) {
+ return EFI_ACCESS_DENIED;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Register image authenticaion status check 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
+DxeImageAuthenticationStatusLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ return RegisterSecurity2Handler (
+ DxeImageAuthenticationStatusHandler,
+ EFI_AUTH_OPERATION_AUTHENTICATION_STATE
+ );
+}
diff --git a/Core/SecurityPkg/Library/DxeImageAuthenticationStatusLib/DxeImageAuthenticationStatusLib.inf b/Core/SecurityPkg/Library/DxeImageAuthenticationStatusLib/DxeImageAuthenticationStatusLib.inf
new file mode 100644
index 0000000000..62fcdaacc6
--- /dev/null
+++ b/Core/SecurityPkg/Library/DxeImageAuthenticationStatusLib/DxeImageAuthenticationStatusLib.inf
@@ -0,0 +1,40 @@
+## @file
+# Provides security service of image authentication status check
+#
+# Authentication Status Library module supports UEFI2.3.1
+#
+# Copyright (c) 2012 - 2014, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeImageAuthenticationStatusLib
+ MODULE_UNI_FILE = DxeImageAuthenticationStatusLib.uni
+ FILE_GUID = EB92D1DE-7C36-4680-BB88-A67E96049F72
+ 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 = DxeImageAuthenticationStatusLibConstructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ DxeImageAuthenticationStatusLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ SecurityManagementLib
diff --git a/Core/SecurityPkg/Library/DxeImageAuthenticationStatusLib/DxeImageAuthenticationStatusLib.uni b/Core/SecurityPkg/Library/DxeImageAuthenticationStatusLib/DxeImageAuthenticationStatusLib.uni
new file mode 100644
index 0000000000..4c5c74ce40
--- /dev/null
+++ b/Core/SecurityPkg/Library/DxeImageAuthenticationStatusLib/DxeImageAuthenticationStatusLib.uni
@@ -0,0 +1,21 @@
+// /** @file
+// Provides security service of image authentication status check
+//
+// Authentication Status Library module supports UEFI2.3.1
+//
+// Copyright (c) 2012 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides security service of image authentication status check"
+
+#string STR_MODULE_DESCRIPTION #language en-US "The Authentication Status Library module supports UEFI2.3.1."
+
diff --git a/Core/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c b/Core/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c
new file mode 100644
index 0000000000..588072c6a1
--- /dev/null
+++ b/Core/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c
@@ -0,0 +1,1999 @@
+/** @file
+ Implement image verification services for secure boot service
+
+ Caution: This file requires additional review when modified.
+ This library will have external input - PE/COFF image.
+ This external input must be validated carefully to avoid security issue like
+ buffer overflow, integer overflow.
+
+ DxeImageVerificationLibImageRead() function will make sure the PE/COFF image content
+ read is within the image buffer.
+
+ DxeImageVerificationHandler(), HashPeImageByType(), HashPeImage() function will accept
+ untrusted PE/COFF image and validate its data structure within this image buffer before use.
+
+Copyright (c) 2009 - 2017, Intel Corporation. All rights reserved.<BR>
+(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "DxeImageVerificationLib.h"
+
+//
+// Caution: This is used by a function which may receive untrusted input.
+// These global variables hold PE/COFF image data, and they should be validated before use.
+//
+EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION mNtHeader;
+UINT32 mPeCoffHeaderOffset;
+EFI_GUID mCertType;
+
+//
+// Information on current PE/COFF image
+//
+UINTN mImageSize;
+UINT8 *mImageBase = NULL;
+UINT8 mImageDigest[MAX_DIGEST_SIZE];
+UINTN mImageDigestSize;
+
+//
+// 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[] = {
+ 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[0], 5, Sha1GetContextSize, Sha1Init, Sha1Update, Sha1Final },
+ { L"SHA224", 28, &mHashOidValue[5], 9, NULL, NULL, NULL, NULL },
+ { L"SHA256", 32, &mHashOidValue[14], 9, Sha256GetContextSize, Sha256Init, Sha256Update, Sha256Final},
+ { L"SHA384", 48, &mHashOidValue[23], 9, Sha384GetContextSize, Sha384Init, Sha384Update, Sha384Final},
+ { L"SHA512", 64, &mHashOidValue[32], 9, Sha512GetContextSize, Sha512Init, Sha512Update, Sha512Final}
+};
+
+EFI_STRING mHashTypeStr;
+
+/**
+ SecureBoot Hook for processing image verification.
+
+ @param[in] VariableName Name of Variable to be found.
+ @param[in] VendorGuid Variable vendor GUID.
+ @param[in] DataSize Size of Data found. If size is less than the
+ data, this value contains the required size.
+ @param[in] Data Data pointer.
+
+**/
+VOID
+EFIAPI
+SecureBootHook (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINTN DataSize,
+ IN VOID *Data
+ );
+
+/**
+ Reads contents of a PE/COFF image in memory buffer.
+
+ Caution: This function may receive untrusted input.
+ PE/COFF image is external input, so this function will make sure the PE/COFF image content
+ read is within the image 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
+DxeImageVerificationLibImageRead (
+ IN VOID *FileHandle,
+ IN UINTN FileOffset,
+ IN OUT UINTN *ReadSize,
+ OUT VOID *Buffer
+ )
+{
+ UINTN EndPosition;
+
+ if (FileHandle == NULL || ReadSize == NULL || Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (MAX_ADDRESS - FileOffset < *ReadSize) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ EndPosition = FileOffset + *ReadSize;
+ if (EndPosition > mImageSize) {
+ *ReadSize = (UINT32)(mImageSize - FileOffset);
+ }
+
+ if (FileOffset >= mImageSize) {
+ *ReadSize = 0;
+ }
+
+ CopyMem (Buffer, (UINT8 *)((UINTN) FileHandle + FileOffset), *ReadSize);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ 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;
+
+ if (File == NULL) {
+ return IMAGE_UNKNOWN;
+ }
+
+ //
+ // 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;
+}
+
+/**
+ Calculate hash of Pe/Coff image based on the authenticode image hashing in
+ PE/COFF Specification 8.0 Appendix A
+
+ Caution: This function may receive untrusted input.
+ PE/COFF image is external input, so this function will validate its data structure
+ within this image buffer before use.
+
+ Notes: PE/COFF image has been checked by BasePeCoffLib PeCoffLoaderGetImageInfo() in
+ its caller function DxeImageVerificationHandler().
+
+ @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;
+ UINT32 CertSize;
+ UINT32 NumberOfRvaAndSizes;
+
+ HashCtx = NULL;
+ SectionHeader = NULL;
+ Status = FALSE;
+
+ if ((HashAlg >= HASHALG_MAX)) {
+ return FALSE;
+ }
+
+ //
+ // Initialize context of hash.
+ //
+ ZeroMem (mImageDigest, MAX_DIGEST_SIZE);
+
+ switch (HashAlg) {
+ case HASHALG_SHA1:
+ mImageDigestSize = SHA1_DIGEST_SIZE;
+ mCertType = gEfiCertSha1Guid;
+ break;
+
+ case HASHALG_SHA256:
+ mImageDigestSize = SHA256_DIGEST_SIZE;
+ mCertType = gEfiCertSha256Guid;
+ break;
+
+ case HASHALG_SHA384:
+ mImageDigestSize = SHA384_DIGEST_SIZE;
+ mCertType = gEfiCertSha384Guid;
+ break;
+
+ case HASHALG_SHA512:
+ mImageDigestSize = SHA512_DIGEST_SIZE;
+ mCertType = gEfiCertSha512Guid;
+ break;
+
+ default:
+ return FALSE;
+ }
+
+ mHashTypeStr = mHash[HashAlg].Name;
+ CtxSize = mHash[HashAlg].GetContextSize();
+
+ HashCtx = AllocatePool (CtxSize);
+ if (HashCtx == NULL) {
+ return FALSE;
+ }
+
+ // 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
+ //
+ if (mNtHeader.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ //
+ // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value
+ // in the PE/COFF Header. If the MachineType is Itanium(IA64) and the
+ // Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
+ // then override the magic value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
+ //
+ Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;
+ } else {
+ //
+ // Get the magic value from the PE/COFF Optional Header
+ //
+ 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) (&mNtHeader.Pe32->OptionalHeader.CheckSum) - (UINTN) HashBase;
+ NumberOfRvaAndSizes = mNtHeader.Pe32->OptionalHeader.NumberOfRvaAndSizes;
+ } else if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
+ //
+ // Use PE32+ offset.
+ //
+ HashSize = (UINTN) (&mNtHeader.Pe32Plus->OptionalHeader.CheckSum) - (UINTN) HashBase;
+ NumberOfRvaAndSizes = mNtHeader.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
+ } else {
+ //
+ // Invalid header magic number.
+ //
+ Status = FALSE;
+ goto Done;
+ }
+
+ Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);
+ if (!Status) {
+ goto Done;
+ }
+
+ //
+ // 5. Skip over the image checksum (it occupies a single ULONG).
+ //
+ if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {
+ //
+ // 6. Since there is no Cert Directory in optional header, hash everything
+ // from the end of the checksum to the end of image header.
+ //
+ if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ //
+ // Use PE32 offset.
+ //
+ HashBase = (UINT8 *) &mNtHeader.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);
+ HashSize = mNtHeader.Pe32->OptionalHeader.SizeOfHeaders - ((UINTN) HashBase - (UINTN) mImageBase);
+ } else {
+ //
+ // Use PE32+ offset.
+ //
+ HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);
+ HashSize = mNtHeader.Pe32Plus->OptionalHeader.SizeOfHeaders - ((UINTN) HashBase - (UINTN) mImageBase);
+ }
+
+ if (HashSize != 0) {
+ Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);
+ if (!Status) {
+ goto Done;
+ }
+ }
+ } else {
+ //
+ // 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) (&mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - (UINTN) HashBase;
+ } else {
+ //
+ // Use PE32+ offset.
+ //
+ HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);
+ HashSize = (UINTN) (&mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - (UINTN) HashBase;
+ }
+
+ if (HashSize != 0) {
+ 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) HashBase - (UINTN) mImageBase);
+ } else {
+ //
+ // Use PE32+ offset.
+ //
+ HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];
+ HashSize = mNtHeader.Pe32Plus->OptionalHeader.SizeOfHeaders - ((UINTN) HashBase - (UINTN) mImageBase);
+ }
+
+ if (HashSize != 0) {
+ 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;
+ }
+
+
+ Section = (EFI_IMAGE_SECTION_HEADER *) (
+ mImageBase +
+ mPeCoffHeaderOffset +
+ sizeof (UINT32) +
+ sizeof (EFI_IMAGE_FILE_HEADER) +
+ mNtHeader.Pe32->FileHeader.SizeOfOptionalHeader
+ );
+
+ //
+ // 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);
+ if (SectionHeader == NULL) {
+ Status = FALSE;
+ goto Done;
+ }
+ //
+ // 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.
+ //
+ 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 (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {
+ CertSize = 0;
+ } else {
+ if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ //
+ // Use PE32 offset.
+ //
+ CertSize = mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size;
+ } else {
+ //
+ // Use PE32+ offset.
+ //
+ CertSize = mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size;
+ }
+ }
+
+ if (mImageSize > CertSize + SumOfBytesHashed) {
+ HashSize = (UINTN) (mImageSize - CertSize - SumOfBytesHashed);
+
+ Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);
+ if (!Status) {
+ goto Done;
+ }
+ } else if (mImageSize < CertSize + SumOfBytesHashed) {
+ Status = FALSE;
+ 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 calculate hash of
+ Pe/Coff image based on the authenticode image hashing in PE/COFF Specification
+ 8.0 Appendix A
+
+ Caution: This function may receive untrusted input.
+ PE/COFF image is external input, so this function will validate its data structure
+ within this image buffer before use.
+
+ @param[in] AuthData Pointer to the Authenticode Signature retrieved from signed image.
+ @param[in] AuthDataSize Size of the Authenticode Signature in bytes.
+
+ @retval EFI_UNSUPPORTED Hash algorithm is not supported.
+ @retval EFI_SUCCESS Hash successfully.
+
+**/
+EFI_STATUS
+HashPeImageByType (
+ IN UINT8 *AuthData,
+ IN UINTN AuthDataSize
+ )
+{
+ UINT8 Index;
+
+ 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.
+ // Fixed offset (+32) is calculated based on two bytes of length encoding.
+ //
+ if ((*(AuthData + 1) & TWO_BYTE_ENCODE) != TWO_BYTE_ENCODE) {
+ //
+ // Only support two bytes of Long Form of Length Encoding.
+ //
+ continue;
+ }
+
+ if (AuthDataSize < 32 + mHash[Index].OidLength) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (CompareMem (AuthData + 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_IMAGE_EXECUTION_INFO_TABLE *ImageExeInfoTable;
+ EFI_IMAGE_EXECUTION_INFO_TABLE *NewImageExeInfoTable;
+ EFI_IMAGE_EXECUTION_INFO *ImageExeInfoEntry;
+ UINTN ImageExeInfoTableSize;
+ UINTN NewImageExeInfoEntrySize;
+ UINTN NameStringLen;
+ UINTN DevicePathSize;
+ CHAR16 *NameStr;
+
+ ImageExeInfoTable = NULL;
+ NewImageExeInfoTable = NULL;
+ ImageExeInfoEntry = NULL;
+ NameStringLen = 0;
+ NameStr = NULL;
+
+ if (DevicePath == NULL) {
+ return ;
+ }
+
+ if (Name != NULL) {
+ NameStringLen = StrSize (Name);
+ } else {
+ NameStringLen = sizeof (CHAR16);
+ }
+
+ EfiGetSystemConfigurationTable (&gEfiImageSecurityDatabaseGuid, (VOID **) &ImageExeInfoTable);
+ if (ImageExeInfoTable != NULL) {
+ //
+ // The table has been found!
+ // We must enlarge the table to accomodate 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);
+
+ //
+ // Signature size can be odd. Pad after signature to ensure next EXECUTION_INFO entry align
+ //
+ NewImageExeInfoEntrySize = sizeof (EFI_IMAGE_EXECUTION_INFO) + NameStringLen + DevicePathSize + SignatureSize;
+
+ NewImageExeInfoTable = (EFI_IMAGE_EXECUTION_INFO_TABLE *) AllocateRuntimePool (ImageExeInfoTableSize + NewImageExeInfoEntrySize);
+ if (NewImageExeInfoTable == NULL) {
+ return ;
+ }
+
+ 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 information.
+ //
+ WriteUnaligned32 ((UINT32 *) ImageExeInfoEntry, Action);
+ WriteUnaligned32 ((UINT32 *) ((UINT8 *) ImageExeInfoEntry + sizeof (EFI_IMAGE_EXECUTION_ACTION)), (UINT32) NewImageExeInfoEntrySize);
+
+ NameStr = (CHAR16 *)(ImageExeInfoEntry + 1);
+ if (Name != NULL) {
+ CopyMem ((UINT8 *) NameStr, Name, NameStringLen);
+ } else {
+ ZeroMem ((UINT8 *) NameStr, sizeof (CHAR16));
+ }
+
+ CopyMem (
+ (UINT8 *) NameStr + NameStringLen,
+ DevicePath,
+ DevicePathSize
+ );
+ if (Signature != NULL) {
+ CopyMem (
+ (UINT8 *) NameStr + NameStringLen + DevicePathSize,
+ Signature,
+ SignatureSize
+ );
+ }
+ //
+ // Update/replace the image execution table.
+ //
+ gBS->InstallConfigurationTable (&gEfiImageSecurityDatabaseGuid, (VOID *) NewImageExeInfoTable);
+
+ //
+ // Free Old table data!
+ //
+ if (ImageExeInfoTable != NULL) {
+ FreePool (ImageExeInfoTable);
+ }
+}
+
+/**
+ Check whether the hash of an given X.509 certificate is in forbidden database (DBX).
+
+ @param[in] Certificate Pointer to X.509 Certificate that is searched for.
+ @param[in] CertSize Size of X.509 Certificate.
+ @param[in] SignatureList Pointer to the Signature List in forbidden database.
+ @param[in] SignatureListSize Size of Signature List.
+ @param[out] RevocationTime Return the time that the certificate was revoked.
+
+ @return TRUE The certificate hash is found in the forbidden database.
+ @return FALSE The certificate hash is not found in the forbidden database.
+
+**/
+BOOLEAN
+IsCertHashFoundInDatabase (
+ IN UINT8 *Certificate,
+ IN UINTN CertSize,
+ IN EFI_SIGNATURE_LIST *SignatureList,
+ IN UINTN SignatureListSize,
+ OUT EFI_TIME *RevocationTime
+ )
+{
+ BOOLEAN IsFound;
+ BOOLEAN Status;
+ EFI_SIGNATURE_LIST *DbxList;
+ UINTN DbxSize;
+ EFI_SIGNATURE_DATA *CertHash;
+ UINTN CertHashCount;
+ UINTN Index;
+ UINT32 HashAlg;
+ VOID *HashCtx;
+ UINT8 CertDigest[MAX_DIGEST_SIZE];
+ UINT8 *DbxCertHash;
+ UINTN SiglistHeaderSize;
+ UINT8 *TBSCert;
+ UINTN TBSCertSize;
+
+ IsFound = FALSE;
+ DbxList = SignatureList;
+ DbxSize = SignatureListSize;
+ HashCtx = NULL;
+ HashAlg = HASHALG_MAX;
+
+ if ((RevocationTime == NULL) || (DbxList == NULL)) {
+ return FALSE;
+ }
+
+ //
+ // Retrieve the TBSCertificate from the X.509 Certificate.
+ //
+ if (!X509GetTBSCert (Certificate, CertSize, &TBSCert, &TBSCertSize)) {
+ return FALSE;
+ }
+
+ while ((DbxSize > 0) && (SignatureListSize >= DbxList->SignatureListSize)) {
+ //
+ // Determine Hash Algorithm of Certificate in the forbidden database.
+ //
+ if (CompareGuid (&DbxList->SignatureType, &gEfiCertX509Sha256Guid)) {
+ HashAlg = HASHALG_SHA256;
+ } else if (CompareGuid (&DbxList->SignatureType, &gEfiCertX509Sha384Guid)) {
+ HashAlg = HASHALG_SHA384;
+ } else if (CompareGuid (&DbxList->SignatureType, &gEfiCertX509Sha512Guid)) {
+ HashAlg = HASHALG_SHA512;
+ } else {
+ DbxSize -= DbxList->SignatureListSize;
+ DbxList = (EFI_SIGNATURE_LIST *) ((UINT8 *) DbxList + DbxList->SignatureListSize);
+ continue;
+ }
+
+ //
+ // Calculate the hash value of current TBSCertificate for comparision.
+ //
+ if (mHash[HashAlg].GetContextSize == NULL) {
+ goto Done;
+ }
+ ZeroMem (CertDigest, MAX_DIGEST_SIZE);
+ HashCtx = AllocatePool (mHash[HashAlg].GetContextSize ());
+ if (HashCtx == NULL) {
+ goto Done;
+ }
+ Status = mHash[HashAlg].HashInit (HashCtx);
+ if (!Status) {
+ goto Done;
+ }
+ Status = mHash[HashAlg].HashUpdate (HashCtx, TBSCert, TBSCertSize);
+ if (!Status) {
+ goto Done;
+ }
+ Status = mHash[HashAlg].HashFinal (HashCtx, CertDigest);
+ if (!Status) {
+ goto Done;
+ }
+
+ SiglistHeaderSize = sizeof (EFI_SIGNATURE_LIST) + DbxList->SignatureHeaderSize;
+ CertHash = (EFI_SIGNATURE_DATA *) ((UINT8 *) DbxList + SiglistHeaderSize);
+ CertHashCount = (DbxList->SignatureListSize - SiglistHeaderSize) / DbxList->SignatureSize;
+ for (Index = 0; Index < CertHashCount; Index++) {
+ //
+ // Iterate each Signature Data Node within this CertList for verify.
+ //
+ DbxCertHash = CertHash->SignatureData;
+ if (CompareMem (DbxCertHash, CertDigest, mHash[HashAlg].DigestLength) == 0) {
+ //
+ // Hash of Certificate is found in forbidden database.
+ //
+ IsFound = TRUE;
+
+ //
+ // Return the revocation time.
+ //
+ CopyMem (RevocationTime, (EFI_TIME *)(DbxCertHash + mHash[HashAlg].DigestLength), sizeof (EFI_TIME));
+ goto Done;
+ }
+ CertHash = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertHash + DbxList->SignatureSize);
+ }
+
+ DbxSize -= DbxList->SignatureListSize;
+ DbxList = (EFI_SIGNATURE_LIST *) ((UINT8 *) DbxList + DbxList->SignatureListSize);
+ }
+
+Done:
+ if (HashCtx != NULL) {
+ FreePool (HashCtx);
+ }
+
+ return IsFound;
+}
+
+/**
+ 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);
+ if (Data == NULL) {
+ return FALSE;
+ }
+
+ 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 - sizeof (EFI_SIGNATURE_LIST) - 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;
+ //
+ // Entries in UEFI_IMAGE_SECURITY_DATABASE that are used to validate image should be measured
+ //
+ if (StrCmp(VariableName, EFI_IMAGE_SECURITY_DATABASE) == 0) {
+ SecureBootHook (VariableName, &gEfiImageSecurityDatabaseGuid, CertList->SignatureSize, Cert);
+ }
+ 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;
+}
+
+/**
+ Check whether the timestamp is valid by comparing the signing time and the revocation time.
+
+ @param SigningTime A pointer to the signing time.
+ @param RevocationTime A pointer to the revocation time.
+
+ @retval TRUE The SigningTime is not later than the RevocationTime.
+ @retval FALSE The SigningTime is later than the RevocationTime.
+
+**/
+BOOLEAN
+IsValidSignatureByTimestamp (
+ IN EFI_TIME *SigningTime,
+ IN EFI_TIME *RevocationTime
+ )
+{
+ if (SigningTime->Year != RevocationTime->Year) {
+ return (BOOLEAN) (SigningTime->Year < RevocationTime->Year);
+ } else if (SigningTime->Month != RevocationTime->Month) {
+ return (BOOLEAN) (SigningTime->Month < RevocationTime->Month);
+ } else if (SigningTime->Day != RevocationTime->Day) {
+ return (BOOLEAN) (SigningTime->Day < RevocationTime->Day);
+ } else if (SigningTime->Hour != RevocationTime->Hour) {
+ return (BOOLEAN) (SigningTime->Hour < RevocationTime->Hour);
+ } else if (SigningTime->Minute != RevocationTime->Minute) {
+ return (BOOLEAN) (SigningTime->Minute < RevocationTime->Minute);
+ }
+
+ return (BOOLEAN) (SigningTime->Second <= RevocationTime->Second);
+}
+
+/**
+ Check if the given time value is zero.
+
+ @param[in] Time Pointer of a time value.
+
+ @retval TRUE The Time is Zero.
+ @retval FALSE The Time is not Zero.
+
+**/
+BOOLEAN
+IsTimeZero (
+ IN EFI_TIME *Time
+ )
+{
+ if ((Time->Year == 0) && (Time->Month == 0) && (Time->Day == 0) &&
+ (Time->Hour == 0) && (Time->Minute == 0) && (Time->Second == 0)) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Check whether the timestamp signature is valid and the signing time is also earlier than
+ the revocation time.
+
+ @param[in] AuthData Pointer to the Authenticode signature retrieved from signed image.
+ @param[in] AuthDataSize Size of the Authenticode signature in bytes.
+ @param[in] RevocationTime The time that the certificate was revoked.
+
+ @retval TRUE Timestamp signature is valid and signing time is no later than the
+ revocation time.
+ @retval FALSE Timestamp signature is not valid or the signing time is later than the
+ revocation time.
+
+**/
+BOOLEAN
+PassTimestampCheck (
+ IN UINT8 *AuthData,
+ IN UINTN AuthDataSize,
+ IN EFI_TIME *RevocationTime
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN VerifyStatus;
+ EFI_SIGNATURE_LIST *CertList;
+ EFI_SIGNATURE_DATA *Cert;
+ UINT8 *DbtData;
+ UINTN DbtDataSize;
+ UINT8 *RootCert;
+ UINTN RootCertSize;
+ UINTN Index;
+ UINTN CertCount;
+ EFI_TIME SigningTime;
+
+ //
+ // Variable Initialization
+ //
+ VerifyStatus = FALSE;
+ DbtData = NULL;
+ CertList = NULL;
+ Cert = NULL;
+ RootCert = NULL;
+ RootCertSize = 0;
+
+ //
+ // If RevocationTime is zero, the certificate shall be considered to always be revoked.
+ //
+ if (IsTimeZero (RevocationTime)) {
+ return FALSE;
+ }
+
+ //
+ // RevocationTime is non-zero, the certificate should be considered to be revoked from that time and onwards.
+ // Using the dbt to get the trusted TSA certificates.
+ //
+ DbtDataSize = 0;
+ Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE2, &gEfiImageSecurityDatabaseGuid, NULL, &DbtDataSize, NULL);
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ goto Done;
+ }
+ DbtData = (UINT8 *) AllocateZeroPool (DbtDataSize);
+ if (DbtData == NULL) {
+ goto Done;
+ }
+ Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE2, &gEfiImageSecurityDatabaseGuid, NULL, &DbtDataSize, (VOID *) DbtData);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ CertList = (EFI_SIGNATURE_LIST *) DbtData;
+ while ((DbtDataSize > 0) && (DbtDataSize >= 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 verify.
+ //
+ RootCert = Cert->SignatureData;
+ RootCertSize = CertList->SignatureSize - sizeof (EFI_GUID);
+ //
+ // Get the signing time if the timestamp signature is valid.
+ //
+ if (ImageTimestampVerify (AuthData, AuthDataSize, RootCert, RootCertSize, &SigningTime)) {
+ //
+ // The signer signature is valid only when the signing time is earlier than revocation time.
+ //
+ if (IsValidSignatureByTimestamp (&SigningTime, RevocationTime)) {
+ VerifyStatus = TRUE;
+ goto Done;
+ }
+ }
+ Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);
+ }
+ }
+ DbtDataSize -= CertList->SignatureListSize;
+ CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
+ }
+
+Done:
+ if (DbtData != NULL) {
+ FreePool (DbtData);
+ }
+
+ return VerifyStatus;
+}
+
+/**
+ Check whether the image signature is forbidden by the forbidden database (dbx).
+ The image is forbidden to load if any certificates for signing are revoked before signing time.
+
+ @param[in] AuthData Pointer to the Authenticode signature retrieved from the signed image.
+ @param[in] AuthDataSize Size of the Authenticode signature in bytes.
+
+ @retval TRUE Image is forbidden by dbx.
+ @retval FALSE Image is not forbidden by dbx.
+
+**/
+BOOLEAN
+IsForbiddenByDbx (
+ IN UINT8 *AuthData,
+ IN UINTN AuthDataSize
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN IsForbidden;
+ UINT8 *Data;
+ UINTN DataSize;
+ EFI_SIGNATURE_LIST *CertList;
+ UINTN CertListSize;
+ EFI_SIGNATURE_DATA *CertData;
+ UINT8 *RootCert;
+ UINTN RootCertSize;
+ UINTN CertCount;
+ UINTN Index;
+ UINT8 *CertBuffer;
+ UINTN BufferLength;
+ UINT8 *TrustedCert;
+ UINTN TrustedCertLength;
+ UINT8 CertNumber;
+ UINT8 *CertPtr;
+ UINT8 *Cert;
+ UINTN CertSize;
+ EFI_TIME RevocationTime;
+ //
+ // Variable Initialization
+ //
+ IsForbidden = FALSE;
+ Data = NULL;
+ CertList = NULL;
+ CertData = NULL;
+ RootCert = NULL;
+ RootCertSize = 0;
+ Cert = NULL;
+ CertBuffer = NULL;
+ BufferLength = 0;
+ TrustedCert = NULL;
+ TrustedCertLength = 0;
+
+ //
+ // The image will not be forbidden if dbx can't be got.
+ //
+ DataSize = 0;
+ Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, NULL);
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ return IsForbidden;
+ }
+ Data = (UINT8 *) AllocateZeroPool (DataSize);
+ if (Data == NULL) {
+ return IsForbidden;
+ }
+
+ Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, (VOID *) Data);
+ if (EFI_ERROR (Status)) {
+ return IsForbidden;
+ }
+
+ //
+ // Verify image signature with RAW X509 certificates in DBX database.
+ // If passed, the image will be forbidden.
+ //
+ CertList = (EFI_SIGNATURE_LIST *) Data;
+ CertListSize = DataSize;
+ while ((CertListSize > 0) && (CertListSize >= CertList->SignatureListSize)) {
+ if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {
+ CertData = (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 verify.
+ //
+ RootCert = CertData->SignatureData;
+ RootCertSize = CertList->SignatureSize - sizeof (EFI_GUID);
+
+ //
+ // Call AuthenticodeVerify library to Verify Authenticode struct.
+ //
+ IsForbidden = AuthenticodeVerify (
+ AuthData,
+ AuthDataSize,
+ RootCert,
+ RootCertSize,
+ mImageDigest,
+ mImageDigestSize
+ );
+ if (IsForbidden) {
+ DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Image is signed but signature is forbidden by DBX.\n"));
+ goto Done;
+ }
+
+ CertData = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertData + CertList->SignatureSize);
+ }
+ }
+
+ CertListSize -= CertList->SignatureListSize;
+ CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
+ }
+
+ //
+ // Check X.509 Certificate Hash & Possible Timestamp.
+ //
+
+ //
+ // Retrieve the certificate stack from AuthData
+ // The output CertStack format will be:
+ // UINT8 CertNumber;
+ // UINT32 Cert1Length;
+ // UINT8 Cert1[];
+ // UINT32 Cert2Length;
+ // UINT8 Cert2[];
+ // ...
+ // UINT32 CertnLength;
+ // UINT8 Certn[];
+ //
+ Pkcs7GetSigners (AuthData, AuthDataSize, &CertBuffer, &BufferLength, &TrustedCert, &TrustedCertLength);
+ if ((BufferLength == 0) || (CertBuffer == NULL)) {
+ IsForbidden = TRUE;
+ goto Done;
+ }
+
+ //
+ // Check if any hash of certificates embedded in AuthData is in the forbidden database.
+ //
+ CertNumber = (UINT8) (*CertBuffer);
+ CertPtr = CertBuffer + 1;
+ for (Index = 0; Index < CertNumber; Index++) {
+ CertSize = (UINTN) ReadUnaligned32 ((UINT32 *)CertPtr);
+ Cert = (UINT8 *)CertPtr + sizeof (UINT32);
+ //
+ // Advance CertPtr to the next cert in image signer's cert list
+ //
+ CertPtr = CertPtr + sizeof (UINT32) + CertSize;
+
+ if (IsCertHashFoundInDatabase (Cert, CertSize, (EFI_SIGNATURE_LIST *)Data, DataSize, &RevocationTime)) {
+ //
+ // Check the timestamp signature and signing time to determine if the image can be trusted.
+ //
+ IsForbidden = TRUE;
+ if (PassTimestampCheck (AuthData, AuthDataSize, &RevocationTime)) {
+ IsForbidden = FALSE;
+ //
+ // Pass DBT check. Continue to check other certs in image signer's cert list against DBX, DBT
+ //
+ continue;
+ }
+ DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Image is signed but signature failed the timestamp check.\n"));
+ goto Done;
+ }
+
+ }
+
+Done:
+ if (Data != NULL) {
+ FreePool (Data);
+ }
+
+ Pkcs7FreeSigners (CertBuffer);
+ Pkcs7FreeSigners (TrustedCert);
+
+ return IsForbidden;
+}
+
+
+/**
+ Check whether the image signature can be verified by the trusted certificates in DB database.
+
+ @param[in] AuthData Pointer to the Authenticode signature retrieved from signed image.
+ @param[in] AuthDataSize Size of the Authenticode signature in bytes.
+
+ @retval TRUE Image passed verification using certificate in db.
+ @retval FALSE Image didn't pass verification using certificate in db.
+
+**/
+BOOLEAN
+IsAllowedByDb (
+ IN UINT8 *AuthData,
+ IN UINTN AuthDataSize
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN VerifyStatus;
+ EFI_SIGNATURE_LIST *CertList;
+ EFI_SIGNATURE_DATA *CertData;
+ UINTN DataSize;
+ UINT8 *Data;
+ UINT8 *RootCert;
+ UINTN RootCertSize;
+ UINTN Index;
+ UINTN CertCount;
+ UINTN DbxDataSize;
+ UINT8 *DbxData;
+ EFI_TIME RevocationTime;
+
+ Data = NULL;
+ CertList = NULL;
+ CertData = NULL;
+ RootCert = NULL;
+ DbxData = NULL;
+ RootCertSize = 0;
+ VerifyStatus = FALSE;
+
+ DataSize = 0;
+ Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, NULL);
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ Data = (UINT8 *) AllocateZeroPool (DataSize);
+ if (Data == NULL) {
+ return VerifyStatus;
+ }
+
+ Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, (VOID *) Data);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Find X509 certificate in Signature List to verify the signature in pkcs7 signed data.
+ //
+ CertList = (EFI_SIGNATURE_LIST *) Data;
+ while ((DataSize > 0) && (DataSize >= CertList->SignatureListSize)) {
+ if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {
+ CertData = (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 verify.
+ //
+ RootCert = CertData->SignatureData;
+ RootCertSize = CertList->SignatureSize - sizeof (EFI_GUID);
+
+ //
+ // Call AuthenticodeVerify library to Verify Authenticode struct.
+ //
+ VerifyStatus = AuthenticodeVerify (
+ AuthData,
+ AuthDataSize,
+ RootCert,
+ RootCertSize,
+ mImageDigest,
+ mImageDigestSize
+ );
+ if (VerifyStatus) {
+ //
+ // Here We still need to check if this RootCert's Hash is revoked
+ //
+ Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, NULL, &DbxDataSize, NULL);
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ goto Done;
+ }
+ DbxData = (UINT8 *) AllocateZeroPool (DbxDataSize);
+ if (DbxData == NULL) {
+ goto Done;
+ }
+
+ Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, NULL, &DbxDataSize, (VOID *) DbxData);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ if (IsCertHashFoundInDatabase (RootCert, RootCertSize, (EFI_SIGNATURE_LIST *)DbxData, DbxDataSize, &RevocationTime)) {
+ //
+ // Check the timestamp signature and signing time to determine if the RootCert can be trusted.
+ //
+ VerifyStatus = PassTimestampCheck (AuthData, AuthDataSize, &RevocationTime);
+ if (!VerifyStatus) {
+ DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Image is signed and signature is accepted by DB, but its root cert failed the timestamp check.\n"));
+ }
+ }
+
+ goto Done;
+ }
+
+ CertData = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertData + CertList->SignatureSize);
+ }
+ }
+
+ DataSize -= CertList->SignatureListSize;
+ CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
+ }
+ }
+
+Done:
+
+ if (VerifyStatus) {
+ SecureBootHook (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid, CertList->SignatureSize, CertData);
+ }
+
+ if (Data != NULL) {
+ FreePool (Data);
+ }
+ if (DbxData != NULL) {
+ FreePool (DbxData);
+ }
+
+ return VerifyStatus;
+}
+
+/**
+ 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.
+
+ The image verification policy is:
+ If the image is signed,
+ At least one valid signature or at least one hash value of the image must match a record
+ in the security database "db", and no valid signature nor any hash value of the image may
+ be reflected in the security database "dbx".
+ Otherwise, the image is not signed,
+ The SHA256 hash value of the image must match a record in the security database "db", and
+ not be reflected in the security data base "dbx".
+
+ Caution: This function may receive untrusted input.
+ PE/COFF image is external input, so this function will validate its data structure
+ within this image buffer before use.
+
+ @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.
+ @param[in] BootPolicy A boot policy that was used to call LoadImage() UEFI service.
+
+ @retval EFI_SUCCESS The file specified by DevicePath and non-NULL
+ FileBuffer did authenticate, and the platform policy dictates
+ that the DXE Foundation may use the file.
+ @retval EFI_SUCCESS The device path specified by NULL device path DevicePath
+ and non-NULL FileBuffer did authenticate, and the platform
+ policy dictates that the DXE Foundation may execute the image in
+ FileBuffer.
+ @retval EFI_OUT_RESOURCE Fail to allocate memory.
+ @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. The image has been added to the file
+ execution table.
+ @retval EFI_ACCESS_DENIED The file specified by File and FileBuffer did not
+ authenticate, and the platform policy dictates that the DXE
+ Foundation many not use File.
+
+**/
+EFI_STATUS
+EFIAPI
+DxeImageVerificationHandler (
+ IN UINT32 AuthenticationStatus,
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *File,
+ IN VOID *FileBuffer,
+ IN UINTN FileSize,
+ IN BOOLEAN BootPolicy
+ )
+{
+ EFI_STATUS Status;
+ UINT16 Magic;
+ EFI_IMAGE_DOS_HEADER *DosHdr;
+ EFI_STATUS VerifyStatus;
+ EFI_SIGNATURE_LIST *SignatureList;
+ UINTN SignatureListSize;
+ EFI_SIGNATURE_DATA *Signature;
+ EFI_IMAGE_EXECUTION_ACTION Action;
+ WIN_CERTIFICATE *WinCertificate;
+ UINT32 Policy;
+ UINT8 *SecureBoot;
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
+ UINT32 NumberOfRvaAndSizes;
+ WIN_CERTIFICATE_EFI_PKCS *PkcsCertData;
+ WIN_CERTIFICATE_UEFI_GUID *WinCertUefiGuid;
+ UINT8 *AuthData;
+ UINTN AuthDataSize;
+ EFI_IMAGE_DATA_DIRECTORY *SecDataDir;
+ UINT32 OffSet;
+ CHAR16 *NameStr;
+
+ SignatureList = NULL;
+ SignatureListSize = 0;
+ WinCertificate = NULL;
+ SecDataDir = NULL;
+ PkcsCertData = NULL;
+ Action = EFI_IMAGE_EXECUTION_AUTH_UNTESTED;
+ Status = EFI_ACCESS_DENIED;
+ VerifyStatus = 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;
+ }
+
+ //
+ // The policy QUERY_USER_ON_SECURITY_VIOLATION and ALLOW_EXECUTE_ON_SECURITY_VIOLATION
+ // violates the UEFI spec and has been removed.
+ //
+ ASSERT (Policy != QUERY_USER_ON_SECURITY_VIOLATION && Policy != ALLOW_EXECUTE_ON_SECURITY_VIOLATION);
+ if (Policy == QUERY_USER_ON_SECURITY_VIOLATION || Policy == ALLOW_EXECUTE_ON_SECURITY_VIOLATION) {
+ CpuDeadLoop ();
+ }
+
+ GetEfiGlobalVariable2 (EFI_SECURE_BOOT_MODE_NAME, (VOID**)&SecureBoot, NULL);
+ //
+ // Skip verification if SecureBoot variable doesn't exist.
+ //
+ if (SecureBoot == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Skip verification if SecureBoot is disabled but not AuditMode
+ //
+ if (*SecureBoot == SECURE_BOOT_MODE_DISABLE) {
+ FreePool (SecureBoot);
+ return EFI_SUCCESS;
+ }
+ FreePool (SecureBoot);
+
+ //
+ // Read the Dos header.
+ //
+ if (FileBuffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ mImageBase = (UINT8 *) FileBuffer;
+ mImageSize = FileSize;
+
+ ZeroMem (&ImageContext, sizeof (ImageContext));
+ ImageContext.Handle = (VOID *) FileBuffer;
+ ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) DxeImageVerificationLibImageRead;
+
+ //
+ // Get information about the image being loaded
+ //
+ Status = PeCoffLoaderGetImageInfo (&ImageContext);
+ if (EFI_ERROR (Status)) {
+ //
+ // The information can't be got from the invalid PeImage
+ //
+ DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: PeImage invalid. Cannot retrieve image information.\n"));
+ goto Done;
+ }
+
+ Status = EFI_ACCESS_DENIED;
+
+ 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.
+ //
+ DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Not a valid PE/COFF image.\n"));
+ goto Done;
+ }
+
+ if (mNtHeader.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ //
+ // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value
+ // in the PE/COFF Header. If the MachineType is Itanium(IA64) and the
+ // Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
+ // then override the magic value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
+ //
+ Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;
+ } else {
+ //
+ // Get the magic value from the PE/COFF Optional Header
+ //
+ Magic = mNtHeader.Pe32->OptionalHeader.Magic;
+ }
+
+ if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ //
+ // Use PE32 offset.
+ //
+ NumberOfRvaAndSizes = mNtHeader.Pe32->OptionalHeader.NumberOfRvaAndSizes;
+ if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {
+ SecDataDir = (EFI_IMAGE_DATA_DIRECTORY *) &mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];
+ }
+ } else {
+ //
+ // Use PE32+ offset.
+ //
+ NumberOfRvaAndSizes = mNtHeader.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
+ if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {
+ SecDataDir = (EFI_IMAGE_DATA_DIRECTORY *) &mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];
+ }
+ }
+
+ //
+ // Start Image Validation.
+ //
+ if (SecDataDir == NULL || SecDataDir->Size == 0) {
+ //
+ // This image is not signed. The SHA256 hash value of the image must match a record in the security database "db",
+ // and not be reflected in the security data base "dbx".
+ //
+ if (!HashPeImage (HASHALG_SHA256)) {
+ DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Failed to hash this image using %s.\n", mHashTypeStr));
+ goto Done;
+ }
+
+ if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE1, mImageDigest, &mCertType, mImageDigestSize)) {
+ //
+ // Image Hash is in forbidden database (DBX).
+ //
+ DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Image is not signed and %s hash of image is forbidden by DBX.\n", mHashTypeStr));
+ goto Done;
+ }
+
+ if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE, mImageDigest, &mCertType, mImageDigestSize)) {
+ //
+ // Image Hash is in allowed database (DB).
+ //
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Image Hash is not found in both forbidden and allowed database.
+ //
+ DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Image is not signed and %s hash of image is not found in DB/DBX.\n", mHashTypeStr));
+ goto Done;
+ }
+
+ //
+ // Verify the signature of the image, multiple signatures are allowed as per PE/COFF Section 4.7
+ // "Attribute Certificate Table".
+ // The first certificate starts at offset (SecDataDir->VirtualAddress) from the start of the file.
+ //
+ for (OffSet = SecDataDir->VirtualAddress;
+ OffSet < (SecDataDir->VirtualAddress + SecDataDir->Size);
+ OffSet += (WinCertificate->dwLength + ALIGN_SIZE (WinCertificate->dwLength))) {
+ WinCertificate = (WIN_CERTIFICATE *) (mImageBase + OffSet);
+ if ((SecDataDir->VirtualAddress + SecDataDir->Size - OffSet) <= sizeof (WIN_CERTIFICATE) ||
+ (SecDataDir->VirtualAddress + SecDataDir->Size - OffSet) < WinCertificate->dwLength) {
+ break;
+ }
+
+ //
+ // Verify the image's Authenticode signature, only DER-encoded PKCS#7 signed data is supported.
+ //
+ if (WinCertificate->wCertificateType == WIN_CERT_TYPE_PKCS_SIGNED_DATA) {
+ //
+ // The certificate is formatted as WIN_CERTIFICATE_EFI_PKCS which is described in the
+ // Authenticode specification.
+ //
+ PkcsCertData = (WIN_CERTIFICATE_EFI_PKCS *) WinCertificate;
+ if (PkcsCertData->Hdr.dwLength <= sizeof (PkcsCertData->Hdr)) {
+ break;
+ }
+ AuthData = PkcsCertData->CertData;
+ AuthDataSize = PkcsCertData->Hdr.dwLength - sizeof(PkcsCertData->Hdr);
+ } else if (WinCertificate->wCertificateType == WIN_CERT_TYPE_EFI_GUID) {
+ //
+ // The certificate is formatted as WIN_CERTIFICATE_UEFI_GUID which is described in UEFI Spec.
+ //
+ WinCertUefiGuid = (WIN_CERTIFICATE_UEFI_GUID *) WinCertificate;
+ if (WinCertUefiGuid->Hdr.dwLength <= OFFSET_OF(WIN_CERTIFICATE_UEFI_GUID, CertData)) {
+ break;
+ }
+ if (!CompareGuid (&WinCertUefiGuid->CertType, &gEfiCertPkcs7Guid)) {
+ continue;
+ }
+ AuthData = WinCertUefiGuid->CertData;
+ AuthDataSize = WinCertUefiGuid->Hdr.dwLength - OFFSET_OF(WIN_CERTIFICATE_UEFI_GUID, CertData);
+ } else {
+ if (WinCertificate->dwLength < sizeof (WIN_CERTIFICATE)) {
+ break;
+ }
+ continue;
+ }
+
+ Status = HashPeImageByType (AuthData, AuthDataSize);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ //
+ // Check the digital signature against the revoked certificate in forbidden database (dbx).
+ //
+ if (IsForbiddenByDbx (AuthData, AuthDataSize)) {
+ Action = EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED;
+ VerifyStatus = EFI_ACCESS_DENIED;
+ break;
+ }
+
+ //
+ // Check the digital signature against the valid certificate in allowed database (db).
+ //
+ if (EFI_ERROR (VerifyStatus)) {
+ if (IsAllowedByDb (AuthData, AuthDataSize)) {
+ VerifyStatus = EFI_SUCCESS;
+ }
+ }
+
+ //
+ // Check the image's hash value.
+ //
+ if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE1, mImageDigest, &mCertType, mImageDigestSize)) {
+ Action = EFI_IMAGE_EXECUTION_AUTH_SIG_FOUND;
+ DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Image is signed but %s hash of image is found in DBX.\n", mHashTypeStr));
+ VerifyStatus = EFI_ACCESS_DENIED;
+ break;
+ } else if (EFI_ERROR (VerifyStatus)) {
+ if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE, mImageDigest, &mCertType, mImageDigestSize)) {
+ VerifyStatus = EFI_SUCCESS;
+ } else {
+ DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Image is signed but signature is not allowed by DB and %s hash of image is not found in DB/DBX.\n", mHashTypeStr));
+ }
+ }
+ }
+
+ if (OffSet != (SecDataDir->VirtualAddress + SecDataDir->Size)) {
+ //
+ // The Size in Certificate Table or the attribute certicate table is corrupted.
+ //
+ VerifyStatus = EFI_ACCESS_DENIED;
+ }
+
+ if (!EFI_ERROR (VerifyStatus)) {
+ return EFI_SUCCESS;
+ } else {
+ Status = EFI_ACCESS_DENIED;
+ if (Action == EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED || Action == EFI_IMAGE_EXECUTION_AUTH_SIG_FOUND) {
+ //
+ // 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);
+ if (SignatureList == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ SignatureList->SignatureHeaderSize = 0;
+ SignatureList->SignatureListSize = (UINT32) SignatureListSize;
+ SignatureList->SignatureSize = (UINT32) (sizeof (EFI_SIGNATURE_DATA) - 1 + mImageDigestSize);
+ CopyMem (&SignatureList->SignatureType, &mCertType, sizeof (EFI_GUID));
+ Signature = (EFI_SIGNATURE_DATA *) ((UINT8 *) SignatureList + sizeof (EFI_SIGNATURE_LIST));
+ CopyMem (Signature->SignatureData, mImageDigest, mImageDigestSize);
+ }
+ }
+
+Done:
+ if (Status != EFI_SUCCESS) {
+ //
+ // Policy decides to defer or reject the image; add its information in image executable information table.
+ //
+ NameStr = ConvertDevicePathToText (File, FALSE, TRUE);
+ AddImageExeInfo (Action, NameStr, File, SignatureList, SignatureListSize);
+ if (NameStr != NULL) {
+ DEBUG((EFI_D_INFO, "The image doesn't pass verification: %s\n", NameStr));
+ FreePool(NameStr);
+ }
+ Status = EFI_SECURITY_VIOLATION;
+ }
+
+ if (SignatureList != NULL) {
+ FreePool (SignatureList);
+ }
+
+ return Status;
+}
+
+/**
+ On Ready To Boot Services Event notification handler.
+
+ Add the image execution information table if it is not in system configuration table.
+
+ @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_IMAGE_EXECUTION_INFO_TABLE *ImageExeInfoTable;
+ UINTN ImageExeInfoTableSize;
+
+ EfiGetSystemConfigurationTable (&gEfiImageSecurityDatabaseGuid, (VOID **) &ImageExeInfoTable);
+ if (ImageExeInfoTable != NULL) {
+ return;
+ }
+
+ ImageExeInfoTableSize = sizeof (EFI_IMAGE_EXECUTION_INFO_TABLE);
+ ImageExeInfoTable = (EFI_IMAGE_EXECUTION_INFO_TABLE *) AllocateRuntimePool (ImageExeInfoTableSize);
+ if (ImageExeInfoTable == NULL) {
+ return ;
+ }
+
+ ImageExeInfoTable->NumberOfImages = 0;
+ gBS->InstallConfigurationTable (&gEfiImageSecurityDatabaseGuid, (VOID *) ImageExeInfoTable);
+
+}
+
+/**
+ 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
+ )
+{
+ EFI_EVENT Event;
+
+ //
+ // Register the event to publish the image execution table.
+ //
+ EfiCreateEventReadyToBootEx (
+ TPL_CALLBACK,
+ OnReadyToBoot,
+ NULL,
+ &Event
+ );
+
+ return RegisterSecurity2Handler (
+ DxeImageVerificationHandler,
+ EFI_AUTH_OPERATION_VERIFY_IMAGE | EFI_AUTH_OPERATION_IMAGE_REQUIRED
+ );
+}
diff --git a/Core/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.h b/Core/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.h
new file mode 100644
index 0000000000..cff6076368
--- /dev/null
+++ b/Core/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.h
@@ -0,0 +1,207 @@
+/** @file
+ The internal header file includes the common header files, defines
+ internal structure and functions used by ImageVerificationLib.
+
+Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __IMAGEVERIFICATIONLIB_H__
+#define __IMAGEVERIFICATIONLIB_H__
+
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseCryptLib.h>
+#include <Library/PcdLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/SecurityManagementLib.h>
+#include <Library/PeCoffLib.h>
+#include <Protocol/FirmwareVolume2.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/BlockIo.h>
+#include <Protocol/SimpleFileSystem.h>
+#include <Protocol/VariableWrite.h>
+#include <Guid/ImageAuthentication.h>
+#include <Guid/AuthenticatedVariableFormat.h>
+#include <IndustryStandard/PeImage.h>
+
+#define EFI_CERT_TYPE_RSA2048_SHA256_SIZE 256
+#define EFI_CERT_TYPE_RSA2048_SIZE 256
+#define MAX_NOTIFY_STRING_LEN 64
+#define TWO_BYTE_ENCODE 0x82
+
+#define ALIGNMENT_SIZE 8
+#define ALIGN_SIZE(a) (((a) % ALIGNMENT_SIZE) ? ALIGNMENT_SIZE - ((a) % ALIGNMENT_SIZE) : 0)
+
+//
+// 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 SHA512 Output (64 bytes) by far
+//
+#define MAX_DIGEST_SIZE SHA512_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/Core/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.inf b/Core/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.inf
new file mode 100644
index 0000000000..3430b6ea9d
--- /dev/null
+++ b/Core/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.inf
@@ -0,0 +1,100 @@
+## @file
+# Provides security service of image verification
+#
+# This library hooks LoadImage() API to verify every image by the verification policy.
+#
+# Caution: This module requires additional review when modified.
+# This library will have external input - PE/COFF image.
+# This external input must be validated carefully to avoid security issues such as
+# buffer overflow or integer overflow.
+#
+# Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeImageVerificationLib
+ MODULE_UNI_FILE = DxeImageVerificationLib.uni
+ 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
+ Measurement.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ CryptoPkg/CryptoPkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+ MemoryAllocationLib
+ BaseLib
+ UefiLib
+ UefiBootServicesTableLib
+ UefiRuntimeServicesTableLib
+ BaseMemoryLib
+ DebugLib
+ DevicePathLib
+ BaseCryptLib
+ SecurityManagementLib
+ PeCoffLib
+ TpmMeasurementLib
+
+[Protocols]
+ gEfiFirmwareVolume2ProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiBlockIoProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiSimpleFileSystemProtocolGuid ## SOMETIMES_CONSUMES
+
+[Guids]
+ ## SOMETIMES_CONSUMES ## Variable:L"DB"
+ ## SOMETIMES_CONSUMES ## Variable:L"DBX"
+ ## SOMETIMES_CONSUMES ## Variable:L"DBT"
+ ## PRODUCES ## SystemTable
+ ## CONSUMES ## SystemTable
+ gEfiImageSecurityDatabaseGuid
+
+ ## SOMETIMES_CONSUMES ## GUID # Unique ID for the type of the signature.
+ ## SOMETIMES_PRODUCES ## GUID # Unique ID for the type of the signature.
+ gEfiCertSha1Guid
+
+ ## SOMETIMES_CONSUMES ## GUID # Unique ID for the type of the signature.
+ ## SOMETIMES_PRODUCES ## GUID # Unique ID for the type of the signature.
+ gEfiCertSha256Guid
+
+ ## SOMETIMES_CONSUMES ## GUID # Unique ID for the type of the signature.
+ ## SOMETIMES_PRODUCES ## GUID # Unique ID for the type of the signature.
+ gEfiCertSha384Guid
+
+ ## SOMETIMES_CONSUMES ## GUID # Unique ID for the type of the signature.
+ ## SOMETIMES_PRODUCES ## GUID # Unique ID for the type of the signature.
+ gEfiCertSha512Guid
+
+ gEfiCertX509Guid ## SOMETIMES_CONSUMES ## GUID # Unique ID for the type of the signature.
+ gEfiCertX509Sha256Guid ## SOMETIMES_CONSUMES ## GUID # Unique ID for the type of the signature.
+ gEfiCertX509Sha384Guid ## SOMETIMES_CONSUMES ## GUID # Unique ID for the type of the signature.
+ gEfiCertX509Sha512Guid ## SOMETIMES_CONSUMES ## GUID # Unique ID for the type of the signature.
+ gEfiCertPkcs7Guid ## SOMETIMES_CONSUMES ## GUID # Unique ID for the type of the certificate.
+
+[Pcd]
+ gEfiSecurityPkgTokenSpaceGuid.PcdOptionRomImageVerificationPolicy ## SOMETIMES_CONSUMES
+ gEfiSecurityPkgTokenSpaceGuid.PcdRemovableMediaImageVerificationPolicy ## SOMETIMES_CONSUMES
+ gEfiSecurityPkgTokenSpaceGuid.PcdFixedMediaImageVerificationPolicy ## SOMETIMES_CONSUMES
diff --git a/Core/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.uni b/Core/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.uni
new file mode 100644
index 0000000000..6575e1c4b9
--- /dev/null
+++ b/Core/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.uni
@@ -0,0 +1,26 @@
+// /** @file
+// Provides security service of image verification
+//
+// This library hooks LoadImage() API to verify every image by the verification policy.
+//
+// Caution: This module requires additional review when modified.
+// This library will have external input - PE/COFF image.
+// This external input must be validated carefully to avoid security issues such as
+// buffer overflow or integer overflow.
+//
+// Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides security service of image verification"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library hooks LoadImage() API to verify every image by the verification policy. Caution: This module requires additional review when modified. This library will have external input - PE/COFF image. This external input must be validated carefully to avoid security issues such as buffer overflow or integer overflow."
+
diff --git a/Core/SecurityPkg/Library/DxeImageVerificationLib/Measurement.c b/Core/SecurityPkg/Library/DxeImageVerificationLib/Measurement.c
new file mode 100644
index 0000000000..6b98747d4a
--- /dev/null
+++ b/Core/SecurityPkg/Library/DxeImageVerificationLib/Measurement.c
@@ -0,0 +1,321 @@
+/** @file
+ Measure TCG required variable.
+
+Copyright (c) 2013 - 2017, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiDxe.h>
+#include <Guid/ImageAuthentication.h>
+#include <IndustryStandard/UefiTcgPlatform.h>
+
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseLib.h>
+#include <Library/TpmMeasurementLib.h>
+
+typedef struct {
+ CHAR16 *VariableName;
+ EFI_GUID *VendorGuid;
+} VARIABLE_TYPE;
+
+typedef struct {
+ CHAR16 *VariableName;
+ EFI_GUID *VendorGuid;
+ VOID *Data;
+ UINTN Size;
+} VARIABLE_RECORD;
+
+#define MEASURED_AUTHORITY_COUNT_MAX 0x100
+
+UINTN mMeasuredAuthorityCount = 0;
+UINTN mMeasuredAuthorityCountMax = 0;
+VARIABLE_RECORD *mMeasuredAuthorityList = NULL;
+
+VARIABLE_TYPE mVariableType[] = {
+ {EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid},
+};
+
+/**
+ This function will check if VarName should be recorded and return the address of VarName if it is needed.
+
+ @param[in] VarName A Null-terminated string that is the name of the vendor's variable.
+
+ @return the address of VarName.
+**/
+CHAR16 *
+AssignVarName (
+ IN CHAR16 *VarName
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < sizeof(mVariableType)/sizeof(mVariableType[0]); Index++) {
+ if (StrCmp (VarName, mVariableType[Index].VariableName) == 0) {
+ return mVariableType[Index].VariableName;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ This function will check if VendorGuid should be recorded and return the address of VendorGuid if it is needed.
+
+ @param[in] VendorGuid A unique identifier for the vendor.
+
+ @return the address of VendorGuid.
+**/
+EFI_GUID *
+AssignVendorGuid (
+ IN EFI_GUID *VendorGuid
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < sizeof(mVariableType)/sizeof(mVariableType[0]); Index++) {
+ if (CompareGuid (VendorGuid, mVariableType[Index].VendorGuid)) {
+ return mVariableType[Index].VendorGuid;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ This function will add variable information to MeasuredAuthorityList.
+
+ @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.
+**/
+EFI_STATUS
+AddDataMeasured (
+ IN CHAR16 *VarName,
+ IN EFI_GUID *VendorGuid,
+ IN VOID *Data,
+ IN UINTN Size
+ )
+{
+ VARIABLE_RECORD *NewMeasuredAuthorityList;
+
+ ASSERT (mMeasuredAuthorityCount <= mMeasuredAuthorityCountMax);
+ if (mMeasuredAuthorityCount == mMeasuredAuthorityCountMax) {
+ //
+ // Need enlarge
+ //
+ NewMeasuredAuthorityList = AllocateZeroPool (sizeof(VARIABLE_RECORD) * (mMeasuredAuthorityCountMax + MEASURED_AUTHORITY_COUNT_MAX));
+ if (NewMeasuredAuthorityList == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ if (mMeasuredAuthorityList != NULL) {
+ CopyMem (NewMeasuredAuthorityList, mMeasuredAuthorityList, sizeof(VARIABLE_RECORD) * mMeasuredAuthorityCount);
+ FreePool (mMeasuredAuthorityList);
+ }
+ mMeasuredAuthorityList = NewMeasuredAuthorityList;
+ mMeasuredAuthorityCountMax += MEASURED_AUTHORITY_COUNT_MAX;
+ }
+
+ //
+ // Add new entry
+ //
+ mMeasuredAuthorityList[mMeasuredAuthorityCount].VariableName = AssignVarName (VarName);
+ mMeasuredAuthorityList[mMeasuredAuthorityCount].VendorGuid = AssignVendorGuid (VendorGuid);
+ mMeasuredAuthorityList[mMeasuredAuthorityCount].Size = Size;
+ mMeasuredAuthorityList[mMeasuredAuthorityCount].Data = AllocatePool (Size);
+ if (mMeasuredAuthorityList[mMeasuredAuthorityCount].Data == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ CopyMem (mMeasuredAuthorityList[mMeasuredAuthorityCount].Data, Data, Size);
+ mMeasuredAuthorityCount++;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function will return if this variable is already measured.
+
+ @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 TRUE The data is already measured.
+ @retval FALSE The data is not measured yet.
+**/
+BOOLEAN
+IsDataMeasured (
+ IN CHAR16 *VarName,
+ IN EFI_GUID *VendorGuid,
+ IN VOID *Data,
+ IN UINTN Size
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < mMeasuredAuthorityCount; Index++) {
+ if ((StrCmp (VarName, mMeasuredAuthorityList[Index].VariableName) == 0) &&
+ (CompareGuid (VendorGuid, mMeasuredAuthorityList[Index].VendorGuid)) &&
+ (CompareMem (Data, mMeasuredAuthorityList[Index].Data, Size) == 0) &&
+ (Size == mMeasuredAuthorityList[Index].Size)) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ This function will return if this variable is SecureAuthority Variable.
+
+ @param[in] VariableName A Null-terminated string that is the name of the vendor's variable.
+ @param[in] VendorGuid A unique identifier for the vendor.
+
+ @retval TRUE This is SecureAuthority Variable
+ @retval FALSE This is not SecureAuthority Variable
+**/
+BOOLEAN
+IsSecureAuthorityVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < sizeof(mVariableType)/sizeof(mVariableType[0]); Index++) {
+ if ((StrCmp (VariableName, mVariableType[Index].VariableName) == 0) &&
+ (CompareGuid (VendorGuid, mVariableType[Index].VendorGuid))) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/**
+ Measure and log an EFI variable, and extend the measurement result into a specific PCR.
+
+ @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 CHAR16 *VarName,
+ IN EFI_GUID *VendorGuid,
+ IN VOID *VarData,
+ IN UINTN VarSize
+ )
+{
+ EFI_STATUS Status;
+ UINTN VarNameLength;
+ UEFI_VARIABLE_DATA *VarLog;
+ UINT32 VarLogSize;
+
+ //
+ // The UEFI_VARIABLE_DATA.VariableData value shall be the EFI_SIGNATURE_DATA value
+ // from the EFI_SIGNATURE_LIST that contained the authority that was used to validate the image
+ //
+ VarNameLength = StrLen (VarName);
+ VarLogSize = (UINT32)(sizeof (*VarLog) + VarNameLength * sizeof (*VarName) + VarSize
+ - sizeof (VarLog->UnicodeName) - sizeof (VarLog->VariableData));
+
+ VarLog = (UEFI_VARIABLE_DATA *) AllocateZeroPool (VarLogSize);
+ if (VarLog == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CopyMem (&VarLog->VariableName, VendorGuid, sizeof(VarLog->VariableName));
+ VarLog->UnicodeNameLength = VarNameLength;
+ VarLog->VariableDataLength = VarSize;
+ CopyMem (
+ VarLog->UnicodeName,
+ VarName,
+ VarNameLength * sizeof (*VarName)
+ );
+ CopyMem (
+ (CHAR16 *)VarLog->UnicodeName + VarNameLength,
+ VarData,
+ VarSize
+ );
+
+ DEBUG ((EFI_D_INFO, "DxeImageVerification: MeasureVariable (Pcr - %x, EventType - %x, ", (UINTN)7, (UINTN)EV_EFI_VARIABLE_AUTHORITY));
+ DEBUG ((EFI_D_INFO, "VariableName - %s, VendorGuid - %g)\n", VarName, VendorGuid));
+
+ Status = TpmMeasureAndLogData (
+ 7,
+ EV_EFI_VARIABLE_AUTHORITY,
+ VarLog,
+ VarLogSize,
+ VarLog,
+ VarLogSize
+ );
+ FreePool (VarLog);
+
+ return Status;
+}
+
+/**
+ SecureBoot Hook for processing image verification.
+
+ @param[in] VariableName Name of Variable to be found.
+ @param[in] VendorGuid Variable vendor GUID.
+ @param[in] DataSize Size of Data found. If size is less than the
+ data, this value contains the required size.
+ @param[in] Data Data pointer.
+
+**/
+VOID
+EFIAPI
+SecureBootHook (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINTN DataSize,
+ IN VOID *Data
+ )
+{
+ EFI_STATUS Status;
+
+ if (!IsSecureAuthorityVariable (VariableName, VendorGuid)) {
+ return ;
+ }
+
+ if (IsDataMeasured (VariableName, VendorGuid, Data, DataSize)) {
+ DEBUG ((EFI_D_ERROR, "MeasureSecureAuthorityVariable - IsDataMeasured\n"));
+ return ;
+ }
+
+ Status = MeasureVariable (
+ VariableName,
+ VendorGuid,
+ Data,
+ DataSize
+ );
+ DEBUG ((EFI_D_INFO, "MeasureBootPolicyVariable - %r\n", Status));
+
+ if (!EFI_ERROR (Status)) {
+ AddDataMeasured (VariableName, VendorGuid, Data, DataSize);
+ }
+
+ return ;
+}
diff --git a/Core/SecurityPkg/Library/DxeRsa2048Sha256GuidedSectionExtractLib/DxeRsa2048Sha256GuidedSectionExtractLib.c b/Core/SecurityPkg/Library/DxeRsa2048Sha256GuidedSectionExtractLib/DxeRsa2048Sha256GuidedSectionExtractLib.c
new file mode 100644
index 0000000000..39768fbac2
--- /dev/null
+++ b/Core/SecurityPkg/Library/DxeRsa2048Sha256GuidedSectionExtractLib/DxeRsa2048Sha256GuidedSectionExtractLib.c
@@ -0,0 +1,402 @@
+/** @file
+
+ This library registers RSA 2048 SHA 256 guided section handler
+ to parse RSA 2048 SHA 256 encapsulation section and extract raw data.
+ It uses the BaseCrypyLib based on OpenSSL to authenticate the signature.
+
+Copyright (c) 2013 - 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiDxe.h>
+#include <Protocol/Hash.h>
+#include <Protocol/SecurityPolicy.h>
+#include <Library/ExtractGuidedSectionLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/PcdLib.h>
+#include <Guid/WinCertificate.h>
+#include <Library/BaseCryptLib.h>
+#include <Library/PerformanceLib.h>
+#include <Guid/SecurityPkgTokenSpace.h>
+
+///
+/// RSA 2048 SHA 256 Guided Section header
+///
+typedef struct {
+ EFI_GUID_DEFINED_SECTION GuidedSectionHeader; ///< EFI guided section header
+ EFI_CERT_BLOCK_RSA_2048_SHA256 CertBlockRsa2048Sha256; ///< RSA 2048-bit Signature
+} RSA_2048_SHA_256_SECTION_HEADER;
+
+typedef struct {
+ EFI_GUID_DEFINED_SECTION2 GuidedSectionHeader; ///< EFI guided section header
+ EFI_CERT_BLOCK_RSA_2048_SHA256 CertBlockRsa2048Sha256; ///< RSA 2048-bit Signature
+} RSA_2048_SHA_256_SECTION2_HEADER;
+
+///
+/// Public Exponent of RSA Key.
+///
+CONST UINT8 mRsaE[] = { 0x01, 0x00, 0x01 };
+
+/**
+
+ GetInfo gets raw data size and attribute of the input guided section.
+ It first checks whether the input guid section is supported.
+ If not, EFI_INVALID_PARAMETER will return.
+
+ @param InputSection Buffer containing the input GUIDed section to be processed.
+ @param OutputBufferSize The size of OutputBuffer.
+ @param ScratchBufferSize The size of ScratchBuffer.
+ @param SectionAttribute The attribute of the input guided section.
+
+ @retval EFI_SUCCESS The size of destination buffer, the size of scratch buffer and
+ the attribute of the input section are successfully retrieved.
+ @retval EFI_INVALID_PARAMETER The GUID in InputSection does not match this instance guid.
+
+**/
+EFI_STATUS
+EFIAPI
+Rsa2048Sha256GuidedSectionGetInfo (
+ IN CONST VOID *InputSection,
+ OUT UINT32 *OutputBufferSize,
+ OUT UINT32 *ScratchBufferSize,
+ OUT UINT16 *SectionAttribute
+ )
+{
+ if (IS_SECTION2 (InputSection)) {
+ //
+ // Check whether the input guid section is recognized.
+ //
+ if (!CompareGuid (
+ &gEfiCertTypeRsa2048Sha256Guid,
+ &(((EFI_GUID_DEFINED_SECTION2 *) InputSection)->SectionDefinitionGuid))) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Retrieve the size and attribute of the input section data.
+ //
+ *SectionAttribute = ((EFI_GUID_DEFINED_SECTION2 *) InputSection)->Attributes;
+ *ScratchBufferSize = 0;
+ *OutputBufferSize = SECTION2_SIZE (InputSection) - sizeof(RSA_2048_SHA_256_SECTION2_HEADER);
+ } else {
+ //
+ // Check whether the input guid section is recognized.
+ //
+ if (!CompareGuid (
+ &gEfiCertTypeRsa2048Sha256Guid,
+ &(((EFI_GUID_DEFINED_SECTION *) InputSection)->SectionDefinitionGuid))) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Retrieve the size and attribute of the input section data.
+ //
+ *SectionAttribute = ((EFI_GUID_DEFINED_SECTION *) InputSection)->Attributes;
+ *ScratchBufferSize = 0;
+ *OutputBufferSize = SECTION_SIZE (InputSection) - sizeof(RSA_2048_SHA_256_SECTION_HEADER);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Extraction handler tries to extract raw data from the input guided section.
+ It also does authentication check for RSA 2048 SHA 256 signature in the input guided section.
+ It first checks whether the input guid section is supported.
+ If not, EFI_INVALID_PARAMETER will return.
+
+ @param InputSection Buffer containing the input GUIDed section to be processed.
+ @param OutputBuffer Buffer to contain the output raw data allocated by the caller.
+ @param ScratchBuffer A pointer to a caller-allocated buffer for function internal use.
+ @param AuthenticationStatus A pointer to a caller-allocated UINT32 that indicates the
+ authentication status of the output buffer.
+
+ @retval EFI_SUCCESS Section Data and Auth Status is extracted successfully.
+ @retval EFI_INVALID_PARAMETER The GUID in InputSection does not match this instance guid.
+
+**/
+EFI_STATUS
+EFIAPI
+Rsa2048Sha256GuidedSectionHandler (
+ IN CONST VOID *InputSection,
+ OUT VOID **OutputBuffer,
+ IN VOID *ScratchBuffer, OPTIONAL
+ OUT UINT32 *AuthenticationStatus
+ )
+{
+ EFI_STATUS Status;
+ UINT32 OutputBufferSize;
+ VOID *DummyInterface;
+ EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlockRsa2048Sha256;
+ BOOLEAN CryptoStatus;
+ UINT8 Digest[SHA256_DIGEST_SIZE];
+ UINT8 *PublicKey;
+ UINTN PublicKeyBufferSize;
+ VOID *HashContext;
+ VOID *Rsa;
+
+ HashContext = NULL;
+ Rsa = NULL;
+
+ if (IS_SECTION2 (InputSection)) {
+ //
+ // Check whether the input guid section is recognized.
+ //
+ if (!CompareGuid (
+ &gEfiCertTypeRsa2048Sha256Guid,
+ &(((EFI_GUID_DEFINED_SECTION2 *)InputSection)->SectionDefinitionGuid))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Get the RSA 2048 SHA 256 information.
+ //
+ CertBlockRsa2048Sha256 = &((RSA_2048_SHA_256_SECTION2_HEADER *) InputSection)->CertBlockRsa2048Sha256;
+ OutputBufferSize = SECTION2_SIZE (InputSection) - sizeof (RSA_2048_SHA_256_SECTION2_HEADER);
+ if ((((EFI_GUID_DEFINED_SECTION *)InputSection)->Attributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) != 0) {
+ PERF_START (NULL, "RsaCopy", "DXE", 0);
+ CopyMem (*OutputBuffer, (UINT8 *)InputSection + sizeof (RSA_2048_SHA_256_SECTION2_HEADER), OutputBufferSize);
+ PERF_END (NULL, "RsaCopy", "DXE", 0);
+ } else {
+ *OutputBuffer = (UINT8 *)InputSection + sizeof (RSA_2048_SHA_256_SECTION2_HEADER);
+ }
+
+ //
+ // Implicitly RSA 2048 SHA 256 GUIDed section should have STATUS_VALID bit set
+ //
+ ASSERT ((((EFI_GUID_DEFINED_SECTION2 *)InputSection)->Attributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) != 0);
+ *AuthenticationStatus = EFI_AUTH_STATUS_IMAGE_SIGNED;
+ } else {
+ //
+ // Check whether the input guid section is recognized.
+ //
+ if (!CompareGuid (
+ &gEfiCertTypeRsa2048Sha256Guid,
+ &(((EFI_GUID_DEFINED_SECTION *)InputSection)->SectionDefinitionGuid))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Get the RSA 2048 SHA 256 information.
+ //
+ CertBlockRsa2048Sha256 = &((RSA_2048_SHA_256_SECTION_HEADER *)InputSection)->CertBlockRsa2048Sha256;
+ OutputBufferSize = SECTION_SIZE (InputSection) - sizeof (RSA_2048_SHA_256_SECTION_HEADER);
+ if ((((EFI_GUID_DEFINED_SECTION *)InputSection)->Attributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) != 0) {
+ PERF_START (NULL, "RsaCopy", "DXE", 0);
+ CopyMem (*OutputBuffer, (UINT8 *)InputSection + sizeof (RSA_2048_SHA_256_SECTION_HEADER), OutputBufferSize);
+ PERF_END (NULL, "RsaCopy", "DXE", 0);
+ } else {
+ *OutputBuffer = (UINT8 *)InputSection + sizeof (RSA_2048_SHA_256_SECTION_HEADER);
+ }
+
+ //
+ // Implicitly RSA 2048 SHA 256 GUIDed section should have STATUS_VALID bit set
+ //
+ ASSERT ((((EFI_GUID_DEFINED_SECTION *) InputSection)->Attributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) != 0);
+ *AuthenticationStatus = EFI_AUTH_STATUS_IMAGE_SIGNED;
+ }
+
+ //
+ // Check whether there exists EFI_SECURITY_POLICY_PROTOCOL_GUID.
+ //
+ Status = gBS->LocateProtocol (&gEfiSecurityPolicyProtocolGuid, NULL, &DummyInterface);
+ if (!EFI_ERROR (Status)) {
+ //
+ // If SecurityPolicy Protocol exist, AUTH platform override bit is set.
+ //
+ *AuthenticationStatus |= EFI_AUTH_STATUS_PLATFORM_OVERRIDE;
+
+ return EFI_SUCCESS;
+ }
+
+ //
+ // All paths from here return EFI_SUCESS and result is returned in AuthenticationStatus
+ //
+ Status = EFI_SUCCESS;
+
+ //
+ // Fail if the HashType is not SHA 256
+ //
+ if (!CompareGuid (&gEfiHashAlgorithmSha256Guid, &CertBlockRsa2048Sha256->HashType)) {
+ DEBUG ((DEBUG_ERROR, "DxeRsa2048Sha256: HASH type of section is not supported\n"));
+ *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;
+ goto Done;
+ }
+
+ //
+ // Allocate hash context buffer required for SHA 256
+ //
+ HashContext = AllocatePool (Sha256GetContextSize ());
+ if (HashContext == NULL) {
+ DEBUG ((DEBUG_ERROR, "DxeRsa2048Sha256: Can not allocate hash context\n"));
+ *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;
+ goto Done;
+ }
+
+ //
+ // Hash public key from data payload with SHA256.
+ //
+ ZeroMem (Digest, SHA256_DIGEST_SIZE);
+ CryptoStatus = Sha256Init (HashContext);
+ if (!CryptoStatus) {
+ DEBUG ((DEBUG_ERROR, "DxeRsa2048Sha256: Sha256Init() failed\n"));
+ *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;
+ goto Done;
+ }
+ CryptoStatus = Sha256Update (HashContext, &CertBlockRsa2048Sha256->PublicKey, sizeof(CertBlockRsa2048Sha256->PublicKey));
+ if (!CryptoStatus) {
+ DEBUG ((DEBUG_ERROR, "DxeRsa2048Sha256: Sha256Update() failed\n"));
+ *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;
+ goto Done;
+ }
+ CryptoStatus = Sha256Final (HashContext, Digest);
+ if (!CryptoStatus) {
+ DEBUG ((DEBUG_ERROR, "DxeRsa2048Sha256: Sha256Final() failed\n"));
+ *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;
+ goto Done;
+ }
+
+ //
+ // Fail if the PublicKey is not one of the public keys in PcdRsa2048Sha256PublicKeyBuffer
+ //
+ PublicKey = (UINT8 *)PcdGetPtr (PcdRsa2048Sha256PublicKeyBuffer);
+ DEBUG ((DEBUG_VERBOSE, "DxePcdRsa2048Sha256: PublicKeyBuffer = %p\n", PublicKey));
+ ASSERT (PublicKey != NULL);
+ DEBUG ((DEBUG_VERBOSE, "DxePcdRsa2048Sha256: PublicKeyBuffer Token = %08x\n", PcdToken (PcdRsa2048Sha256PublicKeyBuffer)));
+ PublicKeyBufferSize = PcdGetSize (PcdRsa2048Sha256PublicKeyBuffer);
+ DEBUG ((DEBUG_VERBOSE, "DxePcdRsa2048Sha256: PublicKeyBuffer Size = %08x\n", PublicKeyBufferSize));
+ ASSERT ((PublicKeyBufferSize % SHA256_DIGEST_SIZE) == 0);
+ CryptoStatus = FALSE;
+ while (PublicKeyBufferSize != 0) {
+ if (CompareMem (Digest, PublicKey, SHA256_DIGEST_SIZE) == 0) {
+ CryptoStatus = TRUE;
+ break;
+ }
+ PublicKey = PublicKey + SHA256_DIGEST_SIZE;
+ PublicKeyBufferSize = PublicKeyBufferSize - SHA256_DIGEST_SIZE;
+ }
+ if (!CryptoStatus) {
+ DEBUG ((DEBUG_ERROR, "DxeRsa2048Sha256: Public key in section is not supported\n"));
+ *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;
+ goto Done;
+ }
+
+ //
+ // Generate & Initialize RSA Context.
+ //
+ Rsa = RsaNew ();
+ if (Rsa == NULL) {
+ DEBUG ((DEBUG_ERROR, "DxeRsa2048Sha256: RsaNew() failed\n"));
+ *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;
+ goto Done;
+ }
+
+ //
+ // Set RSA Key Components.
+ // NOTE: Only N and E are needed to be set as RSA public key for signature verification.
+ //
+ CryptoStatus = RsaSetKey (Rsa, RsaKeyN, CertBlockRsa2048Sha256->PublicKey, sizeof(CertBlockRsa2048Sha256->PublicKey));
+ if (!CryptoStatus) {
+ DEBUG ((DEBUG_ERROR, "DxeRsa2048Sha256: RsaSetKey(RsaKeyN) failed\n"));
+ *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;
+ goto Done;
+ }
+ CryptoStatus = RsaSetKey (Rsa, RsaKeyE, mRsaE, sizeof (mRsaE));
+ if (!CryptoStatus) {
+ DEBUG ((DEBUG_ERROR, "DxeRsa2048Sha256: RsaSetKey(RsaKeyE) failed\n"));
+ *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;
+ goto Done;
+ }
+
+ //
+ // Hash data payload with SHA256.
+ //
+ ZeroMem (Digest, SHA256_DIGEST_SIZE);
+ CryptoStatus = Sha256Init (HashContext);
+ if (!CryptoStatus) {
+ DEBUG ((DEBUG_ERROR, "DxeRsa2048Sha256: Sha256Init() failed\n"));
+ *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;
+ goto Done;
+ }
+ PERF_START (NULL, "RsaShaData", "DXE", 0);
+ CryptoStatus = Sha256Update (HashContext, *OutputBuffer, OutputBufferSize);
+ PERF_END (NULL, "RsaShaData", "DXE", 0);
+ if (!CryptoStatus) {
+ DEBUG ((DEBUG_ERROR, "DxeRsa2048Sha256: Sha256Update() failed\n"));
+ *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;
+ goto Done;
+ }
+ CryptoStatus = Sha256Final (HashContext, Digest);
+ if (!CryptoStatus) {
+ DEBUG ((DEBUG_ERROR, "DxeRsa2048Sha256: Sha256Final() failed\n"));
+ *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;
+ goto Done;
+ }
+
+ //
+ // Verify the RSA 2048 SHA 256 signature.
+ //
+ PERF_START (NULL, "RsaVerify", "DXE", 0);
+ CryptoStatus = RsaPkcs1Verify (
+ Rsa,
+ Digest,
+ SHA256_DIGEST_SIZE,
+ CertBlockRsa2048Sha256->Signature,
+ sizeof (CertBlockRsa2048Sha256->Signature)
+ );
+ PERF_END (NULL, "RsaVerify", "DXE", 0);
+ if (!CryptoStatus) {
+ //
+ // If RSA 2048 SHA 256 signature verification fails, AUTH tested failed bit is set.
+ //
+ DEBUG ((DEBUG_ERROR, "DxeRsa2048Sha256: RsaPkcs1Verify() failed\n"));
+ *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;
+ }
+
+Done:
+ //
+ // Free allocated resources used to perform RSA 2048 SHA 256 signature verification
+ //
+ if (Rsa != NULL) {
+ RsaFree (Rsa);
+ }
+ if (HashContext != NULL) {
+ FreePool (HashContext);
+ }
+
+ DEBUG ((DEBUG_VERBOSE, "DxeRsa2048Sha256: Status = %r AuthenticationStatus = %08x\n", Status, *AuthenticationStatus));
+
+ return Status;
+}
+
+/**
+ Register the handler to extract RSA 2048 SHA 256 guided section.
+
+ @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 Not enough memory to register this handler.
+**/
+EFI_STATUS
+EFIAPI
+DxeRsa2048Sha256GuidedSectionExtractLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ return ExtractGuidedSectionRegisterHandlers (
+ &gEfiCertTypeRsa2048Sha256Guid,
+ Rsa2048Sha256GuidedSectionGetInfo,
+ Rsa2048Sha256GuidedSectionHandler
+ );
+}
diff --git a/Core/SecurityPkg/Library/DxeRsa2048Sha256GuidedSectionExtractLib/DxeRsa2048Sha256GuidedSectionExtractLib.inf b/Core/SecurityPkg/Library/DxeRsa2048Sha256GuidedSectionExtractLib/DxeRsa2048Sha256GuidedSectionExtractLib.inf
new file mode 100644
index 0000000000..4681f08643
--- /dev/null
+++ b/Core/SecurityPkg/Library/DxeRsa2048Sha256GuidedSectionExtractLib/DxeRsa2048Sha256GuidedSectionExtractLib.inf
@@ -0,0 +1,62 @@
+## @file
+# This library doesn't produce any library class. The constructor function uses
+# ExtractGuidedSectionLib service to register an RSA 2048 SHA 256 guided section handler
+# that parses RSA 2048 SHA 256 encapsulation section and extracts raw data.
+#
+# It uses the BaseCrypyLib based on OpenSSL to authenticate the signature.
+#
+# Copyright (c) 2013 - 2015, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeRsa2048Sha256GuidedSectionExtractLib
+ FILE_GUID = 0AD6C423-4732-4cf3-9CE3-0A5416D634A5
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = NULL|DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SAL_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER
+ CONSTRUCTOR = DxeRsa2048Sha256GuidedSectionExtractLibConstructor
+ MODULE_UNI_FILE = DxeRsa2048Sha256GuidedSectionExtractLib.uni
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF
+#
+
+[Sources]
+ DxeRsa2048Sha256GuidedSectionExtractLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ CryptoPkg/CryptoPkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+ ExtractGuidedSectionLib
+ UefiBootServicesTableLib
+ DebugLib
+ BaseMemoryLib
+ MemoryAllocationLib
+ BaseCryptLib
+ PcdLib
+ PerformanceLib
+
+[Pcd]
+ gEfiSecurityPkgTokenSpaceGuid.PcdRsa2048Sha256PublicKeyBuffer ## SOMETIMES_CONSUMES
+
+[Protocols]
+ gEfiSecurityPolicyProtocolGuid ## SOMETIMES_CONSUMES (Set platform override AUTH status if exist)
+
+[Guids]
+ gEfiCertTypeRsa2048Sha256Guid ## PRODUCES ## UNDEFINED # Specifies RSA 2048 SHA 256 authentication algorithm.
+ gEfiHashAlgorithmSha256Guid ## SOMETIMES_CONSUMES ## UNDEFINED
+ \ No newline at end of file
diff --git a/Core/SecurityPkg/Library/DxeRsa2048Sha256GuidedSectionExtractLib/DxeRsa2048Sha256GuidedSectionExtractLib.uni b/Core/SecurityPkg/Library/DxeRsa2048Sha256GuidedSectionExtractLib/DxeRsa2048Sha256GuidedSectionExtractLib.uni
new file mode 100644
index 0000000000..5a043efbb2
--- /dev/null
+++ b/Core/SecurityPkg/Library/DxeRsa2048Sha256GuidedSectionExtractLib/DxeRsa2048Sha256GuidedSectionExtractLib.uni
@@ -0,0 +1,24 @@
+// /** @file
+// This library doesn't produce any library class. The constructor function uses
+//
+// ExtractGuidedSectionLib service to register an RSA 2048 SHA 256 guided section handler
+// that parses RSA 2048 SHA 256 encapsulation section and extracts raw data.
+//
+// It uses the BaseCrypyLib based on OpenSSL to authenticate the signature.
+//
+// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides security service of RSA 2048 SHA 256 guided section verification"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library doesn't produce any library class. The constructor function uses ExtractGuidedSectionLib service to register an RSA 2048 SHA 256 guided section handler that parses RSA2048 SHA256 encapsulation section and extracts raw data. It uses the BaseCryptLib based on OpenSSL to authenticate the signature."
+
diff --git a/Core/SecurityPkg/Library/DxeTcg2PhysicalPresenceLib/DxeTcg2PhysicalPresenceLib.c b/Core/SecurityPkg/Library/DxeTcg2PhysicalPresenceLib/DxeTcg2PhysicalPresenceLib.c
new file mode 100644
index 0000000000..5bf95a18fc
--- /dev/null
+++ b/Core/SecurityPkg/Library/DxeTcg2PhysicalPresenceLib/DxeTcg2PhysicalPresenceLib.c
@@ -0,0 +1,1228 @@
+/** @file
+ Execute pending TPM2 requests from OS or BIOS.
+
+ Caution: This module requires additional review when modified.
+ This driver will have external input - variable.
+ This external input must be validated carefully to avoid security issue.
+
+ Tpm2ExecutePendingTpmRequest() will receive untrusted input and do validation.
+
+Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiDxe.h>
+
+#include <Protocol/Tcg2Protocol.h>
+#include <Protocol/VariableLock.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PrintLib.h>
+#include <Library/HiiLib.h>
+#include <Library/HobLib.h>
+#include <Guid/EventGroup.h>
+#include <Guid/Tcg2PhysicalPresenceData.h>
+#include <Library/Tpm2CommandLib.h>
+#include <Library/Tcg2PhysicalPresenceLib.h>
+#include <Library/Tcg2PpVendorLib.h>
+
+#define CONFIRM_BUFFER_SIZE 4096
+
+EFI_HII_HANDLE mTcg2PpStringPackHandle;
+
+/**
+ Get string by string id from HII Interface.
+
+ @param[in] Id String ID.
+
+ @retval CHAR16 * String from ID.
+ @retval NULL If error occurs.
+
+**/
+CHAR16 *
+Tcg2PhysicalPresenceGetStringById (
+ IN EFI_STRING_ID Id
+ )
+{
+ return HiiGetString (mTcg2PpStringPackHandle, Id, NULL);
+}
+
+/**
+ Send ClearControl and Clear command to TPM.
+
+ @param[in] PlatformAuth platform auth value. NULL means no platform auth change.
+
+ @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
+EFIAPI
+Tpm2CommandClear (
+ IN TPM2B_AUTH *PlatformAuth OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ TPMS_AUTH_COMMAND *AuthSession;
+ TPMS_AUTH_COMMAND LocalAuthSession;
+
+ if (PlatformAuth == NULL) {
+ AuthSession = NULL;
+ } else {
+ AuthSession = &LocalAuthSession;
+ ZeroMem (&LocalAuthSession, sizeof(LocalAuthSession));
+ LocalAuthSession.sessionHandle = TPM_RS_PW;
+ LocalAuthSession.hmac.size = PlatformAuth->size;
+ CopyMem (LocalAuthSession.hmac.buffer, PlatformAuth->buffer, PlatformAuth->size);
+ }
+
+ DEBUG ((EFI_D_INFO, "Tpm2ClearControl ... \n"));
+ Status = Tpm2ClearControl (TPM_RH_PLATFORM, AuthSession, NO);
+ DEBUG ((EFI_D_INFO, "Tpm2ClearControl - %r\n", Status));
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ DEBUG ((EFI_D_INFO, "Tpm2Clear ... \n"));
+ Status = Tpm2Clear (TPM_RH_PLATFORM, AuthSession);
+ DEBUG ((EFI_D_INFO, "Tpm2Clear - %r\n", Status));
+
+Done:
+ ZeroMem (&LocalAuthSession.hmac, sizeof(LocalAuthSession.hmac));
+ return Status;
+}
+
+/**
+ Change EPS.
+
+ @param[in] PlatformAuth platform auth value. NULL means no platform auth change.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+**/
+EFI_STATUS
+Tpm2CommandChangeEps (
+ IN TPM2B_AUTH *PlatformAuth OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ TPMS_AUTH_COMMAND *AuthSession;
+ TPMS_AUTH_COMMAND LocalAuthSession;
+
+ if (PlatformAuth == NULL) {
+ AuthSession = NULL;
+ } else {
+ AuthSession = &LocalAuthSession;
+ ZeroMem (&LocalAuthSession, sizeof(LocalAuthSession));
+ LocalAuthSession.sessionHandle = TPM_RS_PW;
+ LocalAuthSession.hmac.size = PlatformAuth->size;
+ CopyMem (LocalAuthSession.hmac.buffer, PlatformAuth->buffer, PlatformAuth->size);
+ }
+
+ Status = Tpm2ChangeEPS (TPM_RH_PLATFORM, AuthSession);
+ DEBUG ((EFI_D_INFO, "Tpm2ChangeEPS - %r\n", Status));
+
+ ZeroMem(&LocalAuthSession.hmac, sizeof(LocalAuthSession.hmac));
+ return Status;
+}
+
+/**
+ Execute physical presence operation requested by the OS.
+
+ @param[in] PlatformAuth platform auth value. NULL means no platform auth change.
+ @param[in] CommandCode Physical presence operation value.
+ @param[in] CommandParameter Physical presence operation parameter.
+ @param[in, out] PpiFlags The physical presence interface flags.
+
+ @retval TCG_PP_OPERATION_RESPONSE_BIOS_FAILURE Unknown physical presence operation.
+ @retval TCG_PP_OPERATION_RESPONSE_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.
+**/
+UINT32
+Tcg2ExecutePhysicalPresence (
+ IN TPM2B_AUTH *PlatformAuth, OPTIONAL
+ IN UINT32 CommandCode,
+ IN UINT32 CommandParameter,
+ IN OUT EFI_TCG2_PHYSICAL_PRESENCE_FLAGS *PpiFlags
+ )
+{
+ EFI_STATUS Status;
+ EFI_TCG2_EVENT_ALGORITHM_BITMAP TpmHashAlgorithmBitmap;
+ UINT32 ActivePcrBanks;
+
+ switch (CommandCode) {
+ case TCG2_PHYSICAL_PRESENCE_CLEAR:
+ case TCG2_PHYSICAL_PRESENCE_ENABLE_CLEAR:
+ case TCG2_PHYSICAL_PRESENCE_ENABLE_CLEAR_2:
+ case TCG2_PHYSICAL_PRESENCE_ENABLE_CLEAR_3:
+ Status = Tpm2CommandClear (PlatformAuth);
+ if (EFI_ERROR (Status)) {
+ return TCG_PP_OPERATION_RESPONSE_BIOS_FAILURE;
+ } else {
+ return TCG_PP_OPERATION_RESPONSE_SUCCESS;
+ }
+
+ case TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_CLEAR_TRUE:
+ PpiFlags->PPFlags |= TCG2_BIOS_TPM_MANAGEMENT_FLAG_PP_REQUIRED_FOR_CLEAR;
+ return TCG_PP_OPERATION_RESPONSE_SUCCESS;
+
+ case TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_CLEAR_FALSE:
+ PpiFlags->PPFlags &= ~TCG2_BIOS_TPM_MANAGEMENT_FLAG_PP_REQUIRED_FOR_CLEAR;
+ return TCG_PP_OPERATION_RESPONSE_SUCCESS;
+
+ case TCG2_PHYSICAL_PRESENCE_SET_PCR_BANKS:
+ Status = Tpm2GetCapabilitySupportedAndActivePcrs (&TpmHashAlgorithmBitmap, &ActivePcrBanks);
+ ASSERT_EFI_ERROR (Status);
+ Status = Tpm2PcrAllocateBanks (PlatformAuth, TpmHashAlgorithmBitmap, CommandParameter);
+ if (EFI_ERROR (Status)) {
+ return TCG_PP_OPERATION_RESPONSE_BIOS_FAILURE;
+ } else {
+ return TCG_PP_OPERATION_RESPONSE_SUCCESS;
+ }
+
+ case TCG2_PHYSICAL_PRESENCE_CHANGE_EPS:
+ Status = Tpm2CommandChangeEps (PlatformAuth);
+ if (EFI_ERROR (Status)) {
+ return TCG_PP_OPERATION_RESPONSE_BIOS_FAILURE;
+ } else {
+ return TCG_PP_OPERATION_RESPONSE_SUCCESS;
+ }
+
+ case TCG2_PHYSICAL_PRESENCE_LOG_ALL_DIGESTS:
+ Status = Tpm2GetCapabilitySupportedAndActivePcrs (&TpmHashAlgorithmBitmap, &ActivePcrBanks);
+ ASSERT_EFI_ERROR (Status);
+ Status = Tpm2PcrAllocateBanks (PlatformAuth, TpmHashAlgorithmBitmap, TpmHashAlgorithmBitmap);
+ if (EFI_ERROR (Status)) {
+ return TCG_PP_OPERATION_RESPONSE_BIOS_FAILURE;
+ } else {
+ return TCG_PP_OPERATION_RESPONSE_SUCCESS;
+ }
+
+ case TCG2_PHYSICAL_PRESENCE_ENABLE_BLOCK_SID:
+ PpiFlags->PPFlags |= TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_ENABLE_BLOCK_SID;
+ return TCG_PP_OPERATION_RESPONSE_SUCCESS;
+
+ case TCG2_PHYSICAL_PRESENCE_DISABLE_BLOCK_SID:
+ PpiFlags->PPFlags &= ~TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_ENABLE_BLOCK_SID;
+ return TCG_PP_OPERATION_RESPONSE_SUCCESS;
+
+ case TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_ENABLE_BLOCK_SID_FUNC_TRUE:
+ PpiFlags->PPFlags |= TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_PP_REQUIRED_FOR_ENABLE_BLOCK_SID;
+ return TCG_PP_OPERATION_RESPONSE_SUCCESS;
+
+ case TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_ENABLE_BLOCK_SID_FUNC_FALSE:
+ PpiFlags->PPFlags &= ~TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_PP_REQUIRED_FOR_ENABLE_BLOCK_SID;
+ return TCG_PP_OPERATION_RESPONSE_SUCCESS;
+
+ case TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_DISABLE_BLOCK_SID_FUNC_TRUE:
+ PpiFlags->PPFlags |= TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_PP_REQUIRED_FOR_DISABLE_BLOCK_SID;
+ return TCG_PP_OPERATION_RESPONSE_SUCCESS;
+
+ case TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_DISABLE_BLOCK_SID_FUNC_FALSE:
+ PpiFlags->PPFlags &= ~TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_PP_REQUIRED_FOR_DISABLE_BLOCK_SID;
+ return TCG_PP_OPERATION_RESPONSE_SUCCESS;
+
+ default:
+ if (CommandCode <= TCG2_PHYSICAL_PRESENCE_NO_ACTION_MAX) {
+ return TCG_PP_OPERATION_RESPONSE_SUCCESS;
+ } else {
+ return TCG_PP_OPERATION_RESPONSE_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
+Tcg2ReadUserKey (
+ IN BOOLEAN CautionKey
+ )
+{
+ EFI_STATUS Status;
+ EFI_INPUT_KEY Key;
+ UINT16 InputKey;
+
+ 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);
+
+ if (InputKey != SCAN_ESC) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Fill Buffer With BootHashAlg.
+
+ @param[in] Buffer Buffer to be filled.
+ @param[in] BufferSize Size of buffer.
+ @param[in] BootHashAlg BootHashAlg.
+
+**/
+VOID
+Tcg2FillBufferWithBootHashAlg (
+ IN UINT16 *Buffer,
+ IN UINTN BufferSize,
+ IN UINT32 BootHashAlg
+ )
+{
+ Buffer[0] = 0;
+ if ((BootHashAlg & EFI_TCG2_BOOT_HASH_ALG_SHA1) != 0) {
+ if (Buffer[0] != 0) {
+ StrnCatS (Buffer, BufferSize / sizeof (CHAR16), L", ", (BufferSize / sizeof (CHAR16)) - StrLen (Buffer) - 1);
+ }
+ StrnCatS (Buffer, BufferSize / sizeof (CHAR16), L"SHA1", (BufferSize / sizeof (CHAR16)) - StrLen (Buffer) - 1);
+ }
+ if ((BootHashAlg & EFI_TCG2_BOOT_HASH_ALG_SHA256) != 0) {
+ if (Buffer[0] != 0) {
+ StrnCatS (Buffer, BufferSize / sizeof (CHAR16), L", ", (BufferSize / sizeof (CHAR16)) - StrLen (Buffer) - 1);
+ }
+ StrnCatS (Buffer, BufferSize / sizeof (CHAR16), L"SHA256", (BufferSize / sizeof (CHAR16)) - StrLen (Buffer) - 1);
+ }
+ if ((BootHashAlg & EFI_TCG2_BOOT_HASH_ALG_SHA384) != 0) {
+ if (Buffer[0] != 0) {
+ StrnCatS (Buffer, BufferSize / sizeof (CHAR16), L", ", (BufferSize / sizeof (CHAR16)) - StrLen (Buffer) - 1);
+ }
+ StrnCatS (Buffer, BufferSize / sizeof (CHAR16), L"SHA384", (BufferSize / sizeof (CHAR16)) - StrLen (Buffer) - 1);
+ }
+ if ((BootHashAlg & EFI_TCG2_BOOT_HASH_ALG_SHA512) != 0) {
+ if (Buffer[0] != 0) {
+ StrnCatS (Buffer, BufferSize / sizeof (CHAR16), L", ", (BufferSize / sizeof (CHAR16)) - StrLen (Buffer) - 1);
+ }
+ StrnCatS (Buffer, BufferSize / sizeof (CHAR16), L"SHA512", (BufferSize / sizeof (CHAR16)) - StrLen (Buffer) - 1);
+ }
+ if ((BootHashAlg & EFI_TCG2_BOOT_HASH_ALG_SM3_256) != 0) {
+ if (Buffer[0] != 0) {
+ StrnCatS (Buffer, BufferSize / sizeof (CHAR16), L", ", (BufferSize / sizeof (CHAR16)) - StrLen (Buffer) - 1);
+ }
+ StrnCatS (Buffer, BufferSize / sizeof (CHAR16), L"SM3_256", (BufferSize / sizeof (CHAR16)) - StrLen (Buffer) - 1);
+ }
+}
+
+/**
+ Display the confirm text and get user confirmation.
+
+ @param[in] TpmPpCommand The requested TPM physical presence command.
+ @param[in] TpmPpCommandParameter The requested TPM physical presence command parameter.
+
+ @retval TRUE The user has confirmed the changes.
+ @retval FALSE The user doesn't confirm the changes.
+**/
+BOOLEAN
+Tcg2UserConfirm (
+ IN UINT32 TpmPpCommand,
+ IN UINT32 TpmPpCommandParameter
+ )
+{
+ CHAR16 *ConfirmText;
+ CHAR16 *TmpStr1;
+ CHAR16 *TmpStr2;
+ UINTN BufSize;
+ BOOLEAN CautionKey;
+ BOOLEAN NoPpiInfo;
+ UINT16 Index;
+ CHAR16 DstStr[81];
+ CHAR16 TempBuffer[1024];
+ CHAR16 TempBuffer2[1024];
+ EFI_TCG2_PROTOCOL *Tcg2Protocol;
+ EFI_TCG2_BOOT_SERVICE_CAPABILITY ProtocolCapability;
+ UINT32 CurrentPCRBanks;
+ EFI_STATUS Status;
+
+ TmpStr2 = NULL;
+ CautionKey = FALSE;
+ NoPpiInfo = FALSE;
+ BufSize = CONFIRM_BUFFER_SIZE;
+ ConfirmText = AllocateZeroPool (BufSize);
+ ASSERT (ConfirmText != NULL);
+
+ mTcg2PpStringPackHandle = HiiAddPackages (&gEfiTcg2PhysicalPresenceGuid, gImageHandle, DxeTcg2PhysicalPresenceLibStrings, NULL);
+ ASSERT (mTcg2PpStringPackHandle != NULL);
+
+ switch (TpmPpCommand) {
+
+ case TCG2_PHYSICAL_PRESENCE_CLEAR:
+ case TCG2_PHYSICAL_PRESENCE_ENABLE_CLEAR:
+ case TCG2_PHYSICAL_PRESENCE_ENABLE_CLEAR_2:
+ case TCG2_PHYSICAL_PRESENCE_ENABLE_CLEAR_3:
+ CautionKey = TRUE;
+ TmpStr2 = Tcg2PhysicalPresenceGetStringById (STRING_TOKEN (TPM_CLEAR));
+
+ TmpStr1 = Tcg2PhysicalPresenceGetStringById (STRING_TOKEN (TPM_HEAD_STR));
+ UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);
+ FreePool (TmpStr1);
+
+ TmpStr1 = Tcg2PhysicalPresenceGetStringById (STRING_TOKEN (TPM_WARNING_CLEAR));
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), L" \n\n", (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+
+ break;
+
+ case TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_CLEAR_FALSE:
+ CautionKey = TRUE;
+ NoPpiInfo = TRUE;
+ TmpStr2 = Tcg2PhysicalPresenceGetStringById (STRING_TOKEN (TPM_CLEAR));
+
+ TmpStr1 = Tcg2PhysicalPresenceGetStringById (STRING_TOKEN (TPM_PPI_HEAD_STR));
+ UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);
+ FreePool (TmpStr1);
+
+ TmpStr1 = Tcg2PhysicalPresenceGetStringById (STRING_TOKEN (TPM_NOTE_CLEAR));
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+
+ TmpStr1 = Tcg2PhysicalPresenceGetStringById (STRING_TOKEN (TPM_WARNING_CLEAR));
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), L" \n\n", (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+
+ break;
+
+ case TCG2_PHYSICAL_PRESENCE_SET_PCR_BANKS:
+ Status = gBS->LocateProtocol (&gEfiTcg2ProtocolGuid, NULL, (VOID **) &Tcg2Protocol);
+ ASSERT_EFI_ERROR (Status);
+
+ ProtocolCapability.Size = sizeof(ProtocolCapability);
+ Status = Tcg2Protocol->GetCapability (
+ Tcg2Protocol,
+ &ProtocolCapability
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = Tcg2Protocol->GetActivePcrBanks (
+ Tcg2Protocol,
+ &CurrentPCRBanks
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ CautionKey = TRUE;
+ TmpStr2 = Tcg2PhysicalPresenceGetStringById (STRING_TOKEN (TPM_SET_PCR_BANKS));
+
+ TmpStr1 = Tcg2PhysicalPresenceGetStringById (STRING_TOKEN (TPM_HEAD_STR));
+ UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);
+ FreePool (TmpStr1);
+
+ TmpStr1 = Tcg2PhysicalPresenceGetStringById (STRING_TOKEN (TPM_WARNING_SET_PCR_BANKS_1));
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+
+ TmpStr1 = Tcg2PhysicalPresenceGetStringById (STRING_TOKEN (TPM_WARNING_SET_PCR_BANKS_2));
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+
+ Tcg2FillBufferWithBootHashAlg (TempBuffer, sizeof(TempBuffer), TpmPpCommandParameter);
+ Tcg2FillBufferWithBootHashAlg (TempBuffer2, sizeof(TempBuffer2), CurrentPCRBanks);
+
+ TmpStr1 = AllocateZeroPool (BufSize);
+ ASSERT (TmpStr1 != NULL);
+ UnicodeSPrint (TmpStr1, BufSize, L"Current PCRBanks is 0x%x. (%s)\nNew PCRBanks is 0x%x. (%s)\n", CurrentPCRBanks, TempBuffer2, TpmPpCommandParameter, TempBuffer);
+
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), L" \n", (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+
+ break;
+
+ case TCG2_PHYSICAL_PRESENCE_CHANGE_EPS:
+ CautionKey = TRUE;
+ TmpStr2 = Tcg2PhysicalPresenceGetStringById (STRING_TOKEN (TPM_CHANGE_EPS));
+
+ TmpStr1 = Tcg2PhysicalPresenceGetStringById (STRING_TOKEN (TPM_HEAD_STR));
+ UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);
+ FreePool (TmpStr1);
+
+ TmpStr1 = Tcg2PhysicalPresenceGetStringById (STRING_TOKEN (TPM_WARNING_CHANGE_EPS_1));
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+
+ TmpStr1 = Tcg2PhysicalPresenceGetStringById (STRING_TOKEN (TPM_WARNING_CHANGE_EPS_2));
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+
+ break;
+
+ case TCG2_PHYSICAL_PRESENCE_ENABLE_BLOCK_SID:
+ TmpStr2 = Tcg2PhysicalPresenceGetStringById (STRING_TOKEN (TCG_STORAGE_ENABLE_BLOCK_SID));
+
+ TmpStr1 = Tcg2PhysicalPresenceGetStringById (STRING_TOKEN (TCG_STORAGE_HEAD_STR));
+ UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);
+ FreePool (TmpStr1);
+ break;
+
+ case TCG2_PHYSICAL_PRESENCE_DISABLE_BLOCK_SID:
+ TmpStr2 = Tcg2PhysicalPresenceGetStringById (STRING_TOKEN (TCG_STORAGE_DISABLE_BLOCK_SID));
+
+ TmpStr1 = Tcg2PhysicalPresenceGetStringById (STRING_TOKEN (TCG_STORAGE_HEAD_STR));
+ UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);
+ FreePool (TmpStr1);
+ break;
+
+ case TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_ENABLE_BLOCK_SID_FUNC_FALSE:
+ NoPpiInfo = TRUE;
+ TmpStr2 = Tcg2PhysicalPresenceGetStringById (STRING_TOKEN (TCG_STORAGE_PP_ENABLE_BLOCK_SID));
+
+ TmpStr1 = Tcg2PhysicalPresenceGetStringById (STRING_TOKEN (TCG_STORAGE_PPI_HEAD_STR));
+ UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);
+ FreePool (TmpStr1);
+ break;
+
+ case TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_DISABLE_BLOCK_SID_FUNC_FALSE:
+ NoPpiInfo = TRUE;
+ TmpStr2 = Tcg2PhysicalPresenceGetStringById (STRING_TOKEN (TCG_STORAGE_PP_DISABLE_BLOCK_SID));
+
+ TmpStr1 = Tcg2PhysicalPresenceGetStringById (STRING_TOKEN (TCG_STORAGE_PPI_HEAD_STR));
+ UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);
+ FreePool (TmpStr1);
+ break;
+
+ default:
+ ;
+ }
+
+ if (TmpStr2 == NULL) {
+ FreePool (ConfirmText);
+ return FALSE;
+ }
+
+ if (TpmPpCommand < TCG2_PHYSICAL_PRESENCE_STORAGE_MANAGEMENT_BEGIN) {
+ if (CautionKey) {
+ TmpStr1 = Tcg2PhysicalPresenceGetStringById (STRING_TOKEN (TPM_CAUTION_KEY));
+ } else {
+ TmpStr1 = Tcg2PhysicalPresenceGetStringById (STRING_TOKEN (TPM_ACCEPT_KEY));
+ }
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+
+ if (NoPpiInfo) {
+ TmpStr1 = Tcg2PhysicalPresenceGetStringById (STRING_TOKEN (TPM_NO_PPI_INFO));
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+ }
+
+ TmpStr1 = Tcg2PhysicalPresenceGetStringById (STRING_TOKEN (TPM_REJECT_KEY));
+ } else {
+ if (CautionKey) {
+ TmpStr1 = Tcg2PhysicalPresenceGetStringById (STRING_TOKEN (TCG_STORAGE_CAUTION_KEY));
+ } else {
+ TmpStr1 = Tcg2PhysicalPresenceGetStringById (STRING_TOKEN (TCG_STORAGE_ACCEPT_KEY));
+ }
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+
+ if (NoPpiInfo) {
+ TmpStr1 = Tcg2PhysicalPresenceGetStringById (STRING_TOKEN (TCG_STORAGE_NO_PPI_INFO));
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+ }
+
+ TmpStr1 = Tcg2PhysicalPresenceGetStringById (STRING_TOKEN (TCG_STORAGE_REJECT_KEY));
+ }
+ BufSize -= StrSize (ConfirmText);
+ UnicodeSPrint (ConfirmText + StrLen (ConfirmText), BufSize, TmpStr1, TmpStr2);
+
+ DstStr[80] = L'\0';
+ for (Index = 0; Index < StrLen (ConfirmText); Index += 80) {
+ StrnCpyS (DstStr, sizeof (DstStr) / sizeof (CHAR16), ConfirmText + Index, sizeof (DstStr) / sizeof (CHAR16) - 1);
+ Print (DstStr);
+ }
+
+ FreePool (TmpStr1);
+ FreePool (TmpStr2);
+ FreePool (ConfirmText);
+ HiiRemovePackages (mTcg2PpStringPackHandle);
+
+ if (Tcg2ReadUserKey (CautionKey)) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Check if there is a valid physical presence command request. Also updates parameter value
+ to whether the requested physical presence command already confirmed by user
+
+ @param[in] TcgPpData EFI Tcg2 Physical Presence request data.
+ @param[in] Flags The physical presence interface flags.
+ @param[out] RequestConfirmed If the physical presence operation command required user confirm from UI.
+ True, it indicates the command doesn't require user confirm, or already confirmed
+ in last boot cycle by user.
+ False, it indicates the command need user confirm from UI.
+
+ @retval TRUE Physical Presence operation command is valid.
+ @retval FALSE Physical Presence operation command is invalid.
+
+**/
+BOOLEAN
+Tcg2HaveValidTpmRequest (
+ IN EFI_TCG2_PHYSICAL_PRESENCE *TcgPpData,
+ IN EFI_TCG2_PHYSICAL_PRESENCE_FLAGS Flags,
+ OUT BOOLEAN *RequestConfirmed
+ )
+{
+ EFI_TCG2_PROTOCOL *Tcg2Protocol;
+ EFI_STATUS Status;
+ BOOLEAN IsRequestValid;
+
+ *RequestConfirmed = FALSE;
+
+ if (TcgPpData->PPRequest <= TCG2_PHYSICAL_PRESENCE_NO_ACTION_MAX) {
+ //
+ // Need TCG2 protocol.
+ //
+ Status = gBS->LocateProtocol (&gEfiTcg2ProtocolGuid, NULL, (VOID **) &Tcg2Protocol);
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+ }
+
+ switch (TcgPpData->PPRequest) {
+ case TCG2_PHYSICAL_PRESENCE_NO_ACTION:
+ *RequestConfirmed = TRUE;
+ return TRUE;
+
+ case TCG2_PHYSICAL_PRESENCE_CLEAR:
+ case TCG2_PHYSICAL_PRESENCE_ENABLE_CLEAR:
+ case TCG2_PHYSICAL_PRESENCE_ENABLE_CLEAR_2:
+ case TCG2_PHYSICAL_PRESENCE_ENABLE_CLEAR_3:
+ if ((Flags.PPFlags & TCG2_BIOS_TPM_MANAGEMENT_FLAG_PP_REQUIRED_FOR_CLEAR) == 0) {
+ *RequestConfirmed = TRUE;
+ }
+ break;
+
+ case TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_CLEAR_TRUE:
+ *RequestConfirmed = TRUE;
+ break;
+
+ case TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_CLEAR_FALSE:
+ break;
+
+ case TCG2_PHYSICAL_PRESENCE_SET_PCR_BANKS:
+ if ((Flags.PPFlags & TCG2_BIOS_TPM_MANAGEMENT_FLAG_PP_REQUIRED_FOR_CHANGE_PCRS) == 0) {
+ *RequestConfirmed = TRUE;
+ }
+ break;
+
+ case TCG2_PHYSICAL_PRESENCE_CHANGE_EPS:
+ if ((Flags.PPFlags & TCG2_BIOS_TPM_MANAGEMENT_FLAG_PP_REQUIRED_FOR_CHANGE_EPS) == 0) {
+ *RequestConfirmed = TRUE;
+ }
+ break;
+
+ case TCG2_PHYSICAL_PRESENCE_LOG_ALL_DIGESTS:
+ *RequestConfirmed = TRUE;
+ break;
+
+ case TCG2_PHYSICAL_PRESENCE_ENABLE_BLOCK_SID:
+ if ((Flags.PPFlags & TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_PP_REQUIRED_FOR_ENABLE_BLOCK_SID) == 0) {
+ *RequestConfirmed = TRUE;
+ }
+ break;
+
+ case TCG2_PHYSICAL_PRESENCE_DISABLE_BLOCK_SID:
+ if ((Flags.PPFlags & TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_PP_REQUIRED_FOR_DISABLE_BLOCK_SID) == 0) {
+ *RequestConfirmed = TRUE;
+ }
+ break;
+
+ case TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_ENABLE_BLOCK_SID_FUNC_TRUE:
+ case TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_DISABLE_BLOCK_SID_FUNC_TRUE:
+ *RequestConfirmed = TRUE;
+ break;
+
+ case TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_ENABLE_BLOCK_SID_FUNC_FALSE:
+ case TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_DISABLE_BLOCK_SID_FUNC_FALSE:
+ break;
+
+ default:
+ if (TcgPpData->PPRequest >= TCG2_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION) {
+ IsRequestValid = Tcg2PpVendorLibHasValidRequest (TcgPpData->PPRequest, Flags.PPFlags, RequestConfirmed);
+ if (!IsRequestValid) {
+ return FALSE;
+ } else {
+ break;
+ }
+ } else {
+ //
+ // Wrong Physical Presence command
+ //
+ return FALSE;
+ }
+ }
+
+ if ((Flags.PPFlags & TCG2_LIB_PP_FLAG_RESET_TRACK) != 0) {
+ //
+ // It had been confirmed in last boot, it doesn't need confirm again.
+ //
+ *RequestConfirmed = TRUE;
+ }
+
+ //
+ // Physical Presence command is correct
+ //
+ return TRUE;
+}
+
+
+/**
+ Check and execute the requested physical presence command.
+
+ Caution: This function may receive untrusted input.
+ TcgPpData variable is external input, so this function will validate
+ its data structure to be valid value.
+
+ @param[in] PlatformAuth platform auth value. NULL means no platform auth change.
+ @param[in, out] TcgPpData Pointer to the physical presence NV variable.
+ @param[in, out] Flags Pointer to the physical presence interface flags.
+**/
+VOID
+Tcg2ExecutePendingTpmRequest (
+ IN TPM2B_AUTH *PlatformAuth, OPTIONAL
+ IN OUT EFI_TCG2_PHYSICAL_PRESENCE *TcgPpData,
+ IN OUT EFI_TCG2_PHYSICAL_PRESENCE_FLAGS *Flags
+ )
+{
+ EFI_STATUS Status;
+ UINTN DataSize;
+ BOOLEAN RequestConfirmed;
+ EFI_TCG2_PHYSICAL_PRESENCE_FLAGS NewFlags;
+ BOOLEAN ResetRequired;
+ UINT32 NewPPFlags;
+
+ if (TcgPpData->PPRequest == TCG2_PHYSICAL_PRESENCE_NO_ACTION) {
+ //
+ // No operation request
+ //
+ return;
+ }
+
+ if (!Tcg2HaveValidTpmRequest(TcgPpData, *Flags, &RequestConfirmed)) {
+ //
+ // Invalid operation request.
+ //
+ if (TcgPpData->PPRequest <= TCG2_PHYSICAL_PRESENCE_NO_ACTION_MAX) {
+ TcgPpData->PPResponse = TCG_PP_OPERATION_RESPONSE_SUCCESS;
+ } else {
+ TcgPpData->PPResponse = TCG_PP_OPERATION_RESPONSE_BIOS_FAILURE;
+ }
+ TcgPpData->LastPPRequest = TcgPpData->PPRequest;
+ TcgPpData->PPRequest = TCG2_PHYSICAL_PRESENCE_NO_ACTION;
+ TcgPpData->PPRequestParameter = 0;
+
+ DataSize = sizeof (EFI_TCG2_PHYSICAL_PRESENCE);
+ Status = gRT->SetVariable (
+ TCG2_PHYSICAL_PRESENCE_VARIABLE,
+ &gEfiTcg2PhysicalPresenceGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ DataSize,
+ TcgPpData
+ );
+ return;
+ }
+
+ ResetRequired = FALSE;
+ if (TcgPpData->PPRequest >= TCG2_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION) {
+ NewFlags = *Flags;
+ NewPPFlags = NewFlags.PPFlags;
+ TcgPpData->PPResponse = Tcg2PpVendorLibExecutePendingRequest (PlatformAuth, TcgPpData->PPRequest, &NewPPFlags, &ResetRequired);
+ NewFlags.PPFlags = NewPPFlags;
+ } else {
+ if (!RequestConfirmed) {
+ //
+ // Print confirm text and wait for approval.
+ //
+ RequestConfirmed = Tcg2UserConfirm (TcgPpData->PPRequest, TcgPpData->PPRequestParameter);
+ }
+
+ //
+ // Execute requested physical presence command
+ //
+ TcgPpData->PPResponse = TCG_PP_OPERATION_RESPONSE_USER_ABORT;
+ NewFlags = *Flags;
+ if (RequestConfirmed) {
+ TcgPpData->PPResponse = Tcg2ExecutePhysicalPresence (
+ PlatformAuth,
+ TcgPpData->PPRequest,
+ TcgPpData->PPRequestParameter,
+ &NewFlags
+ );
+ }
+ }
+
+ //
+ // Save the flags if it is updated.
+ //
+ if (CompareMem (Flags, &NewFlags, sizeof(EFI_TCG2_PHYSICAL_PRESENCE_FLAGS)) != 0) {
+ *Flags = NewFlags;
+ Status = gRT->SetVariable (
+ TCG2_PHYSICAL_PRESENCE_FLAGS_VARIABLE,
+ &gEfiTcg2PhysicalPresenceGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ sizeof (EFI_TCG2_PHYSICAL_PRESENCE_FLAGS),
+ &NewFlags
+ );
+ }
+
+ //
+ // Clear request
+ //
+ if ((NewFlags.PPFlags & TCG2_LIB_PP_FLAG_RESET_TRACK) == 0) {
+ TcgPpData->LastPPRequest = TcgPpData->PPRequest;
+ TcgPpData->PPRequest = TCG2_PHYSICAL_PRESENCE_NO_ACTION;
+ TcgPpData->PPRequestParameter = 0;
+ }
+
+ //
+ // Save changes
+ //
+ DataSize = sizeof (EFI_TCG2_PHYSICAL_PRESENCE);
+ Status = gRT->SetVariable (
+ TCG2_PHYSICAL_PRESENCE_VARIABLE,
+ &gEfiTcg2PhysicalPresenceGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ DataSize,
+ TcgPpData
+ );
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ if (TcgPpData->PPResponse == TCG_PP_OPERATION_RESPONSE_USER_ABORT) {
+ return;
+ }
+
+ //
+ // Reset system to make new TPM settings in effect
+ //
+ switch (TcgPpData->LastPPRequest) {
+ case TCG2_PHYSICAL_PRESENCE_CLEAR:
+ case TCG2_PHYSICAL_PRESENCE_ENABLE_CLEAR:
+ case TCG2_PHYSICAL_PRESENCE_ENABLE_CLEAR_2:
+ case TCG2_PHYSICAL_PRESENCE_ENABLE_CLEAR_3:
+ case TCG2_PHYSICAL_PRESENCE_SET_PCR_BANKS:
+ case TCG2_PHYSICAL_PRESENCE_CHANGE_EPS:
+ case TCG2_PHYSICAL_PRESENCE_LOG_ALL_DIGESTS:
+ break;
+
+ case TCG2_PHYSICAL_PRESENCE_ENABLE_BLOCK_SID:
+ case TCG2_PHYSICAL_PRESENCE_DISABLE_BLOCK_SID:
+ break;
+
+ case TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_ENABLE_BLOCK_SID_FUNC_TRUE:
+ case TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_DISABLE_BLOCK_SID_FUNC_TRUE:
+ case TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_ENABLE_BLOCK_SID_FUNC_FALSE:
+ case TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_DISABLE_BLOCK_SID_FUNC_FALSE:
+ return;
+
+ default:
+ if (TcgPpData->LastPPRequest >= TCG2_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION) {
+ if (ResetRequired) {
+ break;
+ } else {
+ return ;
+ }
+ }
+ if (TcgPpData->PPRequest != TCG2_PHYSICAL_PRESENCE_NO_ACTION) {
+ break;
+ }
+ return;
+ }
+
+ Print (L"Rebooting system to make TPM2 settings in effect\n");
+ gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);
+ ASSERT (FALSE);
+}
+
+/**
+ Check and execute the pending TPM request.
+
+ The TPM request may come from OS or BIOS. This API will display request information and wait
+ for user confirmation if TPM request exists. The TPM request will be sent to TPM device after
+ the TPM request is confirmed, and one or more reset may be required to make TPM request to
+ take effect.
+
+ This API should be invoked after console in and console out are all ready as they are required
+ to display request information and get user input to confirm the request.
+
+ @param[in] PlatformAuth platform auth value. NULL means no platform auth change.
+**/
+VOID
+EFIAPI
+Tcg2PhysicalPresenceLibProcessRequest (
+ IN TPM2B_AUTH *PlatformAuth OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ UINTN DataSize;
+ EFI_TCG2_PHYSICAL_PRESENCE TcgPpData;
+ EDKII_VARIABLE_LOCK_PROTOCOL *VariableLockProtocol;
+ EFI_TCG2_PHYSICAL_PRESENCE_FLAGS PpiFlags;
+
+ //
+ // This flags variable controls whether physical presence is required for TPM command.
+ // It should be protected from malicious software. We set it as read-only variable here.
+ //
+ Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **)&VariableLockProtocol);
+ if (!EFI_ERROR (Status)) {
+ Status = VariableLockProtocol->RequestToLock (
+ VariableLockProtocol,
+ TCG2_PHYSICAL_PRESENCE_FLAGS_VARIABLE,
+ &gEfiTcg2PhysicalPresenceGuid
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "[TPM2] Error when lock variable %s, Status = %r\n", TCG2_PHYSICAL_PRESENCE_FLAGS_VARIABLE, Status));
+ ASSERT_EFI_ERROR (Status);
+ }
+ }
+
+ //
+ // Check S4 resume
+ //
+ if (GetBootModeHob () == BOOT_ON_S4_RESUME) {
+ DEBUG ((EFI_D_INFO, "S4 Resume, Skip TPM PP process!\n"));
+ return ;
+ }
+
+ //
+ // Initialize physical presence flags.
+ //
+ DataSize = sizeof (EFI_TCG2_PHYSICAL_PRESENCE_FLAGS);
+ Status = gRT->GetVariable (
+ TCG2_PHYSICAL_PRESENCE_FLAGS_VARIABLE,
+ &gEfiTcg2PhysicalPresenceGuid,
+ NULL,
+ &DataSize,
+ &PpiFlags
+ );
+ if (EFI_ERROR (Status)) {
+ PpiFlags.PPFlags = PcdGet32(PcdTcg2PhysicalPresenceFlags);
+ Status = gRT->SetVariable (
+ TCG2_PHYSICAL_PRESENCE_FLAGS_VARIABLE,
+ &gEfiTcg2PhysicalPresenceGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ sizeof (EFI_TCG2_PHYSICAL_PRESENCE_FLAGS),
+ &PpiFlags
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "[TPM2] Set physical presence flag failed, Status = %r\n", Status));
+ return ;
+ }
+ DEBUG((DEBUG_INFO, "[TPM2] Initial physical presence flags value is 0x%x\n", PpiFlags.PPFlags));
+ }
+
+ //
+ // Initialize physical presence variable.
+ //
+ DataSize = sizeof (EFI_TCG2_PHYSICAL_PRESENCE);
+ Status = gRT->GetVariable (
+ TCG2_PHYSICAL_PRESENCE_VARIABLE,
+ &gEfiTcg2PhysicalPresenceGuid,
+ NULL,
+ &DataSize,
+ &TcgPpData
+ );
+ if (EFI_ERROR (Status)) {
+ ZeroMem ((VOID*)&TcgPpData, sizeof (TcgPpData));
+ DataSize = sizeof (EFI_TCG2_PHYSICAL_PRESENCE);
+ Status = gRT->SetVariable (
+ TCG2_PHYSICAL_PRESENCE_VARIABLE,
+ &gEfiTcg2PhysicalPresenceGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ DataSize,
+ &TcgPpData
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "[TPM2] Set physical presence variable failed, Status = %r\n", Status));
+ return ;
+ }
+ }
+
+ DEBUG ((EFI_D_INFO, "[TPM2] Flags=%x, PPRequest=%x (LastPPRequest=%x)\n", PpiFlags.PPFlags, TcgPpData.PPRequest, TcgPpData.LastPPRequest));
+
+ //
+ // Execute pending TPM request.
+ //
+ Tcg2ExecutePendingTpmRequest (PlatformAuth, &TcgPpData, &PpiFlags);
+ DEBUG ((EFI_D_INFO, "[TPM2] PPResponse = %x (LastPPRequest=%x, Flags=%x)\n", TcgPpData.PPResponse, TcgPpData.LastPPRequest, PpiFlags.PPFlags));
+
+}
+
+/**
+ Check if the pending TPM request needs user input to confirm.
+
+ The TPM request may come from OS. This API will check if TPM request exists and need user
+ input to confirmation.
+
+ @retval TRUE TPM needs input to confirm user physical presence.
+ @retval FALSE TPM doesn't need input to confirm user physical presence.
+
+**/
+BOOLEAN
+EFIAPI
+Tcg2PhysicalPresenceLibNeedUserConfirm(
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_TCG2_PHYSICAL_PRESENCE TcgPpData;
+ UINTN DataSize;
+ BOOLEAN RequestConfirmed;
+ EFI_TCG2_PHYSICAL_PRESENCE_FLAGS PpiFlags;
+
+ //
+ // Check S4 resume
+ //
+ if (GetBootModeHob () == BOOT_ON_S4_RESUME) {
+ DEBUG ((EFI_D_INFO, "S4 Resume, Skip TPM PP process!\n"));
+ return FALSE;
+ }
+
+ //
+ // Check Tpm requests
+ //
+ DataSize = sizeof (EFI_TCG2_PHYSICAL_PRESENCE);
+ Status = gRT->GetVariable (
+ TCG2_PHYSICAL_PRESENCE_VARIABLE,
+ &gEfiTcg2PhysicalPresenceGuid,
+ NULL,
+ &DataSize,
+ &TcgPpData
+ );
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ DataSize = sizeof (EFI_TCG2_PHYSICAL_PRESENCE_FLAGS);
+ Status = gRT->GetVariable (
+ TCG2_PHYSICAL_PRESENCE_FLAGS_VARIABLE,
+ &gEfiTcg2PhysicalPresenceGuid,
+ NULL,
+ &DataSize,
+ &PpiFlags
+ );
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ if (TcgPpData.PPRequest == TCG2_PHYSICAL_PRESENCE_NO_ACTION) {
+ //
+ // No operation request
+ //
+ return FALSE;
+ }
+
+ if (!Tcg2HaveValidTpmRequest(&TcgPpData, PpiFlags, &RequestConfirmed)) {
+ //
+ // Invalid operation request.
+ //
+ return FALSE;
+ }
+
+ if (!RequestConfirmed) {
+ //
+ // Need UI to confirm
+ //
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+/**
+ The handler for TPM physical presence function:
+ Return TPM Operation Response to OS Environment.
+
+ @param[out] MostRecentRequest Most recent operation request.
+ @param[out] Response Response to the most recent operation request.
+
+ @return Return Code for Return TPM Operation Response to OS Environment.
+**/
+UINT32
+EFIAPI
+Tcg2PhysicalPresenceLibReturnOperationResponseToOsFunction (
+ OUT UINT32 *MostRecentRequest,
+ OUT UINT32 *Response
+ )
+{
+ EFI_STATUS Status;
+ UINTN DataSize;
+ EFI_TCG2_PHYSICAL_PRESENCE PpData;
+
+ DEBUG ((EFI_D_INFO, "[TPM2] ReturnOperationResponseToOsFunction\n"));
+
+ //
+ // Get the Physical Presence variable
+ //
+ DataSize = sizeof (EFI_TCG2_PHYSICAL_PRESENCE);
+ Status = gRT->GetVariable (
+ TCG2_PHYSICAL_PRESENCE_VARIABLE,
+ &gEfiTcg2PhysicalPresenceGuid,
+ NULL,
+ &DataSize,
+ &PpData
+ );
+ if (EFI_ERROR (Status)) {
+ *MostRecentRequest = 0;
+ *Response = 0;
+ DEBUG ((EFI_D_ERROR, "[TPM2] Get PP variable failure! Status = %r\n", Status));
+ return TCG_PP_RETURN_TPM_OPERATION_RESPONSE_FAILURE;
+ }
+
+ *MostRecentRequest = PpData.LastPPRequest;
+ *Response = PpData.PPResponse;
+
+ return TCG_PP_RETURN_TPM_OPERATION_RESPONSE_SUCCESS;
+}
+
+/**
+ The handler for TPM physical presence function:
+ Submit TPM Operation Request to Pre-OS Environment and
+ Submit TPM Operation Request to Pre-OS Environment 2.
+
+ Caution: This function may receive untrusted input.
+
+ @param[in] OperationRequest TPM physical presence operation request.
+ @param[in] RequestParameter TPM physical presence operation request parameter.
+
+ @return Return Code for Submit TPM Operation Request to Pre-OS Environment and
+ Submit TPM Operation Request to Pre-OS Environment 2.
+**/
+UINT32
+EFIAPI
+Tcg2PhysicalPresenceLibSubmitRequestToPreOSFunction (
+ IN UINT32 OperationRequest,
+ IN UINT32 RequestParameter
+ )
+{
+ EFI_STATUS Status;
+ UINTN DataSize;
+ EFI_TCG2_PHYSICAL_PRESENCE PpData;
+ EFI_TCG2_PHYSICAL_PRESENCE_FLAGS Flags;
+
+ DEBUG ((EFI_D_INFO, "[TPM2] SubmitRequestToPreOSFunction, Request = %x, %x\n", OperationRequest, RequestParameter));
+
+ //
+ // Get the Physical Presence variable
+ //
+ DataSize = sizeof (EFI_TCG2_PHYSICAL_PRESENCE);
+ Status = gRT->GetVariable (
+ TCG2_PHYSICAL_PRESENCE_VARIABLE,
+ &gEfiTcg2PhysicalPresenceGuid,
+ NULL,
+ &DataSize,
+ &PpData
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "[TPM2] Get PP variable failure! Status = %r\n", Status));
+ return TCG_PP_SUBMIT_REQUEST_TO_PREOS_GENERAL_FAILURE;
+ }
+
+ if ((OperationRequest > TCG2_PHYSICAL_PRESENCE_NO_ACTION_MAX) &&
+ (OperationRequest < TCG2_PHYSICAL_PRESENCE_STORAGE_MANAGEMENT_BEGIN) ) {
+ return TCG_PP_SUBMIT_REQUEST_TO_PREOS_NOT_IMPLEMENTED;
+ }
+
+ if ((PpData.PPRequest != OperationRequest) ||
+ (PpData.PPRequestParameter != RequestParameter)) {
+ PpData.PPRequest = (UINT8)OperationRequest;
+ PpData.PPRequestParameter = RequestParameter;
+ DataSize = sizeof (EFI_TCG2_PHYSICAL_PRESENCE);
+ Status = gRT->SetVariable (
+ TCG2_PHYSICAL_PRESENCE_VARIABLE,
+ &gEfiTcg2PhysicalPresenceGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ DataSize,
+ &PpData
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "[TPM2] Set PP variable failure! Status = %r\n", Status));
+ return TCG_PP_SUBMIT_REQUEST_TO_PREOS_GENERAL_FAILURE;
+ }
+ }
+
+ if (OperationRequest >= TCG2_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION) {
+ DataSize = sizeof (EFI_TCG2_PHYSICAL_PRESENCE_FLAGS);
+ Status = gRT->GetVariable (
+ TCG2_PHYSICAL_PRESENCE_FLAGS_VARIABLE,
+ &gEfiTcg2PhysicalPresenceGuid,
+ NULL,
+ &DataSize,
+ &Flags
+ );
+ if (EFI_ERROR (Status)) {
+ Flags.PPFlags = TCG2_BIOS_TPM_MANAGEMENT_FLAG_DEFAULT | TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_DEFAULT;
+ }
+ return Tcg2PpVendorLibSubmitRequestToPreOSFunction (OperationRequest, Flags.PPFlags, RequestParameter);
+ }
+
+ return TCG_PP_SUBMIT_REQUEST_TO_PREOS_SUCCESS;
+}
+
+/**
+ Return TPM2 ManagementFlags set by PP interface.
+
+ @retval ManagementFlags TPM2 Management Flags.
+**/
+UINT32
+EFIAPI
+Tcg2PhysicalPresenceLibGetManagementFlags (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_TCG2_PHYSICAL_PRESENCE_FLAGS PpiFlags;
+ UINTN DataSize;
+
+ DEBUG ((EFI_D_INFO, "[TPM2] GetManagementFlags\n"));
+
+ DataSize = sizeof (EFI_TCG2_PHYSICAL_PRESENCE_FLAGS);
+ Status = gRT->GetVariable (
+ TCG2_PHYSICAL_PRESENCE_FLAGS_VARIABLE,
+ &gEfiTcg2PhysicalPresenceGuid,
+ NULL,
+ &DataSize,
+ &PpiFlags
+ );
+ if (EFI_ERROR (Status)) {
+ PpiFlags.PPFlags = TCG2_BIOS_TPM_MANAGEMENT_FLAG_DEFAULT | TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_DEFAULT;
+ }
+ return PpiFlags.PPFlags;
+}
diff --git a/Core/SecurityPkg/Library/DxeTcg2PhysicalPresenceLib/DxeTcg2PhysicalPresenceLib.inf b/Core/SecurityPkg/Library/DxeTcg2PhysicalPresenceLib/DxeTcg2PhysicalPresenceLib.inf
new file mode 100644
index 0000000000..fc10129989
--- /dev/null
+++ b/Core/SecurityPkg/Library/DxeTcg2PhysicalPresenceLib/DxeTcg2PhysicalPresenceLib.inf
@@ -0,0 +1,72 @@
+## @file
+# Executes TPM 2.0 requests from OS or BIOS
+#
+# This library will check and execute TPM 2.0 request from OS or BIOS. The request may
+# ask for user confirmation before execution.
+#
+# Caution: This module requires additional review when modified.
+# This driver will have external input - variable.
+# This external input must be validated carefully to avoid security issue.
+#
+# Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeTcg2PhysicalPresenceLib
+ MODULE_UNI_FILE = DxeTcg2PhysicalPresenceLib.uni
+ FILE_GUID = 7E507A86-DE8B-4AD3-BC4C-0498389098D3
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = Tcg2PhysicalPresenceLib|DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SAL_DRIVER UEFI_APPLICATION UEFI_DRIVER
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ DxeTcg2PhysicalPresenceLib.c
+ PhysicalPresenceStrings.uni
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+ MemoryAllocationLib
+ UefiLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ UefiRuntimeServicesTableLib
+ BaseMemoryLib
+ DebugLib
+ PrintLib
+ HiiLib
+ HobLib
+ Tpm2CommandLib
+ Tcg2PpVendorLib
+
+[Protocols]
+ gEfiTcg2ProtocolGuid ## SOMETIMES_CONSUMES
+ gEdkiiVariableLockProtocolGuid ## SOMETIMES_CONSUMES
+
+[Pcd]
+ gEfiSecurityPkgTokenSpaceGuid.PcdTcg2PhysicalPresenceFlags ## SOMETIMES_CONSUMES
+
+[Guids]
+ ## SOMETIMES_CONSUMES ## HII
+ ## SOMETIMES_PRODUCES ## Variable:L"Tcg2PhysicalPresence"
+ ## SOMETIMES_CONSUMES ## Variable:L"Tcg2PhysicalPresence"
+ ## SOMETIMES_PRODUCES ## Variable:L"Tcg2PhysicalPresenceFlags"
+ ## SOMETIMES_CONSUMES ## Variable:L"Tcg2PhysicalPresenceFlags"
+ gEfiTcg2PhysicalPresenceGuid
diff --git a/Core/SecurityPkg/Library/DxeTcg2PhysicalPresenceLib/DxeTcg2PhysicalPresenceLib.uni b/Core/SecurityPkg/Library/DxeTcg2PhysicalPresenceLib/DxeTcg2PhysicalPresenceLib.uni
new file mode 100644
index 0000000000..7cb7072c17
--- /dev/null
+++ b/Core/SecurityPkg/Library/DxeTcg2PhysicalPresenceLib/DxeTcg2PhysicalPresenceLib.uni
@@ -0,0 +1,27 @@
+// /** @file
+// Executes TPM 2.0 requests from OS or BIOS
+//
+// This library will check and execute TPM 2.0 request from OS or BIOS. The request may
+// ask for user confirmation before execution.
+//
+// Caution: This module requires additional review when modified.
+// This driver will have external input - variable.
+// This external input must be validated carefully to avoid security issue.
+//
+// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Executes TPM 2.0 requests from OS or BIOS"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library will check and execute TPM 2.0 request from OS or BIOS. The request may ask for user confirmation before execution.\n"
+ "Caution: This module requires additional review when modified. This driver will have external input - variable. This external input must be validated carefully to avoid security issue."
+
diff --git a/Core/SecurityPkg/Library/DxeTcg2PhysicalPresenceLib/PhysicalPresenceStrings.uni b/Core/SecurityPkg/Library/DxeTcg2PhysicalPresenceLib/PhysicalPresenceStrings.uni
new file mode 100644
index 0000000000..0271b890e0
--- /dev/null
+++ b/Core/SecurityPkg/Library/DxeTcg2PhysicalPresenceLib/PhysicalPresenceStrings.uni
@@ -0,0 +1,61 @@
+/** @file
+ String definitions for TPM 2.0 physical presence confirm text.
+
+Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#langdef en-US "English"
+
+#string TPM_HEAD_STR #language en-US "A configuration change was requested to %s this computer's TPM (Trusted Platform Module)\n\n"
+#string TPM_PPI_HEAD_STR #language en-US "A configuration change was requested to allow the Operating System to %s the computer's TPM (Trusted Platform Module) without asking for user confirmation in the future.\n\n"
+
+#string TPM_ACCEPT_KEY #language en-US "Press F10 "
+#string TPM_CAUTION_KEY #language en-US "Press F12 "
+#string TPM_REJECT_KEY #language en-US "to %s the TPM \nPress ESC to reject this change request and continue\n"
+
+#string TPM_ENABLE #language en-US "enable"
+#string TPM_DISABLE #language en-US "disable"
+#string TPM_CLEAR #language en-US "clear"
+#string TPM_SET_PCR_BANKS #language en-US "change the boot measurements to use PCR bank(s) of"
+#string TPM_CHANGE_EPS #language en-US "clear and change identity of"
+#string TPM_DISABLE_ENDORSEMENT_ENABLE_STORAGE #language en-US "disable access to some secrets stored in"
+
+#string TPM_NO_PPI_MAINTAIN #language en-US "maintain"
+#string TPM_NO_PPI_TURN_ON #language en-US "turn on"
+#string TPM_NO_PPI_TURN_OFF #language en-US "turn off"
+#string TPM_NO_PPI_INFO #language en-US "to approve future Operating System requests "
+
+#string TPM_WARNING_DISABLE #language en-US "WARNING: Doing so might prevent security applications that rely on the TPM from functioning as expected.\n\n"
+#string TPM_WARNING_CLEAR #language en-US "WARNING: Clearing erases information stored on the TPM. You will lose all created keys and access to data encrypted by these keys. "
+#string TPM_NOTE_CLEAR #language en-US "NOTE: This action does not clear the TPM, but by approving this configuration change, future actions to clear the TPM will not require user confirmation.\n\n"
+#string TPM_WARNING_SET_PCR_BANKS_1 #language en-US "WARNING: Changing the PCR bank(s) of the boot measurements may prevent the Operating System from properly processing the measurements. Please check if your Operating System supports the new PCR bank(s).\n\n"
+#string TPM_WARNING_SET_PCR_BANKS_2 #language en-US "WARNING: Secrets in the TPM that are bound to the boot state of your machine may become unusable.\n\n"
+#string TPM_WARNING_CHANGE_EPS_1 #language en-US "WARNING: Clearing erases information stored on the TPM. You will lose all created keys and access to data encrypted with these keys.\n\n"
+#string TPM_WARNING_CHANGE_EPS_2 #language en-US "WARNING: Changing the identity of the TPM may require additional steps to establish trust into the new identity.\n\n"
+#string TPM_WARNING_PP_CHANGE_PCRS_FALSE #language en-US "WARNING: Allowing future changes to format of the boot measurement log may affect the Operating System.\n\n"
+#string TPM_WARNING_PP_CHANGE_EPS_FALSE_1 #language en-US "WARNING: Allowing future changes to the TPM's firmware may affect the operation of the TPM and may erase information stored on the TPM.\n\n"
+#string TPM_WARNING_PP_CHANGE_EPS_FALSE_2 #language en-US "You may lose all created keys and access to data encrypted by these keys.\n\n"
+#string TPM_WARNING_DISABLE_ENDORSEMENT_ENABLE_STORAGE #language en-US "WARNING: Doing so might prevent security applications that rely on the TPM from functioning as expected.\n\n"
+
+#string TCG_STORAGE_HEAD_STR #language en-US "A configuration change was requested to %s on subsequent boots\n\n"
+#string TCG_STORAGE_PPI_HEAD_STR #language en-US "A configuration change was requested to allow the Operating System to %s without asking for user confirmation in the future.\n\n"
+
+#string TCG_STORAGE_ACCEPT_KEY #language en-US "Press F10 "
+#string TCG_STORAGE_CAUTION_KEY #language en-US "Press F12 "
+#string TCG_STORAGE_REJECT_KEY #language en-US "to %s\nPress ESC to reject this change request and continue\n"
+
+#string TCG_STORAGE_NO_PPI_INFO #language en-US "to approve future Operating System requests "
+
+#string TCG_STORAGE_ENABLE_BLOCK_SID #language en-US "issue a Block SID authentication command"
+#string TCG_STORAGE_DISABLE_BLOCK_SID #language en-US "disable issuing a Block SID authentication command"
+
+#string TCG_STORAGE_PP_ENABLE_BLOCK_SID #language en-US "enable blocking SID authentication"
+#string TCG_STORAGE_PP_DISABLE_BLOCK_SID #language en-US "disable blocking SID authentication"
diff --git a/Core/SecurityPkg/Library/DxeTcgPhysicalPresenceLib/DxeTcgPhysicalPresenceLib.c b/Core/SecurityPkg/Library/DxeTcgPhysicalPresenceLib/DxeTcgPhysicalPresenceLib.c
new file mode 100644
index 0000000000..4f35be80bb
--- /dev/null
+++ b/Core/SecurityPkg/Library/DxeTcgPhysicalPresenceLib/DxeTcgPhysicalPresenceLib.c
@@ -0,0 +1,1393 @@
+/** @file
+
+ Execute pending TPM requests from OS or BIOS and Lock TPM.
+
+ Caution: This module requires additional review when modified.
+ This driver will have external input - variable.
+ This external input must be validated carefully to avoid security issue.
+
+ ExecutePendingTpmRequest() will receive untrusted input and do validation.
+
+Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiDxe.h>
+
+#include <Protocol/TcgService.h>
+#include <Protocol/VariableLock.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PrintLib.h>
+#include <Library/HiiLib.h>
+#include <Guid/EventGroup.h>
+#include <Guid/PhysicalPresenceData.h>
+#include <Library/TcgPpVendorLib.h>
+
+#define CONFIRM_BUFFER_SIZE 4096
+
+EFI_HII_HANDLE mPpStringPackHandle;
+
+/**
+ Get string by string id from HII Interface.
+
+ @param[in] Id String ID.
+
+ @retval CHAR16 * String from ID.
+ @retval NULL If error occurs.
+
+**/
+CHAR16 *
+PhysicalPresenceGetStringById (
+ IN EFI_STRING_ID Id
+ )
+{
+ return HiiGetString (mPpStringPackHandle, Id, NULL);
+}
+
+/**
+ Get TPM physical presence permanent flags.
+
+ @param[in] TcgProtocol EFI TCG Protocol instance.
+ @param[out] LifetimeLock physicalPresenceLifetimeLock permanent flag.
+ @param[out] CmdEnable physicalPresenceCMDEnable permanent flag.
+
+ @retval EFI_SUCCESS Flags were returns successfully.
+ @retval other Failed to locate EFI TCG Protocol.
+
+**/
+EFI_STATUS
+GetTpmCapability (
+ IN EFI_TCG_PROTOCOL *TcgProtocol,
+ OUT BOOLEAN *LifetimeLock,
+ OUT BOOLEAN *CmdEnable
+ )
+{
+ EFI_STATUS Status;
+ 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];
+
+ //
+ // Fill request header
+ //
+ TpmRsp = (TPM_RSP_COMMAND_HDR*)RecvBuffer;
+ TpmRqu = (TPM_RQU_COMMAND_HDR*)SendBuffer;
+
+ TpmRqu->tag = SwapBytes16 (TPM_TAG_RQU_COMMAND);
+ TpmRqu->paramSize = SwapBytes32 (sizeof (SendBuffer));
+ TpmRqu->ordinal = SwapBytes32 (TPM_ORD_GetCapability);
+
+ //
+ // Set request parameter
+ //
+ SendBufPtr = (UINT32*)(TpmRqu + 1);
+ WriteUnaligned32 (SendBufPtr++, SwapBytes32 (TPM_CAP_FLAG));
+ WriteUnaligned32 (SendBufPtr++, SwapBytes32 (sizeof (TPM_CAP_FLAG_PERMANENT)));
+ WriteUnaligned32 (SendBufPtr, SwapBytes32 (TPM_CAP_FLAG_PERMANENT));
+
+ Status = TcgProtocol->PassThroughToTpm (
+ TcgProtocol,
+ sizeof (SendBuffer),
+ (UINT8*)TpmRqu,
+ sizeof (RecvBuffer),
+ (UINT8*)&RecvBuffer
+ );
+ ASSERT_EFI_ERROR (Status);
+ ASSERT (TpmRsp->tag == SwapBytes16 (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] TcgProtocol EFI TCG Protocol instance.
+ @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 EFI_TCG_PROTOCOL *TcgProtocol,
+ IN TPM_PHYSICAL_PRESENCE PhysicalPresence
+ )
+{
+ EFI_STATUS Status;
+ TPM_RQU_COMMAND_HDR *TpmRqu;
+ TPM_PHYSICAL_PRESENCE *TpmPp;
+ TPM_RSP_COMMAND_HDR TpmRsp;
+ UINT8 Buffer[sizeof (*TpmRqu) + sizeof (*TpmPp)];
+
+ TpmRqu = (TPM_RQU_COMMAND_HDR*)Buffer;
+ TpmPp = (TPM_PHYSICAL_PRESENCE*)(TpmRqu + 1);
+
+ TpmRqu->tag = SwapBytes16 (TPM_TAG_RQU_COMMAND);
+ TpmRqu->paramSize = SwapBytes32 (sizeof (Buffer));
+ TpmRqu->ordinal = SwapBytes32 (TSC_ORD_PhysicalPresence);
+ WriteUnaligned16 (TpmPp, (TPM_PHYSICAL_PRESENCE) SwapBytes16 (PhysicalPresence));
+
+ Status = TcgProtocol->PassThroughToTpm (
+ TcgProtocol,
+ sizeof (Buffer),
+ (UINT8*)TpmRqu,
+ sizeof (TpmRsp),
+ (UINT8*)&TpmRsp
+ );
+ ASSERT_EFI_ERROR (Status);
+ ASSERT (TpmRsp.tag == SwapBytes16 (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 TCG_PP_OPERATION_RESPONSE_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.
+
+**/
+UINT32
+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 TCG_PP_OPERATION_RESPONSE_BIOS_FAILURE;
+ }
+
+ TpmRqu->tag = SwapBytes16 (TPM_TAG_RQU_COMMAND);
+ Size = (UINT32)(sizeof (*TpmRqu) + AdditionalParameterSize);
+ TpmRqu->paramSize = SwapBytes32 (Size);
+ TpmRqu->ordinal = SwapBytes32 (Ordinal);
+ 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 != SwapBytes16 (TPM_TAG_RSP_COMMAND))) {
+ return TCG_PP_OPERATION_RESPONSE_BIOS_FAILURE;
+ }
+ return SwapBytes32 (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 TCG_PP_OPERATION_RESPONSE_BIOS_FAILURE Unknown physical presence operation.
+ @retval TCG_PP_OPERATION_RESPONSE_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.
+
+**/
+UINT32
+ExecutePhysicalPresence (
+ IN EFI_TCG_PROTOCOL *TcgProtocol,
+ IN UINT32 CommandCode,
+ IN OUT EFI_PHYSICAL_PRESENCE_FLAGS *PpiFlags
+ )
+{
+ BOOLEAN BoolVal;
+ UINT32 TpmResponse;
+ UINT32 InData[5];
+
+ switch (CommandCode) {
+ case PHYSICAL_PRESENCE_ENABLE:
+ return TpmCommandNoReturnData (
+ TcgProtocol,
+ TPM_ORD_PhysicalEnable,
+ 0,
+ NULL
+ );
+
+ case PHYSICAL_PRESENCE_DISABLE:
+ return TpmCommandNoReturnData (
+ TcgProtocol,
+ TPM_ORD_PhysicalDisable,
+ 0,
+ NULL
+ );
+
+ case PHYSICAL_PRESENCE_ACTIVATE:
+ BoolVal = FALSE;
+ return TpmCommandNoReturnData (
+ TcgProtocol,
+ TPM_ORD_PhysicalSetDeactivated,
+ sizeof (BoolVal),
+ &BoolVal
+ );
+
+ case PHYSICAL_PRESENCE_DEACTIVATE:
+ BoolVal = TRUE;
+ return TpmCommandNoReturnData (
+ TcgProtocol,
+ TPM_ORD_PhysicalSetDeactivated,
+ sizeof (BoolVal),
+ &BoolVal
+ );
+
+ case PHYSICAL_PRESENCE_CLEAR:
+ return TpmCommandNoReturnData (
+ TcgProtocol,
+ TPM_ORD_ForceClear,
+ 0,
+ NULL
+ );
+
+ case PHYSICAL_PRESENCE_ENABLE_ACTIVATE:
+ TpmResponse = ExecutePhysicalPresence (TcgProtocol, PHYSICAL_PRESENCE_ENABLE, PpiFlags);
+ if (TpmResponse == 0) {
+ TpmResponse = ExecutePhysicalPresence (TcgProtocol, PHYSICAL_PRESENCE_ACTIVATE, PpiFlags);
+ }
+ return TpmResponse;
+
+ case PHYSICAL_PRESENCE_DEACTIVATE_DISABLE:
+ TpmResponse = ExecutePhysicalPresence (TcgProtocol, PHYSICAL_PRESENCE_DEACTIVATE, PpiFlags);
+ if (TpmResponse == 0) {
+ TpmResponse = ExecutePhysicalPresence (TcgProtocol, PHYSICAL_PRESENCE_DISABLE, PpiFlags);
+ }
+ return TpmResponse;
+
+ case PHYSICAL_PRESENCE_SET_OWNER_INSTALL_TRUE:
+ BoolVal = TRUE;
+ return TpmCommandNoReturnData (
+ TcgProtocol,
+ TPM_ORD_SetOwnerInstall,
+ sizeof (BoolVal),
+ &BoolVal
+ );
+
+ case PHYSICAL_PRESENCE_SET_OWNER_INSTALL_FALSE:
+ BoolVal = FALSE;
+ return TpmCommandNoReturnData (
+ TcgProtocol,
+ TPM_ORD_SetOwnerInstall,
+ sizeof (BoolVal),
+ &BoolVal
+ );
+
+ case PHYSICAL_PRESENCE_ENABLE_ACTIVATE_OWNER_TRUE:
+ //
+ // PHYSICAL_PRESENCE_ENABLE_ACTIVATE + PHYSICAL_PRESENCE_SET_OWNER_INSTALL_TRUE
+ // PHYSICAL_PRESENCE_SET_OWNER_INSTALL_TRUE will be executed after reboot
+ //
+ if ((PpiFlags->PPFlags & TCG_VENDOR_LIB_FLAG_RESET_TRACK) == 0) {
+ TpmResponse = ExecutePhysicalPresence (TcgProtocol, PHYSICAL_PRESENCE_ENABLE_ACTIVATE, PpiFlags);
+ PpiFlags->PPFlags |= TCG_VENDOR_LIB_FLAG_RESET_TRACK;
+ } else {
+ TpmResponse = ExecutePhysicalPresence (TcgProtocol, PHYSICAL_PRESENCE_SET_OWNER_INSTALL_TRUE, PpiFlags);
+ PpiFlags->PPFlags &= ~TCG_VENDOR_LIB_FLAG_RESET_TRACK;
+ }
+ return TpmResponse;
+
+ case PHYSICAL_PRESENCE_DEACTIVATE_DISABLE_OWNER_FALSE:
+ TpmResponse = ExecutePhysicalPresence (TcgProtocol, PHYSICAL_PRESENCE_SET_OWNER_INSTALL_FALSE, PpiFlags);
+ if (TpmResponse == 0) {
+ TpmResponse = ExecutePhysicalPresence (TcgProtocol, PHYSICAL_PRESENCE_DEACTIVATE_DISABLE, PpiFlags);
+ }
+ return TpmResponse;
+
+ case PHYSICAL_PRESENCE_DEFERRED_PP_UNOWNERED_FIELD_UPGRADE:
+ InData[0] = SwapBytes32 (TPM_SET_STCLEAR_DATA); // CapabilityArea
+ InData[1] = SwapBytes32 (sizeof(UINT32)); // SubCapSize
+ InData[2] = SwapBytes32 (TPM_SD_DEFERREDPHYSICALPRESENCE); // SubCap
+ InData[3] = SwapBytes32 (sizeof(UINT32)); // SetValueSize
+ InData[4] = SwapBytes32 (1); // UnownedFieldUpgrade; bit0
+ return TpmCommandNoReturnData (
+ TcgProtocol,
+ TPM_ORD_SetCapability,
+ sizeof (UINT32) * 5,
+ InData
+ );
+
+ case PHYSICAL_PRESENCE_SET_OPERATOR_AUTH:
+ //
+ // TPM_SetOperatorAuth
+ // This command requires UI to prompt user for Auth data
+ // Here it is NOT implemented
+ //
+ return TCG_PP_OPERATION_RESPONSE_BIOS_FAILURE;
+
+ case PHYSICAL_PRESENCE_CLEAR_ENABLE_ACTIVATE:
+ TpmResponse = ExecutePhysicalPresence (TcgProtocol, PHYSICAL_PRESENCE_CLEAR, PpiFlags);
+ if (TpmResponse == 0) {
+ TpmResponse = ExecutePhysicalPresence (TcgProtocol, PHYSICAL_PRESENCE_ENABLE_ACTIVATE, PpiFlags);
+ }
+ return TpmResponse;
+
+ case PHYSICAL_PRESENCE_SET_NO_PPI_PROVISION_FALSE:
+ PpiFlags->PPFlags &= ~TCG_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_PROVISION;
+ return 0;
+
+ case PHYSICAL_PRESENCE_SET_NO_PPI_PROVISION_TRUE:
+ PpiFlags->PPFlags |= TCG_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_PROVISION;
+ return 0;
+
+ case PHYSICAL_PRESENCE_SET_NO_PPI_CLEAR_FALSE:
+ PpiFlags->PPFlags &= ~TCG_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_CLEAR;
+ return 0;
+
+ case PHYSICAL_PRESENCE_SET_NO_PPI_CLEAR_TRUE:
+ PpiFlags->PPFlags |= TCG_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_CLEAR;
+ return 0;
+
+ case PHYSICAL_PRESENCE_SET_NO_PPI_MAINTENANCE_FALSE:
+ PpiFlags->PPFlags &= ~TCG_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_MAINTENANCE;
+ return 0;
+
+ case PHYSICAL_PRESENCE_SET_NO_PPI_MAINTENANCE_TRUE:
+ PpiFlags->PPFlags |= TCG_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_MAINTENANCE;
+ return 0;
+
+ case PHYSICAL_PRESENCE_ENABLE_ACTIVATE_CLEAR:
+ //
+ // PHYSICAL_PRESENCE_ENABLE_ACTIVATE + PHYSICAL_PRESENCE_CLEAR
+ // PHYSICAL_PRESENCE_CLEAR will be executed after reboot.
+ //
+ if ((PpiFlags->PPFlags & TCG_VENDOR_LIB_FLAG_RESET_TRACK) == 0) {
+ TpmResponse = ExecutePhysicalPresence (TcgProtocol, PHYSICAL_PRESENCE_ENABLE_ACTIVATE, PpiFlags);
+ PpiFlags->PPFlags |= TCG_VENDOR_LIB_FLAG_RESET_TRACK;
+ } else {
+ TpmResponse = ExecutePhysicalPresence (TcgProtocol, PHYSICAL_PRESENCE_CLEAR, PpiFlags);
+ PpiFlags->PPFlags &= ~TCG_VENDOR_LIB_FLAG_RESET_TRACK;
+ }
+ return TpmResponse;
+
+ case PHYSICAL_PRESENCE_ENABLE_ACTIVATE_CLEAR_ENABLE_ACTIVATE:
+ //
+ // PHYSICAL_PRESENCE_ENABLE_ACTIVATE + PHYSICAL_PRESENCE_CLEAR_ENABLE_ACTIVATE
+ // PHYSICAL_PRESENCE_CLEAR_ENABLE_ACTIVATE will be executed after reboot.
+ //
+ if ((PpiFlags->PPFlags & TCG_VENDOR_LIB_FLAG_RESET_TRACK) == 0) {
+ TpmResponse = ExecutePhysicalPresence (TcgProtocol, PHYSICAL_PRESENCE_ENABLE_ACTIVATE, PpiFlags);
+ PpiFlags->PPFlags |= TCG_VENDOR_LIB_FLAG_RESET_TRACK;
+ } else {
+ TpmResponse = ExecutePhysicalPresence (TcgProtocol, PHYSICAL_PRESENCE_CLEAR_ENABLE_ACTIVATE, PpiFlags);
+ PpiFlags->PPFlags &= ~TCG_VENDOR_LIB_FLAG_RESET_TRACK;
+ }
+ return TpmResponse;
+
+ default:
+ ;
+ }
+ return TCG_PP_OPERATION_RESPONSE_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 or device error.
+
+**/
+BOOLEAN
+ReadUserKey (
+ IN BOOLEAN CautionKey
+ )
+{
+ EFI_STATUS Status;
+ EFI_INPUT_KEY Key;
+ UINT16 InputKey;
+ UINTN Index;
+
+ InputKey = 0;
+ do {
+ Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
+ if (Status == EFI_NOT_READY) {
+ gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &Index);
+ continue;
+ }
+
+ if (Status == EFI_DEVICE_ERROR) {
+ return FALSE;
+ }
+
+ 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);
+
+ if (InputKey != SCAN_ESC) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ The constructor function register UNI strings into imageHandle.
+
+ It will ASSERT() if that operation fails and it will always return EFI_SUCCESS.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The constructor successfully added string package.
+ @retval Other value The constructor can't add string package.
+
+**/
+EFI_STATUS
+EFIAPI
+TcgPhysicalPresenceLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ mPpStringPackHandle = HiiAddPackages (&gEfiPhysicalPresenceGuid, ImageHandle, DxeTcgPhysicalPresenceLibStrings, NULL);
+ ASSERT (mPpStringPackHandle != NULL);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ 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 UINT32 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);
+
+ switch (TpmPpCommand) {
+ case PHYSICAL_PRESENCE_ENABLE:
+ TmpStr2 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_ENABLE));
+
+ TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_HEAD_STR));
+ UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);
+ FreePool (TmpStr1);
+
+ TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_ACCEPT_KEY));
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+ break;
+
+ case PHYSICAL_PRESENCE_DISABLE:
+ TmpStr2 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_DISABLE));
+
+ TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_HEAD_STR));
+ UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);
+ FreePool (TmpStr1);
+
+ TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_WARNING));
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+
+ TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_ACCEPT_KEY));
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+ break;
+
+ case PHYSICAL_PRESENCE_ACTIVATE:
+ TmpStr2 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_ACTIVATE));
+
+ TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_HEAD_STR));
+ UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);
+ FreePool (TmpStr1);
+
+ TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_ACCEPT_KEY));
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+ break;
+
+ case PHYSICAL_PRESENCE_DEACTIVATE:
+ TmpStr2 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_DEACTIVATE));
+
+ TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_HEAD_STR));
+ UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);
+ FreePool (TmpStr1);
+
+ TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_WARNING));
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+
+ TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_ACCEPT_KEY));
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+ break;
+
+ case PHYSICAL_PRESENCE_CLEAR:
+ CautionKey = TRUE;
+ TmpStr2 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_CLEAR));
+
+ TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_HEAD_STR));
+ UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);
+ FreePool (TmpStr1);
+
+ TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_WARNING_CLEAR));
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), L" \n\n", (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+
+ TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_CAUTION_KEY));
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+ break;
+
+ case PHYSICAL_PRESENCE_ENABLE_ACTIVATE:
+ TmpStr2 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_ENABLE_ACTIVATE));
+
+ TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_HEAD_STR));
+ UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);
+ FreePool (TmpStr1);
+
+ TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_NOTE_ON));
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+
+ TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_ACCEPT_KEY));
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+ break;
+
+ case PHYSICAL_PRESENCE_DEACTIVATE_DISABLE:
+ TmpStr2 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_DEACTIVATE_DISABLE));
+
+ TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_HEAD_STR));
+ UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);
+ FreePool (TmpStr1);
+
+ TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_NOTE_OFF));
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+
+ TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_WARNING));
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+
+ TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_ACCEPT_KEY));
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+ break;
+
+ case PHYSICAL_PRESENCE_SET_OWNER_INSTALL_TRUE:
+ TmpStr2 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_ALLOW_TAKE_OWNERSHIP));
+
+ TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_HEAD_STR));
+ UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);
+ FreePool (TmpStr1);
+
+ TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_ACCEPT_KEY));
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+ break;
+
+ case PHYSICAL_PRESENCE_SET_OWNER_INSTALL_FALSE:
+ TmpStr2 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_DISALLOW_TAKE_OWNERSHIP));
+
+ TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_HEAD_STR));
+ UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);
+ FreePool (TmpStr1);
+
+ TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_ACCEPT_KEY));
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+ break;
+
+ case PHYSICAL_PRESENCE_ENABLE_ACTIVATE_OWNER_TRUE:
+ TmpStr2 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_TURN_ON));
+
+ TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_HEAD_STR));
+ UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);
+ FreePool (TmpStr1);
+
+ TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_NOTE_ON));
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+
+ TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_ACCEPT_KEY));
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+ break;
+
+ case PHYSICAL_PRESENCE_DEACTIVATE_DISABLE_OWNER_FALSE:
+ TmpStr2 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_TURN_OFF));
+
+ TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_HEAD_STR));
+ UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);
+ FreePool (TmpStr1);
+
+ TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_NOTE_OFF));
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+
+ TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_WARNING));
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+
+ TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_ACCEPT_KEY));
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+ break;
+
+ case PHYSICAL_PRESENCE_DEFERRED_PP_UNOWNERED_FIELD_UPGRADE:
+ CautionKey = TRUE;
+ TmpStr2 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_UNOWNED_FIELD_UPGRADE));
+
+ TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_UPGRADE_HEAD_STR));
+ UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);
+ FreePool (TmpStr1);
+
+ TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_WARNING_MAINTAIN));
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+
+ TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_CAUTION_KEY));
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+ break;
+
+ case PHYSICAL_PRESENCE_SET_OPERATOR_AUTH:
+ //
+ // TPM_SetOperatorAuth
+ // This command requires UI to prompt user for Auth data
+ // Here it is NOT implemented
+ //
+ break;
+
+ case PHYSICAL_PRESENCE_CLEAR_ENABLE_ACTIVATE:
+ CautionKey = TRUE;
+ TmpStr2 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_CLEAR_TURN_ON));
+
+ TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_HEAD_STR));
+ UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);
+ FreePool (TmpStr1);
+
+ TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_NOTE_ON));
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+
+ TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_WARNING_CLEAR));
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+
+ TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_WARNING_CLEAR_CONT));
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+
+ TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_CAUTION_KEY));
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+ break;
+
+ case PHYSICAL_PRESENCE_SET_NO_PPI_PROVISION_TRUE:
+ TmpStr2 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_NO_PPI_PROVISION));
+
+ TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_PPI_HEAD_STR));
+ UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);
+ FreePool (TmpStr1);
+
+ TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_ACCEPT_KEY));
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+
+ TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_NO_PPI_INFO));
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+ break;
+
+ case PHYSICAL_PRESENCE_SET_NO_PPI_CLEAR_TRUE:
+ CautionKey = TRUE;
+ TmpStr2 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_CLEAR));
+
+ TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_PPI_HEAD_STR));
+ UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);
+ FreePool (TmpStr1);
+
+ TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_NOTE_CLEAR));
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+
+ TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_WARNING_CLEAR));
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), L" \n\n", (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+
+ TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_CAUTION_KEY));
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+
+ TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_NO_PPI_INFO));
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+ break;
+
+ case PHYSICAL_PRESENCE_SET_NO_PPI_MAINTENANCE_TRUE:
+ CautionKey = TRUE;
+ TmpStr2 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_NO_PPI_MAINTAIN));
+
+ TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_PPI_HEAD_STR));
+ UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);
+ FreePool (TmpStr1);
+
+ TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_WARNING_MAINTAIN));
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+
+ TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_CAUTION_KEY));
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+
+ TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_NO_PPI_INFO));
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+ break;
+
+ case PHYSICAL_PRESENCE_ENABLE_ACTIVATE_CLEAR:
+ CautionKey = TRUE;
+ TmpStr2 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_ENABLE_ACTIVATE_CLEAR));
+
+ TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_HEAD_STR));
+ UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);
+ FreePool (TmpStr1);
+
+ TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_WARNING_CLEAR));
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), L" \n\n", (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+
+ TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_CAUTION_KEY));
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+ break;
+
+ case PHYSICAL_PRESENCE_ENABLE_ACTIVATE_CLEAR_ENABLE_ACTIVATE:
+ CautionKey = TRUE;
+ TmpStr2 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_ENABLE_ACTIVATE_CLEAR_ENABLE_ACTIVATE));
+
+ TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_HEAD_STR));
+ UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);
+ FreePool (TmpStr1);
+
+ TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_NOTE_ON));
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+
+ TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_WARNING_CLEAR));
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+
+ TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_WARNING_CLEAR_CONT));
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+
+ TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_CAUTION_KEY));
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+ break;
+
+ default:
+ ;
+ }
+
+ if (TmpStr2 == NULL) {
+ FreePool (ConfirmText);
+ return FALSE;
+ }
+
+ TmpStr1 = PhysicalPresenceGetStringById (STRING_TOKEN (TPM_REJECT_KEY));
+ BufSize -= StrSize (ConfirmText);
+ UnicodeSPrint (ConfirmText + StrLen (ConfirmText), BufSize, TmpStr1, TmpStr2);
+
+ DstStr[80] = L'\0';
+ for (Index = 0; Index < StrLen (ConfirmText); Index += 80) {
+ StrnCpyS(DstStr, sizeof (DstStr) / sizeof (CHAR16), ConfirmText + Index, sizeof (DstStr) / sizeof (CHAR16) - 1);
+ Print (DstStr);
+ }
+
+ FreePool (TmpStr1);
+ FreePool (TmpStr2);
+ FreePool (ConfirmText);
+
+ if (ReadUserKey (CautionKey)) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Check if there is a valid physical presence command request. Also updates parameter value
+ to whether the requested physical presence command already confirmed by user
+
+ @param[in] TcgPpData EFI TCG Physical Presence request data.
+ @param[in] Flags The physical presence interface flags.
+ @param[out] RequestConfirmed If the physical presence operation command required user confirm from UI.
+ True, it indicates the command doesn't require user confirm, or already confirmed
+ in last boot cycle by user.
+ False, it indicates the command need user confirm from UI.
+
+ @retval TRUE Physical Presence operation command is valid.
+ @retval FALSE Physical Presence operation command is invalid.
+
+**/
+BOOLEAN
+HaveValidTpmRequest (
+ IN EFI_PHYSICAL_PRESENCE *TcgPpData,
+ IN EFI_PHYSICAL_PRESENCE_FLAGS Flags,
+ OUT BOOLEAN *RequestConfirmed
+ )
+{
+ BOOLEAN IsRequestValid;
+
+ *RequestConfirmed = FALSE;
+
+ switch (TcgPpData->PPRequest) {
+ case PHYSICAL_PRESENCE_NO_ACTION:
+ *RequestConfirmed = TRUE;
+ return TRUE;
+ case PHYSICAL_PRESENCE_ENABLE:
+ case PHYSICAL_PRESENCE_DISABLE:
+ case PHYSICAL_PRESENCE_ACTIVATE:
+ case PHYSICAL_PRESENCE_DEACTIVATE:
+ case PHYSICAL_PRESENCE_ENABLE_ACTIVATE:
+ case PHYSICAL_PRESENCE_DEACTIVATE_DISABLE:
+ case PHYSICAL_PRESENCE_SET_OWNER_INSTALL_TRUE:
+ case PHYSICAL_PRESENCE_SET_OWNER_INSTALL_FALSE:
+ case PHYSICAL_PRESENCE_ENABLE_ACTIVATE_OWNER_TRUE:
+ case PHYSICAL_PRESENCE_DEACTIVATE_DISABLE_OWNER_FALSE:
+ case PHYSICAL_PRESENCE_SET_OPERATOR_AUTH:
+ if ((Flags.PPFlags & TCG_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_PROVISION) != 0) {
+ *RequestConfirmed = TRUE;
+ }
+ break;
+
+ case PHYSICAL_PRESENCE_CLEAR:
+ case PHYSICAL_PRESENCE_ENABLE_ACTIVATE_CLEAR:
+ if ((Flags.PPFlags & TCG_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_CLEAR) != 0) {
+ *RequestConfirmed = TRUE;
+ }
+ break;
+
+ case PHYSICAL_PRESENCE_DEFERRED_PP_UNOWNERED_FIELD_UPGRADE:
+ if ((Flags.PPFlags & TCG_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_MAINTENANCE) != 0) {
+ *RequestConfirmed = TRUE;
+ }
+ break;
+
+ case PHYSICAL_PRESENCE_CLEAR_ENABLE_ACTIVATE:
+ case PHYSICAL_PRESENCE_ENABLE_ACTIVATE_CLEAR_ENABLE_ACTIVATE:
+ if ((Flags.PPFlags & TCG_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_CLEAR) != 0 && (Flags.PPFlags & TCG_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_PROVISION) != 0) {
+ *RequestConfirmed = TRUE;
+ }
+ break;
+
+ case PHYSICAL_PRESENCE_SET_NO_PPI_PROVISION_FALSE:
+ case PHYSICAL_PRESENCE_SET_NO_PPI_CLEAR_FALSE:
+ case PHYSICAL_PRESENCE_SET_NO_PPI_MAINTENANCE_FALSE:
+ *RequestConfirmed = TRUE;
+ break;
+
+ case PHYSICAL_PRESENCE_SET_NO_PPI_PROVISION_TRUE:
+ case PHYSICAL_PRESENCE_SET_NO_PPI_CLEAR_TRUE:
+ case PHYSICAL_PRESENCE_SET_NO_PPI_MAINTENANCE_TRUE:
+ break;
+
+ default:
+ if (TcgPpData->PPRequest >= TCG_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION) {
+ IsRequestValid = TcgPpVendorLibHasValidRequest (TcgPpData->PPRequest, Flags.PPFlags, RequestConfirmed);
+ if (!IsRequestValid) {
+ return FALSE;
+ } else {
+ break;
+ }
+ } else {
+ //
+ // Wrong Physical Presence command
+ //
+ return FALSE;
+ }
+ }
+
+ if ((Flags.PPFlags & TCG_VENDOR_LIB_FLAG_RESET_TRACK) != 0) {
+ //
+ // It had been confirmed in last boot, it doesn't need confirm again.
+ //
+ *RequestConfirmed = TRUE;
+ }
+
+ //
+ // Physical Presence command is correct
+ //
+ return TRUE;
+}
+
+
+/**
+ Check and execute the requested physical presence command.
+
+ Caution: This function may receive untrusted input.
+ TcgPpData variable is external input, so this function will validate
+ its data structure to be valid value.
+
+ @param[in] TcgProtocol EFI TCG Protocol instance.
+ @param[in] TcgPpData Point to the physical presence NV variable.
+ @param[in] Flags The physical presence interface flags.
+
+**/
+VOID
+ExecutePendingTpmRequest (
+ IN EFI_TCG_PROTOCOL *TcgProtocol,
+ IN EFI_PHYSICAL_PRESENCE *TcgPpData,
+ IN EFI_PHYSICAL_PRESENCE_FLAGS Flags
+ )
+{
+ EFI_STATUS Status;
+ UINTN DataSize;
+ BOOLEAN RequestConfirmed;
+ EFI_PHYSICAL_PRESENCE_FLAGS NewFlags;
+ BOOLEAN ResetRequired;
+ UINT32 NewPPFlags;
+
+ if (!HaveValidTpmRequest(TcgPpData, Flags, &RequestConfirmed)) {
+ //
+ // Invalid operation request.
+ //
+ TcgPpData->PPResponse = TCG_PP_OPERATION_RESPONSE_BIOS_FAILURE;
+ TcgPpData->LastPPRequest = TcgPpData->PPRequest;
+ TcgPpData->PPRequest = PHYSICAL_PRESENCE_NO_ACTION;
+ 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
+ );
+ return;
+ }
+
+ ResetRequired = FALSE;
+ if (TcgPpData->PPRequest >= TCG_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION) {
+ NewFlags = Flags;
+ NewPPFlags = NewFlags.PPFlags;
+ TcgPpData->PPResponse = TcgPpVendorLibExecutePendingRequest (TcgPpData->PPRequest, &NewPPFlags, &ResetRequired);
+ NewFlags.PPFlags = (UINT8)NewPPFlags;
+ } else {
+ if (!RequestConfirmed) {
+ //
+ // Print confirm text and wait for approval.
+ //
+ RequestConfirmed = UserConfirm (TcgPpData->PPRequest);
+ }
+
+ //
+ // Execute requested physical presence command
+ //
+ TcgPpData->PPResponse = TCG_PP_OPERATION_RESPONSE_USER_ABORT;
+ NewFlags = Flags;
+ if (RequestConfirmed) {
+ TcgPpData->PPResponse = ExecutePhysicalPresence (TcgProtocol, TcgPpData->PPRequest, &NewFlags);
+ }
+ }
+
+ //
+ // Save the flags if it is updated.
+ //
+ if (CompareMem (&Flags, &NewFlags, sizeof(EFI_PHYSICAL_PRESENCE_FLAGS)) != 0) {
+ Status = gRT->SetVariable (
+ PHYSICAL_PRESENCE_FLAGS_VARIABLE,
+ &gEfiPhysicalPresenceGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ sizeof (EFI_PHYSICAL_PRESENCE_FLAGS),
+ &NewFlags
+ );
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+ }
+
+ //
+ // Clear request
+ //
+ if ((NewFlags.PPFlags & TCG_VENDOR_LIB_FLAG_RESET_TRACK) == 0) {
+ TcgPpData->LastPPRequest = TcgPpData->PPRequest;
+ TcgPpData->PPRequest = PHYSICAL_PRESENCE_NO_ACTION;
+ }
+
+ //
+ // 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 == TCG_PP_OPERATION_RESPONSE_USER_ABORT) {
+ return;
+ }
+
+ //
+ // Reset system to make new TPM settings in effect
+ //
+ switch (TcgPpData->LastPPRequest) {
+ case PHYSICAL_PRESENCE_ACTIVATE:
+ case PHYSICAL_PRESENCE_DEACTIVATE:
+ case PHYSICAL_PRESENCE_CLEAR:
+ case PHYSICAL_PRESENCE_ENABLE_ACTIVATE:
+ case PHYSICAL_PRESENCE_DEACTIVATE_DISABLE:
+ case PHYSICAL_PRESENCE_ENABLE_ACTIVATE_OWNER_TRUE:
+ case PHYSICAL_PRESENCE_DEACTIVATE_DISABLE_OWNER_FALSE:
+ case PHYSICAL_PRESENCE_DEFERRED_PP_UNOWNERED_FIELD_UPGRADE:
+ case PHYSICAL_PRESENCE_CLEAR_ENABLE_ACTIVATE:
+ case PHYSICAL_PRESENCE_ENABLE_ACTIVATE_CLEAR:
+ case PHYSICAL_PRESENCE_ENABLE_ACTIVATE_CLEAR_ENABLE_ACTIVATE:
+ break;
+ default:
+ if (TcgPpData->LastPPRequest >= TCG_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION) {
+ if (ResetRequired) {
+ break;
+ } else {
+ return ;
+ }
+ }
+ if (TcgPpData->PPRequest != PHYSICAL_PRESENCE_NO_ACTION) {
+ 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 pending TPM request and Lock TPM.
+
+ The TPM request may come from OS or BIOS. This API will display request information and wait
+ for user confirmation if TPM request exists. The TPM request will be sent to TPM device after
+ the TPM request is confirmed, and one or more reset may be required to make TPM request to
+ take effect. At last, it will lock TPM to prevent TPM state change by malware.
+
+ This API should be invoked after console in and console out are all ready as they are required
+ to display request information and get user input to confirm the request. This API should also
+ be invoked as early as possible as TPM is locked in this function.
+
+**/
+VOID
+EFIAPI
+TcgPhysicalPresenceLibProcessRequest (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN LifetimeLock;
+ BOOLEAN CmdEnable;
+ UINTN DataSize;
+ EFI_PHYSICAL_PRESENCE TcgPpData;
+ EFI_TCG_PROTOCOL *TcgProtocol;
+ EDKII_VARIABLE_LOCK_PROTOCOL *VariableLockProtocol;
+ EFI_PHYSICAL_PRESENCE_FLAGS PpiFlags;
+
+ Status = gBS->LocateProtocol (&gEfiTcgProtocolGuid, NULL, (VOID **)&TcgProtocol);
+ if (EFI_ERROR (Status)) {
+ return ;
+ }
+
+ //
+ // Initialize physical presence flags.
+ //
+ DataSize = sizeof (EFI_PHYSICAL_PRESENCE_FLAGS);
+ Status = gRT->GetVariable (
+ PHYSICAL_PRESENCE_FLAGS_VARIABLE,
+ &gEfiPhysicalPresenceGuid,
+ NULL,
+ &DataSize,
+ &PpiFlags
+ );
+ if (EFI_ERROR (Status)) {
+ PpiFlags.PPFlags = TCG_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_PROVISION;
+ Status = gRT->SetVariable (
+ PHYSICAL_PRESENCE_FLAGS_VARIABLE,
+ &gEfiPhysicalPresenceGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ sizeof (EFI_PHYSICAL_PRESENCE_FLAGS),
+ &PpiFlags
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "[TPM] Set physical presence flag failed, Status = %r\n", Status));
+ return ;
+ }
+ }
+ DEBUG ((EFI_D_INFO, "[TPM] PpiFlags = %x\n", PpiFlags.PPFlags));
+
+ //
+ // This flags variable controls whether physical presence is required for TPM command.
+ // It should be protected from malicious software. We set it as read-only variable here.
+ //
+ Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **)&VariableLockProtocol);
+ if (!EFI_ERROR (Status)) {
+ Status = VariableLockProtocol->RequestToLock (
+ VariableLockProtocol,
+ PHYSICAL_PRESENCE_FLAGS_VARIABLE,
+ &gEfiPhysicalPresenceGuid
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "[TPM] Error when lock variable %s, Status = %r\n", PHYSICAL_PRESENCE_FLAGS_VARIABLE, Status));
+ ASSERT_EFI_ERROR (Status);
+ }
+ }
+
+ //
+ // Initialize physical presence variable.
+ //
+ DataSize = sizeof (EFI_PHYSICAL_PRESENCE);
+ Status = gRT->GetVariable (
+ PHYSICAL_PRESENCE_VARIABLE,
+ &gEfiPhysicalPresenceGuid,
+ NULL,
+ &DataSize,
+ &TcgPpData
+ );
+ if (EFI_ERROR (Status)) {
+ ZeroMem ((VOID*)&TcgPpData, sizeof (TcgPpData));
+ 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)) {
+ DEBUG ((EFI_D_ERROR, "[TPM] Set physical presence variable failed, Status = %r\n", Status));
+ return;
+ }
+ }
+
+ DEBUG ((EFI_D_INFO, "[TPM] Flags=%x, PPRequest=%x\n", PpiFlags.PPFlags, TcgPpData.PPRequest));
+
+ if (TcgPpData.PPRequest == PHYSICAL_PRESENCE_NO_ACTION) {
+ //
+ // No operation request
+ //
+ return;
+ }
+
+ Status = GetTpmCapability (TcgProtocol, &LifetimeLock, &CmdEnable);
+ if (EFI_ERROR (Status)) {
+ return ;
+ }
+
+ if (!CmdEnable) {
+ if (LifetimeLock) {
+ //
+ // physicalPresenceCMDEnable is locked, can't execute physical presence command.
+ //
+ return ;
+ }
+ Status = TpmPhysicalPresence (TcgProtocol, TPM_PHYSICAL_PRESENCE_CMD_ENABLE);
+ if (EFI_ERROR (Status)) {
+ return ;
+ }
+ }
+
+ //
+ // Set operator physical presence flags
+ //
+ TpmPhysicalPresence (TcgProtocol, TPM_PHYSICAL_PRESENCE_PRESENT);
+
+ //
+ // Execute pending TPM request.
+ //
+ ExecutePendingTpmRequest (TcgProtocol, &TcgPpData, PpiFlags);
+ DEBUG ((EFI_D_INFO, "[TPM] PPResponse = %x\n", TcgPpData.PPResponse));
+
+ //
+ // Lock physical presence.
+ //
+ TpmPhysicalPresence (TcgProtocol, TPM_PHYSICAL_PRESENCE_NOTPRESENT | TPM_PHYSICAL_PRESENCE_LOCK);
+}
+
+/**
+ Check if the pending TPM request needs user input to confirm.
+
+ The TPM request may come from OS. This API will check if TPM request exists and need user
+ input to confirmation.
+
+ @retval TRUE TPM needs input to confirm user physical presence.
+ @retval FALSE TPM doesn't need input to confirm user physical presence.
+
+**/
+BOOLEAN
+EFIAPI
+TcgPhysicalPresenceLibNeedUserConfirm(
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_PRESENCE TcgPpData;
+ UINTN DataSize;
+ BOOLEAN RequestConfirmed;
+ BOOLEAN LifetimeLock;
+ BOOLEAN CmdEnable;
+ EFI_TCG_PROTOCOL *TcgProtocol;
+ EFI_PHYSICAL_PRESENCE_FLAGS PpiFlags;
+
+ Status = gBS->LocateProtocol (&gEfiTcgProtocolGuid, NULL, (VOID **)&TcgProtocol);
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ //
+ // Check Tpm requests
+ //
+ DataSize = sizeof (EFI_PHYSICAL_PRESENCE);
+ Status = gRT->GetVariable (
+ PHYSICAL_PRESENCE_VARIABLE,
+ &gEfiPhysicalPresenceGuid,
+ NULL,
+ &DataSize,
+ &TcgPpData
+ );
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ DataSize = sizeof (EFI_PHYSICAL_PRESENCE_FLAGS);
+ Status = gRT->GetVariable (
+ PHYSICAL_PRESENCE_FLAGS_VARIABLE,
+ &gEfiPhysicalPresenceGuid,
+ NULL,
+ &DataSize,
+ &PpiFlags
+ );
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ if (TcgPpData.PPRequest == PHYSICAL_PRESENCE_NO_ACTION) {
+ //
+ // No operation request
+ //
+ return FALSE;
+ }
+
+ if (!HaveValidTpmRequest(&TcgPpData, PpiFlags, &RequestConfirmed)) {
+ //
+ // Invalid operation request.
+ //
+ return FALSE;
+ }
+
+ //
+ // Check Tpm Capability
+ //
+ Status = GetTpmCapability (TcgProtocol, &LifetimeLock, &CmdEnable);
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ if (!CmdEnable) {
+ if (LifetimeLock) {
+ //
+ // physicalPresenceCMDEnable is locked, can't execute physical presence command.
+ //
+ return FALSE;
+ }
+ }
+
+ if (!RequestConfirmed) {
+ //
+ // Need UI to confirm
+ //
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
diff --git a/Core/SecurityPkg/Library/DxeTcgPhysicalPresenceLib/DxeTcgPhysicalPresenceLib.inf b/Core/SecurityPkg/Library/DxeTcgPhysicalPresenceLib/DxeTcgPhysicalPresenceLib.inf
new file mode 100644
index 0000000000..3aacba5c2b
--- /dev/null
+++ b/Core/SecurityPkg/Library/DxeTcgPhysicalPresenceLib/DxeTcgPhysicalPresenceLib.inf
@@ -0,0 +1,69 @@
+## @file
+# Executes pending TPM 1.2 requests from OS or BIOS and Locks TPM
+#
+# This library will check and execute TPM 1.2 request from OS or BIOS. The request may
+# ask for user confirmation before execution. This Library will also lock TPM physical
+# presence at last.
+#
+# Caution: This module requires additional review when modified.
+# This driver will have external input - variable.
+# This external input must be validated carefully to avoid security issue.
+#
+# Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeTcgPhysicalPresenceLib
+ MODULE_UNI_FILE = DxeTcgPhysicalPresenceLib.uni
+ FILE_GUID = EBC43A46-34AC-4F07-A7F5-A5394619361C
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = TcgPhysicalPresenceLib|DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SAL_DRIVER UEFI_APPLICATION UEFI_DRIVER
+ CONSTRUCTOR = TcgPhysicalPresenceLibConstructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ DxeTcgPhysicalPresenceLib.c
+ PhysicalPresenceStrings.uni
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+ MemoryAllocationLib
+ UefiLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ UefiRuntimeServicesTableLib
+ BaseMemoryLib
+ DebugLib
+ PrintLib
+ HiiLib
+ TcgPpVendorLib
+
+[Protocols]
+ gEfiTcgProtocolGuid ## SOMETIMES_CONSUMES
+ gEdkiiVariableLockProtocolGuid ## SOMETIMES_CONSUMES
+
+[Guids]
+ ## SOMETIMES_CONSUMES ## HII
+ ## SOMETIMES_PRODUCES ## Variable:L"PhysicalPresence"
+ ## SOMETIMES_CONSUMES ## Variable:L"PhysicalPresence"
+ ## SOMETIMES_PRODUCES ## Variable:L"PhysicalPresenceFlags"
+ ## SOMETIMES_CONSUMES ## Variable:L"PhysicalPresenceFlags"
+ gEfiPhysicalPresenceGuid
diff --git a/Core/SecurityPkg/Library/DxeTcgPhysicalPresenceLib/DxeTcgPhysicalPresenceLib.uni b/Core/SecurityPkg/Library/DxeTcgPhysicalPresenceLib/DxeTcgPhysicalPresenceLib.uni
new file mode 100644
index 0000000000..26f8dd3e99
--- /dev/null
+++ b/Core/SecurityPkg/Library/DxeTcgPhysicalPresenceLib/DxeTcgPhysicalPresenceLib.uni
@@ -0,0 +1,27 @@
+// /** @file
+// Executes pending TPM 1.2 requests from OS or BIOS and Locks TPM
+//
+// This library will check and execute TPM 1.2 request from OS or BIOS. The request may
+// ask for user confirmation before execution. This Library will also lock TPM physical
+// presence at last.
+//
+// Caution: This module requires additional review when modified.
+// This driver will have external input - variable.
+// This external input must be validated carefully to avoid security issue.
+//
+// Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Executes pending TPM 1.2 requests from OS or BIOS and Locks TPM"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library will ask for user confirmation for the pending TPM physical present requests. Once confirmed, it will execute the request, and locks TPM physical presence at last. Caution: This module requires additional review when modified. This driver will have external input - variable. This external input must be validated carefully to avoid security issue."
+
diff --git a/Core/SecurityPkg/Library/DxeTcgPhysicalPresenceLib/PhysicalPresenceStrings.uni b/Core/SecurityPkg/Library/DxeTcgPhysicalPresenceLib/PhysicalPresenceStrings.uni
new file mode 100644
index 0000000000..065cd63be1
--- /dev/null
+++ b/Core/SecurityPkg/Library/DxeTcgPhysicalPresenceLib/PhysicalPresenceStrings.uni
@@ -0,0 +1,52 @@
+/** @file
+ String definitions for TPM 1.2 physical presence confirm text.
+
+Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#langdef en-US "English"
+
+#string TPM_HEAD_STR #language en-US "A configuration change was requested to %s this computer's TPM (Trusted Platform Module)\n\n"
+#string TPM_PPI_HEAD_STR #language en-US "A configuration change was requested to allow the Operating System to %s the computer's TPM (Trusted Platform Module) without asking for user confirmation in the future.\n\n"
+#string TPM_UPGRADE_HEAD_STR #language en-US "A configuration change was requested to %s to the TPM's (Trusted Platform Module) firmware.\n\n"
+
+#string TPM_ACCEPT_KEY #language en-US "Press F10 "
+#string TPM_CAUTION_KEY #language en-US "Press F12 "
+#string TPM_REJECT_KEY #language en-US "to %s the TPM \nPress ESC to reject this change request and continue\n"
+
+#string TPM_ENABLE #language en-US "enable"
+#string TPM_DISABLE #language en-US "disable"
+#string TPM_ACTIVATE #language en-US "activate"
+#string TPM_DEACTIVATE #language en-US "deactivate"
+#string TPM_CLEAR #language en-US "clear"
+#string TPM_ENABLE_ACTIVATE #language en-US "enable and activate"
+#string TPM_DEACTIVATE_DISABLE #language en-US "deactivate and disable"
+#string TPM_ALLOW_TAKE_OWNERSHIP #language en-US "allow a user to take ownership of"
+#string TPM_DISALLOW_TAKE_OWNERSHIP #language en-US "disallow a user to take ownership of"
+#string TPM_TURN_ON #language en-US "enable, activate, and allow a user to take ownership of"
+#string TPM_TURN_OFF #language en-US "deactivate, disable, and disallow a user to take ownership of"
+#string TPM_CLEAR_TURN_ON #language en-US "clear, enable, and activate"
+#string TPM_ENABLE_ACTIVATE_CLEAR #language en-US "enable, activate and clear"
+#string TPM_ENABLE_ACTIVATE_CLEAR_ENABLE_ACTIVATE #language en-US "enable, activate, clear, enable, and activate"
+#string TPM_UNOWNED_FIELD_UPGRADE #language en-US "allow field upgrade"
+
+#string TPM_NO_PPI_PROVISION #language en-US "provision"
+#string TPM_NO_PPI_MAINTAIN #language en-US "maintain"
+#string TPM_NO_PPI_INFO #language en-US "to approve future Operating System requests "
+
+#string TPM_WARNING_MAINTAIN #language en-US "WARNING: Allowing changes to the TPM's firmware may affect the operation of the TPM and may erase information stored on the TPM.\nYou may lose all created keys and access to data encrypted by these keys.\n\n"
+#string TPM_WARNING #language en-US "WARNING: Doing so might prevent security applications that rely on the TPM from functioning as expected\n\n"
+#string TPM_WARNING_CLEAR #language en-US "WARNING: Clearing erases information stored on the TPM. You will lose all created keys and access to data encrypted by these keys. "
+#string TPM_WARNING_CLEAR_CONT #language en-US "Take ownership as soon as possible after this step.\n\n"
+#string TPM_NOTE_OFF #language en-US "NOTE: This action will turn off the TPM\n\n"
+#string TPM_NOTE_ON #language en-US "NOTE: This action will turn on the TPM\n\n"
+#string TPM_NOTE_CLEAR #language en-US "NOTE: This action does not clear the TPM, but by approving this configuration change, future actions to clear the TPM will not require user confirmation.\n\n"
diff --git a/Core/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c b/Core/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c
new file mode 100644
index 0000000000..aacafa83b3
--- /dev/null
+++ b/Core/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c
@@ -0,0 +1,702 @@
+/** @file
+ The library instance provides security service of TPM2 measure boot.
+
+ Caution: This file requires additional review when modified.
+ This library will have external input - PE/COFF image and GPT partition.
+ This external input must be validated carefully to avoid security issue like
+ buffer overflow, integer overflow.
+
+ DxeTpm2MeasureBootLibImageRead() function will make sure the PE/COFF image content
+ read is within the image buffer.
+
+ Tcg2MeasurePeImage() function will accept untrusted PE/COFF image and validate its
+ data structure within this image buffer before use.
+
+ Tcg2MeasureGptTable() function will receive untrusted GPT partition table, and parse
+ partition data carefully.
+
+Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.<BR>
+(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiDxe.h>
+
+#include <Protocol/Tcg2Protocol.h>
+#include <Protocol/BlockIo.h>
+#include <Protocol/DiskIo.h>
+#include <Protocol/DevicePathToText.h>
+#include <Protocol/FirmwareVolumeBlock.h>
+
+#include <Guid/MeasuredFvHob.h>
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/BaseCryptLib.h>
+#include <Library/PeCoffLib.h>
+#include <Library/SecurityManagementLib.h>
+#include <Library/HobLib.h>
+
+//
+// Flag to check GPT partition. It only need be measured once.
+//
+BOOLEAN mTcg2MeasureGptTableFlag = FALSE;
+UINTN mTcg2MeasureGptCount = 0;
+VOID *mTcg2FileBuffer;
+UINTN mTcg2ImageSize;
+//
+// Measured FV handle cache
+//
+EFI_HANDLE mTcg2CacheMeasuredHandle = NULL;
+MEASURED_HOB_DATA *mTcg2MeasuredHobData = NULL;
+
+/**
+ Reads contents of a PE/COFF image in memory buffer.
+
+ Caution: This function may receive untrusted input.
+ PE/COFF image is external input, so this function will make sure the PE/COFF image content
+ read is within the image 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
+DxeTpm2MeasureBootLibImageRead (
+ IN VOID *FileHandle,
+ IN UINTN FileOffset,
+ IN OUT UINTN *ReadSize,
+ OUT VOID *Buffer
+ )
+{
+ UINTN EndPosition;
+
+ if (FileHandle == NULL || ReadSize == NULL || Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (MAX_ADDRESS - FileOffset < *ReadSize) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ EndPosition = FileOffset + *ReadSize;
+ if (EndPosition > mTcg2ImageSize) {
+ *ReadSize = (UINT32)(mTcg2ImageSize - FileOffset);
+ }
+
+ if (FileOffset >= mTcg2ImageSize) {
+ *ReadSize = 0;
+ }
+
+ CopyMem (Buffer, (UINT8 *)((UINTN) FileHandle + FileOffset), *ReadSize);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Measure GPT table data into TPM log.
+
+ Caution: This function may receive untrusted input.
+ The GPT partition table is external input, so this function should parse partition data carefully.
+
+ @param Tcg2Protocol Pointer to the located TCG2 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
+Tcg2MeasureGptTable (
+ IN EFI_TCG2_PROTOCOL *Tcg2Protocol,
+ 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;
+ EFI_TCG2_EVENT *Tcg2Event;
+ EFI_GPT_DATA *GptData;
+ UINT32 EventSize;
+
+ if (mTcg2MeasureGptCount > 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 (!IsZeroGuid (&PartitionEntry->PartitionTypeGUID)) {
+ NumberOfPartition++;
+ }
+ PartitionEntry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartitionEntry + PrimaryHeader->SizeOfPartitionEntry);
+ }
+
+ //
+ // Prepare Data for Measurement
+ //
+ EventSize = (UINT32)(sizeof (EFI_GPT_DATA) - sizeof (GptData->Partitions)
+ + NumberOfPartition * PrimaryHeader->SizeOfPartitionEntry);
+ Tcg2Event = (EFI_TCG2_EVENT *) AllocateZeroPool (EventSize + sizeof (EFI_TCG2_EVENT) - sizeof(Tcg2Event->Event));
+ if (Tcg2Event == NULL) {
+ FreePool (PrimaryHeader);
+ FreePool (EntryPtr);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Tcg2Event->Size = EventSize + sizeof (EFI_TCG2_EVENT) - sizeof(Tcg2Event->Event);
+ Tcg2Event->Header.HeaderSize = sizeof(EFI_TCG2_EVENT_HEADER);
+ Tcg2Event->Header.HeaderVersion = EFI_TCG2_EVENT_HEADER_VERSION;
+ Tcg2Event->Header.PCRIndex = 5;
+ Tcg2Event->Header.EventType = EV_EFI_GPT_EVENT;
+ GptData = (EFI_GPT_DATA *) Tcg2Event->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 (!IsZeroGuid (&PartitionEntry->PartitionTypeGUID)) {
+ CopyMem (
+ (UINT8 *)&GptData->Partitions + NumberOfPartition * PrimaryHeader->SizeOfPartitionEntry,
+ (UINT8 *)PartitionEntry,
+ PrimaryHeader->SizeOfPartitionEntry
+ );
+ NumberOfPartition++;
+ }
+ PartitionEntry =(EFI_PARTITION_ENTRY *)((UINT8 *)PartitionEntry + PrimaryHeader->SizeOfPartitionEntry);
+ }
+
+ //
+ // Measure the GPT data
+ //
+ Status = Tcg2Protocol->HashLogExtendEvent (
+ Tcg2Protocol,
+ 0,
+ (EFI_PHYSICAL_ADDRESS) (UINTN) (VOID *) GptData,
+ (UINT64) EventSize,
+ Tcg2Event
+ );
+ if (!EFI_ERROR (Status)) {
+ mTcg2MeasureGptCount++;
+ }
+
+ FreePool (PrimaryHeader);
+ FreePool (EntryPtr);
+ FreePool (Tcg2Event);
+
+ return Status;
+}
+
+/**
+ Measure PE image into TPM log based on the authenticode image hashing in
+ PE/COFF Specification 8.0 Appendix A.
+
+ Caution: This function may receive untrusted input.
+ PE/COFF image is external input, so this function will validate its data structure
+ within this image buffer before use.
+
+ @param[in] Tcg2Protocol Pointer to the located TCG2 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 EFI_UNSUPPORTED ImageType is unsupported or PE image is mal-format.
+ @retval other error value
+
+**/
+EFI_STATUS
+EFIAPI
+Tcg2MeasurePeImage (
+ IN EFI_TCG2_PROTOCOL *Tcg2Protocol,
+ IN EFI_PHYSICAL_ADDRESS ImageAddress,
+ IN UINTN ImageSize,
+ IN UINTN LinkTimeBase,
+ IN UINT16 ImageType,
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_TCG2_EVENT *Tcg2Event;
+ EFI_IMAGE_LOAD_EVENT *ImageLoad;
+ UINT32 FilePathSize;
+ UINT32 EventSize;
+
+ Status = EFI_UNSUPPORTED;
+ ImageLoad = NULL;
+ FilePathSize = (UINT32) GetDevicePathSize (FilePath);
+
+ //
+ // Determine destination PCR by BootPolicy
+ //
+ EventSize = sizeof (*ImageLoad) - sizeof (ImageLoad->DevicePath) + FilePathSize;
+ Tcg2Event = AllocateZeroPool (EventSize + sizeof (EFI_TCG2_EVENT) - sizeof(Tcg2Event->Event));
+ if (Tcg2Event == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Tcg2Event->Size = EventSize + sizeof (EFI_TCG2_EVENT) - sizeof(Tcg2Event->Event);
+ Tcg2Event->Header.HeaderSize = sizeof(EFI_TCG2_EVENT_HEADER);
+ Tcg2Event->Header.HeaderVersion = EFI_TCG2_EVENT_HEADER_VERSION;
+ ImageLoad = (EFI_IMAGE_LOAD_EVENT *) Tcg2Event->Event;
+
+ switch (ImageType) {
+ case EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION:
+ Tcg2Event->Header.EventType = EV_EFI_BOOT_SERVICES_APPLICATION;
+ Tcg2Event->Header.PCRIndex = 4;
+ break;
+ case EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER:
+ Tcg2Event->Header.EventType = EV_EFI_BOOT_SERVICES_DRIVER;
+ Tcg2Event->Header.PCRIndex = 2;
+ break;
+ case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER:
+ Tcg2Event->Header.EventType = EV_EFI_RUNTIME_SERVICES_DRIVER;
+ Tcg2Event->Header.PCRIndex = 2;
+ break;
+ default:
+ DEBUG ((
+ EFI_D_ERROR,
+ "Tcg2MeasurePeImage: Unknown subsystem type %d",
+ ImageType
+ ));
+ goto Finish;
+ }
+
+ ImageLoad->ImageLocationInMemory = ImageAddress;
+ ImageLoad->ImageLengthInMemory = ImageSize;
+ ImageLoad->ImageLinkTimeAddress = LinkTimeBase;
+ ImageLoad->LengthOfDevicePath = FilePathSize;
+ if ((FilePath != NULL) && (FilePathSize != 0)) {
+ CopyMem (ImageLoad->DevicePath, FilePath, FilePathSize);
+ }
+
+ //
+ // Log the PE data
+ //
+ Status = Tcg2Protocol->HashLogExtendEvent (
+ Tcg2Protocol,
+ PE_COFF_IMAGE,
+ ImageAddress,
+ ImageSize,
+ Tcg2Event
+ );
+ if (Status == EFI_VOLUME_FULL) {
+ //
+ // Volume full here means the image is hashed and its result is extended to PCR.
+ // But the event log cann't be saved since log area is full.
+ // Just return EFI_SUCCESS in order not to block the image load.
+ //
+ Status = EFI_SUCCESS;
+ }
+
+Finish:
+ FreePool (Tcg2Event);
+
+ 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] 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.
+ @param[in] BootPolicy A boot policy that was used to call LoadImage() UEFI service.
+
+ @retval EFI_SUCCESS The file specified by DevicePath and non-NULL
+ FileBuffer did authenticate, and the platform policy dictates
+ that the DXE Foundation may use the file.
+ @retval other error value
+**/
+EFI_STATUS
+EFIAPI
+DxeTpm2MeasureBootHandler (
+ IN UINT32 AuthenticationStatus,
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *File,
+ IN VOID *FileBuffer,
+ IN UINTN FileSize,
+ IN BOOLEAN BootPolicy
+ )
+{
+ EFI_TCG2_PROTOCOL *Tcg2Protocol;
+ EFI_STATUS Status;
+ EFI_TCG2_BOOT_SERVICE_CAPABILITY ProtocolCapability;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
+ EFI_DEVICE_PATH_PROTOCOL *OrigDevicePathNode;
+ EFI_HANDLE Handle;
+ EFI_HANDLE TempHandle;
+ BOOLEAN ApplicationRequired;
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol;
+ EFI_PHYSICAL_ADDRESS FvAddress;
+ UINT32 Index;
+
+ Status = gBS->LocateProtocol (&gEfiTcg2ProtocolGuid, NULL, (VOID **) &Tcg2Protocol);
+ if (EFI_ERROR (Status)) {
+ //
+ // Tcg2 protocol is not installed. So, TPM2 is not present.
+ // Don't do any measurement, and directly return EFI_SUCCESS.
+ //
+ DEBUG ((EFI_D_VERBOSE, "DxeTpm2MeasureBootHandler - Tcg2 - %r\n", Status));
+ return EFI_SUCCESS;
+ }
+
+ ProtocolCapability.Size = (UINT8) sizeof (ProtocolCapability);
+ Status = Tcg2Protocol->GetCapability (
+ Tcg2Protocol,
+ &ProtocolCapability
+ );
+ if (EFI_ERROR (Status) || (!ProtocolCapability.TPMPresentFlag)) {
+ //
+ // TPM device doesn't work or activate.
+ //
+ DEBUG ((EFI_D_ERROR, "DxeTpm2MeasureBootHandler (%r) - TPMPresentFlag - %x\n", Status, ProtocolCapability.TPMPresentFlag));
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Copy File Device Path
+ //
+ OrigDevicePathNode = DuplicateDevicePath (File);
+
+ //
+ // 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) && !mTcg2MeasureGptTableFlag) {
+ //
+ // Find the gpt partion on the given devicepath
+ //
+ DevicePathNode = OrigDevicePathNode;
+ ASSERT (DevicePathNode != NULL);
+ 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 = Tcg2MeasureGptTable (Tcg2Protocol, Handle);
+ DEBUG ((EFI_D_INFO, "DxeTpm2MeasureBootHandler - Tcg2MeasureGptTable - %r\n", Status));
+ if (!EFI_ERROR (Status)) {
+ //
+ // GPT disk check done.
+ //
+ mTcg2MeasureGptTableFlag = 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 FVB protocol.
+ //
+ DevicePathNode = OrigDevicePathNode;
+ Status = gBS->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid, &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 PE image from unmeasured Firmware volume need be measured
+ // The PE image from measured Firmware volume will be mearsured according to policy below.
+ // If it is driver, do not measure
+ // If it is application, still measure.
+ //
+ ApplicationRequired = TRUE;
+
+ if (mTcg2CacheMeasuredHandle != Handle && mTcg2MeasuredHobData != NULL) {
+ //
+ // Search for Root FV of this PE image
+ //
+ TempHandle = Handle;
+ do {
+ Status = gBS->HandleProtocol(
+ TempHandle,
+ &gEfiFirmwareVolumeBlockProtocolGuid,
+ (VOID**)&FvbProtocol
+ );
+ TempHandle = FvbProtocol->ParentHandle;
+ } while (!EFI_ERROR(Status) && FvbProtocol->ParentHandle != NULL);
+
+ //
+ // Search in measured FV Hob
+ //
+ Status = FvbProtocol->GetPhysicalAddress(FvbProtocol, &FvAddress);
+ if (EFI_ERROR(Status)){
+ return Status;
+ }
+
+ ApplicationRequired = FALSE;
+
+ for (Index = 0; Index < mTcg2MeasuredHobData->Num; Index++) {
+ if(mTcg2MeasuredHobData->MeasuredFvBuf[Index].BlobBase == FvAddress) {
+ //
+ // Cache measured FV for next measurement
+ //
+ mTcg2CacheMeasuredHandle = Handle;
+ ApplicationRequired = TRUE;
+ break;
+ }
+ }
+ }
+ }
+
+ //
+ // File is not found.
+ //
+ if (FileBuffer == NULL) {
+ Status = EFI_SECURITY_VIOLATION;
+ goto Finish;
+ }
+
+ mTcg2ImageSize = FileSize;
+ mTcg2FileBuffer = FileBuffer;
+
+ //
+ // Measure PE Image
+ //
+ DevicePathNode = OrigDevicePathNode;
+ ZeroMem (&ImageContext, sizeof (ImageContext));
+ ImageContext.Handle = (VOID *) FileBuffer;
+ ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) DxeTpm2MeasureBootLibImageRead;
+
+ //
+ // 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;
+ ToText = ConvertDevicePathToText (
+ DevicePathNode,
+ FALSE,
+ TRUE
+ );
+ if (ToText != NULL) {
+ DEBUG ((DEBUG_INFO, "The measured image path is %s.\n", ToText));
+ FreePool (ToText);
+ }
+ DEBUG_CODE_END ();
+
+ //
+ // Measure PE image into TPM log.
+ //
+ Status = Tcg2MeasurePeImage (
+ Tcg2Protocol,
+ (EFI_PHYSICAL_ADDRESS) (UINTN) FileBuffer,
+ FileSize,
+ (UINTN) ImageContext.ImageAddress,
+ ImageContext.ImageType,
+ DevicePathNode
+ );
+ DEBUG ((EFI_D_INFO, "DxeTpm2MeasureBootHandler - Tcg2MeasurePeImage - %r\n", Status));
+ }
+
+ //
+ // Done, free the allocated resource.
+ //
+Finish:
+ if (OrigDevicePathNode != NULL) {
+ FreePool (OrigDevicePathNode);
+ }
+
+ DEBUG ((EFI_D_INFO, "DxeTpm2MeasureBootHandler - %r\n", Status));
+
+ 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
+DxeTpm2MeasureBootLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_HOB_GUID_TYPE *GuidHob;
+
+ GuidHob = NULL;
+
+ GuidHob = GetFirstGuidHob (&gMeasuredFvHobGuid);
+
+ if (GuidHob != NULL) {
+ mTcg2MeasuredHobData = GET_GUID_HOB_DATA (GuidHob);
+ }
+
+ return RegisterSecurity2Handler (
+ DxeTpm2MeasureBootHandler,
+ EFI_AUTH_OPERATION_MEASURE_IMAGE | EFI_AUTH_OPERATION_IMAGE_REQUIRED
+ );
+}
diff --git a/Core/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.inf b/Core/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.inf
new file mode 100644
index 0000000000..a11988e4aa
--- /dev/null
+++ b/Core/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.inf
@@ -0,0 +1,67 @@
+## @file
+# Provides security service for TPM 2.0 measured boot
+#
+# This library instance hooks LoadImage() API to measure every image that
+# is not measured in PEI phase. And, it will also measure GPT partition.
+#
+# Caution: This module requires additional review when modified.
+# This library will have external input - PE/COFF image and GPT partition.
+# This external input must be validated carefully to avoid security issues such
+# as buffer overflow or integer overflow.
+#
+# Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeTpm2MeasureBootLib
+ MODULE_UNI_FILE = DxeTpm2MeasureBootLib.uni
+ FILE_GUID = 778CE4F4-36BD-4ae7-B8F0-10B420B0D174
+ 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 = DxeTpm2MeasureBootLibConstructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ DxeTpm2MeasureBootLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ SecurityPkg/SecurityPkg.dec
+ CryptoPkg/CryptoPkg.dec
+
+[LibraryClasses]
+ BaseMemoryLib
+ DebugLib
+ MemoryAllocationLib
+ DevicePathLib
+ UefiBootServicesTableLib
+ BaseCryptLib
+ PeCoffLib
+ BaseLib
+ SecurityManagementLib
+ HobLib
+
+[Guids]
+ gMeasuredFvHobGuid ## SOMETIMES_CONSUMES ## HOB
+
+[Protocols]
+ gEfiTcg2ProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiFirmwareVolumeBlockProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiBlockIoProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiDiskIoProtocolGuid ## SOMETIMES_CONSUMES
+
diff --git a/Core/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.uni b/Core/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.uni
new file mode 100644
index 0000000000..260dd04481
--- /dev/null
+++ b/Core/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.uni
@@ -0,0 +1,27 @@
+// /** @file
+// Provides security service for TPM 2.0 measured boot
+//
+// This library instance hooks LoadImage() API to measure every image that
+// is not measured in PEI phase. And, it will also measure GPT partition.
+//
+// Caution: This module requires additional review when modified.
+// This library will have external input - PE/COFF image and GPT partition.
+// This external input must be validated carefully to avoid security issues such
+// as buffer overflow or integer overflow.
+//
+// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides security service for TPM 2.0 measured boot"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library instance hooks LoadImage() API to measure every image that is not measured in PEI phase. And, it will also measure GPT partition. Caution: This module requires additional review when modified. This library will have external input - PE/COFF image and GPT partition. This external input must be validated carefully to avoid security issues such as buffer overflow or integer overflow."
+
diff --git a/Core/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c b/Core/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c
new file mode 100644
index 0000000000..8167a21929
--- /dev/null
+++ b/Core/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c
@@ -0,0 +1,1011 @@
+/** @file
+ The library instance provides security service of TPM measure boot.
+
+ Caution: This file requires additional review when modified.
+ This library will have external input - PE/COFF image and GPT partition.
+ This external input must be validated carefully to avoid security issue like
+ buffer overflow, integer overflow.
+
+ DxeTpmMeasureBootLibImageRead() function will make sure the PE/COFF image content
+ read is within the image buffer.
+
+ TcgMeasurePeImage() function will accept untrusted PE/COFF image and validate its
+ data structure within this image buffer before use.
+
+ TcgMeasureGptTable() function will receive untrusted GPT partition table, and parse
+ partition data carefully.
+
+Copyright (c) 2009 - 2017, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiDxe.h>
+
+#include <Protocol/TcgService.h>
+#include <Protocol/BlockIo.h>
+#include <Protocol/DiskIo.h>
+#include <Protocol/FirmwareVolumeBlock.h>
+
+#include <Guid/MeasuredFvHob.h>
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/BaseCryptLib.h>
+#include <Library/PeCoffLib.h>
+#include <Library/SecurityManagementLib.h>
+#include <Library/HobLib.h>
+
+//
+// Flag to check GPT partition. It only need be measured once.
+//
+BOOLEAN mMeasureGptTableFlag = FALSE;
+UINTN mMeasureGptCount = 0;
+VOID *mFileBuffer;
+UINTN mTpmImageSize;
+//
+// Measured FV handle cache
+//
+EFI_HANDLE mCacheMeasuredHandle = NULL;
+MEASURED_HOB_DATA *mMeasuredHobData = NULL;
+
+/**
+ Reads contents of a PE/COFF image in memory buffer.
+
+ Caution: This function may receive untrusted input.
+ PE/COFF image is external input, so this function will make sure the PE/COFF image content
+ read is within the image 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
+DxeTpmMeasureBootLibImageRead (
+ IN VOID *FileHandle,
+ IN UINTN FileOffset,
+ IN OUT UINTN *ReadSize,
+ OUT VOID *Buffer
+ )
+{
+ UINTN EndPosition;
+
+ if (FileHandle == NULL || ReadSize == NULL || Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (MAX_ADDRESS - FileOffset < *ReadSize) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ EndPosition = FileOffset + *ReadSize;
+ if (EndPosition > mTpmImageSize) {
+ *ReadSize = (UINT32)(mTpmImageSize - FileOffset);
+ }
+
+ if (FileOffset >= mTpmImageSize) {
+ *ReadSize = 0;
+ }
+
+ CopyMem (Buffer, (UINT8 *)((UINTN) FileHandle + FileOffset), *ReadSize);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Measure GPT table data into TPM log.
+
+ Caution: This function may receive untrusted input.
+ The GPT partition table is external input, so this function should parse partition data carefully.
+
+ @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 (!IsZeroGuid (&PartitionEntry->PartitionTypeGUID)) {
+ NumberOfPartition++;
+ }
+ PartitionEntry = (EFI_PARTITION_ENTRY *)((UINT8 *)PartitionEntry + PrimaryHeader->SizeOfPartitionEntry);
+ }
+
+ //
+ // Prepare 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_HDR));
+ 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 (!IsZeroGuid (&PartitionEntry->PartitionTypeGUID)) {
+ CopyMem (
+ (UINT8 *)&GptData->Partitions + NumberOfPartition * PrimaryHeader->SizeOfPartitionEntry,
+ (UINT8 *)PartitionEntry,
+ PrimaryHeader->SizeOfPartitionEntry
+ );
+ NumberOfPartition++;
+ }
+ PartitionEntry =(EFI_PARTITION_ENTRY *)((UINT8 *)PartitionEntry + PrimaryHeader->SizeOfPartitionEntry);
+ }
+
+ //
+ // 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.
+
+ Caution: This function may receive untrusted input.
+ PE/COFF image is external input, so this function will validate its data structure
+ within this image buffer before use.
+
+ Notes: PE/COFF image has been checked by BasePeCoffLib PeCoffLoaderGetImageInfo() in
+ its caller function DxeTpmMeasureBootHandler().
+
+ @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 EFI_UNSUPPORTED ImageType is unsupported or PE image is mal-format.
+ @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;
+ UINTN Pos;
+ UINT16 Magic;
+ UINT32 EventSize;
+ UINT32 EventNumber;
+ EFI_PHYSICAL_ADDRESS EventLogLastEntry;
+ EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
+ UINT32 NumberOfRvaAndSizes;
+ BOOLEAN HashStatus;
+ UINT32 CertSize;
+
+ Status = EFI_UNSUPPORTED;
+ 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
+ ));
+ goto Finish;
+ }
+
+ ImageLoad->ImageLocationInMemory = ImageAddress;
+ ImageLoad->ImageLengthInMemory = ImageSize;
+ ImageLoad->ImageLinkTimeAddress = LinkTimeBase;
+ ImageLoad->LengthOfDevicePath = FilePathSize;
+ if ((FilePath != NULL) && (FilePathSize != 0)) {
+ 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;
+ }
+
+ Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINT8 *) (UINTN) ImageAddress + PeCoffHeaderOffset);
+ if (Hdr.Pe32->Signature != EFI_IMAGE_NT_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;
+ }
+
+ HashStatus = Sha1Init (Sha1Ctx);
+ if (!HashStatus) {
+ goto Finish;
+ }
+
+ //
+ // Measuring PE/COFF Image Header;
+ // But CheckSum field and SECURITY data directory (certificate) are excluded
+ //
+ if (Hdr.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ //
+ // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value
+ // in the PE/COFF Header. If the MachineType is Itanium(IA64) and the
+ // Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
+ // then override the magic value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
+ //
+ Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;
+ } else {
+ //
+ // Get the magic value from the PE/COFF Optional Header
+ //
+ 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
+ //
+ NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
+ HashSize = (UINTN) (&Hdr.Pe32->OptionalHeader.CheckSum) - (UINTN) HashBase;
+ } else {
+ //
+ // Use PE32+ offset
+ //
+ NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
+ HashSize = (UINTN) (&Hdr.Pe32Plus->OptionalHeader.CheckSum) - (UINTN) HashBase;
+ }
+
+ HashStatus = Sha1Update (Sha1Ctx, HashBase, HashSize);
+ if (!HashStatus) {
+ goto Finish;
+ }
+
+ //
+ // 5. Skip over the image checksum (it occupies a single ULONG).
+ //
+ if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {
+ //
+ // 6. Since there is no Cert Directory in optional header, hash everything
+ // from the end of the checksum to the end of image header.
+ //
+ if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ //
+ // Use PE32 offset.
+ //
+ HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);
+ HashSize = Hdr.Pe32->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress);
+ } else {
+ //
+ // Use PE32+ offset.
+ //
+ HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);
+ HashSize = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress);
+ }
+
+ if (HashSize != 0) {
+ HashStatus = Sha1Update (Sha1Ctx, HashBase, HashSize);
+ if (!HashStatus) {
+ goto Finish;
+ }
+ }
+ } else {
+ //
+ // 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) (&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - (UINTN) HashBase;
+ } else {
+ //
+ // Use PE32+ offset
+ //
+ HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);
+ HashSize = (UINTN) (&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - (UINTN) HashBase;
+ }
+
+ if (HashSize != 0) {
+ HashStatus = Sha1Update (Sha1Ctx, HashBase, HashSize);
+ if (!HashStatus) {
+ goto Finish;
+ }
+ }
+
+ //
+ // 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) (HashBase - ImageAddress);
+ } else {
+ //
+ // Use PE32+ offset
+ //
+ HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];
+ HashSize = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress);
+ }
+
+ if (HashSize != 0) {
+ HashStatus = Sha1Update (Sha1Ctx, HashBase, HashSize);
+ if (!HashStatus) {
+ goto Finish;
+ }
+ }
+ }
+
+ //
+ // 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;
+
+ HashStatus = Sha1Update (Sha1Ctx, HashBase, HashSize);
+ if (!HashStatus) {
+ goto Finish;
+ }
+
+ 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 (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {
+ CertSize = 0;
+ } else {
+ if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ //
+ // Use PE32 offset.
+ //
+ CertSize = Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size;
+ } else {
+ //
+ // Use PE32+ offset.
+ //
+ CertSize = Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size;
+ }
+ }
+
+ if (ImageSize > CertSize + SumOfBytesHashed) {
+ HashSize = (UINTN) (ImageSize - CertSize - SumOfBytesHashed);
+
+ HashStatus = Sha1Update (Sha1Ctx, HashBase, HashSize);
+ if (!HashStatus) {
+ goto Finish;
+ }
+ } else if (ImageSize < CertSize + SumOfBytesHashed) {
+ goto Finish;
+ }
+ }
+
+ //
+ // 17. Finalize the SHA hash.
+ //
+ HashStatus = Sha1Final (Sha1Ctx, (UINT8 *) &TcgEvent->Digest);
+ if (!HashStatus) {
+ goto Finish;
+ }
+
+ //
+ // Log the PE data
+ //
+ EventNumber = 1;
+ Status = TcgProtocol->HashLogExtendEvent (
+ TcgProtocol,
+ (EFI_PHYSICAL_ADDRESS) (UINTN) (VOID *) NULL,
+ 0,
+ TPM_ALG_SHA,
+ TcgEvent,
+ &EventNumber,
+ &EventLogLastEntry
+ );
+ if (Status == EFI_OUT_OF_RESOURCES) {
+ //
+ // Out of resource here means the image is hashed and its result is extended to PCR.
+ // But the event log cann't be saved since log area is full.
+ // Just return EFI_SUCCESS in order not to block the image load.
+ //
+ Status = EFI_SUCCESS;
+ }
+
+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] 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.
+ @param[in] BootPolicy A boot policy that was used to call LoadImage() UEFI service.
+
+ @retval EFI_SUCCESS The file specified by DevicePath and non-NULL
+ FileBuffer did authenticate, and the platform policy dictates
+ that the DXE Foundation may use the file.
+ @retval other error value
+**/
+EFI_STATUS
+EFIAPI
+DxeTpmMeasureBootHandler (
+ IN UINT32 AuthenticationStatus,
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *File,
+ IN VOID *FileBuffer,
+ IN UINTN FileSize,
+ IN BOOLEAN BootPolicy
+ )
+{
+ 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;
+ EFI_HANDLE TempHandle;
+ BOOLEAN ApplicationRequired;
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol;
+ EFI_PHYSICAL_ADDRESS FvAddress;
+ UINT32 Index;
+
+ 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 || (!ProtocolCapability.TPMPresentFlag)) {
+ //
+ // TPM device doesn't work or activate.
+ //
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Copy File Device Path
+ //
+ OrigDevicePathNode = DuplicateDevicePath (File);
+
+ //
+ // 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;
+ ASSERT (DevicePathNode != NULL);
+ 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 FVB protocol.
+ //
+ DevicePathNode = OrigDevicePathNode;
+ Status = gBS->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid, &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 PE image from unmeasured Firmware volume need be measured
+ // The PE image from measured Firmware volume will be mearsured according to policy below.
+ // If it is driver, do not measure
+ // If it is application, still measure.
+ //
+ ApplicationRequired = TRUE;
+
+ if (mCacheMeasuredHandle != Handle && mMeasuredHobData != NULL) {
+ //
+ // Search for Root FV of this PE image
+ //
+ TempHandle = Handle;
+ do {
+ Status = gBS->HandleProtocol(
+ TempHandle,
+ &gEfiFirmwareVolumeBlockProtocolGuid,
+ (VOID**)&FvbProtocol
+ );
+ TempHandle = FvbProtocol->ParentHandle;
+ } while (!EFI_ERROR(Status) && FvbProtocol->ParentHandle != NULL);
+
+ //
+ // Search in measured FV Hob
+ //
+ Status = FvbProtocol->GetPhysicalAddress(FvbProtocol, &FvAddress);
+ if (EFI_ERROR(Status)){
+ return Status;
+ }
+
+ ApplicationRequired = FALSE;
+
+ for (Index = 0; Index < mMeasuredHobData->Num; Index++) {
+ if(mMeasuredHobData->MeasuredFvBuf[Index].BlobBase == FvAddress) {
+ //
+ // Cache measured FV for next measurement
+ //
+ mCacheMeasuredHandle = Handle;
+ ApplicationRequired = TRUE;
+ break;
+ }
+ }
+ }
+ }
+
+ //
+ // File is not found.
+ //
+ if (FileBuffer == NULL) {
+ Status = EFI_SECURITY_VIOLATION;
+ goto Finish;
+ }
+
+ mTpmImageSize = FileSize;
+ mFileBuffer = FileBuffer;
+
+ //
+ // Measure PE Image
+ //
+ DevicePathNode = OrigDevicePathNode;
+ ZeroMem (&ImageContext, sizeof (ImageContext));
+ ImageContext.Handle = (VOID *) FileBuffer;
+ ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) DxeTpmMeasureBootLibImageRead;
+
+ //
+ // 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;
+ ToText = ConvertDevicePathToText (
+ DevicePathNode,
+ FALSE,
+ TRUE
+ );
+ if (ToText != NULL) {
+ DEBUG ((DEBUG_INFO, "The measured image path is %s.\n", ToText));
+ FreePool (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:
+ if (OrigDevicePathNode != NULL) {
+ 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
+ )
+{
+ EFI_HOB_GUID_TYPE *GuidHob;
+
+ GuidHob = NULL;
+
+ GuidHob = GetFirstGuidHob (&gMeasuredFvHobGuid);
+
+ if (GuidHob != NULL) {
+ mMeasuredHobData = GET_GUID_HOB_DATA (GuidHob);
+ }
+
+ return RegisterSecurity2Handler (
+ DxeTpmMeasureBootHandler,
+ EFI_AUTH_OPERATION_MEASURE_IMAGE | EFI_AUTH_OPERATION_IMAGE_REQUIRED
+ );
+}
diff --git a/Core/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.inf b/Core/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.inf
new file mode 100644
index 0000000000..553e68321e
--- /dev/null
+++ b/Core/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.inf
@@ -0,0 +1,67 @@
+## @file
+# Provides security service for TPM 1.2 measured boot
+#
+# This library instance hooks LoadImage() API to measure every image that
+# is not measured in PEI phase. And, it will also measure GPT partition.
+#
+# Caution: This module requires additional review when modified.
+# This library will have external input - PE/COFF image and GPT partition.
+# This external input must be validated carefully to avoid security issues such
+# as buffer overflow or integer overflow.
+#
+# Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeTpmMeasureBootLib
+ MODULE_UNI_FILE = DxeTpmMeasureBootLib.uni
+ 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
+ HobLib
+
+[Guids]
+ gMeasuredFvHobGuid ## SOMETIMES_CONSUMES ## HOB
+
+[Protocols]
+ gEfiTcgProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiFirmwareVolumeBlockProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiBlockIoProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiDiskIoProtocolGuid ## SOMETIMES_CONSUMES
+
diff --git a/Core/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.uni b/Core/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.uni
new file mode 100644
index 0000000000..74d6e76d52
--- /dev/null
+++ b/Core/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.uni
@@ -0,0 +1,27 @@
+// /** @file
+// Provides security service for TPM 1.2 measured boot
+//
+// This library instance hooks LoadImage() API to measure every image that
+// is not measured in PEI phase. And, it will also measure GPT partition.
+//
+// Caution: This module requires additional review when modified.
+// This library will have external input - PE/COFF image and GPT partition.
+// This external input must be validated carefully to avoid security issues such
+// as buffer overflow or integer overflow.
+//
+// Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides security service for TPM 1.2 measured boot"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library instance hooks LoadImage() API to measure every image that is not measured in PEI phase. And, it will also measure GPT partition. Caution: This module requires additional review when modified. This library will have external input - PE/COFF image and GPT partition. This external input must be validated carefully to avoid security issues such as buffer overflow or integer overflow."
+
diff --git a/Core/SecurityPkg/Library/DxeTpmMeasurementLib/DxeTpmMeasurementLib.c b/Core/SecurityPkg/Library/DxeTpmMeasurementLib/DxeTpmMeasurementLib.c
new file mode 100644
index 0000000000..7a2ec7f221
--- /dev/null
+++ b/Core/SecurityPkg/Library/DxeTpmMeasurementLib/DxeTpmMeasurementLib.c
@@ -0,0 +1,212 @@
+/** @file
+ This library is used by other modules to measure data to TPM.
+
+Copyright (c) 2012 - 2015, Intel Corporation. All rights reserved. <BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiDxe.h>
+
+#include <Protocol/TcgService.h>
+#include <Protocol/Tcg2Protocol.h>
+
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DebugLib.h>
+#include <Library/TpmMeasurementLib.h>
+
+#include <Guid/Acpi.h>
+#include <IndustryStandard/Acpi.h>
+
+
+
+/**
+ Tpm12 measure and log data, and extend the measurement result into a specific PCR.
+
+ @param[in] PcrIndex PCR Index.
+ @param[in] EventType Event type.
+ @param[in] EventLog Measurement event log.
+ @param[in] LogLen Event log length in bytes.
+ @param[in] HashData The start of the data buffer to be hashed, extended.
+ @param[in] HashDataLen The length, in bytes, of the buffer referenced by HashData
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_UNSUPPORTED TPM device not available.
+ @retval EFI_OUT_OF_RESOURCES Out of memory.
+ @retval EFI_DEVICE_ERROR The operation was unsuccessful.
+**/
+EFI_STATUS
+Tpm12MeasureAndLogData (
+ IN UINT32 PcrIndex,
+ IN UINT32 EventType,
+ IN VOID *EventLog,
+ IN UINT32 LogLen,
+ IN VOID *HashData,
+ IN UINT64 HashDataLen
+ )
+{
+ EFI_STATUS Status;
+ EFI_TCG_PROTOCOL *TcgProtocol;
+ TCG_PCR_EVENT *TcgEvent;
+ EFI_PHYSICAL_ADDRESS EventLogLastEntry;
+ UINT32 EventNumber;
+
+ TcgEvent = NULL;
+
+ //
+ // Tpm active/deactive state is checked in HashLogExtendEvent
+ //
+ Status = gBS->LocateProtocol (&gEfiTcgProtocolGuid, NULL, (VOID **) &TcgProtocol);
+ if (EFI_ERROR(Status)){
+ return Status;
+ }
+
+ TcgEvent = (TCG_PCR_EVENT *)AllocateZeroPool (sizeof (TCG_PCR_EVENT_HDR) + LogLen);
+ if(TcgEvent == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ TcgEvent->PCRIndex = PcrIndex;
+ TcgEvent->EventType = EventType;
+ TcgEvent->EventSize = LogLen;
+ CopyMem (&TcgEvent->Event[0], EventLog, LogLen);
+ EventNumber = 1;
+ Status = TcgProtocol->HashLogExtendEvent (
+ TcgProtocol,
+ (EFI_PHYSICAL_ADDRESS)(UINTN)HashData,
+ HashDataLen,
+ TPM_ALG_SHA,
+ TcgEvent,
+ &EventNumber,
+ &EventLogLastEntry
+ );
+
+ FreePool (TcgEvent);
+
+ return Status;
+}
+
+/**
+ Tpm20 measure and log data, and extend the measurement result into a specific PCR.
+
+ @param[in] PcrIndex PCR Index.
+ @param[in] EventType Event type.
+ @param[in] EventLog Measurement event log.
+ @param[in] LogLen Event log length in bytes.
+ @param[in] HashData The start of the data buffer to be hashed, extended.
+ @param[in] HashDataLen The length, in bytes, of the buffer referenced by HashData
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_UNSUPPORTED TPM device not available.
+ @retval EFI_OUT_OF_RESOURCES Out of memory.
+ @retval EFI_DEVICE_ERROR The operation was unsuccessful.
+**/
+EFI_STATUS
+Tpm20MeasureAndLogData (
+ IN UINT32 PcrIndex,
+ IN UINT32 EventType,
+ IN VOID *EventLog,
+ IN UINT32 LogLen,
+ IN VOID *HashData,
+ IN UINT64 HashDataLen
+ )
+{
+ EFI_STATUS Status;
+ EFI_TCG2_PROTOCOL *Tcg2Protocol;
+ EFI_TCG2_EVENT *Tcg2Event;
+
+ //
+ // TPMPresentFlag is checked in HashLogExtendEvent
+ //
+ Status = gBS->LocateProtocol (&gEfiTcg2ProtocolGuid, NULL, (VOID **) &Tcg2Protocol);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Tcg2Event = (EFI_TCG2_EVENT *) AllocateZeroPool (LogLen + sizeof (EFI_TCG2_EVENT));
+ if(Tcg2Event == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Tcg2Event->Size = (UINT32)LogLen + sizeof (EFI_TCG2_EVENT) - sizeof(Tcg2Event->Event);
+ Tcg2Event->Header.HeaderSize = sizeof(EFI_TCG2_EVENT_HEADER);
+ Tcg2Event->Header.HeaderVersion = EFI_TCG2_EVENT_HEADER_VERSION;
+ Tcg2Event->Header.PCRIndex = PcrIndex;
+ Tcg2Event->Header.EventType = EventType;
+ CopyMem (&Tcg2Event->Event[0], EventLog, LogLen);
+
+ Status = Tcg2Protocol->HashLogExtendEvent (
+ Tcg2Protocol,
+ 0,
+ (EFI_PHYSICAL_ADDRESS)(UINTN)HashData,
+ HashDataLen,
+ Tcg2Event
+ );
+ FreePool (Tcg2Event);
+
+ return Status;
+}
+
+/**
+ Tpm measure and log data, and extend the measurement result into a specific PCR.
+
+ @param[in] PcrIndex PCR Index.
+ @param[in] EventType Event type.
+ @param[in] EventLog Measurement event log.
+ @param[in] LogLen Event log length in bytes.
+ @param[in] HashData The start of the data buffer to be hashed, extended.
+ @param[in] HashDataLen The length, in bytes, of the buffer referenced by HashData
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_UNSUPPORTED TPM device not available.
+ @retval EFI_OUT_OF_RESOURCES Out of memory.
+ @retval EFI_DEVICE_ERROR The operation was unsuccessful.
+**/
+EFI_STATUS
+EFIAPI
+TpmMeasureAndLogData (
+ IN UINT32 PcrIndex,
+ IN UINT32 EventType,
+ IN VOID *EventLog,
+ IN UINT32 LogLen,
+ IN VOID *HashData,
+ IN UINT64 HashDataLen
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Try to measure using Tpm1.2 protocol
+ //
+ Status = Tpm12MeasureAndLogData(
+ PcrIndex,
+ EventType,
+ EventLog,
+ LogLen,
+ HashData,
+ HashDataLen
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Try to measure using Tpm20 protocol
+ //
+ Status = Tpm20MeasureAndLogData(
+ PcrIndex,
+ EventType,
+ EventLog,
+ LogLen,
+ HashData,
+ HashDataLen
+ );
+ }
+
+ return Status;
+}
diff --git a/Core/SecurityPkg/Library/DxeTpmMeasurementLib/DxeTpmMeasurementLib.inf b/Core/SecurityPkg/Library/DxeTpmMeasurementLib/DxeTpmMeasurementLib.inf
new file mode 100644
index 0000000000..410eb788db
--- /dev/null
+++ b/Core/SecurityPkg/Library/DxeTpmMeasurementLib/DxeTpmMeasurementLib.inf
@@ -0,0 +1,49 @@
+## @file
+# Provides TPM measurement functions for TPM1.2 and TPM 2.0
+#
+# This library provides TpmMeasureAndLogData() to measure and log data, and
+# extend the measurement result into a specific PCR.
+#
+# Copyright (c) 2012 - 2015, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeTpmMeasurementLib
+ FILE_GUID = 30930D10-AF5B-4abf-80E6-EB4FFC0AE9D1
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = TpmMeasurementLib|DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SAL_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER
+ MODULE_UNI_FILE = DxeTpmMeasurementLib.uni
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF
+#
+
+[Sources]
+ DxeTpmMeasurementLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ MemoryAllocationLib
+ UefiBootServicesTableLib
+
+[Protocols]
+ gEfiTcgProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiTcg2ProtocolGuid ## SOMETIMES_CONSUMES
diff --git a/Core/SecurityPkg/Library/DxeTpmMeasurementLib/DxeTpmMeasurementLib.uni b/Core/SecurityPkg/Library/DxeTpmMeasurementLib/DxeTpmMeasurementLib.uni
new file mode 100644
index 0000000000..3003d5c136
--- /dev/null
+++ b/Core/SecurityPkg/Library/DxeTpmMeasurementLib/DxeTpmMeasurementLib.uni
@@ -0,0 +1,22 @@
+// /** @file
+// Provides TPM measurement functions for TPM1.2 and TPM 2.0
+//
+// This library provides TpmMeasureAndLogData() to to measure and log data, and
+// extend the measurement result into a specific PCR.
+//
+// Copyright (c) 2012 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides TPM measurement functions for TPM1.2 and TPM 2.0"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library provides TpmMeasureAndLogData() to to measure and log data, and extend the measurement result into a specific PCR."
+
diff --git a/Core/SecurityPkg/Library/DxeTrEEPhysicalPresenceLib/DxeTrEEPhysicalPresenceLib.c b/Core/SecurityPkg/Library/DxeTrEEPhysicalPresenceLib/DxeTrEEPhysicalPresenceLib.c
new file mode 100644
index 0000000000..31b02d907a
--- /dev/null
+++ b/Core/SecurityPkg/Library/DxeTrEEPhysicalPresenceLib/DxeTrEEPhysicalPresenceLib.c
@@ -0,0 +1,743 @@
+/** @file
+ Execute pending TPM2 requests from OS or BIOS.
+
+ Caution: This module requires additional review when modified.
+ This driver will have external input - variable.
+ This external input must be validated carefully to avoid security issue.
+
+ TrEEExecutePendingTpmRequest() will receive untrusted input and do validation.
+
+Copyright (c) 2013 - 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiDxe.h>
+
+#include <Protocol/TrEEProtocol.h>
+#include <Protocol/VariableLock.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PrintLib.h>
+#include <Library/HiiLib.h>
+#include <Guid/EventGroup.h>
+#include <Guid/TrEEPhysicalPresenceData.h>
+#include <Library/Tpm2CommandLib.h>
+#include <Library/TrEEPpVendorLib.h>
+
+#define CONFIRM_BUFFER_SIZE 4096
+
+EFI_HII_HANDLE mTrEEPpStringPackHandle;
+
+/**
+ Get string by string id from HII Interface.
+
+ @param[in] Id String ID.
+
+ @retval CHAR16 * String from ID.
+ @retval NULL If error occurs.
+
+**/
+CHAR16 *
+TrEEPhysicalPresenceGetStringById (
+ IN EFI_STRING_ID Id
+ )
+{
+ return HiiGetString (mTrEEPpStringPackHandle, Id, NULL);
+}
+
+/**
+ Send ClearControl and Clear command to TPM.
+
+ @param[in] PlatformAuth platform auth value. NULL means no platform auth change.
+
+ @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
+EFIAPI
+TpmCommandClear (
+ IN TPM2B_AUTH *PlatformAuth OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ TPMS_AUTH_COMMAND *AuthSession;
+ TPMS_AUTH_COMMAND LocalAuthSession;
+
+ if (PlatformAuth == NULL) {
+ AuthSession = NULL;
+ } else {
+ AuthSession = &LocalAuthSession;
+ ZeroMem (&LocalAuthSession, sizeof(LocalAuthSession));
+ LocalAuthSession.sessionHandle = TPM_RS_PW;
+ LocalAuthSession.hmac.size = PlatformAuth->size;
+ CopyMem (LocalAuthSession.hmac.buffer, PlatformAuth->buffer, PlatformAuth->size);
+ }
+
+ DEBUG ((EFI_D_INFO, "Tpm2ClearControl ... \n"));
+ Status = Tpm2ClearControl (TPM_RH_PLATFORM, AuthSession, NO);
+ DEBUG ((EFI_D_INFO, "Tpm2ClearControl - %r\n", Status));
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ DEBUG ((EFI_D_INFO, "Tpm2Clear ... \n"));
+ Status = Tpm2Clear (TPM_RH_PLATFORM, AuthSession);
+ DEBUG ((EFI_D_INFO, "Tpm2Clear - %r\n", Status));
+
+Done:
+ ZeroMem (&LocalAuthSession.hmac, sizeof(LocalAuthSession.hmac));
+ return Status;
+}
+
+/**
+ Execute physical presence operation requested by the OS.
+
+ @param[in] PlatformAuth platform auth value. NULL means no platform auth change.
+ @param[in] CommandCode Physical presence operation value.
+ @param[in, out] PpiFlags The physical presence interface flags.
+
+ @retval TREE_PP_OPERATION_RESPONSE_BIOS_FAILURE Unknown physical presence operation.
+ @retval TREE_PP_OPERATION_RESPONSE_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.
+**/
+UINT32
+TrEEExecutePhysicalPresence (
+ IN TPM2B_AUTH *PlatformAuth, OPTIONAL
+ IN UINT32 CommandCode,
+ IN OUT EFI_TREE_PHYSICAL_PRESENCE_FLAGS *PpiFlags
+ )
+{
+ EFI_STATUS Status;
+
+ switch (CommandCode) {
+ case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR:
+ case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_2:
+ case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_3:
+ case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_4:
+ Status = TpmCommandClear (PlatformAuth);
+ if (EFI_ERROR (Status)) {
+ return TREE_PP_OPERATION_RESPONSE_BIOS_FAILURE;
+ } else {
+ return TREE_PP_OPERATION_RESPONSE_SUCCESS;
+ }
+
+ case TREE_PHYSICAL_PRESENCE_SET_NO_PPI_CLEAR_FALSE:
+ PpiFlags->PPFlags &= ~TREE_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_CLEAR;
+ return TREE_PP_OPERATION_RESPONSE_SUCCESS;
+
+ case TREE_PHYSICAL_PRESENCE_SET_NO_PPI_CLEAR_TRUE:
+ PpiFlags->PPFlags |= TREE_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_CLEAR;
+ return TREE_PP_OPERATION_RESPONSE_SUCCESS;
+
+ default:
+ if (CommandCode <= TREE_PHYSICAL_PRESENCE_NO_ACTION_MAX) {
+ return TREE_PP_OPERATION_RESPONSE_SUCCESS;
+ } else {
+ return TREE_PP_OPERATION_RESPONSE_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
+TrEEReadUserKey (
+ IN BOOLEAN CautionKey
+ )
+{
+ EFI_STATUS Status;
+ EFI_INPUT_KEY Key;
+ UINT16 InputKey;
+
+ 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);
+
+ if (InputKey != SCAN_ESC) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ The constructor function register UNI strings into imageHandle.
+
+ It will ASSERT() if that operation fails and it will always return EFI_SUCCESS.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The constructor successfully added string package.
+ @retval Other value The constructor can't add string package.
+**/
+EFI_STATUS
+EFIAPI
+TrEEPhysicalPresenceLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ mTrEEPpStringPackHandle = HiiAddPackages (&gEfiTrEEPhysicalPresenceGuid, ImageHandle, DxeTrEEPhysicalPresenceLibStrings, NULL);
+ ASSERT (mTrEEPpStringPackHandle != NULL);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ 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
+TrEEUserConfirm (
+ IN UINT32 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);
+
+ switch (TpmPpCommand) {
+
+ case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR:
+ case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_2:
+ case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_3:
+ case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_4:
+ CautionKey = TRUE;
+ TmpStr2 = TrEEPhysicalPresenceGetStringById (STRING_TOKEN (TPM_CLEAR));
+
+ TmpStr1 = TrEEPhysicalPresenceGetStringById (STRING_TOKEN (TPM_HEAD_STR));
+ UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);
+ FreePool (TmpStr1);
+
+ TmpStr1 = TrEEPhysicalPresenceGetStringById (STRING_TOKEN (TPM_WARNING_CLEAR));
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), L" \n\n", (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+
+ TmpStr1 = TrEEPhysicalPresenceGetStringById (STRING_TOKEN (TPM_CAUTION_KEY));
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+ break;
+
+ case TREE_PHYSICAL_PRESENCE_SET_NO_PPI_CLEAR_TRUE:
+ CautionKey = TRUE;
+ TmpStr2 = TrEEPhysicalPresenceGetStringById (STRING_TOKEN (TPM_CLEAR));
+
+ TmpStr1 = TrEEPhysicalPresenceGetStringById (STRING_TOKEN (TPM_PPI_HEAD_STR));
+ UnicodeSPrint (ConfirmText, BufSize, TmpStr1, TmpStr2);
+ FreePool (TmpStr1);
+
+ TmpStr1 = TrEEPhysicalPresenceGetStringById (STRING_TOKEN (TPM_NOTE_CLEAR));
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+
+ TmpStr1 = TrEEPhysicalPresenceGetStringById (STRING_TOKEN (TPM_WARNING_CLEAR));
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), L" \n\n", (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+
+ TmpStr1 = TrEEPhysicalPresenceGetStringById (STRING_TOKEN (TPM_CAUTION_KEY));
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+
+ TmpStr1 = TrEEPhysicalPresenceGetStringById (STRING_TOKEN (TPM_NO_PPI_INFO));
+ StrnCatS (ConfirmText, BufSize / sizeof (CHAR16), TmpStr1, (BufSize / sizeof (CHAR16)) - StrLen (ConfirmText) - 1);
+ FreePool (TmpStr1);
+ break;
+
+ default:
+ ;
+ }
+
+ if (TmpStr2 == NULL) {
+ FreePool (ConfirmText);
+ return FALSE;
+ }
+
+ TmpStr1 = TrEEPhysicalPresenceGetStringById (STRING_TOKEN (TPM_REJECT_KEY));
+ BufSize -= StrSize (ConfirmText);
+ UnicodeSPrint (ConfirmText + StrLen (ConfirmText), BufSize, TmpStr1, TmpStr2);
+
+ DstStr[80] = L'\0';
+ for (Index = 0; Index < StrLen (ConfirmText); Index += 80) {
+ StrnCpyS(DstStr, sizeof (DstStr) / sizeof (CHAR16), ConfirmText + Index, sizeof (DstStr) / sizeof (CHAR16) - 1);
+ Print (DstStr);
+ }
+
+ FreePool (TmpStr1);
+ FreePool (TmpStr2);
+ FreePool (ConfirmText);
+
+ if (TrEEReadUserKey (CautionKey)) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Check if there is a valid physical presence command request. Also updates parameter value
+ to whether the requested physical presence command already confirmed by user
+
+ @param[in] TcgPpData EFI TrEE Physical Presence request data.
+ @param[in] Flags The physical presence interface flags.
+ @param[out] RequestConfirmed If the physical presence operation command required user confirm from UI.
+ True, it indicates the command doesn't require user confirm, or already confirmed
+ in last boot cycle by user.
+ False, it indicates the command need user confirm from UI.
+
+ @retval TRUE Physical Presence operation command is valid.
+ @retval FALSE Physical Presence operation command is invalid.
+
+**/
+BOOLEAN
+TrEEHaveValidTpmRequest (
+ IN EFI_TREE_PHYSICAL_PRESENCE *TcgPpData,
+ IN EFI_TREE_PHYSICAL_PRESENCE_FLAGS Flags,
+ OUT BOOLEAN *RequestConfirmed
+ )
+{
+ BOOLEAN IsRequestValid;
+
+ *RequestConfirmed = FALSE;
+
+ switch (TcgPpData->PPRequest) {
+ case TREE_PHYSICAL_PRESENCE_NO_ACTION:
+ *RequestConfirmed = TRUE;
+ return TRUE;
+ case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR:
+ case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_2:
+ case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_3:
+ case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_4:
+ if ((Flags.PPFlags & TREE_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_CLEAR) != 0) {
+ *RequestConfirmed = TRUE;
+ }
+ break;
+
+ case TREE_PHYSICAL_PRESENCE_SET_NO_PPI_CLEAR_FALSE:
+ *RequestConfirmed = TRUE;
+ break;
+
+ case TREE_PHYSICAL_PRESENCE_SET_NO_PPI_CLEAR_TRUE:
+ break;
+
+ default:
+ if (TcgPpData->PPRequest >= TREE_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION) {
+ IsRequestValid = TrEEPpVendorLibHasValidRequest (TcgPpData->PPRequest, Flags.PPFlags, RequestConfirmed);
+ if (!IsRequestValid) {
+ return FALSE;
+ } else {
+ break;
+ }
+ } else {
+ //
+ // Wrong Physical Presence command
+ //
+ return FALSE;
+ }
+ }
+
+ if ((Flags.PPFlags & TREE_VENDOR_LIB_FLAG_RESET_TRACK) != 0) {
+ //
+ // It had been confirmed in last boot, it doesn't need confirm again.
+ //
+ *RequestConfirmed = TRUE;
+ }
+
+ //
+ // Physical Presence command is correct
+ //
+ return TRUE;
+}
+
+
+/**
+ Check and execute the requested physical presence command.
+
+ Caution: This function may receive untrusted input.
+ TcgPpData variable is external input, so this function will validate
+ its data structure to be valid value.
+
+ @param[in] PlatformAuth platform auth value. NULL means no platform auth change.
+ @param[in] TcgPpData Point to the physical presence NV variable.
+ @param[in] Flags The physical presence interface flags.
+**/
+VOID
+TrEEExecutePendingTpmRequest (
+ IN TPM2B_AUTH *PlatformAuth, OPTIONAL
+ IN EFI_TREE_PHYSICAL_PRESENCE *TcgPpData,
+ IN EFI_TREE_PHYSICAL_PRESENCE_FLAGS Flags
+ )
+{
+ EFI_STATUS Status;
+ UINTN DataSize;
+ BOOLEAN RequestConfirmed;
+ EFI_TREE_PHYSICAL_PRESENCE_FLAGS NewFlags;
+ BOOLEAN ResetRequired;
+ UINT32 NewPPFlags;
+
+ if (TcgPpData->PPRequest == TREE_PHYSICAL_PRESENCE_NO_ACTION) {
+ //
+ // No operation request
+ //
+ return;
+ }
+
+ if (!TrEEHaveValidTpmRequest(TcgPpData, Flags, &RequestConfirmed)) {
+ //
+ // Invalid operation request.
+ //
+ if (TcgPpData->PPRequest <= TREE_PHYSICAL_PRESENCE_NO_ACTION_MAX) {
+ TcgPpData->PPResponse = TREE_PP_OPERATION_RESPONSE_SUCCESS;
+ } else {
+ TcgPpData->PPResponse = TREE_PP_OPERATION_RESPONSE_BIOS_FAILURE;
+ }
+ TcgPpData->LastPPRequest = TcgPpData->PPRequest;
+ TcgPpData->PPRequest = TREE_PHYSICAL_PRESENCE_NO_ACTION;
+ DataSize = sizeof (EFI_TREE_PHYSICAL_PRESENCE);
+ Status = gRT->SetVariable (
+ TREE_PHYSICAL_PRESENCE_VARIABLE,
+ &gEfiTrEEPhysicalPresenceGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ DataSize,
+ TcgPpData
+ );
+ return;
+ }
+
+ ResetRequired = FALSE;
+ if (TcgPpData->PPRequest >= TREE_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION) {
+ NewFlags = Flags;
+ NewPPFlags = NewFlags.PPFlags;
+ TcgPpData->PPResponse = TrEEPpVendorLibExecutePendingRequest (PlatformAuth, TcgPpData->PPRequest, &NewPPFlags, &ResetRequired);
+ NewFlags.PPFlags = (UINT8)NewPPFlags;
+ } else {
+ if (!RequestConfirmed) {
+ //
+ // Print confirm text and wait for approval.
+ //
+ RequestConfirmed = TrEEUserConfirm (TcgPpData->PPRequest
+ );
+ }
+
+ //
+ // Execute requested physical presence command
+ //
+ TcgPpData->PPResponse = TREE_PP_OPERATION_RESPONSE_USER_ABORT;
+ NewFlags = Flags;
+ if (RequestConfirmed) {
+ TcgPpData->PPResponse = TrEEExecutePhysicalPresence (PlatformAuth, TcgPpData->PPRequest,
+ &NewFlags);
+ }
+ }
+
+ //
+ // Save the flags if it is updated.
+ //
+ if (CompareMem (&Flags, &NewFlags, sizeof(EFI_TREE_PHYSICAL_PRESENCE_FLAGS)) != 0) {
+ Status = gRT->SetVariable (
+ TREE_PHYSICAL_PRESENCE_FLAGS_VARIABLE,
+ &gEfiTrEEPhysicalPresenceGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ sizeof (EFI_TREE_PHYSICAL_PRESENCE_FLAGS),
+ &NewFlags
+ );
+ }
+
+ //
+ // Clear request
+ //
+ if ((NewFlags.PPFlags & TREE_VENDOR_LIB_FLAG_RESET_TRACK) == 0) {
+ TcgPpData->LastPPRequest = TcgPpData->PPRequest;
+ TcgPpData->PPRequest = TREE_PHYSICAL_PRESENCE_NO_ACTION;
+ }
+
+ //
+ // Save changes
+ //
+ DataSize = sizeof (EFI_TREE_PHYSICAL_PRESENCE);
+ Status = gRT->SetVariable (
+ TREE_PHYSICAL_PRESENCE_VARIABLE,
+ &gEfiTrEEPhysicalPresenceGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ DataSize,
+ TcgPpData
+ );
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ if (TcgPpData->PPResponse == TREE_PP_OPERATION_RESPONSE_USER_ABORT) {
+ return;
+ }
+
+ //
+ // Reset system to make new TPM settings in effect
+ //
+ switch (TcgPpData->LastPPRequest) {
+ case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR:
+ case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_2:
+ case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_3:
+ case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_4:
+ break;
+ default:
+ if (TcgPpData->LastPPRequest >= TREE_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION) {
+ if (ResetRequired) {
+ break;
+ } else {
+ return ;
+ }
+ }
+ if (TcgPpData->PPRequest != TREE_PHYSICAL_PRESENCE_NO_ACTION) {
+ break;
+ }
+ return;
+ }
+
+ Print (L"Rebooting system to make TPM2 settings in effect\n");
+ gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);
+ ASSERT (FALSE);
+}
+
+/**
+ Check and execute the pending TPM request.
+
+ The TPM request may come from OS or BIOS. This API will display request information and wait
+ for user confirmation if TPM request exists. The TPM request will be sent to TPM device after
+ the TPM request is confirmed, and one or more reset may be required to make TPM request to
+ take effect.
+
+ This API should be invoked after console in and console out are all ready as they are required
+ to display request information and get user input to confirm the request.
+
+ @param[in] PlatformAuth platform auth value. NULL means no platform auth change.
+**/
+VOID
+EFIAPI
+TrEEPhysicalPresenceLibProcessRequest (
+ IN TPM2B_AUTH *PlatformAuth OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ UINTN DataSize;
+ EFI_TREE_PHYSICAL_PRESENCE TcgPpData;
+ EFI_TREE_PROTOCOL *TreeProtocol;
+ EDKII_VARIABLE_LOCK_PROTOCOL *VariableLockProtocol;
+ EFI_TREE_PHYSICAL_PRESENCE_FLAGS PpiFlags;
+
+ Status = gBS->LocateProtocol (&gEfiTrEEProtocolGuid, NULL, (VOID **) &TreeProtocol);
+ if (EFI_ERROR (Status)) {
+ return ;
+ }
+
+ //
+ // Initialize physical presence flags.
+ //
+ DataSize = sizeof (EFI_TREE_PHYSICAL_PRESENCE_FLAGS);
+ Status = gRT->GetVariable (
+ TREE_PHYSICAL_PRESENCE_FLAGS_VARIABLE,
+ &gEfiTrEEPhysicalPresenceGuid,
+ NULL,
+ &DataSize,
+ &PpiFlags
+ );
+ if (EFI_ERROR (Status)) {
+ PpiFlags.PPFlags = 0;
+ Status = gRT->SetVariable (
+ TREE_PHYSICAL_PRESENCE_FLAGS_VARIABLE,
+ &gEfiTrEEPhysicalPresenceGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ sizeof (EFI_TREE_PHYSICAL_PRESENCE_FLAGS),
+ &PpiFlags
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "[TPM2] Set physical presence flag failed, Status = %r\n", Status));
+ return ;
+ }
+ }
+ DEBUG ((EFI_D_INFO, "[TPM2] PpiFlags = %x\n", PpiFlags.PPFlags));
+
+ //
+ // This flags variable controls whether physical presence is required for TPM command.
+ // It should be protected from malicious software. We set it as read-only variable here.
+ //
+ Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **)&VariableLockProtocol);
+ if (!EFI_ERROR (Status)) {
+ Status = VariableLockProtocol->RequestToLock (
+ VariableLockProtocol,
+ TREE_PHYSICAL_PRESENCE_FLAGS_VARIABLE,
+ &gEfiTrEEPhysicalPresenceGuid
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "[TPM2] Error when lock variable %s, Status = %r\n", TREE_PHYSICAL_PRESENCE_FLAGS_VARIABLE, Status));
+ ASSERT_EFI_ERROR (Status);
+ }
+ }
+
+ //
+ // Initialize physical presence variable.
+ //
+ DataSize = sizeof (EFI_TREE_PHYSICAL_PRESENCE);
+ Status = gRT->GetVariable (
+ TREE_PHYSICAL_PRESENCE_VARIABLE,
+ &gEfiTrEEPhysicalPresenceGuid,
+ NULL,
+ &DataSize,
+ &TcgPpData
+ );
+ if (EFI_ERROR (Status)) {
+ ZeroMem ((VOID*)&TcgPpData, sizeof (TcgPpData));
+ DataSize = sizeof (EFI_TREE_PHYSICAL_PRESENCE);
+ Status = gRT->SetVariable (
+ TREE_PHYSICAL_PRESENCE_VARIABLE,
+ &gEfiTrEEPhysicalPresenceGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ DataSize,
+ &TcgPpData
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "[TPM2] Set physical presence variable failed, Status = %r\n", Status));
+ return ;
+ }
+ }
+
+ DEBUG ((EFI_D_INFO, "[TPM2] Flags=%x, PPRequest=%x (LastPPRequest=%x)\n", PpiFlags.PPFlags, TcgPpData.PPRequest, TcgPpData.LastPPRequest));
+
+ //
+ // Execute pending TPM request.
+ //
+ TrEEExecutePendingTpmRequest (PlatformAuth, &TcgPpData, PpiFlags);
+ DEBUG ((EFI_D_INFO, "[TPM2] PPResponse = %x (LastPPRequest=%x, Flags=%x)\n", TcgPpData.PPResponse, TcgPpData.LastPPRequest, PpiFlags.PPFlags));
+
+}
+
+/**
+ Check if the pending TPM request needs user input to confirm.
+
+ The TPM request may come from OS. This API will check if TPM request exists and need user
+ input to confirmation.
+
+ @retval TRUE TPM needs input to confirm user physical presence.
+ @retval FALSE TPM doesn't need input to confirm user physical presence.
+
+**/
+BOOLEAN
+EFIAPI
+TrEEPhysicalPresenceLibNeedUserConfirm(
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_TREE_PHYSICAL_PRESENCE TcgPpData;
+ UINTN DataSize;
+ BOOLEAN RequestConfirmed;
+ EFI_TREE_PROTOCOL *TreeProtocol;
+ EFI_TREE_PHYSICAL_PRESENCE_FLAGS PpiFlags;
+
+ Status = gBS->LocateProtocol (&gEfiTrEEProtocolGuid, NULL, (VOID **) &TreeProtocol);
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ //
+ // Check Tpm requests
+ //
+ DataSize = sizeof (EFI_TREE_PHYSICAL_PRESENCE);
+ Status = gRT->GetVariable (
+ TREE_PHYSICAL_PRESENCE_VARIABLE,
+ &gEfiTrEEPhysicalPresenceGuid,
+ NULL,
+ &DataSize,
+ &TcgPpData
+ );
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ DataSize = sizeof (EFI_TREE_PHYSICAL_PRESENCE_FLAGS);
+ Status = gRT->GetVariable (
+ TREE_PHYSICAL_PRESENCE_FLAGS_VARIABLE,
+ &gEfiTrEEPhysicalPresenceGuid,
+ NULL,
+ &DataSize,
+ &PpiFlags
+ );
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ if (TcgPpData.PPRequest == TREE_PHYSICAL_PRESENCE_NO_ACTION) {
+ //
+ // No operation request
+ //
+ return FALSE;
+ }
+
+ if (!TrEEHaveValidTpmRequest(&TcgPpData, PpiFlags, &RequestConfirmed)) {
+ //
+ // Invalid operation request.
+ //
+ return FALSE;
+ }
+
+ if (!RequestConfirmed) {
+ //
+ // Need UI to confirm
+ //
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
diff --git a/Core/SecurityPkg/Library/DxeTrEEPhysicalPresenceLib/DxeTrEEPhysicalPresenceLib.inf b/Core/SecurityPkg/Library/DxeTrEEPhysicalPresenceLib/DxeTrEEPhysicalPresenceLib.inf
new file mode 100644
index 0000000000..1c123efe78
--- /dev/null
+++ b/Core/SecurityPkg/Library/DxeTrEEPhysicalPresenceLib/DxeTrEEPhysicalPresenceLib.inf
@@ -0,0 +1,69 @@
+## @file
+# Executes TPM 2.0 requests from OS or BIOS
+#
+# This library will check and execute TPM 2.0 request from OS or BIOS. The request may
+# ask for user confirmation before execution.
+#
+# Caution: This module requires additional review when modified.
+# This driver will have external input - variable.
+# This external input must be validated carefully to avoid security issue.
+#
+# Copyright (c) 2013 - 2015, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeTrEEPhysicalPresenceLib
+ MODULE_UNI_FILE = DxeTrEEPhysicalPresenceLib.uni
+ FILE_GUID = 601ECB06-7874-489e-A280-805780F6C861
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = TrEEPhysicalPresenceLib|DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SAL_DRIVER UEFI_APPLICATION UEFI_DRIVER
+ CONSTRUCTOR = TrEEPhysicalPresenceLibConstructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ DxeTrEEPhysicalPresenceLib.c
+ PhysicalPresenceStrings.uni
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+ MemoryAllocationLib
+ UefiLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ UefiRuntimeServicesTableLib
+ BaseMemoryLib
+ DebugLib
+ PrintLib
+ HiiLib
+ Tpm2CommandLib
+ TrEEPpVendorLib
+
+[Protocols]
+ gEfiTrEEProtocolGuid ## SOMETIMES_CONSUMES
+ gEdkiiVariableLockProtocolGuid ## SOMETIMES_CONSUMES
+
+[Guids]
+ ## SOMETIMES_CONSUMES ## HII
+ ## SOMETIMES_PRODUCES ## Variable:L"PhysicalPresence"
+ ## SOMETIMES_CONSUMES ## Variable:L"PhysicalPresence"
+ ## SOMETIMES_PRODUCES ## Variable:L"PhysicalPresenceFlags"
+ ## SOMETIMES_CONSUMES ## Variable:L"PhysicalPresenceFlags"
+ gEfiTrEEPhysicalPresenceGuid
diff --git a/Core/SecurityPkg/Library/DxeTrEEPhysicalPresenceLib/DxeTrEEPhysicalPresenceLib.uni b/Core/SecurityPkg/Library/DxeTrEEPhysicalPresenceLib/DxeTrEEPhysicalPresenceLib.uni
new file mode 100644
index 0000000000..7cb7072c17
--- /dev/null
+++ b/Core/SecurityPkg/Library/DxeTrEEPhysicalPresenceLib/DxeTrEEPhysicalPresenceLib.uni
@@ -0,0 +1,27 @@
+// /** @file
+// Executes TPM 2.0 requests from OS or BIOS
+//
+// This library will check and execute TPM 2.0 request from OS or BIOS. The request may
+// ask for user confirmation before execution.
+//
+// Caution: This module requires additional review when modified.
+// This driver will have external input - variable.
+// This external input must be validated carefully to avoid security issue.
+//
+// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Executes TPM 2.0 requests from OS or BIOS"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library will check and execute TPM 2.0 request from OS or BIOS. The request may ask for user confirmation before execution.\n"
+ "Caution: This module requires additional review when modified. This driver will have external input - variable. This external input must be validated carefully to avoid security issue."
+
diff --git a/Core/SecurityPkg/Library/DxeTrEEPhysicalPresenceLib/PhysicalPresenceStrings.uni b/Core/SecurityPkg/Library/DxeTrEEPhysicalPresenceLib/PhysicalPresenceStrings.uni
new file mode 100644
index 0000000000..633789f33f
--- /dev/null
+++ b/Core/SecurityPkg/Library/DxeTrEEPhysicalPresenceLib/PhysicalPresenceStrings.uni
@@ -0,0 +1,29 @@
+/** @file
+ String definitions for TPM 2.0 physical presence confirm text.
+
+Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#langdef en-US "English"
+
+#string TPM_HEAD_STR #language en-US "A configuration change was requested to %s this computer's TPM (Trusted Platform Module)\n\n"
+#string TPM_PPI_HEAD_STR #language en-US "A configuration change was requested to allow the Operating System to %s the computer's TPM (Trusted Platform Module) without asking for user confirmation in the future.\n\n"
+
+#string TPM_ACCEPT_KEY #language en-US "Press F10 "
+#string TPM_CAUTION_KEY #language en-US "Press F12 "
+#string TPM_REJECT_KEY #language en-US "to %s the TPM \nPress ESC to reject this change request and continue\n"
+
+#string TPM_CLEAR #language en-US "clear"
+
+#string TPM_NO_PPI_INFO #language en-US "to approve future Operating System requests "
+
+#string TPM_WARNING_CLEAR #language en-US "WARNING: Clearing erases information stored on the TPM. You will lose all created keys and access to data encrypted by these keys. "
+#string TPM_NOTE_CLEAR #language en-US "NOTE: This action does not clear the TPM, but by approving this configuration change, future actions to clear the TPM will not require user confirmation.\n\n"
diff --git a/Core/SecurityPkg/Library/FmpAuthenticationLibPkcs7/FmpAuthenticationLibPkcs7.c b/Core/SecurityPkg/Library/FmpAuthenticationLibPkcs7/FmpAuthenticationLibPkcs7.c
new file mode 100644
index 0000000000..69c637c764
--- /dev/null
+++ b/Core/SecurityPkg/Library/FmpAuthenticationLibPkcs7/FmpAuthenticationLibPkcs7.c
@@ -0,0 +1,222 @@
+/** @file
+ FMP Authentication PKCS7 handler.
+ Provide generic FMP authentication functions for DXE/PEI post memory phase.
+
+ Caution: This module requires additional review when modified.
+ This module will have external input - capsule image.
+ This external input must be validated carefully to avoid security issue like
+ buffer overflow, integer overflow.
+
+ FmpAuthenticatedHandlerPkcs7(), AuthenticateFmpImage() will receive
+ untrusted input and do basic validation.
+
+ Copyright (c) 2016 - 2017, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Uefi.h>
+
+#include <Guid/SystemResourceTable.h>
+#include <Guid/FirmwareContentsSigned.h>
+#include <Guid/WinCertificate.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseCryptLib.h>
+#include <Library/FmpAuthenticationLib.h>
+#include <Library/PcdLib.h>
+#include <Protocol/FirmwareManagement.h>
+#include <Guid/SystemResourceTable.h>
+
+/**
+ The handler is used to do the authentication for FMP capsule based upon
+ EFI_FIRMWARE_IMAGE_AUTHENTICATION.
+
+ Caution: This function may receive untrusted input.
+
+ This function assumes the caller AuthenticateFmpImage()
+ already did basic validation for EFI_FIRMWARE_IMAGE_AUTHENTICATION.
+
+ @param[in] Image Points to an FMP authentication image, started from EFI_FIRMWARE_IMAGE_AUTHENTICATION.
+ @param[in] ImageSize Size of the authentication image in bytes.
+ @param[in] PublicKeyData The public key data used to validate the signature.
+ @param[in] PublicKeyDataLength The length of the public key data.
+
+ @retval RETURN_SUCCESS Authentication pass.
+ The LastAttemptStatus should be LAST_ATTEMPT_STATUS_SUCCESS.
+ @retval RETURN_SECURITY_VIOLATION Authentication fail.
+ The LastAttemptStatus should be LAST_ATTEMPT_STATUS_ERROR_AUTH_ERROR.
+ @retval RETURN_INVALID_PARAMETER The image is in an invalid format.
+ The LastAttemptStatus should be LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT.
+ @retval RETURN_OUT_OF_RESOURCES No Authentication handler associated with CertType.
+ The LastAttemptStatus should be LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES.
+**/
+RETURN_STATUS
+FmpAuthenticatedHandlerPkcs7 (
+ IN EFI_FIRMWARE_IMAGE_AUTHENTICATION *Image,
+ IN UINTN ImageSize,
+ IN CONST UINT8 *PublicKeyData,
+ IN UINTN PublicKeyDataLength
+ )
+{
+ RETURN_STATUS Status;
+ BOOLEAN CryptoStatus;
+ VOID *P7Data;
+ UINTN P7Length;
+ VOID *TempBuffer;
+
+ DEBUG((DEBUG_INFO, "FmpAuthenticatedHandlerPkcs7 - Image: 0x%08x - 0x%08x\n", (UINTN)Image, (UINTN)ImageSize));
+
+ P7Length = Image->AuthInfo.Hdr.dwLength - (OFFSET_OF(WIN_CERTIFICATE_UEFI_GUID, CertData));
+ P7Data = Image->AuthInfo.CertData;
+
+ // It is a signature across the variable data and the Monotonic Count value.
+ TempBuffer = AllocatePool(ImageSize - Image->AuthInfo.Hdr.dwLength);
+ if (TempBuffer == NULL) {
+ DEBUG((DEBUG_ERROR, "FmpAuthenticatedHandlerPkcs7: TempBuffer == NULL\n"));
+ Status = RETURN_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ CopyMem(
+ TempBuffer,
+ (UINT8 *)Image + sizeof(Image->MonotonicCount) + Image->AuthInfo.Hdr.dwLength,
+ ImageSize - sizeof(Image->MonotonicCount) - Image->AuthInfo.Hdr.dwLength
+ );
+ CopyMem(
+ (UINT8 *)TempBuffer + ImageSize - sizeof(Image->MonotonicCount) - Image->AuthInfo.Hdr.dwLength,
+ &Image->MonotonicCount,
+ sizeof(Image->MonotonicCount)
+ );
+ CryptoStatus = Pkcs7Verify(
+ P7Data,
+ P7Length,
+ PublicKeyData,
+ PublicKeyDataLength,
+ (UINT8 *)TempBuffer,
+ ImageSize - Image->AuthInfo.Hdr.dwLength
+ );
+ FreePool(TempBuffer);
+ if (!CryptoStatus) {
+ //
+ // If PKCS7 signature verification fails, AUTH tested failed bit is set.
+ //
+ DEBUG((DEBUG_ERROR, "FmpAuthenticatedHandlerPkcs7: Pkcs7Verify() failed\n"));
+ Status = RETURN_SECURITY_VIOLATION;
+ goto Done;
+ }
+ DEBUG((DEBUG_INFO, "FmpAuthenticatedHandlerPkcs7: PASS verification\n"));
+
+ Status = RETURN_SUCCESS;
+
+Done:
+ return Status;
+}
+
+/**
+ The function is used to do the authentication for FMP capsule based upon
+ EFI_FIRMWARE_IMAGE_AUTHENTICATION.
+
+ The FMP capsule image should start with EFI_FIRMWARE_IMAGE_AUTHENTICATION,
+ followed by the payload.
+
+ If the return status is RETURN_SUCCESS, the caller may continue the rest
+ FMP update process.
+ If the return status is NOT RETURN_SUCCESS, the caller should stop the FMP
+ update process and convert the return status to LastAttemptStatus
+ to indicate that FMP update fails.
+ The LastAttemptStatus can be got from ESRT table or via
+ EFI_FIRMWARE_MANAGEMENT_PROTOCOL.GetImageInfo().
+
+ Caution: This function may receive untrusted input.
+
+ @param[in] Image Points to an FMP authentication image, started from EFI_FIRMWARE_IMAGE_AUTHENTICATION.
+ @param[in] ImageSize Size of the authentication image in bytes.
+ @param[in] PublicKeyData The public key data used to validate the signature.
+ @param[in] PublicKeyDataLength The length of the public key data.
+
+ @retval RETURN_SUCCESS Authentication pass.
+ The LastAttemptStatus should be LAST_ATTEMPT_STATUS_SUCCESS.
+ @retval RETURN_SECURITY_VIOLATION Authentication fail.
+ The LastAttemptStatus should be LAST_ATTEMPT_STATUS_ERROR_AUTH_ERROR.
+ @retval RETURN_INVALID_PARAMETER The image is in an invalid format.
+ The LastAttemptStatus should be LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT.
+ @retval RETURN_UNSUPPORTED No Authentication handler associated with CertType.
+ The LastAttemptStatus should be LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT.
+ @retval RETURN_UNSUPPORTED Image or ImageSize is invalid.
+ The LastAttemptStatus should be LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT.
+ @retval RETURN_OUT_OF_RESOURCES No Authentication handler associated with CertType.
+ The LastAttemptStatus should be LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES.
+**/
+RETURN_STATUS
+EFIAPI
+AuthenticateFmpImage (
+ IN EFI_FIRMWARE_IMAGE_AUTHENTICATION *Image,
+ IN UINTN ImageSize,
+ IN CONST UINT8 *PublicKeyData,
+ IN UINTN PublicKeyDataLength
+ )
+{
+ GUID *CertType;
+ EFI_STATUS Status;
+
+ if ((Image == NULL) || (ImageSize == 0)) {
+ return RETURN_UNSUPPORTED;
+ }
+
+ if (ImageSize < sizeof(EFI_FIRMWARE_IMAGE_AUTHENTICATION)) {
+ DEBUG((DEBUG_ERROR, "AuthenticateFmpImage - ImageSize too small\n"));
+ return RETURN_INVALID_PARAMETER;
+ }
+ if (Image->AuthInfo.Hdr.dwLength <= OFFSET_OF(WIN_CERTIFICATE_UEFI_GUID, CertData)) {
+ DEBUG((DEBUG_ERROR, "AuthenticateFmpImage - dwLength too small\n"));
+ return RETURN_INVALID_PARAMETER;
+ }
+ if ((UINTN) Image->AuthInfo.Hdr.dwLength > MAX_UINTN - sizeof(UINT64)) {
+ DEBUG((DEBUG_ERROR, "AuthenticateFmpImage - dwLength too big\n"));
+ return RETURN_INVALID_PARAMETER;
+ }
+ if (ImageSize <= sizeof(Image->MonotonicCount) + Image->AuthInfo.Hdr.dwLength) {
+ DEBUG((DEBUG_ERROR, "AuthenticateFmpImage - ImageSize too small\n"));
+ return RETURN_INVALID_PARAMETER;
+ }
+ if (Image->AuthInfo.Hdr.wRevision != 0x0200) {
+ DEBUG((DEBUG_ERROR, "AuthenticateFmpImage - wRevision: 0x%02x, expect - 0x%02x\n", (UINTN)Image->AuthInfo.Hdr.wRevision, (UINTN)0x0200));
+ return RETURN_INVALID_PARAMETER;
+ }
+ if (Image->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) {
+ DEBUG((DEBUG_ERROR, "AuthenticateFmpImage - wCertificateType: 0x%02x, expect - 0x%02x\n", (UINTN)Image->AuthInfo.Hdr.wCertificateType, (UINTN)WIN_CERT_TYPE_EFI_GUID));
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ CertType = &Image->AuthInfo.CertType;
+ DEBUG((DEBUG_INFO, "AuthenticateFmpImage - CertType: %g\n", CertType));
+
+ if (CompareGuid (&gEfiCertPkcs7Guid, CertType)) {
+ //
+ // Call the match handler to extract raw data for the input section data.
+ //
+ Status = FmpAuthenticatedHandlerPkcs7 (
+ Image,
+ ImageSize,
+ PublicKeyData,
+ PublicKeyDataLength
+ );
+ return Status;
+ }
+
+ //
+ // Not found, the input guided section is not supported.
+ //
+ return RETURN_UNSUPPORTED;
+}
+
diff --git a/Core/SecurityPkg/Library/FmpAuthenticationLibPkcs7/FmpAuthenticationLibPkcs7.inf b/Core/SecurityPkg/Library/FmpAuthenticationLibPkcs7/FmpAuthenticationLibPkcs7.inf
new file mode 100644
index 0000000000..215b3cbecd
--- /dev/null
+++ b/Core/SecurityPkg/Library/FmpAuthenticationLibPkcs7/FmpAuthenticationLibPkcs7.inf
@@ -0,0 +1,49 @@
+## @file
+# FMP Authentication PKCS7 handler.
+#
+# Instance of FmpAuthentication Library for DXE/PEI post memory phase.
+#
+# Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = FmpAuthenticationLibPkcs7
+ MODULE_UNI_FILE = FmpAuthenticationLibPkcs7.uni
+ FILE_GUID = F4EA205B-7345-452C-9D62-53BA6F3B8910
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = FmpAuthenticationLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ FmpAuthenticationLibPkcs7.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ SecurityPkg/SecurityPkg.dec
+ CryptoPkg/CryptoPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ MemoryAllocationLib
+ BaseCryptLib
+
+[Guids]
+ gEfiCertPkcs7Guid ## CONSUMES ## GUID
diff --git a/Core/SecurityPkg/Library/FmpAuthenticationLibPkcs7/FmpAuthenticationLibPkcs7.uni b/Core/SecurityPkg/Library/FmpAuthenticationLibPkcs7/FmpAuthenticationLibPkcs7.uni
new file mode 100644
index 0000000000..d327e53a59
--- /dev/null
+++ b/Core/SecurityPkg/Library/FmpAuthenticationLibPkcs7/FmpAuthenticationLibPkcs7.uni
@@ -0,0 +1,26 @@
+// /** @file
+// FMP Authentication PKCS7 handler.
+//
+// This library provide FMP Authentication PKCS7 handler to verify EFI_FIRMWARE_IMAGE_AUTHENTICATION.
+//
+// Caution: This module requires additional review when modified.
+// This library will have external input - capsule image.
+// This external input must be validated carefully to avoid security issues such as
+// buffer overflow or integer overflow.
+//
+// Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "FMP Authentication PKCS7 handler."
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library provide FMP Authentication PKCS7 handler to verify EFI_FIRMWARE_IMAGE_AUTHENTICATION."
+
diff --git a/Core/SecurityPkg/Library/FmpAuthenticationLibRsa2048Sha256/FmpAuthenticationLibRsa2048Sha256.c b/Core/SecurityPkg/Library/FmpAuthenticationLibRsa2048Sha256/FmpAuthenticationLibRsa2048Sha256.c
new file mode 100644
index 0000000000..b40993fd1b
--- /dev/null
+++ b/Core/SecurityPkg/Library/FmpAuthenticationLibRsa2048Sha256/FmpAuthenticationLibRsa2048Sha256.c
@@ -0,0 +1,360 @@
+/** @file
+ FMP Authentication RSA2048SHA256 handler.
+ Provide generic FMP authentication functions for DXE/PEI post memory phase.
+
+ Caution: This module requires additional review when modified.
+ This module will have external input - capsule image.
+ This external input must be validated carefully to avoid security issue like
+ buffer overflow, integer overflow.
+
+ FmpAuthenticatedHandlerRsa2048Sha256(), AuthenticateFmpImage() will receive
+ untrusted input and do basic validation.
+
+ Copyright (c) 2016 - 2017, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Uefi.h>
+
+#include <Guid/SystemResourceTable.h>
+#include <Guid/FirmwareContentsSigned.h>
+#include <Guid/WinCertificate.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseCryptLib.h>
+#include <Library/FmpAuthenticationLib.h>
+#include <Library/PcdLib.h>
+#include <Protocol/FirmwareManagement.h>
+#include <Guid/SystemResourceTable.h>
+
+///
+/// Public Exponent of RSA Key.
+///
+STATIC CONST UINT8 mRsaE[] = { 0x01, 0x00, 0x01 };
+
+/**
+ The handler is used to do the authentication for FMP capsule based upon
+ EFI_FIRMWARE_IMAGE_AUTHENTICATION.
+
+ Caution: This function may receive untrusted input.
+
+ This function assumes the caller AuthenticateFmpImage()
+ already did basic validation for EFI_FIRMWARE_IMAGE_AUTHENTICATION.
+
+ @param[in] Image Points to an FMP authentication image, started from EFI_FIRMWARE_IMAGE_AUTHENTICATION.
+ @param[in] ImageSize Size of the authentication image in bytes.
+ @param[in] PublicKeyData The public key data used to validate the signature.
+ @param[in] PublicKeyDataLength The length of the public key data.
+
+ @retval RETURN_SUCCESS Authentication pass.
+ The LastAttemptStatus should be LAST_ATTEMPT_STATUS_SUCCESS.
+ @retval RETURN_SECURITY_VIOLATION Authentication fail.
+ The LastAttemptStatus should be LAST_ATTEMPT_STATUS_ERROR_AUTH_ERROR.
+ @retval RETURN_INVALID_PARAMETER The image is in an invalid format.
+ The LastAttemptStatus should be LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT.
+ @retval RETURN_OUT_OF_RESOURCES No Authentication handler associated with CertType.
+ The LastAttemptStatus should be LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES.
+**/
+RETURN_STATUS
+FmpAuthenticatedHandlerRsa2048Sha256 (
+ IN EFI_FIRMWARE_IMAGE_AUTHENTICATION *Image,
+ IN UINTN ImageSize,
+ IN CONST UINT8 *PublicKeyData,
+ IN UINTN PublicKeyDataLength
+ )
+{
+ RETURN_STATUS Status;
+ EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlockRsa2048Sha256;
+ BOOLEAN CryptoStatus;
+ UINT8 Digest[SHA256_DIGEST_SIZE];
+ UINT8 *PublicKey;
+ UINTN PublicKeyBufferSize;
+ VOID *HashContext;
+ VOID *Rsa;
+
+ DEBUG ((DEBUG_INFO, "FmpAuthenticatedHandlerRsa2048Sha256 - Image: 0x%08x - 0x%08x\n", (UINTN)Image, (UINTN)ImageSize));
+
+ if (Image->AuthInfo.Hdr.dwLength != OFFSET_OF(WIN_CERTIFICATE_UEFI_GUID, CertData) + sizeof(EFI_CERT_BLOCK_RSA_2048_SHA256)) {
+ DEBUG((DEBUG_ERROR, "FmpAuthenticatedHandlerRsa2048Sha256 - dwLength: 0x%04x, dwLength - 0x%04x\n", (UINTN)Image->AuthInfo.Hdr.dwLength, (UINTN)OFFSET_OF(WIN_CERTIFICATE_UEFI_GUID, CertData) + sizeof(EFI_CERT_BLOCK_RSA_2048_SHA256)));
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ CertBlockRsa2048Sha256 = (EFI_CERT_BLOCK_RSA_2048_SHA256 *)Image->AuthInfo.CertData;
+ if (!CompareGuid(&CertBlockRsa2048Sha256->HashType, &gEfiHashAlgorithmSha256Guid)) {
+ DEBUG((DEBUG_ERROR, "FmpAuthenticatedHandlerRsa2048Sha256 - HashType: %g, expect - %g\n", &CertBlockRsa2048Sha256->HashType, &gEfiHashAlgorithmSha256Guid));
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ HashContext = NULL;
+ Rsa = NULL;
+
+ //
+ // Allocate hash context buffer required for SHA 256
+ //
+ HashContext = AllocatePool (Sha256GetContextSize ());
+ if (HashContext == NULL) {
+ CryptoStatus = FALSE;
+ DEBUG ((DEBUG_ERROR, "FmpAuthenticatedHandlerRsa2048Sha256: Can not allocate hash context\n"));
+ Status = RETURN_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ //
+ // Hash public key from data payload with SHA256.
+ //
+ ZeroMem (Digest, SHA256_DIGEST_SIZE);
+ CryptoStatus = Sha256Init (HashContext);
+ if (!CryptoStatus) {
+ DEBUG ((DEBUG_ERROR, "FmpAuthenticatedHandlerRsa2048Sha256: Sha256Init() failed\n"));
+ Status = RETURN_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ CryptoStatus = Sha256Update (HashContext, &CertBlockRsa2048Sha256->PublicKey, sizeof(CertBlockRsa2048Sha256->PublicKey));
+ if (!CryptoStatus) {
+ DEBUG ((DEBUG_ERROR, "FmpAuthenticatedHandlerRsa2048Sha256: Sha256Update() failed\n"));
+ Status = RETURN_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ CryptoStatus = Sha256Final (HashContext, Digest);
+ if (!CryptoStatus) {
+ DEBUG ((DEBUG_ERROR, "FmpAuthenticatedHandlerRsa2048Sha256: Sha256Final() failed\n"));
+ Status = RETURN_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ //
+ // Fail if the PublicKey is not one of the public keys in PcdRsa2048Sha256PublicKeyBuffer
+ //
+ PublicKey = (VOID *)PublicKeyData;
+ PublicKeyBufferSize = PublicKeyDataLength;
+ CryptoStatus = FALSE;
+ while (PublicKeyBufferSize != 0) {
+ if (CompareMem (Digest, PublicKey, SHA256_DIGEST_SIZE) == 0) {
+ CryptoStatus = TRUE;
+ break;
+ }
+ PublicKey = PublicKey + SHA256_DIGEST_SIZE;
+ PublicKeyBufferSize = PublicKeyBufferSize - SHA256_DIGEST_SIZE;
+ }
+ if (!CryptoStatus) {
+ DEBUG ((DEBUG_ERROR, "FmpAuthenticatedHandlerRsa2048Sha256: Public key in section is not supported\n"));
+ Status = RETURN_SECURITY_VIOLATION;
+ goto Done;
+ }
+
+ //
+ // Generate & Initialize RSA Context.
+ //
+ Rsa = RsaNew ();
+ if (Rsa == NULL) {
+ CryptoStatus = FALSE;
+ DEBUG ((DEBUG_ERROR, "FmpAuthenticatedHandlerRsa2048Sha256: RsaNew() failed\n"));
+ Status = RETURN_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ //
+ // Set RSA Key Components.
+ // NOTE: Only N and E are needed to be set as RSA public key for signature verification.
+ //
+ CryptoStatus = RsaSetKey (Rsa, RsaKeyN, CertBlockRsa2048Sha256->PublicKey, sizeof(CertBlockRsa2048Sha256->PublicKey));
+ if (!CryptoStatus) {
+ DEBUG ((DEBUG_ERROR, "FmpAuthenticatedHandlerRsa2048Sha256: RsaSetKey(RsaKeyN) failed\n"));
+ Status = RETURN_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ CryptoStatus = RsaSetKey (Rsa, RsaKeyE, mRsaE, sizeof (mRsaE));
+ if (!CryptoStatus) {
+ DEBUG ((DEBUG_ERROR, "FmpAuthenticatedHandlerRsa2048Sha256: RsaSetKey(RsaKeyE) failed\n"));
+ Status = RETURN_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ //
+ // Hash data payload with SHA256.
+ //
+ ZeroMem (Digest, SHA256_DIGEST_SIZE);
+ CryptoStatus = Sha256Init (HashContext);
+ if (!CryptoStatus) {
+ DEBUG ((DEBUG_ERROR, "FmpAuthenticatedHandlerRsa2048Sha256: Sha256Init() failed\n"));
+ Status = RETURN_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ // It is a signature across the variable data and the Monotonic Count value.
+ CryptoStatus = Sha256Update (
+ HashContext,
+ (UINT8 *)Image + sizeof(Image->MonotonicCount) + Image->AuthInfo.Hdr.dwLength,
+ ImageSize - sizeof(Image->MonotonicCount) - Image->AuthInfo.Hdr.dwLength
+ );
+ if (!CryptoStatus) {
+ DEBUG((DEBUG_ERROR, "FmpAuthenticatedHandlerRsa2048Sha256: Sha256Update() failed\n"));
+ Status = RETURN_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ CryptoStatus = Sha256Update (
+ HashContext,
+ (UINT8 *)&Image->MonotonicCount,
+ sizeof(Image->MonotonicCount)
+ );
+ if (!CryptoStatus) {
+ DEBUG ((DEBUG_ERROR, "FmpAuthenticatedHandlerRsa2048Sha256: Sha256Update() failed\n"));
+ Status = RETURN_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ CryptoStatus = Sha256Final (HashContext, Digest);
+ if (!CryptoStatus) {
+ DEBUG ((DEBUG_ERROR, "FmpAuthenticatedHandlerRsa2048Sha256: Sha256Final() failed\n"));
+ Status = RETURN_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ //
+ // Verify the RSA 2048 SHA 256 signature.
+ //
+ CryptoStatus = RsaPkcs1Verify (
+ Rsa,
+ Digest,
+ SHA256_DIGEST_SIZE,
+ CertBlockRsa2048Sha256->Signature,
+ sizeof (CertBlockRsa2048Sha256->Signature)
+ );
+ if (!CryptoStatus) {
+ //
+ // If RSA 2048 SHA 256 signature verification fails, AUTH tested failed bit is set.
+ //
+ DEBUG ((DEBUG_ERROR, "FmpAuthenticatedHandlerRsa2048Sha256: RsaPkcs1Verify() failed\n"));
+ Status = RETURN_SECURITY_VIOLATION;
+ goto Done;
+ }
+ DEBUG ((DEBUG_INFO, "FmpAuthenticatedHandlerRsa2048Sha256: PASS verification\n"));
+
+ Status = RETURN_SUCCESS;
+
+Done:
+ //
+ // Free allocated resources used to perform RSA 2048 SHA 256 signature verification
+ //
+ if (Rsa != NULL) {
+ RsaFree (Rsa);
+ }
+ if (HashContext != NULL) {
+ FreePool (HashContext);
+ }
+
+ return Status;
+}
+
+/**
+ The function is used to do the authentication for FMP capsule based upon
+ EFI_FIRMWARE_IMAGE_AUTHENTICATION.
+
+ The FMP capsule image should start with EFI_FIRMWARE_IMAGE_AUTHENTICATION,
+ followed by the payload.
+
+ If the return status is RETURN_SUCCESS, the caller may continue the rest
+ FMP update process.
+ If the return status is NOT RETURN_SUCCESS, the caller should stop the FMP
+ update process and convert the return status to LastAttemptStatus
+ to indicate that FMP update fails.
+ The LastAttemptStatus can be got from ESRT table or via
+ EFI_FIRMWARE_MANAGEMENT_PROTOCOL.GetImageInfo().
+
+ Caution: This function may receive untrusted input.
+
+ @param[in] Image Points to an FMP authentication image, started from EFI_FIRMWARE_IMAGE_AUTHENTICATION.
+ @param[in] ImageSize Size of the authentication image in bytes.
+ @param[in] PublicKeyData The public key data used to validate the signature.
+ @param[in] PublicKeyDataLength The length of the public key data.
+
+ @retval RETURN_SUCCESS Authentication pass.
+ The LastAttemptStatus should be LAST_ATTEMPT_STATUS_SUCCESS.
+ @retval RETURN_SECURITY_VIOLATION Authentication fail.
+ The LastAttemptStatus should be LAST_ATTEMPT_STATUS_ERROR_AUTH_ERROR.
+ @retval RETURN_INVALID_PARAMETER The image is in an invalid format.
+ The LastAttemptStatus should be LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT.
+ @retval RETURN_UNSUPPORTED No Authentication handler associated with CertType.
+ The LastAttemptStatus should be LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT.
+ @retval RETURN_UNSUPPORTED Image or ImageSize is invalid.
+ The LastAttemptStatus should be LAST_ATTEMPT_STATUS_ERROR_INVALID_FORMAT.
+ @retval RETURN_OUT_OF_RESOURCES No Authentication handler associated with CertType.
+ The LastAttemptStatus should be LAST_ATTEMPT_STATUS_ERROR_INSUFFICIENT_RESOURCES.
+**/
+RETURN_STATUS
+EFIAPI
+AuthenticateFmpImage (
+ IN EFI_FIRMWARE_IMAGE_AUTHENTICATION *Image,
+ IN UINTN ImageSize,
+ IN CONST UINT8 *PublicKeyData,
+ IN UINTN PublicKeyDataLength
+ )
+{
+ GUID *CertType;
+ EFI_STATUS Status;
+
+ if ((Image == NULL) || (ImageSize == 0)) {
+ return RETURN_UNSUPPORTED;
+ }
+
+ if ((PublicKeyDataLength % SHA256_DIGEST_SIZE) != 0) {
+ DEBUG ((DEBUG_ERROR, "PublicKeyDataLength is not multiple SHA256 size\n"));
+ return RETURN_UNSUPPORTED;
+ }
+
+ if (ImageSize < sizeof(EFI_FIRMWARE_IMAGE_AUTHENTICATION)) {
+ DEBUG((DEBUG_ERROR, "AuthenticateFmpImage - ImageSize too small\n"));
+ return RETURN_INVALID_PARAMETER;
+ }
+ if (Image->AuthInfo.Hdr.dwLength <= OFFSET_OF(WIN_CERTIFICATE_UEFI_GUID, CertData)) {
+ DEBUG((DEBUG_ERROR, "AuthenticateFmpImage - dwLength too small\n"));
+ return RETURN_INVALID_PARAMETER;
+ }
+ if ((UINTN) Image->AuthInfo.Hdr.dwLength > MAX_UINTN - sizeof(UINT64)) {
+ DEBUG((DEBUG_ERROR, "AuthenticateFmpImage - dwLength too big\n"));
+ return RETURN_INVALID_PARAMETER;
+ }
+ if (ImageSize <= sizeof(Image->MonotonicCount) + Image->AuthInfo.Hdr.dwLength) {
+ DEBUG((DEBUG_ERROR, "AuthenticateFmpImage - ImageSize too small\n"));
+ return RETURN_INVALID_PARAMETER;
+ }
+ if (Image->AuthInfo.Hdr.wRevision != 0x0200) {
+ DEBUG((DEBUG_ERROR, "AuthenticateFmpImage - wRevision: 0x%02x, expect - 0x%02x\n", (UINTN)Image->AuthInfo.Hdr.wRevision, (UINTN)0x0200));
+ return RETURN_INVALID_PARAMETER;
+ }
+ if (Image->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) {
+ DEBUG((DEBUG_ERROR, "AuthenticateFmpImage - wCertificateType: 0x%02x, expect - 0x%02x\n", (UINTN)Image->AuthInfo.Hdr.wCertificateType, (UINTN)WIN_CERT_TYPE_EFI_GUID));
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ CertType = &Image->AuthInfo.CertType;
+ DEBUG((DEBUG_INFO, "AuthenticateFmpImage - CertType: %g\n", CertType));
+
+ if (CompareGuid (&gEfiCertTypeRsa2048Sha256Guid, CertType)) {
+ //
+ // Call the match handler to extract raw data for the input section data.
+ //
+ Status = FmpAuthenticatedHandlerRsa2048Sha256 (
+ Image,
+ ImageSize,
+ PublicKeyData,
+ PublicKeyDataLength
+ );
+ return Status;
+ }
+
+ //
+ // Not found, the input guided section is not supported.
+ //
+ return RETURN_UNSUPPORTED;
+}
+
diff --git a/Core/SecurityPkg/Library/FmpAuthenticationLibRsa2048Sha256/FmpAuthenticationLibRsa2048Sha256.inf b/Core/SecurityPkg/Library/FmpAuthenticationLibRsa2048Sha256/FmpAuthenticationLibRsa2048Sha256.inf
new file mode 100644
index 0000000000..633f407f31
--- /dev/null
+++ b/Core/SecurityPkg/Library/FmpAuthenticationLibRsa2048Sha256/FmpAuthenticationLibRsa2048Sha256.inf
@@ -0,0 +1,53 @@
+## @file
+# FMP Authentication RSA2048SHA256 handler.
+#
+# Instance of FmpAuthentication Library for DXE/PEI post memory phase.
+#
+# Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = FmpAuthenticationLibRsa2048Sha256
+ MODULE_UNI_FILE = FmpAuthenticationLibRsa2048Sha256.uni
+ FILE_GUID = 105FF0EA-A0C0-48A8-B8F7-E8B4D62A1019
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = FmpAuthenticationLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ FmpAuthenticationLibRsa2048Sha256.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ SecurityPkg/SecurityPkg.dec
+ CryptoPkg/CryptoPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ MemoryAllocationLib
+ BaseCryptLib
+
+[Pcd]
+ gEfiSecurityPkgTokenSpaceGuid.PcdRsa2048Sha256PublicKeyBuffer ## CONSUMES
+
+[Guids]
+ gEfiCertTypeRsa2048Sha256Guid ## CONSUMES ## GUID
+ gEfiHashAlgorithmSha256Guid ## CONSUMES ## GUID
diff --git a/Core/SecurityPkg/Library/FmpAuthenticationLibRsa2048Sha256/FmpAuthenticationLibRsa2048Sha256.uni b/Core/SecurityPkg/Library/FmpAuthenticationLibRsa2048Sha256/FmpAuthenticationLibRsa2048Sha256.uni
new file mode 100644
index 0000000000..902edef8fa
--- /dev/null
+++ b/Core/SecurityPkg/Library/FmpAuthenticationLibRsa2048Sha256/FmpAuthenticationLibRsa2048Sha256.uni
@@ -0,0 +1,26 @@
+// /** @file
+// FMP Authentication RSA2048SHA256 handler.
+//
+// This library provide FMP Authentication RSA2048SHA256 handler to verify EFI_FIRMWARE_IMAGE_AUTHENTICATION.
+//
+// Caution: This module requires additional review when modified.
+// This library will have external input - capsule image.
+// This external input must be validated carefully to avoid security issues such as
+// buffer overflow or integer overflow.
+//
+// Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "FMP Authentication RSA2048SHA256 handler."
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library provide FMP Authentication RSA2048SHA256 handler to verify EFI_FIRMWARE_IMAGE_AUTHENTICATION."
+
diff --git a/Core/SecurityPkg/Library/HashInstanceLibSha1/HashInstanceLibSha1.c b/Core/SecurityPkg/Library/HashInstanceLibSha1/HashInstanceLibSha1.c
new file mode 100644
index 0000000000..6dc3508be0
--- /dev/null
+++ b/Core/SecurityPkg/Library/HashInstanceLibSha1/HashInstanceLibSha1.c
@@ -0,0 +1,155 @@
+/** @file
+ This library is BaseCrypto SHA1 hash instance.
+ It can be registered to BaseCrypto router, to serve as hash engine.
+
+Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved. <BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiPei.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/Tpm2CommandLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseCryptLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/HashLib.h>
+
+/**
+ The function set SHA1 to digest list.
+
+ @param DigestList digest list
+ @param Sha1Digest SHA1 digest
+**/
+VOID
+Tpm2SetSha1ToDigestList (
+ IN TPML_DIGEST_VALUES *DigestList,
+ IN UINT8 *Sha1Digest
+ )
+{
+ DigestList->count = 1;
+ DigestList->digests[0].hashAlg = TPM_ALG_SHA1;
+ CopyMem (
+ DigestList->digests[0].digest.sha1,
+ Sha1Digest,
+ SHA1_DIGEST_SIZE
+ );
+}
+
+/**
+ Start hash sequence.
+
+ @param HashHandle Hash handle.
+
+ @retval EFI_SUCCESS Hash sequence start and HandleHandle returned.
+ @retval EFI_OUT_OF_RESOURCES No enough resource to start hash.
+**/
+EFI_STATUS
+EFIAPI
+Sha1HashInit (
+ OUT HASH_HANDLE *HashHandle
+ )
+{
+ VOID *Sha1Ctx;
+ UINTN CtxSize;
+
+ CtxSize = Sha1GetContextSize ();
+ Sha1Ctx = AllocatePool (CtxSize);
+ ASSERT (Sha1Ctx != NULL);
+
+ Sha1Init (Sha1Ctx);
+
+ *HashHandle = (HASH_HANDLE)Sha1Ctx;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Update hash sequence data.
+
+ @param HashHandle Hash handle.
+ @param DataToHash Data to be hashed.
+ @param DataToHashLen Data size.
+
+ @retval EFI_SUCCESS Hash sequence updated.
+**/
+EFI_STATUS
+EFIAPI
+Sha1HashUpdate (
+ IN HASH_HANDLE HashHandle,
+ IN VOID *DataToHash,
+ IN UINTN DataToHashLen
+ )
+{
+ VOID *Sha1Ctx;
+
+ Sha1Ctx = (VOID *)HashHandle;
+ Sha1Update (Sha1Ctx, DataToHash, DataToHashLen);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Complete hash sequence complete.
+
+ @param HashHandle Hash handle.
+ @param DigestList Digest list.
+
+ @retval EFI_SUCCESS Hash sequence complete and DigestList is returned.
+**/
+EFI_STATUS
+EFIAPI
+Sha1HashFinal (
+ IN HASH_HANDLE HashHandle,
+ OUT TPML_DIGEST_VALUES *DigestList
+ )
+{
+ UINT8 Digest[SHA1_DIGEST_SIZE];
+ VOID *Sha1Ctx;
+
+ Sha1Ctx = (VOID *)HashHandle;
+ Sha1Final (Sha1Ctx, Digest);
+
+ FreePool (Sha1Ctx);
+
+ Tpm2SetSha1ToDigestList (DigestList, Digest);
+
+ return EFI_SUCCESS;
+}
+
+HASH_INTERFACE mSha1InternalHashInstance = {
+ HASH_ALGORITHM_SHA1_GUID,
+ Sha1HashInit,
+ Sha1HashUpdate,
+ Sha1HashFinal,
+};
+
+/**
+ The function register SHA1 instance.
+
+ @retval EFI_SUCCESS SHA1 instance is registered, or system dose not surpport registr SHA1 instance
+**/
+EFI_STATUS
+EFIAPI
+HashInstanceLibSha1Constructor (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+
+ Status = RegisterHashInterfaceLib (&mSha1InternalHashInstance);
+ if ((Status == EFI_SUCCESS) || (Status == EFI_UNSUPPORTED)) {
+ //
+ // Unsupported means platform policy does not need this instance enabled.
+ //
+ return EFI_SUCCESS;
+ }
+ return Status;
+} \ No newline at end of file
diff --git a/Core/SecurityPkg/Library/HashInstanceLibSha1/HashInstanceLibSha1.inf b/Core/SecurityPkg/Library/HashInstanceLibSha1/HashInstanceLibSha1.inf
new file mode 100644
index 0000000000..588c5f1ac4
--- /dev/null
+++ b/Core/SecurityPkg/Library/HashInstanceLibSha1/HashInstanceLibSha1.inf
@@ -0,0 +1,46 @@
+## @file
+# Provides BaseCrypto SHA1 hash service
+#
+# This library can be registered to BaseCrypto router, to serve as hash engine.
+#
+# Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = HashInstanceLibSha1
+ MODULE_UNI_FILE = HashInstanceLibSha1.uni
+ FILE_GUID = 9A7A6AB4-9DA6-4aa4-90CB-6D4B79EDA7B9
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = NULL
+ CONSTRUCTOR = HashInstanceLibSha1Constructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF
+#
+
+[Sources]
+ HashInstanceLibSha1.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ SecurityPkg/SecurityPkg.dec
+ CryptoPkg/CryptoPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ Tpm2CommandLib
+ MemoryAllocationLib
+ BaseCryptLib
diff --git a/Core/SecurityPkg/Library/HashInstanceLibSha1/HashInstanceLibSha1.uni b/Core/SecurityPkg/Library/HashInstanceLibSha1/HashInstanceLibSha1.uni
new file mode 100644
index 0000000000..03c8dcc416
--- /dev/null
+++ b/Core/SecurityPkg/Library/HashInstanceLibSha1/HashInstanceLibSha1.uni
@@ -0,0 +1,21 @@
+// /** @file
+// Provides BaseCrypto SHA1 hash service
+//
+// This library can be registered to BaseCrypto router, to serve as hash engine.
+//
+// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides BaseCrypto SHA1 hash service"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library can be registered to BaseCrypto router, to serve as hash engine."
+
diff --git a/Core/SecurityPkg/Library/HashInstanceLibSha256/HashInstanceLibSha256.c b/Core/SecurityPkg/Library/HashInstanceLibSha256/HashInstanceLibSha256.c
new file mode 100644
index 0000000000..32e03120be
--- /dev/null
+++ b/Core/SecurityPkg/Library/HashInstanceLibSha256/HashInstanceLibSha256.c
@@ -0,0 +1,155 @@
+/** @file
+ This library is BaseCrypto SHA256 hash instance.
+ It can be registered to BaseCrypto router, to serve as hash engine.
+
+Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved. <BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiPei.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/Tpm2CommandLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseCryptLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/HashLib.h>
+
+/**
+ The function set SHA256 to digest list.
+
+ @param DigestList digest list
+ @param Sha256Digest SHA256 digest
+**/
+VOID
+Tpm2SetSha256ToDigestList (
+ IN TPML_DIGEST_VALUES *DigestList,
+ IN UINT8 *Sha256Digest
+ )
+{
+ DigestList->count = 1;
+ DigestList->digests[0].hashAlg = TPM_ALG_SHA256;
+ CopyMem (
+ DigestList->digests[0].digest.sha256,
+ Sha256Digest,
+ SHA256_DIGEST_SIZE
+ );
+}
+
+/**
+ Start hash sequence.
+
+ @param HashHandle Hash handle.
+
+ @retval EFI_SUCCESS Hash sequence start and HandleHandle returned.
+ @retval EFI_OUT_OF_RESOURCES No enough resource to start hash.
+**/
+EFI_STATUS
+EFIAPI
+Sha256HashInit (
+ OUT HASH_HANDLE *HashHandle
+ )
+{
+ VOID *Sha256Ctx;
+ UINTN CtxSize;
+
+ CtxSize = Sha256GetContextSize ();
+ Sha256Ctx = AllocatePool (CtxSize);
+ ASSERT (Sha256Ctx != NULL);
+
+ Sha256Init (Sha256Ctx);
+
+ *HashHandle = (HASH_HANDLE)Sha256Ctx;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Update hash sequence data.
+
+ @param HashHandle Hash handle.
+ @param DataToHash Data to be hashed.
+ @param DataToHashLen Data size.
+
+ @retval EFI_SUCCESS Hash sequence updated.
+**/
+EFI_STATUS
+EFIAPI
+Sha256HashUpdate (
+ IN HASH_HANDLE HashHandle,
+ IN VOID *DataToHash,
+ IN UINTN DataToHashLen
+ )
+{
+ VOID *Sha256Ctx;
+
+ Sha256Ctx = (VOID *)HashHandle;
+ Sha256Update (Sha256Ctx, DataToHash, DataToHashLen);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Complete hash sequence complete.
+
+ @param HashHandle Hash handle.
+ @param DigestList Digest list.
+
+ @retval EFI_SUCCESS Hash sequence complete and DigestList is returned.
+**/
+EFI_STATUS
+EFIAPI
+Sha256HashFinal (
+ IN HASH_HANDLE HashHandle,
+ OUT TPML_DIGEST_VALUES *DigestList
+ )
+{
+ UINT8 Digest[SHA256_DIGEST_SIZE];
+ VOID *Sha256Ctx;
+
+ Sha256Ctx = (VOID *)HashHandle;
+ Sha256Final (Sha256Ctx, Digest);
+
+ FreePool (Sha256Ctx);
+
+ Tpm2SetSha256ToDigestList (DigestList, Digest);
+
+ return EFI_SUCCESS;
+}
+
+HASH_INTERFACE mSha256InternalHashInstance = {
+ HASH_ALGORITHM_SHA256_GUID,
+ Sha256HashInit,
+ Sha256HashUpdate,
+ Sha256HashFinal,
+};
+
+/**
+ The function register SHA256 instance.
+
+ @retval EFI_SUCCESS SHA256 instance is registered, or system dose not surpport registr SHA256 instance
+**/
+EFI_STATUS
+EFIAPI
+HashInstanceLibSha256Constructor (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+
+ Status = RegisterHashInterfaceLib (&mSha256InternalHashInstance);
+ if ((Status == EFI_SUCCESS) || (Status == EFI_UNSUPPORTED)) {
+ //
+ // Unsupported means platform policy does not need this instance enabled.
+ //
+ return EFI_SUCCESS;
+ }
+ return Status;
+} \ No newline at end of file
diff --git a/Core/SecurityPkg/Library/HashInstanceLibSha256/HashInstanceLibSha256.inf b/Core/SecurityPkg/Library/HashInstanceLibSha256/HashInstanceLibSha256.inf
new file mode 100644
index 0000000000..a4b2ccf9e2
--- /dev/null
+++ b/Core/SecurityPkg/Library/HashInstanceLibSha256/HashInstanceLibSha256.inf
@@ -0,0 +1,46 @@
+## @file
+# Provides BaseCrypto SHA256 hash service
+#
+# This library can be registered to BaseCrypto router, to serve as hash engine.
+#
+# Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = HashInstanceLibSha256
+ MODULE_UNI_FILE = HashInstanceLibSha256.uni
+ FILE_GUID = 5810798A-ED30-4080-8DD7-B9667A748C02
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = NULL
+ CONSTRUCTOR = HashInstanceLibSha256Constructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF
+#
+
+[Sources]
+ HashInstanceLibSha256.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ SecurityPkg/SecurityPkg.dec
+ CryptoPkg/CryptoPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ Tpm2CommandLib
+ MemoryAllocationLib
+ BaseCryptLib
diff --git a/Core/SecurityPkg/Library/HashInstanceLibSha256/HashInstanceLibSha256.uni b/Core/SecurityPkg/Library/HashInstanceLibSha256/HashInstanceLibSha256.uni
new file mode 100644
index 0000000000..a0706f7bf1
--- /dev/null
+++ b/Core/SecurityPkg/Library/HashInstanceLibSha256/HashInstanceLibSha256.uni
@@ -0,0 +1,21 @@
+// /** @file
+// Provides BaseCrypto SHA256 hash service
+//
+// This library can be registered to BaseCrypto router, to serve as hash engine.
+//
+// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides BaseCrypto SHA256 hash service"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library can be registered to BaseCrypto router, to serve as hash engine."
+
diff --git a/Core/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterCommon.c b/Core/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterCommon.c
new file mode 100644
index 0000000000..adca938410
--- /dev/null
+++ b/Core/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterCommon.c
@@ -0,0 +1,77 @@
+/** @file
+ This is BaseCrypto router support function.
+
+Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved. <BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiPei.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/Tpm2CommandLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/HashLib.h>
+#include <Protocol/Tcg2Protocol.h>
+
+typedef struct {
+ EFI_GUID Guid;
+ UINT32 Mask;
+} TPM2_HASH_MASK;
+
+TPM2_HASH_MASK mTpm2HashMask[] = {
+ {HASH_ALGORITHM_SHA1_GUID, HASH_ALG_SHA1},
+ {HASH_ALGORITHM_SHA256_GUID, HASH_ALG_SHA256},
+ {HASH_ALGORITHM_SHA384_GUID, HASH_ALG_SHA384},
+ {HASH_ALGORITHM_SHA512_GUID, HASH_ALG_SHA512},
+};
+
+/**
+ The function get hash mask info from algorithm.
+
+ @param HashGuid Hash Guid
+
+ @return HashMask
+**/
+UINT32
+EFIAPI
+Tpm2GetHashMaskFromAlgo (
+ IN EFI_GUID *HashGuid
+ )
+{
+ UINTN Index;
+ for (Index = 0; Index < sizeof(mTpm2HashMask)/sizeof(mTpm2HashMask[0]); Index++) {
+ if (CompareGuid (HashGuid, &mTpm2HashMask[Index].Guid)) {
+ return mTpm2HashMask[Index].Mask;
+ }
+ }
+ return 0;
+}
+
+/**
+ The function set digest to digest list.
+
+ @param DigestList digest list
+ @param Digest digest data
+**/
+VOID
+EFIAPI
+Tpm2SetHashToDigestList (
+ IN OUT TPML_DIGEST_VALUES *DigestList,
+ IN TPML_DIGEST_VALUES *Digest
+ )
+{
+ CopyMem (
+ &DigestList->digests[DigestList->count],
+ &Digest->digests[0],
+ sizeof(Digest->digests[0])
+ );
+ DigestList->count ++;
+}
diff --git a/Core/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterCommon.h b/Core/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterCommon.h
new file mode 100644
index 0000000000..88e328bfbc
--- /dev/null
+++ b/Core/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterCommon.h
@@ -0,0 +1,44 @@
+/** @file
+ This is BaseCrypto router support function definition.
+
+Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved. <BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _HASH_LIB_BASE_CRYPTO_ROUTER_COMMON_H_
+#define _HASH_LIB_BASE_CRYPTO_ROUTER_COMMON_H_
+
+/**
+ The function get hash mask info from algorithm.
+
+ @param HashGuid Hash Guid
+
+ @return HashMask
+**/
+UINT32
+EFIAPI
+Tpm2GetHashMaskFromAlgo (
+ IN EFI_GUID *HashGuid
+ );
+
+/**
+ The function set digest to digest list.
+
+ @param DigestList digest list
+ @param Digest digest data
+**/
+VOID
+EFIAPI
+Tpm2SetHashToDigestList (
+ IN OUT TPML_DIGEST_VALUES *DigestList,
+ IN TPML_DIGEST_VALUES *Digest
+ );
+
+#endif
diff --git a/Core/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterDxe.c b/Core/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterDxe.c
new file mode 100644
index 0000000000..7bb5087550
--- /dev/null
+++ b/Core/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterDxe.c
@@ -0,0 +1,306 @@
+/** @file
+ This library is BaseCrypto router. It will redirect hash request to each individual
+ hash handler registerd, such as SHA1, SHA256.
+ Platform can use PcdTpm2HashMask to mask some hash engines.
+
+Copyright (c) 2013 - 2017, Intel Corporation. All rights reserved. <BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiPei.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/Tpm2CommandLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+#include <Library/HashLib.h>
+
+#include "HashLibBaseCryptoRouterCommon.h"
+
+HASH_INTERFACE mHashInterface[HASH_COUNT] = {{{0}, NULL, NULL, NULL}};
+UINTN mHashInterfaceCount = 0;
+
+UINT32 mSupportedHashMaskLast = 0;
+UINT32 mSupportedHashMaskCurrent = 0;
+
+/**
+ Check mismatch of supported HashMask between modules
+ that may link different HashInstanceLib instances.
+
+**/
+VOID
+CheckSupportedHashMaskMismatch (
+ VOID
+ )
+{
+ if (mSupportedHashMaskCurrent != mSupportedHashMaskLast) {
+ DEBUG ((
+ DEBUG_WARN,
+ "WARNING: There is mismatch of supported HashMask (0x%x - 0x%x) between modules\n",
+ mSupportedHashMaskCurrent,
+ mSupportedHashMaskLast
+ ));
+ DEBUG ((DEBUG_WARN, "that are linking different HashInstanceLib instances!\n"));
+ }
+}
+
+/**
+ Start hash sequence.
+
+ @param HashHandle Hash handle.
+
+ @retval EFI_SUCCESS Hash sequence start and HandleHandle returned.
+ @retval EFI_OUT_OF_RESOURCES No enough resource to start hash.
+**/
+EFI_STATUS
+EFIAPI
+HashStart (
+ OUT HASH_HANDLE *HashHandle
+ )
+{
+ HASH_HANDLE *HashCtx;
+ UINTN Index;
+ UINT32 HashMask;
+
+ if (mHashInterfaceCount == 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ CheckSupportedHashMaskMismatch ();
+
+ HashCtx = AllocatePool (sizeof(*HashCtx) * mHashInterfaceCount);
+ ASSERT (HashCtx != NULL);
+
+ for (Index = 0; Index < mHashInterfaceCount; Index++) {
+ HashMask = Tpm2GetHashMaskFromAlgo (&mHashInterface[Index].HashGuid);
+ if ((HashMask & PcdGet32 (PcdTpm2HashMask)) != 0) {
+ mHashInterface[Index].HashInit (&HashCtx[Index]);
+ }
+ }
+
+ *HashHandle = (HASH_HANDLE)HashCtx;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Update hash sequence data.
+
+ @param HashHandle Hash handle.
+ @param DataToHash Data to be hashed.
+ @param DataToHashLen Data size.
+
+ @retval EFI_SUCCESS Hash sequence updated.
+**/
+EFI_STATUS
+EFIAPI
+HashUpdate (
+ IN HASH_HANDLE HashHandle,
+ IN VOID *DataToHash,
+ IN UINTN DataToHashLen
+ )
+{
+ HASH_HANDLE *HashCtx;
+ UINTN Index;
+ UINT32 HashMask;
+
+ if (mHashInterfaceCount == 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ CheckSupportedHashMaskMismatch ();
+
+ HashCtx = (HASH_HANDLE *)HashHandle;
+
+ for (Index = 0; Index < mHashInterfaceCount; Index++) {
+ HashMask = Tpm2GetHashMaskFromAlgo (&mHashInterface[Index].HashGuid);
+ if ((HashMask & PcdGet32 (PcdTpm2HashMask)) != 0) {
+ mHashInterface[Index].HashUpdate (HashCtx[Index], DataToHash, DataToHashLen);
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Hash sequence complete and extend to PCR.
+
+ @param HashHandle Hash handle.
+ @param PcrIndex PCR to be extended.
+ @param DataToHash Data to be hashed.
+ @param DataToHashLen Data size.
+ @param DigestList Digest list.
+
+ @retval EFI_SUCCESS Hash sequence complete and DigestList is returned.
+**/
+EFI_STATUS
+EFIAPI
+HashCompleteAndExtend (
+ IN HASH_HANDLE HashHandle,
+ IN TPMI_DH_PCR PcrIndex,
+ IN VOID *DataToHash,
+ IN UINTN DataToHashLen,
+ OUT TPML_DIGEST_VALUES *DigestList
+ )
+{
+ TPML_DIGEST_VALUES Digest;
+ HASH_HANDLE *HashCtx;
+ UINTN Index;
+ EFI_STATUS Status;
+ UINT32 HashMask;
+
+ if (mHashInterfaceCount == 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ CheckSupportedHashMaskMismatch ();
+
+ HashCtx = (HASH_HANDLE *)HashHandle;
+ ZeroMem (DigestList, sizeof(*DigestList));
+
+ for (Index = 0; Index < mHashInterfaceCount; Index++) {
+ HashMask = Tpm2GetHashMaskFromAlgo (&mHashInterface[Index].HashGuid);
+ if ((HashMask & PcdGet32 (PcdTpm2HashMask)) != 0) {
+ mHashInterface[Index].HashUpdate (HashCtx[Index], DataToHash, DataToHashLen);
+ mHashInterface[Index].HashFinal (HashCtx[Index], &Digest);
+ Tpm2SetHashToDigestList (DigestList, &Digest);
+ }
+ }
+
+ FreePool (HashCtx);
+
+ Status = Tpm2PcrExtend (
+ PcrIndex,
+ DigestList
+ );
+ return Status;
+}
+
+/**
+ Hash data and extend to PCR.
+
+ @param PcrIndex PCR to be extended.
+ @param DataToHash Data to be hashed.
+ @param DataToHashLen Data size.
+ @param DigestList Digest list.
+
+ @retval EFI_SUCCESS Hash data and DigestList is returned.
+**/
+EFI_STATUS
+EFIAPI
+HashAndExtend (
+ IN TPMI_DH_PCR PcrIndex,
+ IN VOID *DataToHash,
+ IN UINTN DataToHashLen,
+ OUT TPML_DIGEST_VALUES *DigestList
+ )
+{
+ HASH_HANDLE HashHandle;
+ EFI_STATUS Status;
+
+ if (mHashInterfaceCount == 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ CheckSupportedHashMaskMismatch ();
+
+ HashStart (&HashHandle);
+ HashUpdate (HashHandle, DataToHash, DataToHashLen);
+ Status = HashCompleteAndExtend (HashHandle, PcrIndex, NULL, 0, DigestList);
+
+ return Status;
+}
+
+/**
+ This service register Hash.
+
+ @param HashInterface Hash interface
+
+ @retval EFI_SUCCESS This hash interface is registered successfully.
+ @retval EFI_UNSUPPORTED System does not support register this interface.
+ @retval EFI_ALREADY_STARTED System already register this interface.
+**/
+EFI_STATUS
+EFIAPI
+RegisterHashInterfaceLib (
+ IN HASH_INTERFACE *HashInterface
+ )
+{
+ UINTN Index;
+ UINT32 HashMask;
+ EFI_STATUS Status;
+
+ //
+ // Check allow
+ //
+ HashMask = Tpm2GetHashMaskFromAlgo (&HashInterface->HashGuid);
+ if ((HashMask & PcdGet32 (PcdTpm2HashMask)) == 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (mHashInterfaceCount >= sizeof(mHashInterface)/sizeof(mHashInterface[0])) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Check duplication
+ //
+ for (Index = 0; Index < mHashInterfaceCount; Index++) {
+ if (CompareGuid (&mHashInterface[Index].HashGuid, &HashInterface->HashGuid)) {
+ DEBUG ((DEBUG_ERROR, "Hash Interface (%g) has been registered\n", &HashInterface->HashGuid));
+ return EFI_ALREADY_STARTED;
+ }
+ }
+
+ //
+ // Record hash algorithm bitmap of CURRENT module which consumes HashLib.
+ //
+ mSupportedHashMaskCurrent = PcdGet32 (PcdTcg2HashAlgorithmBitmap) | HashMask;
+ Status = PcdSet32S (PcdTcg2HashAlgorithmBitmap, mSupportedHashMaskCurrent);
+ ASSERT_EFI_ERROR (Status);
+
+ CopyMem (&mHashInterface[mHashInterfaceCount], HashInterface, sizeof(*HashInterface));
+ mHashInterfaceCount ++;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ The constructor function of HashLibBaseCryptoRouterDxe.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The constructor executed correctly.
+
+**/
+EFI_STATUS
+EFIAPI
+HashLibBaseCryptoRouterDxeConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Record hash algorithm bitmap of LAST module which also consumes HashLib.
+ //
+ mSupportedHashMaskLast = PcdGet32 (PcdTcg2HashAlgorithmBitmap);
+
+ //
+ // Set PcdTcg2HashAlgorithmBitmap to 0 in CONSTRUCTOR for CURRENT module.
+ //
+ Status = PcdSet32S (PcdTcg2HashAlgorithmBitmap, 0);
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
diff --git a/Core/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterDxe.inf b/Core/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterDxe.inf
new file mode 100644
index 0000000000..6e660d4f14
--- /dev/null
+++ b/Core/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterDxe.inf
@@ -0,0 +1,56 @@
+## @file
+# Provides hash service by registered hash handler
+#
+# This library is BaseCrypto router. It will redirect hash request to each individual
+# hash handler registered, such as SHA1, SHA256. Platform can use PcdTpm2HashMask to
+# mask some hash engines.
+#
+# Copyright (c) 2013 - 2017, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = HashLibBaseCryptoRouterDxe
+ MODULE_UNI_FILE = HashLibBaseCryptoRouterDxe.uni
+ FILE_GUID = 158DC712-F15A-44dc-93BB-1675045BE066
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = HashLib|DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SAL_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER
+ CONSTRUCTOR = HashLibBaseCryptoRouterDxeConstructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF
+#
+
+[Sources]
+ HashLibBaseCryptoRouterCommon.h
+ HashLibBaseCryptoRouterCommon.c
+ HashLibBaseCryptoRouterDxe.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ Tpm2CommandLib
+ MemoryAllocationLib
+ PcdLib
+
+[Pcd]
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpm2HashMask ## CONSUMES
+ ## SOMETIMES_CONSUMES
+ ## SOMETIMES_PRODUCES
+ gEfiSecurityPkgTokenSpaceGuid.PcdTcg2HashAlgorithmBitmap
+
diff --git a/Core/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterDxe.uni b/Core/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterDxe.uni
new file mode 100644
index 0000000000..db7d8a26f2
--- /dev/null
+++ b/Core/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterDxe.uni
@@ -0,0 +1,23 @@
+// /** @file
+// Provides hash service by registered hash handler
+//
+// This library is BaseCrypto router. It will redirect hash request to each individual
+// hash handler registered, such as SHA1, SHA256. Platform can use PcdTpm2HashMask to
+// mask some hash engines.
+//
+// Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides hash service by registered hash handler"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library is BaseCrypto router. It will redirect hash request to each individual hash handler registered, such as SHA1, SHA256. Platform can use PcdTpm2HashMask to mask some hash engines."
+
diff --git a/Core/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterPei.c b/Core/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterPei.c
new file mode 100644
index 0000000000..dbee0f2531
--- /dev/null
+++ b/Core/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterPei.c
@@ -0,0 +1,437 @@
+/** @file
+ This library is BaseCrypto router. It will redirect hash request to each individual
+ hash handler registerd, such as SHA1, SHA256.
+ Platform can use PcdTpm2HashMask to mask some hash engines.
+
+Copyright (c) 2013 - 2017, Intel Corporation. All rights reserved. <BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiPei.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/Tpm2CommandLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+#include <Library/HobLib.h>
+#include <Library/HashLib.h>
+#include <Guid/ZeroGuid.h>
+
+#include "HashLibBaseCryptoRouterCommon.h"
+
+#define HASH_LIB_PEI_ROUTER_GUID \
+ { 0x84681c08, 0x6873, 0x46f3, { 0x8b, 0xb7, 0xab, 0x66, 0x18, 0x95, 0xa1, 0xb3 } }
+
+EFI_GUID mHashLibPeiRouterGuid = HASH_LIB_PEI_ROUTER_GUID;
+
+typedef struct {
+ //
+ // If gZeroGuid, SupportedHashMask is 0 for FIRST module which consumes HashLib
+ // or the hash algorithm bitmap of LAST module which consumes HashLib.
+ // HashInterfaceCount and HashInterface are all 0.
+ // If gEfiCallerIdGuid, HashInterfaceCount, HashInterface and SupportedHashMask
+ // are the hash interface information of CURRENT module which consumes HashLib.
+ //
+ EFI_GUID Identifier;
+ UINTN HashInterfaceCount;
+ HASH_INTERFACE HashInterface[HASH_COUNT];
+ UINT32 SupportedHashMask;
+} HASH_INTERFACE_HOB;
+
+/**
+ This function gets hash interface hob.
+
+ @param Identifier Identifier to get hash interface hob.
+
+ @retval hash interface hob.
+**/
+HASH_INTERFACE_HOB *
+InternalGetHashInterfaceHob (
+ EFI_GUID *Identifier
+ )
+{
+ EFI_PEI_HOB_POINTERS Hob;
+ HASH_INTERFACE_HOB *HashInterfaceHob;
+
+ Hob.Raw = GetFirstGuidHob (&mHashLibPeiRouterGuid);
+ while (Hob.Raw != NULL) {
+ HashInterfaceHob = GET_GUID_HOB_DATA (Hob);
+ if (CompareGuid (&HashInterfaceHob->Identifier, Identifier)) {
+ //
+ // Found the matched one.
+ //
+ return HashInterfaceHob;
+ }
+ Hob.Raw = GET_NEXT_HOB (Hob);
+ Hob.Raw = GetNextGuidHob (&mHashLibPeiRouterGuid, Hob.Raw);
+ }
+ return NULL;
+}
+
+/**
+ This function creates hash interface hob.
+
+ @param Identifier Identifier to create hash interface hob.
+
+ @retval hash interface hob.
+**/
+HASH_INTERFACE_HOB *
+InternalCreateHashInterfaceHob (
+ EFI_GUID *Identifier
+ )
+{
+ HASH_INTERFACE_HOB LocalHashInterfaceHob;
+
+ ZeroMem (&LocalHashInterfaceHob, sizeof(LocalHashInterfaceHob));
+ CopyGuid (&LocalHashInterfaceHob.Identifier, Identifier);
+ return BuildGuidDataHob (&mHashLibPeiRouterGuid, &LocalHashInterfaceHob, sizeof(LocalHashInterfaceHob));
+}
+
+/**
+ Check mismatch of supported HashMask between modules
+ that may link different HashInstanceLib instances.
+
+ @param HashInterfaceHobCurrent Pointer to hash interface hob for CURRENT module.
+
+**/
+VOID
+CheckSupportedHashMaskMismatch (
+ IN HASH_INTERFACE_HOB *HashInterfaceHobCurrent
+ )
+{
+ HASH_INTERFACE_HOB *HashInterfaceHobLast;
+
+ HashInterfaceHobLast = InternalGetHashInterfaceHob (&gZeroGuid);
+ ASSERT (HashInterfaceHobLast != NULL);
+
+ if ((HashInterfaceHobLast->SupportedHashMask != 0) &&
+ (HashInterfaceHobCurrent->SupportedHashMask != HashInterfaceHobLast->SupportedHashMask)) {
+ DEBUG ((
+ DEBUG_WARN,
+ "WARNING: There is mismatch of supported HashMask (0x%x - 0x%x) between modules\n",
+ HashInterfaceHobCurrent->SupportedHashMask,
+ HashInterfaceHobLast->SupportedHashMask
+ ));
+ DEBUG ((DEBUG_WARN, "that are linking different HashInstanceLib instances!\n"));
+ }
+}
+
+/**
+ Start hash sequence.
+
+ @param HashHandle Hash handle.
+
+ @retval EFI_SUCCESS Hash sequence start and HandleHandle returned.
+ @retval EFI_OUT_OF_RESOURCES No enough resource to start hash.
+**/
+EFI_STATUS
+EFIAPI
+HashStart (
+ OUT HASH_HANDLE *HashHandle
+ )
+{
+ HASH_INTERFACE_HOB *HashInterfaceHob;
+ HASH_HANDLE *HashCtx;
+ UINTN Index;
+ UINT32 HashMask;
+
+ HashInterfaceHob = InternalGetHashInterfaceHob (&gEfiCallerIdGuid);
+ if (HashInterfaceHob == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (HashInterfaceHob->HashInterfaceCount == 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ CheckSupportedHashMaskMismatch (HashInterfaceHob);
+
+ HashCtx = AllocatePool (sizeof(*HashCtx) * HashInterfaceHob->HashInterfaceCount);
+ ASSERT (HashCtx != NULL);
+
+ for (Index = 0; Index < HashInterfaceHob->HashInterfaceCount; Index++) {
+ HashMask = Tpm2GetHashMaskFromAlgo (&HashInterfaceHob->HashInterface[Index].HashGuid);
+ if ((HashMask & PcdGet32 (PcdTpm2HashMask)) != 0) {
+ HashInterfaceHob->HashInterface[Index].HashInit (&HashCtx[Index]);
+ }
+ }
+
+ *HashHandle = (HASH_HANDLE)HashCtx;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Update hash sequence data.
+
+ @param HashHandle Hash handle.
+ @param DataToHash Data to be hashed.
+ @param DataToHashLen Data size.
+
+ @retval EFI_SUCCESS Hash sequence updated.
+**/
+EFI_STATUS
+EFIAPI
+HashUpdate (
+ IN HASH_HANDLE HashHandle,
+ IN VOID *DataToHash,
+ IN UINTN DataToHashLen
+ )
+{
+ HASH_INTERFACE_HOB *HashInterfaceHob;
+ HASH_HANDLE *HashCtx;
+ UINTN Index;
+ UINT32 HashMask;
+
+ HashInterfaceHob = InternalGetHashInterfaceHob (&gEfiCallerIdGuid);
+ if (HashInterfaceHob == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (HashInterfaceHob->HashInterfaceCount == 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ CheckSupportedHashMaskMismatch (HashInterfaceHob);
+
+ HashCtx = (HASH_HANDLE *)HashHandle;
+
+ for (Index = 0; Index < HashInterfaceHob->HashInterfaceCount; Index++) {
+ HashMask = Tpm2GetHashMaskFromAlgo (&HashInterfaceHob->HashInterface[Index].HashGuid);
+ if ((HashMask & PcdGet32 (PcdTpm2HashMask)) != 0) {
+ HashInterfaceHob->HashInterface[Index].HashUpdate (HashCtx[Index], DataToHash, DataToHashLen);
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Hash sequence complete and extend to PCR.
+
+ @param HashHandle Hash handle.
+ @param PcrIndex PCR to be extended.
+ @param DataToHash Data to be hashed.
+ @param DataToHashLen Data size.
+ @param DigestList Digest list.
+
+ @retval EFI_SUCCESS Hash sequence complete and DigestList is returned.
+**/
+EFI_STATUS
+EFIAPI
+HashCompleteAndExtend (
+ IN HASH_HANDLE HashHandle,
+ IN TPMI_DH_PCR PcrIndex,
+ IN VOID *DataToHash,
+ IN UINTN DataToHashLen,
+ OUT TPML_DIGEST_VALUES *DigestList
+ )
+{
+ TPML_DIGEST_VALUES Digest;
+ HASH_INTERFACE_HOB *HashInterfaceHob;
+ HASH_HANDLE *HashCtx;
+ UINTN Index;
+ EFI_STATUS Status;
+ UINT32 HashMask;
+
+ HashInterfaceHob = InternalGetHashInterfaceHob (&gEfiCallerIdGuid);
+ if (HashInterfaceHob == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (HashInterfaceHob->HashInterfaceCount == 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ CheckSupportedHashMaskMismatch (HashInterfaceHob);
+
+ HashCtx = (HASH_HANDLE *)HashHandle;
+ ZeroMem (DigestList, sizeof(*DigestList));
+
+ for (Index = 0; Index < HashInterfaceHob->HashInterfaceCount; Index++) {
+ HashMask = Tpm2GetHashMaskFromAlgo (&HashInterfaceHob->HashInterface[Index].HashGuid);
+ if ((HashMask & PcdGet32 (PcdTpm2HashMask)) != 0) {
+ HashInterfaceHob->HashInterface[Index].HashUpdate (HashCtx[Index], DataToHash, DataToHashLen);
+ HashInterfaceHob->HashInterface[Index].HashFinal (HashCtx[Index], &Digest);
+ Tpm2SetHashToDigestList (DigestList, &Digest);
+ }
+ }
+
+ FreePool (HashCtx);
+
+ Status = Tpm2PcrExtend (
+ PcrIndex,
+ DigestList
+ );
+ return Status;
+}
+
+/**
+ Hash data and extend to PCR.
+
+ @param PcrIndex PCR to be extended.
+ @param DataToHash Data to be hashed.
+ @param DataToHashLen Data size.
+ @param DigestList Digest list.
+
+ @retval EFI_SUCCESS Hash data and DigestList is returned.
+**/
+EFI_STATUS
+EFIAPI
+HashAndExtend (
+ IN TPMI_DH_PCR PcrIndex,
+ IN VOID *DataToHash,
+ IN UINTN DataToHashLen,
+ OUT TPML_DIGEST_VALUES *DigestList
+ )
+{
+ HASH_INTERFACE_HOB *HashInterfaceHob;
+ HASH_HANDLE HashHandle;
+ EFI_STATUS Status;
+
+ HashInterfaceHob = InternalGetHashInterfaceHob (&gEfiCallerIdGuid);
+ if (HashInterfaceHob == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (HashInterfaceHob->HashInterfaceCount == 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ CheckSupportedHashMaskMismatch (HashInterfaceHob);
+
+ HashStart (&HashHandle);
+ HashUpdate (HashHandle, DataToHash, DataToHashLen);
+ Status = HashCompleteAndExtend (HashHandle, PcrIndex, NULL, 0, DigestList);
+
+ return Status;
+}
+
+/**
+ This service register Hash.
+
+ @param HashInterface Hash interface
+
+ @retval EFI_SUCCESS This hash interface is registered successfully.
+ @retval EFI_UNSUPPORTED System does not support register this interface.
+ @retval EFI_ALREADY_STARTED System already register this interface.
+**/
+EFI_STATUS
+EFIAPI
+RegisterHashInterfaceLib (
+ IN HASH_INTERFACE *HashInterface
+ )
+{
+ UINTN Index;
+ HASH_INTERFACE_HOB *HashInterfaceHob;
+ UINT32 HashMask;
+ EFI_STATUS Status;
+
+ //
+ // Check allow
+ //
+ HashMask = Tpm2GetHashMaskFromAlgo (&HashInterface->HashGuid);
+ if ((HashMask & PcdGet32 (PcdTpm2HashMask)) == 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ HashInterfaceHob = InternalGetHashInterfaceHob (&gEfiCallerIdGuid);
+ if (HashInterfaceHob == NULL) {
+ HashInterfaceHob = InternalCreateHashInterfaceHob (&gEfiCallerIdGuid);
+ if (HashInterfaceHob == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ if (HashInterfaceHob->HashInterfaceCount >= HASH_COUNT) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Check duplication
+ //
+ for (Index = 0; Index < HashInterfaceHob->HashInterfaceCount; Index++) {
+ if (CompareGuid (&HashInterfaceHob->HashInterface[Index].HashGuid, &HashInterface->HashGuid)) {
+ DEBUG ((DEBUG_ERROR, "Hash Interface (%g) has been registered\n", &HashInterface->HashGuid));
+ return EFI_ALREADY_STARTED;
+ }
+ }
+
+ //
+ // Record hash algorithm bitmap of CURRENT module which consumes HashLib.
+ //
+ HashInterfaceHob->SupportedHashMask = PcdGet32 (PcdTcg2HashAlgorithmBitmap) | HashMask;
+ Status = PcdSet32S (PcdTcg2HashAlgorithmBitmap, HashInterfaceHob->SupportedHashMask);
+ ASSERT_EFI_ERROR (Status);
+
+ CopyMem (&HashInterfaceHob->HashInterface[HashInterfaceHob->HashInterfaceCount], HashInterface, sizeof(*HashInterface));
+ HashInterfaceHob->HashInterfaceCount ++;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ The constructor function of HashLibBaseCryptoRouterPei.
+
+ @param FileHandle The handle of FFS header the loaded driver.
+ @param PeiServices The pointer to the PEI services.
+
+ @retval EFI_SUCCESS The constructor executes successfully.
+ @retval EFI_OUT_OF_RESOURCES There is no enough resource for the constructor.
+
+**/
+EFI_STATUS
+EFIAPI
+HashLibBaseCryptoRouterPeiConstructor (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ EFI_STATUS Status;
+ HASH_INTERFACE_HOB *HashInterfaceHob;
+
+ HashInterfaceHob = InternalGetHashInterfaceHob (&gZeroGuid);
+ if (HashInterfaceHob == NULL) {
+ //
+ // No HOB with gZeroGuid Identifier has been created,
+ // this is FIRST module which consumes HashLib.
+ // Create the HOB with gZeroGuid Identifier.
+ //
+ HashInterfaceHob = InternalCreateHashInterfaceHob (&gZeroGuid);
+ if (HashInterfaceHob == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ } else {
+ //
+ // Record hash algorithm bitmap of LAST module which also consumes HashLib.
+ //
+ HashInterfaceHob->SupportedHashMask = PcdGet32 (PcdTcg2HashAlgorithmBitmap);
+ }
+
+ HashInterfaceHob = InternalGetHashInterfaceHob (&gEfiCallerIdGuid);
+ if (HashInterfaceHob != NULL) {
+ //
+ // In PEI phase, some modules may call RegisterForShadow and will be
+ // shadowed and executed again after memory is discovered.
+ // This is the second execution of this module, clear the hash interface
+ // information registered at its first execution.
+ //
+ ZeroMem (&HashInterfaceHob->HashInterface, sizeof (*HashInterfaceHob) - sizeof (EFI_GUID));
+ }
+
+ //
+ // Set PcdTcg2HashAlgorithmBitmap to 0 in CONSTRUCTOR for CURRENT module.
+ //
+ Status = PcdSet32S (PcdTcg2HashAlgorithmBitmap, 0);
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
diff --git a/Core/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterPei.inf b/Core/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterPei.inf
new file mode 100644
index 0000000000..eebf90e2ef
--- /dev/null
+++ b/Core/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterPei.inf
@@ -0,0 +1,62 @@
+## @file
+# Provides hash service by registered hash handler
+#
+# This library is BaseCrypto router. It will redirect hash request to each individual
+# hash handler registered, such as SHA1, SHA256. Platform can use PcdTpm2HashMask to
+# mask some hash engines.
+#
+# Copyright (c) 2013 - 2017, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = HashLibBaseCryptoRouterPei
+ MODULE_UNI_FILE = HashLibBaseCryptoRouterPei.uni
+ FILE_GUID = DDCBCFBA-8EEB-488a-96D6-097831A6E50B
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = HashLib|PEIM
+ CONSTRUCTOR = HashLibBaseCryptoRouterPeiConstructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF
+#
+
+[Sources]
+ HashLibBaseCryptoRouterCommon.h
+ HashLibBaseCryptoRouterCommon.c
+ HashLibBaseCryptoRouterPei.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ SecurityPkg/SecurityPkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ Tpm2CommandLib
+ MemoryAllocationLib
+ PcdLib
+ HobLib
+
+[Guids]
+ ## CONSUMES ## GUID
+ gZeroGuid
+
+[Pcd]
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpm2HashMask ## CONSUMES
+ ## SOMETIMES_CONSUMES
+ ## SOMETIMES_PRODUCES
+ gEfiSecurityPkgTokenSpaceGuid.PcdTcg2HashAlgorithmBitmap
+
diff --git a/Core/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterPei.uni b/Core/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterPei.uni
new file mode 100644
index 0000000000..db7d8a26f2
--- /dev/null
+++ b/Core/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterPei.uni
@@ -0,0 +1,23 @@
+// /** @file
+// Provides hash service by registered hash handler
+//
+// This library is BaseCrypto router. It will redirect hash request to each individual
+// hash handler registered, such as SHA1, SHA256. Platform can use PcdTpm2HashMask to
+// mask some hash engines.
+//
+// Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides hash service by registered hash handler"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library is BaseCrypto router. It will redirect hash request to each individual hash handler registered, such as SHA1, SHA256. Platform can use PcdTpm2HashMask to mask some hash engines."
+
diff --git a/Core/SecurityPkg/Library/HashLibTpm2/HashLibTpm2.c b/Core/SecurityPkg/Library/HashLibTpm2/HashLibTpm2.c
new file mode 100644
index 0000000000..cd5dde5be3
--- /dev/null
+++ b/Core/SecurityPkg/Library/HashLibTpm2/HashLibTpm2.c
@@ -0,0 +1,342 @@
+/** @file
+ This library uses TPM2 device to calculation hash.
+
+Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved. <BR>
+(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiPei.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/Tpm2CommandLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/HashLib.h>
+#include <Library/PcdLib.h>
+
+typedef struct {
+ TPM_ALG_ID AlgoId;
+ UINT32 Mask;
+} TPM2_HASH_MASK;
+
+TPM2_HASH_MASK mTpm2HashMask[] = {
+ {TPM_ALG_SHA1, HASH_ALG_SHA1},
+ {TPM_ALG_SHA256, HASH_ALG_SHA256},
+ {TPM_ALG_SHA384, HASH_ALG_SHA384},
+ {TPM_ALG_SHA512, HASH_ALG_SHA512},
+};
+
+/**
+ The function get algorith from hash mask info.
+
+ @return Hash algorithm
+**/
+TPM_ALG_ID
+Tpm2GetAlgoFromHashMask (
+ VOID
+ )
+{
+ UINT32 HashMask;
+ UINTN Index;
+
+ HashMask = PcdGet32 (PcdTpm2HashMask);
+ for (Index = 0; Index < sizeof(mTpm2HashMask)/sizeof(mTpm2HashMask[0]); Index++) {
+ if (mTpm2HashMask[Index].Mask == HashMask) {
+ return mTpm2HashMask[Index].AlgoId;
+ }
+ }
+
+ return TPM_ALG_NULL;
+}
+
+/**
+ Start hash sequence.
+
+ @param HashHandle Hash handle.
+
+ @retval EFI_SUCCESS Hash sequence start and HandleHandle returned.
+ @retval EFI_OUT_OF_RESOURCES No enough resource to start hash.
+**/
+EFI_STATUS
+EFIAPI
+HashStart (
+ OUT HASH_HANDLE *HashHandle
+ )
+{
+ TPMI_DH_OBJECT SequenceHandle;
+ EFI_STATUS Status;
+ TPM_ALG_ID AlgoId;
+
+ AlgoId = Tpm2GetAlgoFromHashMask ();
+
+ Status = Tpm2HashSequenceStart (AlgoId, &SequenceHandle);
+ if (!EFI_ERROR (Status)) {
+ *HashHandle = (HASH_HANDLE)SequenceHandle;
+ }
+ return Status;
+}
+
+/**
+ Update hash sequence data.
+
+ @param HashHandle Hash handle.
+ @param DataToHash Data to be hashed.
+ @param DataToHashLen Data size.
+
+ @retval EFI_SUCCESS Hash sequence updated.
+**/
+EFI_STATUS
+EFIAPI
+HashUpdate (
+ IN HASH_HANDLE HashHandle,
+ IN VOID *DataToHash,
+ IN UINTN DataToHashLen
+ )
+{
+ UINT8 *Buffer;
+ UINT64 HashLen;
+ TPM2B_MAX_BUFFER HashBuffer;
+ EFI_STATUS Status;
+
+ Buffer = (UINT8 *)(UINTN)DataToHash;
+ for (HashLen = DataToHashLen; HashLen > sizeof(HashBuffer.buffer); HashLen -= sizeof(HashBuffer.buffer)) {
+
+ HashBuffer.size = sizeof(HashBuffer.buffer);
+ CopyMem(HashBuffer.buffer, Buffer, sizeof(HashBuffer.buffer));
+ Buffer += sizeof(HashBuffer.buffer);
+
+ Status = Tpm2SequenceUpdate((TPMI_DH_OBJECT)HashHandle, &HashBuffer);
+ if (EFI_ERROR(Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+ }
+
+ //
+ // Last one
+ //
+ HashBuffer.size = (UINT16)HashLen;
+ CopyMem(HashBuffer.buffer, Buffer, (UINTN)HashLen);
+ Status = Tpm2SequenceUpdate((TPMI_DH_OBJECT)HashHandle, &HashBuffer);
+ if (EFI_ERROR(Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Hash sequence complete and extend to PCR.
+
+ @param HashHandle Hash handle.
+ @param PcrIndex PCR to be extended.
+ @param DataToHash Data to be hashed.
+ @param DataToHashLen Data size.
+ @param DigestList Digest list.
+
+ @retval EFI_SUCCESS Hash sequence complete and DigestList is returned.
+**/
+EFI_STATUS
+EFIAPI
+HashCompleteAndExtend (
+ IN HASH_HANDLE HashHandle,
+ IN TPMI_DH_PCR PcrIndex,
+ IN VOID *DataToHash,
+ IN UINTN DataToHashLen,
+ OUT TPML_DIGEST_VALUES *DigestList
+ )
+{
+ UINT8 *Buffer;
+ UINT64 HashLen;
+ TPM2B_MAX_BUFFER HashBuffer;
+ EFI_STATUS Status;
+ TPM_ALG_ID AlgoId;
+ TPM2B_DIGEST Result;
+
+ AlgoId = Tpm2GetAlgoFromHashMask ();
+
+ Buffer = (UINT8 *)(UINTN)DataToHash;
+ for (HashLen = DataToHashLen; HashLen > sizeof(HashBuffer.buffer); HashLen -= sizeof(HashBuffer.buffer)) {
+
+ HashBuffer.size = sizeof(HashBuffer.buffer);
+ CopyMem(HashBuffer.buffer, Buffer, sizeof(HashBuffer.buffer));
+ Buffer += sizeof(HashBuffer.buffer);
+
+ Status = Tpm2SequenceUpdate((TPMI_DH_OBJECT)HashHandle, &HashBuffer);
+ if (EFI_ERROR(Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+ }
+
+ //
+ // Last one
+ //
+ HashBuffer.size = (UINT16)HashLen;
+ CopyMem(HashBuffer.buffer, Buffer, (UINTN)HashLen);
+
+ ZeroMem(DigestList, sizeof(*DigestList));
+ DigestList->count = HASH_COUNT;
+
+ if (AlgoId == TPM_ALG_NULL) {
+ Status = Tpm2EventSequenceComplete (
+ PcrIndex,
+ (TPMI_DH_OBJECT)HashHandle,
+ &HashBuffer,
+ DigestList
+ );
+ } else {
+ Status = Tpm2SequenceComplete (
+ (TPMI_DH_OBJECT)HashHandle,
+ &HashBuffer,
+ &Result
+ );
+ if (EFI_ERROR(Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ DigestList->count = 1;
+ DigestList->digests[0].hashAlg = AlgoId;
+ CopyMem (&DigestList->digests[0].digest, Result.buffer, Result.size);
+ Status = Tpm2PcrExtend (
+ PcrIndex,
+ DigestList
+ );
+ }
+ if (EFI_ERROR(Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Hash data and extend to PCR.
+
+ @param PcrIndex PCR to be extended.
+ @param DataToHash Data to be hashed.
+ @param DataToHashLen Data size.
+ @param DigestList Digest list.
+
+ @retval EFI_SUCCESS Hash data and DigestList is returned.
+**/
+EFI_STATUS
+EFIAPI
+HashAndExtend (
+ IN TPMI_DH_PCR PcrIndex,
+ IN VOID *DataToHash,
+ IN UINTN DataToHashLen,
+ OUT TPML_DIGEST_VALUES *DigestList
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *Buffer;
+ UINT64 HashLen;
+ TPMI_DH_OBJECT SequenceHandle;
+ TPM2B_MAX_BUFFER HashBuffer;
+ TPM_ALG_ID AlgoId;
+ TPM2B_EVENT EventData;
+ TPM2B_DIGEST Result;
+
+ DEBUG((EFI_D_VERBOSE, "\n HashAndExtend Entry \n"));
+
+ SequenceHandle = 0xFFFFFFFF; // Know bad value
+
+ AlgoId = Tpm2GetAlgoFromHashMask ();
+
+ if ((AlgoId == TPM_ALG_NULL) && (DataToHashLen <= sizeof(EventData.buffer))) {
+ EventData.size = (UINT16)DataToHashLen;
+ CopyMem (EventData.buffer, DataToHash, DataToHashLen);
+ Status = Tpm2PcrEvent (PcrIndex, &EventData, DigestList);
+ if (EFI_ERROR(Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+ return EFI_SUCCESS;
+ }
+
+ Status = Tpm2HashSequenceStart(AlgoId, &SequenceHandle);
+ if (EFI_ERROR(Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+ DEBUG((EFI_D_VERBOSE, "\n Tpm2HashSequenceStart Success \n"));
+
+ Buffer = (UINT8 *)(UINTN)DataToHash;
+ for (HashLen = DataToHashLen; HashLen > sizeof(HashBuffer.buffer); HashLen -= sizeof(HashBuffer.buffer)) {
+
+ HashBuffer.size = sizeof(HashBuffer.buffer);
+ CopyMem(HashBuffer.buffer, Buffer, sizeof(HashBuffer.buffer));
+ Buffer += sizeof(HashBuffer.buffer);
+
+ Status = Tpm2SequenceUpdate(SequenceHandle, &HashBuffer);
+ if (EFI_ERROR(Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+ }
+ DEBUG((EFI_D_VERBOSE, "\n Tpm2SequenceUpdate Success \n"));
+
+ HashBuffer.size = (UINT16)HashLen;
+ CopyMem(HashBuffer.buffer, Buffer, (UINTN)HashLen);
+
+ ZeroMem(DigestList, sizeof(*DigestList));
+ DigestList->count = HASH_COUNT;
+
+ if (AlgoId == TPM_ALG_NULL) {
+ Status = Tpm2EventSequenceComplete (
+ PcrIndex,
+ SequenceHandle,
+ &HashBuffer,
+ DigestList
+ );
+ if (EFI_ERROR(Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+ DEBUG((EFI_D_VERBOSE, "\n Tpm2EventSequenceComplete Success \n"));
+ } else {
+ Status = Tpm2SequenceComplete (
+ SequenceHandle,
+ &HashBuffer,
+ &Result
+ );
+ if (EFI_ERROR(Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+ DEBUG((EFI_D_VERBOSE, "\n Tpm2SequenceComplete Success \n"));
+
+ DigestList->count = 1;
+ DigestList->digests[0].hashAlg = AlgoId;
+ CopyMem (&DigestList->digests[0].digest, Result.buffer, Result.size);
+ Status = Tpm2PcrExtend (
+ PcrIndex,
+ DigestList
+ );
+ if (EFI_ERROR(Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+ DEBUG((EFI_D_VERBOSE, "\n Tpm2PcrExtend Success \n"));
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This service register Hash.
+
+ @param HashInterface Hash interface
+
+ @retval EFI_SUCCESS This hash interface is registered successfully.
+ @retval EFI_UNSUPPORTED System does not support register this interface.
+ @retval EFI_ALREADY_STARTED System already register this interface.
+**/
+EFI_STATUS
+EFIAPI
+RegisterHashInterfaceLib (
+ IN HASH_INTERFACE *HashInterface
+ )
+{
+ return EFI_UNSUPPORTED;
+} \ No newline at end of file
diff --git a/Core/SecurityPkg/Library/HashLibTpm2/HashLibTpm2.inf b/Core/SecurityPkg/Library/HashLibTpm2/HashLibTpm2.inf
new file mode 100644
index 0000000000..f807cc7f3d
--- /dev/null
+++ b/Core/SecurityPkg/Library/HashLibTpm2/HashLibTpm2.inf
@@ -0,0 +1,49 @@
+## @file
+# Provides hash service using TPM2 device
+#
+# This library uses TPM2 device to calculate hash. Platform can use PcdTpm2HashMask to
+# mask some hash calculation.
+#
+# Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = HashLibTpm2
+ MODULE_UNI_FILE = HashLibTpm2.uni
+ FILE_GUID = 1317F0D5-7842-475c-B1CA-6EDC20DCBE7D
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = HashLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF
+#
+
+[Sources]
+ HashLibTpm2.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ SecurityPkg/SecurityPkg.dec
+ CryptoPkg/CryptoPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ Tpm2CommandLib
+ MemoryAllocationLib
+ PcdLib
+
+[Pcd]
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpm2HashMask ## CONSUMES
diff --git a/Core/SecurityPkg/Library/HashLibTpm2/HashLibTpm2.uni b/Core/SecurityPkg/Library/HashLibTpm2/HashLibTpm2.uni
new file mode 100644
index 0000000000..ac2895a792
--- /dev/null
+++ b/Core/SecurityPkg/Library/HashLibTpm2/HashLibTpm2.uni
@@ -0,0 +1,22 @@
+// /** @file
+// Provides hash service using TPM2 device
+//
+// This library uses TPM2 device to calculate hash. Platform can use PcdTpm2HashMask to
+// mask some hash calculation.
+//
+// Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides hash service using TPM2 device"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library uses TPM2 device to calculate hash. Platform can use PcdTpm2HashMask to mask some hash calculation."
+
diff --git a/Core/SecurityPkg/Library/OpalPasswordSupportLib/OpalPasswordSupportLib.c b/Core/SecurityPkg/Library/OpalPasswordSupportLib/OpalPasswordSupportLib.c
new file mode 100644
index 0000000000..837582359e
--- /dev/null
+++ b/Core/SecurityPkg/Library/OpalPasswordSupportLib/OpalPasswordSupportLib.c
@@ -0,0 +1,781 @@
+/** @file
+ Implementation of Opal password support library.
+
+Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "OpalPasswordSupportNotify.h"
+
+#define OPAL_PASSWORD_MAX_LENGTH 32
+
+LIST_ENTRY mDeviceList = INITIALIZE_LIST_HEAD_VARIABLE (mDeviceList);
+BOOLEAN gInSmm = FALSE;
+EFI_GUID gOpalPasswordNotifyProtocolGuid = OPAL_PASSWORD_NOTIFY_PROTOCOL_GUID;
+
+/**
+
+ The function performs determines the available actions for the OPAL_DISK provided.
+
+ @param[in] SupportedAttributes The support attribute for the device.
+ @param[in] LockingFeature The locking status for the device.
+ @param[in] OwnerShip The ownership for the device.
+ @param[out] AvalDiskActions Pointer to fill-out with appropriate disk actions.
+
+**/
+TCG_RESULT
+EFIAPI
+OpalSupportGetAvailableActions(
+ IN OPAL_DISK_SUPPORT_ATTRIBUTE *SupportedAttributes,
+ IN TCG_LOCKING_FEATURE_DESCRIPTOR *LockingFeature,
+ IN UINT16 OwnerShip,
+ OUT OPAL_DISK_ACTIONS *AvalDiskActions
+ )
+{
+ BOOLEAN ExistingPassword;
+
+ NULL_CHECK(AvalDiskActions);
+
+ AvalDiskActions->AdminPass = 1;
+ AvalDiskActions->UserPass = 0;
+ AvalDiskActions->DisableUser = 0;
+ AvalDiskActions->Unlock = 0;
+
+ //
+ // Revert is performed on locking sp, so only allow if locking sp is enabled
+ //
+ if (LockingFeature->LockingEnabled) {
+ AvalDiskActions->Revert = 1;
+ }
+
+ //
+ // Psid revert is available for any device with media encryption support
+ // Revert is allowed for any device with media encryption support, however it requires
+ //
+ if (SupportedAttributes->MediaEncryption) {
+
+ //
+ // Only allow psid revert if media encryption is enabled.
+ // Otherwise, someone who steals a disk can psid revert the disk and the user Data is still
+ // intact and accessible
+ //
+ AvalDiskActions->PsidRevert = 1;
+ AvalDiskActions->RevertKeepDataForced = 0;
+
+ //
+ // Secure erase is performed by generating a new encryption key
+ // this is only available is encryption is supported
+ //
+ AvalDiskActions->SecureErase = 1;
+ } else {
+ AvalDiskActions->PsidRevert = 0;
+ AvalDiskActions->SecureErase = 0;
+
+ //
+ // If no media encryption is supported, then a revert (using password) will not
+ // erase the Data (since you can't generate a new encryption key)
+ //
+ AvalDiskActions->RevertKeepDataForced = 1;
+ }
+
+ if (LockingFeature->Locked) {
+ AvalDiskActions->Unlock = 1;
+ } else {
+ AvalDiskActions->Unlock = 0;
+ }
+
+ //
+ // Only allow user to set password if an admin password exists
+ //
+ ExistingPassword = OpalUtilAdminPasswordExists(OwnerShip, LockingFeature);
+ AvalDiskActions->UserPass = ExistingPassword;
+
+ //
+ // This will still show up even if there isn't a user, which is fine
+ //
+ AvalDiskActions->DisableUser = ExistingPassword;
+
+ return TcgResultSuccess;
+}
+
+/**
+ Creates a session with OPAL_UID_ADMIN_SP as OPAL_ADMIN_SP_PSID_AUTHORITY, then reverts device using Admin SP Revert method.
+
+ @param[in] Session The opal session for the opal device.
+ @param[in] Psid PSID of device to revert.
+ @param[in] PsidLength Length of PSID in bytes.
+ @param[in] DevicePath The device path for the opal devcie.
+
+**/
+TCG_RESULT
+EFIAPI
+OpalSupportPsidRevert(
+ IN OPAL_SESSION *Session,
+ IN VOID *Psid,
+ IN UINT32 PsidLength,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ TCG_RESULT Ret;
+
+ NULL_CHECK(Session);
+ NULL_CHECK(Psid);
+
+ Ret = OpalUtilPsidRevert (Session, Psid, PsidLength);
+ if (Ret == TcgResultSuccess && !gInSmm) {
+ OpalSupportSendPasword (DevicePath, 0, NULL);
+ }
+
+ return Ret;
+}
+
+/**
+ Opens a session with OPAL_UID_ADMIN_SP as OPAL_ADMIN_SP_SID_AUTHORITY,
+ sets OPAL_UID_ADMIN_SP_C_PIN_SID with the new password,
+ and sets OPAL_LOCKING_SP_C_PIN_ADMIN1 with the new password.
+
+ @param[in] Session The opal session for the opal device.
+ @param[in] OldPassword Current admin password
+ @param[in] OldPasswordLength Length of current admin password in bytes
+ @param[in] NewPassword New admin password to set
+ @param[in] NewPasswordLength Length of new password in bytes
+ @param[in] DevicePath The device path for the opal devcie.
+ @param[in] SetAdmin Whether set admin password or user password.
+ TRUE for admin, FALSE for user.
+
+**/
+TCG_RESULT
+EFIAPI
+OpalSupportSetPassword(
+ IN OPAL_SESSION *Session,
+ IN VOID *OldPassword,
+ IN UINT32 OldPasswordLength,
+ IN VOID *NewPassword,
+ IN UINT32 NewPasswordLength,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ IN BOOLEAN SetAdmin
+ )
+{
+ TCG_RESULT Ret;
+
+ NULL_CHECK(Session);
+ NULL_CHECK(OldPassword);
+ NULL_CHECK(NewPassword);
+
+ if (SetAdmin) {
+ Ret = OpalUtilSetAdminPassword(Session, OldPassword, OldPasswordLength, NewPassword, NewPasswordLength);
+ } else {
+ Ret = OpalUtilSetUserPassword(Session, OldPassword, OldPasswordLength, NewPassword, NewPasswordLength);
+ }
+ if (Ret == TcgResultSuccess && !gInSmm) {
+ OpalSupportSendPasword (DevicePath, NewPasswordLength, NewPassword);
+ }
+
+ return Ret;
+}
+
+/**
+ Starts a session with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_ADMIN1_AUTHORITY and disables the User1 authority.
+
+ @param[in] Session The opal session for the opal device.
+ @param[in] Password Admin password
+ @param[in] PasswordLength Length of password in bytes
+ @param[out] PasswordFailed Indicates if password failed (start session didn't work)
+ @param[in] DevicePath The device path for the opal devcie.
+
+**/
+TCG_RESULT
+EFIAPI
+OpalSupportDisableUser(
+ IN OPAL_SESSION *Session,
+ IN VOID *Password,
+ IN UINT32 PasswordLength,
+ OUT BOOLEAN *PasswordFailed,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ TCG_RESULT Ret;
+
+ NULL_CHECK(Session);
+ NULL_CHECK(Password);
+ NULL_CHECK(PasswordFailed);
+
+ Ret = OpalUtilDisableUser(Session, Password, PasswordLength, PasswordFailed);
+ if (Ret == TcgResultSuccess && !gInSmm) {
+ OpalSupportSendPasword (DevicePath, PasswordLength, Password);
+ }
+
+ return Ret;
+}
+
+/**
+ Enable Opal Feature for the input device.
+
+ @param[in] Session The opal session for the opal device.
+ @param[in] Msid Msid
+ @param[in] MsidLength Msid Length
+ @param[in] Password Admin password
+ @param[in] PassLength Length of password in bytes
+ @param[in] DevicePath The device path for the opal devcie.
+
+**/
+TCG_RESULT
+EFIAPI
+OpalSupportEnableOpalFeature (
+ IN OPAL_SESSION *Session,
+ IN VOID *Msid,
+ IN UINT32 MsidLength,
+ IN VOID *Password,
+ IN UINT32 PassLength,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ TCG_RESULT Ret;
+
+ NULL_CHECK(Session);
+ NULL_CHECK(Msid);
+ NULL_CHECK(Password);
+
+ Ret = OpalUtilSetAdminPasswordAsSid(
+ Session,
+ Msid,
+ MsidLength,
+ Password,
+ PassLength
+ );
+ if (Ret == TcgResultSuccess) {
+ //
+ // Enable global locking range
+ //
+ Ret = OpalUtilSetOpalLockingRange(
+ Session,
+ Password,
+ PassLength,
+ OPAL_LOCKING_SP_LOCKING_GLOBALRANGE,
+ 0,
+ 0,
+ TRUE,
+ TRUE,
+ FALSE,
+ FALSE
+ );
+ }
+
+ if (Ret == TcgResultSuccess && !gInSmm) {
+ OpalSupportSendPasword (DevicePath, PassLength, Password);
+ }
+
+ return Ret;
+}
+
+/**
+ Opens a session with OPAL_UID_ADMIN_SP as OPAL_ADMIN_SP_PSID_AUTHORITY, then reverts the device using the RevertSP method.
+
+ @param[in] Session The opal session for the opal device.
+ @param[in] KeepUserData TRUE to keep existing Data on the disk, or FALSE to erase it
+ @param[in] Password Admin password
+ @param[in] PasswordLength Length of password in bytes
+ @param[in] Msid Msid
+ @param[in] MsidLength Msid Length
+ @param[out] PasswordFailed indicates if password failed (start session didn't work)
+ @param[in] DevicePath The device path for the opal devcie.
+
+**/
+TCG_RESULT
+EFIAPI
+OpalSupportRevert(
+ IN OPAL_SESSION *Session,
+ IN BOOLEAN KeepUserData,
+ IN VOID *Password,
+ IN UINT32 PasswordLength,
+ IN VOID *Msid,
+ IN UINT32 MsidLength,
+ OUT BOOLEAN *PasswordFailed,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ TCG_RESULT Ret;
+
+ NULL_CHECK(Session);
+ NULL_CHECK(Password);
+ NULL_CHECK(Msid);
+ NULL_CHECK(PasswordFailed);
+
+ Ret = OpalUtilRevert(Session, KeepUserData, Password, PasswordLength, PasswordFailed, Msid, MsidLength);
+ if (Ret == TcgResultSuccess && !gInSmm) {
+ OpalSupportSendPasword (DevicePath, 0, NULL);
+ }
+
+ return Ret;
+}
+
+/**
+ Starts a session with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_USER1_AUTHORITY or OPAL_LOCKING_SP_ADMIN1_AUTHORITY
+ and updates the global locking range ReadLocked and WriteLocked columns to FALSE.
+
+ @param[in] Session The opal session for the opal device.
+ @param[in] Password Admin or user password
+ @param[in] PasswordLength Length of password in bytes
+ @param[in] DevicePath The device path for the opal devcie.
+
+**/
+TCG_RESULT
+EFIAPI
+OpalSupportUnlock(
+ IN OPAL_SESSION *Session,
+ IN VOID *Password,
+ IN UINT32 PasswordLength,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ TCG_RESULT Ret;
+
+ NULL_CHECK(Session);
+ NULL_CHECK(Password);
+
+ Ret = OpalUtilUpdateGlobalLockingRange(Session, Password, PasswordLength, FALSE, FALSE);
+ if (Ret == TcgResultSuccess && !gInSmm) {
+ OpalSupportSendPasword (DevicePath, PasswordLength, Password);
+ }
+
+ return Ret;
+}
+
+/**
+ Starts a session with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_USER1_AUTHORITY or OPAL_LOCKING_SP_ADMIN1_AUTHORITY
+ and updates the global locking range ReadLocked and WriteLocked columns to TRUE.
+
+ @param[in] Session The opal session for the opal device.
+ @param[in] Password Admin or user password
+ @param[in] PasswordLength Length of password in bytes
+ @param[in] DevicePath The device path for the opal devcie.
+
+**/
+TCG_RESULT
+EFIAPI
+OpalSupportLock(
+ IN OPAL_SESSION *Session,
+ IN VOID *Password,
+ IN UINT32 PasswordLength,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ TCG_RESULT Ret;
+
+ NULL_CHECK(Session);
+ NULL_CHECK(Password);
+
+ Ret = OpalUtilUpdateGlobalLockingRange(Session, Password, PasswordLength, TRUE, TRUE);
+ if (Ret == TcgResultSuccess && !gInSmm) {
+ OpalSupportSendPasword (DevicePath, PasswordLength, Password);
+ }
+
+ return Ret;
+}
+
+/**
+ Initialize the communicate Buffer using DataSize and Function.
+
+ @param[out] DataPtr Points to the Data in the communicate Buffer.
+ @param[in] DataSize The Data Size to send to SMM.
+ @param[in] Function The function number to initialize the communicate Header.
+
+ @retval EFI_INVALID_PARAMETER The Data Size is too big.
+ @retval EFI_SUCCESS Find the specified variable.
+
+**/
+VOID*
+OpalInitCommunicateBuffer (
+ OUT VOID **DataPtr OPTIONAL,
+ IN UINTN DataSize,
+ IN UINTN Function
+ )
+{
+ EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;
+ OPAL_SMM_COMMUNICATE_HEADER *SmmFunctionHeader;
+ VOID *Buffer;
+ EDKII_PI_SMM_COMMUNICATION_REGION_TABLE *SmmCommRegionTable;
+ EFI_MEMORY_DESCRIPTOR *SmmCommMemRegion;
+ UINTN Index;
+ UINTN Size;
+ EFI_STATUS Status;
+
+ Buffer = NULL;
+ Status = EfiGetSystemConfigurationTable (
+ &gEdkiiPiSmmCommunicationRegionTableGuid,
+ (VOID **) &SmmCommRegionTable
+ );
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ ASSERT (SmmCommRegionTable != NULL);
+ SmmCommMemRegion = (EFI_MEMORY_DESCRIPTOR *) (SmmCommRegionTable + 1);
+ Size = 0;
+ for (Index = 0; Index < SmmCommRegionTable->NumberOfEntries; Index++) {
+ if (SmmCommMemRegion->Type == EfiConventionalMemory) {
+ Size = EFI_PAGES_TO_SIZE ((UINTN) SmmCommMemRegion->NumberOfPages);
+ if (Size >= (DataSize + OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data) + OFFSET_OF (OPAL_SMM_COMMUNICATE_HEADER, Data))) {
+ break;
+ }
+ }
+ SmmCommMemRegion = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) SmmCommMemRegion + SmmCommRegionTable->DescriptorSize);
+ }
+ ASSERT (Index < SmmCommRegionTable->NumberOfEntries);
+
+ Buffer = (VOID*)(UINTN)SmmCommMemRegion->PhysicalStart;
+ ASSERT (Buffer != NULL);
+
+ SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) Buffer;
+ CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gOpalPasswordNotifyProtocolGuid);
+ SmmCommunicateHeader->MessageLength = DataSize + OFFSET_OF (OPAL_SMM_COMMUNICATE_HEADER, Data);
+
+ SmmFunctionHeader = (OPAL_SMM_COMMUNICATE_HEADER *) SmmCommunicateHeader->Data;
+ SmmFunctionHeader->Function = Function;
+ if (DataPtr != NULL) {
+ *DataPtr = SmmFunctionHeader->Data;
+ }
+
+ return Buffer;
+}
+
+/**
+ Send the Data in communicate Buffer to SMM.
+
+ @param[in] Buffer Points to the Data in the communicate Buffer.
+ @param[in] DataSize This Size of the function Header and the Data.
+
+ @retval EFI_SUCCESS Success is returned from the functin in SMM.
+ @retval Others Failure is returned from the function in SMM.
+
+**/
+EFI_STATUS
+OpalSendCommunicateBuffer (
+ IN VOID *Buffer,
+ IN UINTN DataSize
+ )
+{
+ EFI_STATUS Status;
+ UINTN CommSize;
+ EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;
+ OPAL_SMM_COMMUNICATE_HEADER *SmmFunctionHeader;
+ EFI_SMM_COMMUNICATION_PROTOCOL *SmmCommunication;
+
+ Status = gBS->LocateProtocol (&gEfiSmmCommunicationProtocolGuid, NULL, (VOID **) &SmmCommunication);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ CommSize = DataSize + OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data) + OFFSET_OF (OPAL_SMM_COMMUNICATE_HEADER, Data);
+ Status = SmmCommunication->Communicate (SmmCommunication, Buffer, &CommSize);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) Buffer;
+ SmmFunctionHeader = (OPAL_SMM_COMMUNICATE_HEADER *)SmmCommunicateHeader->Data;
+
+ return SmmFunctionHeader->ReturnStatus;
+}
+
+/**
+ Transfer the password to the smm driver.
+
+ @param[in] DevicePath The device path for the opal devcie.
+ @param PasswordLen The input password length.
+ @param Password Input password buffer.
+
+ @retval EFI_SUCCESS Do the required action success.
+ @retval Others Error occured.
+
+**/
+EFI_STATUS
+EFIAPI
+OpalSupportSendPasword(
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ UINTN PasswordLen,
+ VOID *Password
+ )
+{
+ OPAL_COMM_DEVICE_LIST *Parameter;
+ VOID *Buffer;
+ UINTN Length;
+ EFI_STATUS Status;
+ UINTN DevicePathLen;
+
+ Parameter = NULL;
+ Buffer = NULL;
+
+ if (DevicePath == NULL) {
+ //
+ // Assume DevicePath == NULL only when library used by SMM driver
+ // and should not run to here, just return success.
+ //
+ return EFI_SUCCESS;
+ }
+
+ DevicePathLen = GetDevicePathSize (DevicePath);
+ Length = OFFSET_OF (OPAL_COMM_DEVICE_LIST, OpalDevicePath) + DevicePathLen;
+ Buffer = OpalInitCommunicateBuffer((VOID**)&Parameter, Length, SMM_FUNCTION_SET_OPAL_PASSWORD);
+ if (Buffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (Password != NULL) {
+ CopyMem((VOID*)Parameter->Password, Password, PasswordLen);
+ Parameter->PasswordLength = (UINT8)PasswordLen;
+ }
+ CopyMem (&Parameter->OpalDevicePath, DevicePath, DevicePathLen);
+
+ Status = OpalSendCommunicateBuffer(Buffer, Length);
+ if (EFI_ERROR(Status)) {
+ goto EXIT;
+ }
+
+EXIT:
+ ZeroMem(Parameter, Length);
+ return Status;
+}
+
+/**
+ Get saved Opal device list.
+
+ @retval return opal device list.
+
+**/
+LIST_ENTRY*
+EFIAPI
+OpalSupportGetOpalDeviceList (
+ VOID
+ )
+{
+ return &mDeviceList;
+}
+
+/**
+ Check if the password is full zero.
+
+ @param[in] Password Points to the Data Buffer
+
+ @retval TRUE This password string is full zero.
+ @retval FALSE This password string is not full zero.
+
+**/
+BOOLEAN
+OpalPasswordIsFullZero (
+ IN UINT8 *Password
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < OPAL_PASSWORD_MAX_LENGTH; Index++) {
+ if (Password[Index] != 0) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+/**
+ Save hdd password to SMM.
+
+ @param[in] DevicePath Input device path info for the device.
+ @param[in] Password The hdd password of attached ATA device.
+ @param[in] PasswordLength The hdd password length.
+
+ @retval EFI_OUT_OF_RESOURCES Insufficient resources to create database record
+ @retval EFI_SUCCESS The function has been successfully executed.
+
+**/
+EFI_STATUS
+OpalSavePasswordToSmm (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ IN UINT8 *Password,
+ IN UINT8 PasswordLength
+ )
+{
+ OPAL_DISK_AND_PASSWORD_INFO *List;
+ OPAL_DISK_AND_PASSWORD_INFO *Dev;
+ LIST_ENTRY *Entry;
+ UINTN DevicePathLen;
+
+ DevicePathLen = GetDevicePathSize (DevicePath);
+
+ for (Entry = mDeviceList.ForwardLink; Entry != &mDeviceList; Entry = Entry->ForwardLink) {
+ List = BASE_CR (Entry, OPAL_DISK_AND_PASSWORD_INFO, Link);
+ if (CompareMem (&List->OpalDevicePath, DevicePath, DevicePathLen) == 0) {
+ CopyMem(List->Password, Password, OPAL_PASSWORD_MAX_LENGTH);
+ return EFI_SUCCESS;
+ }
+ }
+
+ Dev = AllocateZeroPool (OFFSET_OF (OPAL_DISK_AND_PASSWORD_INFO, OpalDevicePath) + DevicePathLen);
+ if (Dev == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Dev->PasswordLength = PasswordLength;
+ CopyMem(&(Dev->Password), Password, OPAL_PASSWORD_MAX_LENGTH);
+ CopyMem(&(Dev->OpalDevicePath), DevicePath, DevicePathLen);
+
+ InsertHeadList (&mDeviceList, &Dev->Link);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Communication service SMI Handler entry.
+
+ This SMI handler provides services for saving HDD password and saving S3 boot script when ready to boot.
+
+ @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
+ @param[in] RegisterContext 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 and quiesced. No other handlers
+ should still be called.
+ @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has been quiesced but other handlers should
+ still be called.
+ @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other handlers should still
+ be called.
+ @retval EFI_INTERRUPT_PENDING The interrupt could not be quiesced.
+**/
+EFI_STATUS
+EFIAPI
+SmmOpalPasswordHandler (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *RegisterContext,
+ IN OUT VOID *CommBuffer,
+ IN OUT UINTN *CommBufferSize
+ )
+{
+ EFI_STATUS Status;
+ OPAL_SMM_COMMUNICATE_HEADER *SmmFunctionHeader;
+ UINTN TempCommBufferSize;
+ UINT8 *NewPassword;
+ UINT8 PasswordLength;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+
+ if (CommBuffer == NULL || CommBufferSize == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ TempCommBufferSize = *CommBufferSize;
+ if (TempCommBufferSize < OFFSET_OF (OPAL_SMM_COMMUNICATE_HEADER, Data)) {
+ return EFI_SUCCESS;
+ }
+
+ Status = EFI_SUCCESS;
+ SmmFunctionHeader = (OPAL_SMM_COMMUNICATE_HEADER *)CommBuffer;
+
+ DevicePath = &((OPAL_COMM_DEVICE_LIST*)(SmmFunctionHeader->Data))->OpalDevicePath;
+ PasswordLength = ((OPAL_COMM_DEVICE_LIST*)(SmmFunctionHeader->Data))->PasswordLength;
+ NewPassword = ((OPAL_COMM_DEVICE_LIST*)(SmmFunctionHeader->Data))->Password;
+
+ switch (SmmFunctionHeader->Function) {
+ case SMM_FUNCTION_SET_OPAL_PASSWORD:
+ if (OpalPasswordIsFullZero (NewPassword) || PasswordLength == 0) {
+ Status = EFI_INVALID_PARAMETER;
+ goto EXIT;
+ }
+
+ Status = OpalSavePasswordToSmm (DevicePath, NewPassword, PasswordLength);
+ break;
+
+ default:
+ Status = EFI_UNSUPPORTED;
+ break;
+ }
+
+EXIT:
+ SmmFunctionHeader->ReturnStatus = Status;
+
+ //
+ // Return EFI_SUCCESS cause only one handler can be trigged.
+ // so return EFI_WARN_INTERRUPT_SOURCE_PENDING to make all handler can be trigged.
+ //
+ return EFI_WARN_INTERRUPT_SOURCE_PENDING;
+}
+
+/**
+ The constructor function.
+
+ Register SMI handler when link to SMM driver.
+
+ @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+OpalPasswordSupportLibConstructor (
+ VOID
+ )
+{
+ EFI_SMM_BASE2_PROTOCOL *SmmBase2;
+ EFI_SMM_SYSTEM_TABLE2 *Smst;
+ EFI_HANDLE SmmHandle;
+ EFI_STATUS Status;
+
+ Status = gBS->LocateProtocol (&gEfiSmmBase2ProtocolGuid, NULL, (VOID**) &SmmBase2);
+ if (EFI_ERROR (Status)) {
+ return RETURN_SUCCESS;
+ }
+ Status = SmmBase2->InSmm (SmmBase2, &gInSmm);
+ if (EFI_ERROR (Status)) {
+ return RETURN_SUCCESS;
+ }
+ if (!gInSmm) {
+ return RETURN_SUCCESS;
+ }
+
+ //
+ // Good, we are in SMM
+ //
+ Status = SmmBase2->GetSmstLocation (SmmBase2, &Smst);
+ if (EFI_ERROR (Status)) {
+ return RETURN_SUCCESS;
+ }
+
+ SmmHandle = NULL;
+ Status = Smst->SmiHandlerRegister (SmmOpalPasswordHandler, &gOpalPasswordNotifyProtocolGuid, &SmmHandle);
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ The Destructor function.
+
+ Clean the saved opal device list.
+
+ @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+OpalPasswordSupportLibDestructor (
+ VOID
+ )
+{
+ OPAL_DISK_AND_PASSWORD_INFO *Device;
+
+ while (!IsListEmpty (&mDeviceList)) {
+ Device = BASE_CR (mDeviceList.ForwardLink, OPAL_DISK_AND_PASSWORD_INFO, Link);
+
+ RemoveEntryList (&Device->Link);
+ FreePool (Device);
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Core/SecurityPkg/Library/OpalPasswordSupportLib/OpalPasswordSupportLib.inf b/Core/SecurityPkg/Library/OpalPasswordSupportLib/OpalPasswordSupportLib.inf
new file mode 100644
index 0000000000..b7831356e5
--- /dev/null
+++ b/Core/SecurityPkg/Library/OpalPasswordSupportLib/OpalPasswordSupportLib.inf
@@ -0,0 +1,55 @@
+## @file
+# This is a OpalPassword support library.
+#
+# This module is used to provide API used by Opal password solution.
+#
+# Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+[Defines]
+ INF_VERSION = 0x00010017
+ BASE_NAME = OpalPasswordSupportLib
+ FILE_GUID = 00F93D8C-00A6-42D0-9327-11CE309B944A
+ VERSION_STRING = 1.0
+ MODULE_TYPE = BASE
+ LIBRARY_CLASS = OpalPasswordSupportLib|DXE_DRIVER DXE_CORE DXE_SMM_DRIVER
+
+ CONSTRUCTOR = OpalPasswordSupportLibConstructor
+ DESTRUCTOR = OpalPasswordSupportLibDestructor
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ OpalPasswordSupportLib.c
+ OpalPasswordSupportNotify.h
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ PrintLib
+ DebugLib
+ TimerLib
+ TcgStorageOpalLib
+ UefiLib
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[Protocols]
+ gEfiStorageSecurityCommandProtocolGuid ## CONSUMES
+ gEfiSmmCommunicationProtocolGuid ## CONSUMES
+ gEfiSmmBase2ProtocolGuid ## CONSUMES # only for SMM version
+
+[Guids]
+ gEdkiiPiSmmCommunicationRegionTableGuid ## CONSUMES ## SystemTable
diff --git a/Core/SecurityPkg/Library/OpalPasswordSupportLib/OpalPasswordSupportNotify.h b/Core/SecurityPkg/Library/OpalPasswordSupportLib/OpalPasswordSupportNotify.h
new file mode 100644
index 0000000000..f0ad3a1136
--- /dev/null
+++ b/Core/SecurityPkg/Library/OpalPasswordSupportLib/OpalPasswordSupportNotify.h
@@ -0,0 +1,56 @@
+/** @file
+ Implementation of Opal password support library.
+
+Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _DXE_OPAL_NOTIFY_H_
+#define _DXE_OPAL_NOTIFY_H_
+
+#include <PiDxe.h>
+#include <PiSmm.h>
+
+#include <Uefi/UefiAcpiDataTable.h>
+#include <Guid/PiSmmCommunicationRegionTable.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/OpalPasswordSupportLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+#include <Protocol/SmmCommunication.h>
+#include <Protocol/SmmBase2.h>
+
+
+#pragma pack(1)
+
+typedef struct {
+ UINTN Function;
+ EFI_STATUS ReturnStatus;
+ UINT8 Data[1];
+} OPAL_SMM_COMMUNICATE_HEADER;
+
+typedef struct {
+ UINT8 Password[32];
+ UINT8 PasswordLength;
+
+ EFI_DEVICE_PATH_PROTOCOL OpalDevicePath;
+} OPAL_COMM_DEVICE_LIST;
+
+#pragma pack()
+
+#define SMM_FUNCTION_SET_OPAL_PASSWORD 1
+
+#define OPAL_PASSWORD_NOTIFY_PROTOCOL_GUID {0x0ff2ddd0, 0xefc9, 0x4f49, { 0x99, 0x7a, 0xcb, 0x59, 0x44, 0xe6, 0x97, 0xd3 } }
+
+#endif
diff --git a/Core/SecurityPkg/Library/PeiRsa2048Sha256GuidedSectionExtractLib/PeiRsa2048Sha256GuidedSectionExtractLib.c b/Core/SecurityPkg/Library/PeiRsa2048Sha256GuidedSectionExtractLib/PeiRsa2048Sha256GuidedSectionExtractLib.c
new file mode 100644
index 0000000000..ba1c700ad0
--- /dev/null
+++ b/Core/SecurityPkg/Library/PeiRsa2048Sha256GuidedSectionExtractLib/PeiRsa2048Sha256GuidedSectionExtractLib.c
@@ -0,0 +1,387 @@
+/** @file
+
+ This library registers RSA 2048 SHA 256 guided section handler
+ to parse RSA 2048 SHA 256 encapsulation section and extract raw data.
+ It uses the BaseCrypyLib based on OpenSSL to authenticate the signature.
+
+Copyright (c) 2013 - 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiPei.h>
+#include <Protocol/Hash.h>
+#include <Library/ExtractGuidedSectionLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+#include <Guid/WinCertificate.h>
+#include <Library/BaseCryptLib.h>
+#include <Library/PerformanceLib.h>
+#include <Guid/SecurityPkgTokenSpace.h>
+
+///
+/// RSA 2048 SHA 256 Guided Section header
+///
+typedef struct {
+ EFI_GUID_DEFINED_SECTION GuidedSectionHeader; ///< EFI guided section header
+ EFI_CERT_BLOCK_RSA_2048_SHA256 CertBlockRsa2048Sha256; ///< RSA 2048-bit Signature
+} RSA_2048_SHA_256_SECTION_HEADER;
+
+typedef struct {
+ EFI_GUID_DEFINED_SECTION2 GuidedSectionHeader; ///< EFI guided section header
+ EFI_CERT_BLOCK_RSA_2048_SHA256 CertBlockRsa2048Sha256; ///< RSA 2048-bit Signature
+} RSA_2048_SHA_256_SECTION2_HEADER;
+
+///
+/// Public Exponent of RSA Key.
+///
+CONST UINT8 mRsaE[] = { 0x01, 0x00, 0x01 };
+
+/**
+
+ GetInfo gets raw data size and attribute of the input guided section.
+ It first checks whether the input guid section is supported.
+ If not, EFI_INVALID_PARAMETER will return.
+
+ @param InputSection Buffer containing the input GUIDed section to be processed.
+ @param OutputBufferSize The size of OutputBuffer.
+ @param ScratchBufferSize The size of ScratchBuffer.
+ @param SectionAttribute The attribute of the input guided section.
+
+ @retval EFI_SUCCESS The size of destination buffer, the size of scratch buffer and
+ the attribute of the input section are successfully retrieved.
+ @retval EFI_INVALID_PARAMETER The GUID in InputSection does not match this instance guid.
+
+**/
+EFI_STATUS
+EFIAPI
+Rsa2048Sha256GuidedSectionGetInfo (
+ IN CONST VOID *InputSection,
+ OUT UINT32 *OutputBufferSize,
+ OUT UINT32 *ScratchBufferSize,
+ OUT UINT16 *SectionAttribute
+ )
+{
+ if (IS_SECTION2 (InputSection)) {
+ //
+ // Check whether the input guid section is recognized.
+ //
+ if (!CompareGuid (
+ &gEfiCertTypeRsa2048Sha256Guid,
+ &(((EFI_GUID_DEFINED_SECTION2 *) InputSection)->SectionDefinitionGuid))) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Retrieve the size and attribute of the input section data.
+ //
+ *SectionAttribute = ((EFI_GUID_DEFINED_SECTION2 *) InputSection)->Attributes;
+ *ScratchBufferSize = 0;
+ *OutputBufferSize = SECTION2_SIZE (InputSection) - sizeof(RSA_2048_SHA_256_SECTION2_HEADER);
+ } else {
+ //
+ // Check whether the input guid section is recognized.
+ //
+ if (!CompareGuid (
+ &gEfiCertTypeRsa2048Sha256Guid,
+ &(((EFI_GUID_DEFINED_SECTION *) InputSection)->SectionDefinitionGuid))) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Retrieve the size and attribute of the input section data.
+ //
+ *SectionAttribute = ((EFI_GUID_DEFINED_SECTION *) InputSection)->Attributes;
+ *ScratchBufferSize = 0;
+ *OutputBufferSize = SECTION_SIZE (InputSection) - sizeof(RSA_2048_SHA_256_SECTION_HEADER);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Extraction handler tries to extract raw data from the input guided section.
+ It also does authentication check for RSA 2048 SHA 256 signature in the input guided section.
+ It first checks whether the input guid section is supported.
+ If not, EFI_INVALID_PARAMETER will return.
+
+ @param InputSection Buffer containing the input GUIDed section to be processed.
+ @param OutputBuffer Buffer to contain the output raw data allocated by the caller.
+ @param ScratchBuffer A pointer to a caller-allocated buffer for function internal use.
+ @param AuthenticationStatus A pointer to a caller-allocated UINT32 that indicates the
+ authentication status of the output buffer.
+
+ @retval EFI_SUCCESS Section Data and Auth Status is extracted successfully.
+ @retval EFI_INVALID_PARAMETER The GUID in InputSection does not match this instance guid.
+
+**/
+EFI_STATUS
+EFIAPI
+Rsa2048Sha256GuidedSectionHandler (
+ IN CONST VOID *InputSection,
+ OUT VOID **OutputBuffer,
+ IN VOID *ScratchBuffer, OPTIONAL
+ OUT UINT32 *AuthenticationStatus
+ )
+{
+ EFI_STATUS Status;
+ UINT32 OutputBufferSize;
+ EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlockRsa2048Sha256;
+ BOOLEAN CryptoStatus;
+ UINT8 Digest[SHA256_DIGEST_SIZE];
+ UINT8 *PublicKey;
+ UINTN PublicKeyBufferSize;
+ VOID *HashContext;
+ VOID *Rsa;
+
+ HashContext = NULL;
+ Rsa = NULL;
+
+ if (IS_SECTION2 (InputSection)) {
+ //
+ // Check whether the input guid section is recognized.
+ //
+ if (!CompareGuid (
+ &gEfiCertTypeRsa2048Sha256Guid,
+ &(((EFI_GUID_DEFINED_SECTION2 *)InputSection)->SectionDefinitionGuid))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Get the RSA 2048 SHA 256 information.
+ //
+ CertBlockRsa2048Sha256 = &((RSA_2048_SHA_256_SECTION2_HEADER *) InputSection)->CertBlockRsa2048Sha256;
+ OutputBufferSize = SECTION2_SIZE (InputSection) - sizeof (RSA_2048_SHA_256_SECTION2_HEADER);
+ if ((((EFI_GUID_DEFINED_SECTION *)InputSection)->Attributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) != 0) {
+ PERF_START (NULL, "RsaCopy", "PEI", 0);
+ CopyMem (*OutputBuffer, (UINT8 *)InputSection + sizeof (RSA_2048_SHA_256_SECTION2_HEADER), OutputBufferSize);
+ PERF_END (NULL, "RsaCopy", "PEI", 0);
+ } else {
+ *OutputBuffer = (UINT8 *)InputSection + sizeof (RSA_2048_SHA_256_SECTION2_HEADER);
+ }
+
+ //
+ // Implicitly RSA 2048 SHA 256 GUIDed section should have STATUS_VALID bit set
+ //
+ ASSERT ((((EFI_GUID_DEFINED_SECTION2 *)InputSection)->Attributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) != 0);
+ *AuthenticationStatus = EFI_AUTH_STATUS_IMAGE_SIGNED;
+ } else {
+ //
+ // Check whether the input guid section is recognized.
+ //
+ if (!CompareGuid (
+ &gEfiCertTypeRsa2048Sha256Guid,
+ &(((EFI_GUID_DEFINED_SECTION *)InputSection)->SectionDefinitionGuid))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Get the RSA 2048 SHA 256 information.
+ //
+ CertBlockRsa2048Sha256 = &((RSA_2048_SHA_256_SECTION_HEADER *)InputSection)->CertBlockRsa2048Sha256;
+ OutputBufferSize = SECTION_SIZE (InputSection) - sizeof (RSA_2048_SHA_256_SECTION_HEADER);
+ if ((((EFI_GUID_DEFINED_SECTION *)InputSection)->Attributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) != 0) {
+ PERF_START (NULL, "RsaCopy", "PEI", 0);
+ CopyMem (*OutputBuffer, (UINT8 *)InputSection + sizeof (RSA_2048_SHA_256_SECTION_HEADER), OutputBufferSize);
+ PERF_END (NULL, "RsaCopy", "PEI", 0);
+ } else {
+ *OutputBuffer = (UINT8 *)InputSection + sizeof (RSA_2048_SHA_256_SECTION_HEADER);
+ }
+
+ //
+ // Implicitly RSA 2048 SHA 256 GUIDed section should have STATUS_VALID bit set
+ //
+ ASSERT ((((EFI_GUID_DEFINED_SECTION *) InputSection)->Attributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) != 0);
+ *AuthenticationStatus = EFI_AUTH_STATUS_IMAGE_SIGNED;
+ }
+
+ //
+ // All paths from here return EFI_SUCESS and result is returned in AuthenticationStatus
+ //
+ Status = EFI_SUCCESS;
+
+ //
+ // Fail if the HashType is not SHA 256
+ //
+ if (!CompareGuid (&gEfiHashAlgorithmSha256Guid, &CertBlockRsa2048Sha256->HashType)) {
+ DEBUG ((DEBUG_ERROR, "PeiRsa2048Sha256: HASH type of section is not supported\n"));
+ *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;
+ goto Done;
+ }
+
+ //
+ // Allocate hash context buffer required for SHA 256
+ //
+ HashContext = AllocatePool (Sha256GetContextSize ());
+ if (HashContext == NULL) {
+ DEBUG ((DEBUG_ERROR, "PeiRsa2048Sha256: Can not allocate hash context\n"));
+ *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;
+ goto Done;
+ }
+
+ //
+ // Hash public key from data payload with SHA256.
+ //
+ ZeroMem (Digest, SHA256_DIGEST_SIZE);
+ CryptoStatus = Sha256Init (HashContext);
+ if (!CryptoStatus) {
+ DEBUG ((DEBUG_ERROR, "PeiRsa2048Sha256: Sha256Init() failed\n"));
+ *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;
+ goto Done;
+ }
+ CryptoStatus = Sha256Update (HashContext, &CertBlockRsa2048Sha256->PublicKey, sizeof(CertBlockRsa2048Sha256->PublicKey));
+ if (!CryptoStatus) {
+ DEBUG ((DEBUG_ERROR, "PeiRsa2048Sha256: Sha256Update() failed\n"));
+ *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;
+ goto Done;
+ }
+ CryptoStatus = Sha256Final (HashContext, Digest);
+ if (!CryptoStatus) {
+ DEBUG ((DEBUG_ERROR, "PeiRsa2048Sha256: Sha256Final() failed\n"));
+ *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;
+ goto Done;
+ }
+
+ //
+ // Fail if the PublicKey is not one of the public keys in PcdRsa2048Sha256PublicKeyBuffer
+ //
+ PublicKey = (UINT8 *)PcdGetPtr (PcdRsa2048Sha256PublicKeyBuffer);
+ DEBUG ((DEBUG_VERBOSE, "PeiPcdRsa2048Sha256: PublicKeyBuffer = %p\n", PublicKey));
+ ASSERT (PublicKey != NULL);
+ DEBUG ((DEBUG_VERBOSE, "PeiPcdRsa2048Sha256: PublicKeyBuffer Token = %08x\n", PcdToken (PcdRsa2048Sha256PublicKeyBuffer)));
+ PublicKeyBufferSize = PcdGetSize (PcdRsa2048Sha256PublicKeyBuffer);
+ DEBUG ((DEBUG_VERBOSE, "PeiPcdRsa2048Sha256: PublicKeyBuffer Size = %08x\n", PublicKeyBufferSize));
+ ASSERT ((PublicKeyBufferSize % SHA256_DIGEST_SIZE) == 0);
+ CryptoStatus = FALSE;
+ while (PublicKeyBufferSize != 0) {
+ if (CompareMem (Digest, PublicKey, SHA256_DIGEST_SIZE) == 0) {
+ CryptoStatus = TRUE;
+ break;
+ }
+ PublicKey = PublicKey + SHA256_DIGEST_SIZE;
+ PublicKeyBufferSize = PublicKeyBufferSize - SHA256_DIGEST_SIZE;
+ }
+ if (!CryptoStatus) {
+ DEBUG ((DEBUG_ERROR, "PeiRsa2048Sha256: Public key in section is not supported\n"));
+ *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;
+ goto Done;
+ }
+
+ //
+ // Generate & Initialize RSA Context.
+ //
+ Rsa = RsaNew ();
+ if (Rsa == NULL) {
+ DEBUG ((DEBUG_ERROR, "PeiRsa2048Sha256: RsaNew() failed\n"));
+ *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;
+ goto Done;
+ }
+
+ //
+ // Set RSA Key Components.
+ // NOTE: Only N and E are needed to be set as RSA public key for signature verification.
+ //
+ CryptoStatus = RsaSetKey (Rsa, RsaKeyN, CertBlockRsa2048Sha256->PublicKey, sizeof(CertBlockRsa2048Sha256->PublicKey));
+ if (!CryptoStatus) {
+ DEBUG ((DEBUG_ERROR, "PeiRsa2048Sha256: RsaSetKey(RsaKeyN) failed\n"));
+ *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;
+ goto Done;
+ }
+ CryptoStatus = RsaSetKey (Rsa, RsaKeyE, mRsaE, sizeof (mRsaE));
+ if (!CryptoStatus) {
+ DEBUG ((DEBUG_ERROR, "PeiRsa2048Sha256: RsaSetKey(RsaKeyE) failed\n"));
+ *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;
+ goto Done;
+ }
+
+ //
+ // Hash data payload with SHA256.
+ //
+ ZeroMem (Digest, SHA256_DIGEST_SIZE);
+ CryptoStatus = Sha256Init (HashContext);
+ if (!CryptoStatus) {
+ DEBUG ((DEBUG_ERROR, "PeiRsa2048Sha256: Sha256Init() failed\n"));
+ *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;
+ goto Done;
+ }
+ PERF_START (NULL, "RsaShaData", "PEI", 0);
+ CryptoStatus = Sha256Update (HashContext, *OutputBuffer, OutputBufferSize);
+ PERF_END (NULL, "RsaShaData", "PEI", 0);
+ if (!CryptoStatus) {
+ DEBUG ((DEBUG_ERROR, "PeiRsa2048Sha256: Sha256Update() failed\n"));
+ *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;
+ goto Done;
+ }
+ CryptoStatus = Sha256Final (HashContext, Digest);
+ if (!CryptoStatus) {
+ DEBUG ((DEBUG_ERROR, "PeiRsa2048Sha256: Sha256Final() failed\n"));
+ *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;
+ goto Done;
+ }
+
+ //
+ // Verify the RSA 2048 SHA 256 signature.
+ //
+ PERF_START (NULL, "RsaVerify", "PEI", 0);
+ CryptoStatus = RsaPkcs1Verify (
+ Rsa,
+ Digest,
+ SHA256_DIGEST_SIZE,
+ CertBlockRsa2048Sha256->Signature,
+ sizeof (CertBlockRsa2048Sha256->Signature)
+ );
+ PERF_END (NULL, "RsaVerify", "PEI", 0);
+ if (!CryptoStatus) {
+ //
+ // If RSA 2048 SHA 256 signature verification fails, AUTH tested failed bit is set.
+ //
+ DEBUG ((DEBUG_ERROR, "PeiRsa2048Sha256: RsaPkcs1Verify() failed\n"));
+ *AuthenticationStatus |= EFI_AUTH_STATUS_TEST_FAILED;
+ }
+
+Done:
+ //
+ // Free allocated resources used to perform RSA 2048 SHA 256 signature verification
+ //
+ if (Rsa != NULL) {
+ RsaFree (Rsa);
+ }
+ if (HashContext != NULL) {
+ FreePool (HashContext);
+ }
+
+ DEBUG ((DEBUG_VERBOSE, "PeiRsa2048Sha256: Status = %r AuthenticationStatus = %08x\n", Status, *AuthenticationStatus));
+
+ return Status;
+}
+
+/**
+ Register the handler to extract RSA 2048 SHA 256 guided section.
+
+ @param FileHandle The handle of FFS header the loaded driver.
+ @param PeiServices The pointer to the PEI services.
+
+ @retval EFI_SUCCESS Register successfully.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to register this handler.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiRsa2048Sha256GuidedSectionExtractLibConstructor (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ return ExtractGuidedSectionRegisterHandlers (
+ &gEfiCertTypeRsa2048Sha256Guid,
+ Rsa2048Sha256GuidedSectionGetInfo,
+ Rsa2048Sha256GuidedSectionHandler
+ );
+}
diff --git a/Core/SecurityPkg/Library/PeiRsa2048Sha256GuidedSectionExtractLib/PeiRsa2048Sha256GuidedSectionExtractLib.inf b/Core/SecurityPkg/Library/PeiRsa2048Sha256GuidedSectionExtractLib/PeiRsa2048Sha256GuidedSectionExtractLib.inf
new file mode 100644
index 0000000000..3b781c71c7
--- /dev/null
+++ b/Core/SecurityPkg/Library/PeiRsa2048Sha256GuidedSectionExtractLib/PeiRsa2048Sha256GuidedSectionExtractLib.inf
@@ -0,0 +1,58 @@
+## @file
+# This library doesn't produce any library class. The constructor function uses
+# ExtractGuidedSectionLib service to register an RSA 2048 SHA 256 guided section handler
+# that parses RSA 2048 SHA 256 encapsulation section and extracts raw data.
+#
+# It uses the BaseCrypyLib based on OpenSSL to authenticate the signature.
+#
+# Copyright (c) 2013 - 2015, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PeiRsa2048Sha256GuidedSectionExtractLib
+ FILE_GUID = FD5F2C91-4878-4007-BBA1-1B91DD325438
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = NULL|PEI_CORE PEIM
+ CONSTRUCTOR = PeiRsa2048Sha256GuidedSectionExtractLibConstructor
+ MODULE_UNI_FILE = PeiRsa2048Sha256GuidedSectionExtractLib.uni
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF
+#
+
+[Sources]
+ PeiRsa2048Sha256GuidedSectionExtractLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ CryptoPkg/CryptoPkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+ ExtractGuidedSectionLib
+ DebugLib
+ BaseMemoryLib
+ MemoryAllocationLib
+ BaseCryptLib
+ PcdLib
+ PerformanceLib
+
+[Pcd]
+ gEfiSecurityPkgTokenSpaceGuid.PcdRsa2048Sha256PublicKeyBuffer ## SOMETIMES_CONSUMES
+
+[Guids]
+ gEfiCertTypeRsa2048Sha256Guid ## PRODUCES ## UNDEFINED # Specifies RSA 2048 SHA 256 authentication algorithm.
+ gEfiHashAlgorithmSha256Guid ## SOMETIMES_CONSUMES ## UNDEFINED
+ \ No newline at end of file
diff --git a/Core/SecurityPkg/Library/PeiRsa2048Sha256GuidedSectionExtractLib/PeiRsa2048Sha256GuidedSectionExtractLib.uni b/Core/SecurityPkg/Library/PeiRsa2048Sha256GuidedSectionExtractLib/PeiRsa2048Sha256GuidedSectionExtractLib.uni
new file mode 100644
index 0000000000..5a043efbb2
--- /dev/null
+++ b/Core/SecurityPkg/Library/PeiRsa2048Sha256GuidedSectionExtractLib/PeiRsa2048Sha256GuidedSectionExtractLib.uni
@@ -0,0 +1,24 @@
+// /** @file
+// This library doesn't produce any library class. The constructor function uses
+//
+// ExtractGuidedSectionLib service to register an RSA 2048 SHA 256 guided section handler
+// that parses RSA 2048 SHA 256 encapsulation section and extracts raw data.
+//
+// It uses the BaseCrypyLib based on OpenSSL to authenticate the signature.
+//
+// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides security service of RSA 2048 SHA 256 guided section verification"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library doesn't produce any library class. The constructor function uses ExtractGuidedSectionLib service to register an RSA 2048 SHA 256 guided section handler that parses RSA2048 SHA256 encapsulation section and extracts raw data. It uses the BaseCryptLib based on OpenSSL to authenticate the signature."
+
diff --git a/Core/SecurityPkg/Library/PeiTcg2PhysicalPresenceLib/PeiTcg2PhysicalPresenceLib.c b/Core/SecurityPkg/Library/PeiTcg2PhysicalPresenceLib/PeiTcg2PhysicalPresenceLib.c
new file mode 100644
index 0000000000..e190718907
--- /dev/null
+++ b/Core/SecurityPkg/Library/PeiTcg2PhysicalPresenceLib/PeiTcg2PhysicalPresenceLib.c
@@ -0,0 +1,59 @@
+/** @file
+ Get TPM 2.0 physical presence information.
+
+ This library will get TPM 2.0 physical presence information.
+
+Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiPei.h>
+
+#include <Guid/Tcg2PhysicalPresenceData.h>
+#include <Ppi/ReadOnlyVariable2.h>
+
+#include <Library/DebugLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/PeiServicesTablePointerLib.h>
+#include <Library/Tcg2PhysicalPresenceLib.h>
+
+/**
+ Return TPM2 ManagementFlags set by PP interface.
+
+ @retval ManagementFlags TPM2 Management Flags.
+**/
+UINT32
+EFIAPI
+Tcg2PhysicalPresenceLibGetManagementFlags (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_PEI_READ_ONLY_VARIABLE2_PPI *VariablePpi;
+ EFI_TCG2_PHYSICAL_PRESENCE_FLAGS PpiFlags;
+ UINTN DataSize;
+
+ Status = PeiServicesLocatePpi (&gEfiPeiReadOnlyVariable2PpiGuid, 0, NULL, (VOID **) &VariablePpi);
+ ASSERT_EFI_ERROR (Status);
+
+ DataSize = sizeof (EFI_TCG2_PHYSICAL_PRESENCE_FLAGS);
+ Status = VariablePpi->GetVariable (
+ VariablePpi,
+ TCG2_PHYSICAL_PRESENCE_FLAGS_VARIABLE,
+ &gEfiTcg2PhysicalPresenceGuid,
+ NULL,
+ &DataSize,
+ &PpiFlags
+ );
+ if (EFI_ERROR (Status)) {
+ PpiFlags.PPFlags = TCG2_BIOS_TPM_MANAGEMENT_FLAG_DEFAULT | TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_DEFAULT;
+ }
+ return PpiFlags.PPFlags;
+}
diff --git a/Core/SecurityPkg/Library/PeiTcg2PhysicalPresenceLib/PeiTcg2PhysicalPresenceLib.inf b/Core/SecurityPkg/Library/PeiTcg2PhysicalPresenceLib/PeiTcg2PhysicalPresenceLib.inf
new file mode 100644
index 0000000000..6d0b7a00cb
--- /dev/null
+++ b/Core/SecurityPkg/Library/PeiTcg2PhysicalPresenceLib/PeiTcg2PhysicalPresenceLib.inf
@@ -0,0 +1,52 @@
+## @file
+# Get TPM 2.0 physical presence information.
+#
+# This library will get TPM 2.0 physical presence information.
+#
+# Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PeiTcg2PhysicalPresenceLib
+ MODULE_UNI_FILE = PeiTcg2PhysicalPresenceLib.uni
+ FILE_GUID = AB82E7BE-0970-480b-93EB-3D332B89F99E
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = Tcg2PhysicalPresenceLib|PEIM
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ PeiTcg2PhysicalPresenceLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+ DebugLib
+ PeiServicesLib
+ PeiServicesTablePointerLib
+
+[Guids]
+ ## SOMETIMES_CONSUMES ## Variable:L"PhysicalPresenceFlags"
+ gEfiTcg2PhysicalPresenceGuid
+
+[Ppis]
+ gEfiPeiReadOnlyVariable2PpiGuid ## CONSUMES
+
+[Depex]
+ gEfiPeiReadOnlyVariable2PpiGuid \ No newline at end of file
diff --git a/Core/SecurityPkg/Library/PeiTcg2PhysicalPresenceLib/PeiTcg2PhysicalPresenceLib.uni b/Core/SecurityPkg/Library/PeiTcg2PhysicalPresenceLib/PeiTcg2PhysicalPresenceLib.uni
new file mode 100644
index 0000000000..b562ca223c
--- /dev/null
+++ b/Core/SecurityPkg/Library/PeiTcg2PhysicalPresenceLib/PeiTcg2PhysicalPresenceLib.uni
@@ -0,0 +1,21 @@
+// /** @file
+// Get TPM 2.0 physical presence information.
+//
+// This library will get TPM 2.0 physical presence information.
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Get TPM 2.0 physical presence information."
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library will get TPM 2.0 physical presence information."
+
diff --git a/Core/SecurityPkg/Library/PlatformSecureLibNull/PlatformSecureLibNull.c b/Core/SecurityPkg/Library/PlatformSecureLibNull/PlatformSecureLibNull.c
new file mode 100644
index 0000000000..8dc07ec74a
--- /dev/null
+++ b/Core/SecurityPkg/Library/PlatformSecureLibNull/PlatformSecureLibNull.c
@@ -0,0 +1,67 @@
+/** @file
+ NULL PlatformSecureLib instance does NOT really detect whether a physical present
+ user exists but return TRUE directly. This instance can be used to verify security
+ related features during platform enabling and development. It should be replaced
+ by a platform-specific method(e.g. Button pressed) in a real platform for product.
+
+Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+BOOLEAN mUserPhysicalPresence = FALSE;
+
+/**
+
+ This function provides a platform-specific method to detect whether the platform
+ is operating by a physically present user.
+
+ Programmatic changing of platform security policy (such as disable Secure Boot,
+ or switch between Standard/Custom Secure Boot mode) MUST NOT be possible during
+ Boot Services or after exiting EFI Boot Services. Only a physically present user
+ is allowed to perform these operations.
+
+ 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 is operated by a physically present user.
+ @retval FALSE The platform is NOT operated by a physically present user.
+
+**/
+BOOLEAN
+EFIAPI
+UserPhysicalPresent (
+ VOID
+ )
+{
+ return mUserPhysicalPresence;
+}
+
+
+/**
+ Save user physical presence state from a PCD to mUserPhysicalPresence.
+
+ @param ImageHandle ImageHandle of the loaded driver.
+ @param SystemTable Pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS PcdUserPhysicalPresence is got successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+PlatformSecureLibNullConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+
+ mUserPhysicalPresence = PcdGetBool(PcdUserPhysicalPresence);
+
+ return EFI_SUCCESS;
+}
diff --git a/Core/SecurityPkg/Library/PlatformSecureLibNull/PlatformSecureLibNull.inf b/Core/SecurityPkg/Library/PlatformSecureLibNull/PlatformSecureLibNull.inf
new file mode 100644
index 0000000000..be415f4166
--- /dev/null
+++ b/Core/SecurityPkg/Library/PlatformSecureLibNull/PlatformSecureLibNull.inf
@@ -0,0 +1,44 @@
+## @file
+# NULL platform secure library instance that alway returns TRUE for a user physical present
+#
+# NULL PlatformSecureLib instance does NOT really detect whether a physical present
+# user exists but returns TRUE directly. This instance can be used to verify security
+# related features during platform enabling and development. It should be replaced
+# by a platform-specific method(e.g. Button pressed) in a real platform for product.
+#
+# Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PlatformSecureLibNull
+ MODULE_UNI_FILE = PlatformSecureLibNull.uni
+ FILE_GUID = 7FA68D82-10A4-4e71-9524-D3D9500D3CDF
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = PlatformSecureLib|DXE_RUNTIME_DRIVER DXE_SMM_DRIVER DXE_DRIVER
+ CONSTRUCTOR = PlatformSecureLibNullConstructor
+
+#
+# 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
+ SecurityPkg/SecurityPkg.dec
+
+[Pcd]
+ gEfiSecurityPkgTokenSpaceGuid.PcdUserPhysicalPresence ## CONSUMES
+
diff --git a/Core/SecurityPkg/Library/PlatformSecureLibNull/PlatformSecureLibNull.uni b/Core/SecurityPkg/Library/PlatformSecureLibNull/PlatformSecureLibNull.uni
new file mode 100644
index 0000000000..8cfa8b08db
--- /dev/null
+++ b/Core/SecurityPkg/Library/PlatformSecureLibNull/PlatformSecureLibNull.uni
@@ -0,0 +1,24 @@
+// /** @file
+// NULL platform secure library instance that alway returns TRUE for a user physical present
+//
+// NULL PlatformSecureLib instance does NOT really detect whether a physical present
+// user exists but returns TRUE directly. This instance can be used to verify security
+// related features during platform enabling and development. It should be replaced
+// by a platform-specific method(e.g. Button pressed) in a real platform for product.
+//
+// Copyright (c) 2011 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "NULL platform secure library instance that always returns TRUE for a user physical present"
+
+#string STR_MODULE_DESCRIPTION #language en-US "NULL PlatformSecureLib instance does NOT really detect whether a physical present user exists but returns TRUE directly. This instance can be used to verify security related features during platform enabling and development. It should be replaced by a platform-specific method(e.g. Button pressed) in a real platform for product."
+
diff --git a/Core/SecurityPkg/Library/SmmTcg2PhysicalPresenceLib/SmmTcg2PhysicalPresenceLib.c b/Core/SecurityPkg/Library/SmmTcg2PhysicalPresenceLib/SmmTcg2PhysicalPresenceLib.c
new file mode 100644
index 0000000000..ba4db1113a
--- /dev/null
+++ b/Core/SecurityPkg/Library/SmmTcg2PhysicalPresenceLib/SmmTcg2PhysicalPresenceLib.c
@@ -0,0 +1,387 @@
+/** @file
+ Handle TPM 2.0 physical presence requests from OS.
+
+ This library will handle TPM 2.0 physical presence request from OS.
+
+ Caution: This module requires additional review when modified.
+ This driver will have external input - variable.
+ This external input must be validated carefully to avoid security issue.
+
+ Tcg2PhysicalPresenceLibSubmitRequestToPreOSFunction() and Tcg2PhysicalPresenceLibGetUserConfirmationStatusFunction()
+ will receive untrusted input and do validation.
+
+Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiSmm.h>
+
+#include <Guid/Tcg2PhysicalPresenceData.h>
+
+#include <Protocol/SmmVariable.h>
+
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/Tcg2PpVendorLib.h>
+#include <Library/SmmServicesTableLib.h>
+
+EFI_SMM_VARIABLE_PROTOCOL *mTcg2PpSmmVariable;
+
+/**
+ The handler for TPM physical presence function:
+ Return TPM Operation Response to OS Environment.
+
+ This API should be invoked in OS runtime phase to interface with ACPI method.
+
+ @param[out] MostRecentRequest Most recent operation request.
+ @param[out] Response Response to the most recent operation request.
+
+ @return Return Code for Return TPM Operation Response to OS Environment.
+**/
+UINT32
+EFIAPI
+Tcg2PhysicalPresenceLibReturnOperationResponseToOsFunction (
+ OUT UINT32 *MostRecentRequest,
+ OUT UINT32 *Response
+ )
+{
+ EFI_STATUS Status;
+ UINTN DataSize;
+ EFI_TCG2_PHYSICAL_PRESENCE PpData;
+
+ DEBUG ((EFI_D_INFO, "[TPM2] ReturnOperationResponseToOsFunction\n"));
+
+ //
+ // Get the Physical Presence variable
+ //
+ DataSize = sizeof (EFI_TCG2_PHYSICAL_PRESENCE);
+ Status = mTcg2PpSmmVariable->SmmGetVariable (
+ TCG2_PHYSICAL_PRESENCE_VARIABLE,
+ &gEfiTcg2PhysicalPresenceGuid,
+ NULL,
+ &DataSize,
+ &PpData
+ );
+ if (EFI_ERROR (Status)) {
+ *MostRecentRequest = 0;
+ *Response = 0;
+ DEBUG ((EFI_D_ERROR, "[TPM2] Get PP variable failure! Status = %r\n", Status));
+ return TCG_PP_RETURN_TPM_OPERATION_RESPONSE_FAILURE;
+ }
+
+ *MostRecentRequest = PpData.LastPPRequest;
+ *Response = PpData.PPResponse;
+
+ return TCG_PP_RETURN_TPM_OPERATION_RESPONSE_SUCCESS;
+}
+
+/**
+ The handler for TPM physical presence function:
+ Submit TPM Operation Request to Pre-OS Environment and
+ Submit TPM Operation Request to Pre-OS Environment 2.
+
+ This API should be invoked in OS runtime phase to interface with ACPI method.
+
+ Caution: This function may receive untrusted input.
+
+ @param[in, out] Pointer to OperationRequest TPM physical presence operation request.
+ @param[in, out] Pointer to RequestParameter TPM physical presence operation request parameter.
+
+ @return Return Code for Submit TPM Operation Request to Pre-OS Environment and
+ Submit TPM Operation Request to Pre-OS Environment 2.
+ **/
+UINT32
+Tcg2PhysicalPresenceLibSubmitRequestToPreOSFunctionEx (
+ IN OUT UINT32 *OperationRequest,
+ IN OUT UINT32 *RequestParameter
+ )
+{
+ EFI_STATUS Status;
+ UINT32 ReturnCode;
+ UINTN DataSize;
+ EFI_TCG2_PHYSICAL_PRESENCE PpData;
+ EFI_TCG2_PHYSICAL_PRESENCE_FLAGS Flags;
+
+ DEBUG ((EFI_D_INFO, "[TPM2] SubmitRequestToPreOSFunction, Request = %x, %x\n", *OperationRequest, *RequestParameter));
+ ReturnCode = TCG_PP_SUBMIT_REQUEST_TO_PREOS_SUCCESS;
+
+ //
+ // Get the Physical Presence variable
+ //
+ DataSize = sizeof (EFI_TCG2_PHYSICAL_PRESENCE);
+ Status = mTcg2PpSmmVariable->SmmGetVariable (
+ TCG2_PHYSICAL_PRESENCE_VARIABLE,
+ &gEfiTcg2PhysicalPresenceGuid,
+ NULL,
+ &DataSize,
+ &PpData
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "[TPM2] Get PP variable failure! Status = %r\n", Status));
+ ReturnCode = TCG_PP_SUBMIT_REQUEST_TO_PREOS_GENERAL_FAILURE;
+ goto EXIT;
+ }
+
+ if ((*OperationRequest > TCG2_PHYSICAL_PRESENCE_NO_ACTION_MAX) &&
+ (*OperationRequest < TCG2_PHYSICAL_PRESENCE_STORAGE_MANAGEMENT_BEGIN) ) {
+ ReturnCode = TCG_PP_SUBMIT_REQUEST_TO_PREOS_NOT_IMPLEMENTED;
+ goto EXIT;
+ }
+
+ if ((PpData.PPRequest != *OperationRequest) ||
+ (PpData.PPRequestParameter != *RequestParameter)) {
+ PpData.PPRequest = (UINT8)*OperationRequest;
+ PpData.PPRequestParameter = *RequestParameter;
+ DataSize = sizeof (EFI_TCG2_PHYSICAL_PRESENCE);
+ Status = mTcg2PpSmmVariable->SmmSetVariable (
+ TCG2_PHYSICAL_PRESENCE_VARIABLE,
+ &gEfiTcg2PhysicalPresenceGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ DataSize,
+ &PpData
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "[TPM2] Set PP variable failure! Status = %r\n", Status));
+ ReturnCode = TCG_PP_SUBMIT_REQUEST_TO_PREOS_GENERAL_FAILURE;
+ goto EXIT;
+ }
+ }
+
+ if (*OperationRequest >= TCG2_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION) {
+ DataSize = sizeof (EFI_TCG2_PHYSICAL_PRESENCE_FLAGS);
+ Status = mTcg2PpSmmVariable->SmmGetVariable (
+ TCG2_PHYSICAL_PRESENCE_FLAGS_VARIABLE,
+ &gEfiTcg2PhysicalPresenceGuid,
+ NULL,
+ &DataSize,
+ &Flags
+ );
+ if (EFI_ERROR (Status)) {
+ Flags.PPFlags = TCG2_BIOS_TPM_MANAGEMENT_FLAG_DEFAULT | TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_DEFAULT;
+ }
+ ReturnCode = Tcg2PpVendorLibSubmitRequestToPreOSFunction (*OperationRequest, Flags.PPFlags, *RequestParameter);
+ }
+
+EXIT:
+ //
+ // Sync PPRQ/PPRM from PP Variable if PP submission fails
+ //
+ if (ReturnCode != TCG_PP_SUBMIT_REQUEST_TO_PREOS_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "[TPM2] Submit PP Request failure! Sync PPRQ/PPRM with PP variable.\n", Status));
+ DataSize = sizeof (EFI_TCG2_PHYSICAL_PRESENCE);
+ ZeroMem(&PpData, DataSize);
+ Status = mTcg2PpSmmVariable->SmmGetVariable (
+ TCG2_PHYSICAL_PRESENCE_VARIABLE,
+ &gEfiTcg2PhysicalPresenceGuid,
+ NULL,
+ &DataSize,
+ &PpData
+ );
+ *OperationRequest = (UINT32)PpData.PPRequest;
+ *RequestParameter = PpData.PPRequestParameter;
+ }
+
+ return ReturnCode;
+}
+
+/**
+ The handler for TPM physical presence function:
+ Submit TPM Operation Request to Pre-OS Environment and
+ Submit TPM Operation Request to Pre-OS Environment 2.
+
+ This API should be invoked in OS runtime phase to interface with ACPI method.
+
+ Caution: This function may receive untrusted input.
+
+ @param[in] OperationRequest TPM physical presence operation request.
+ @param[in] RequestParameter TPM physical presence operation request parameter.
+
+ @return Return Code for Submit TPM Operation Request to Pre-OS Environment and
+ Submit TPM Operation Request to Pre-OS Environment 2.
+**/
+UINT32
+EFIAPI
+Tcg2PhysicalPresenceLibSubmitRequestToPreOSFunction (
+ IN UINT32 OperationRequest,
+ IN UINT32 RequestParameter
+ )
+{
+ UINT32 TempOperationRequest;
+ UINT32 TempRequestParameter;
+
+ TempOperationRequest = OperationRequest;
+ TempRequestParameter = RequestParameter;
+
+ return Tcg2PhysicalPresenceLibSubmitRequestToPreOSFunctionEx(&TempOperationRequest, &TempRequestParameter);
+}
+
+/**
+ The handler for TPM physical presence function:
+ Get User Confirmation Status for Operation.
+
+ This API should be invoked in OS runtime phase to interface with ACPI method.
+
+ Caution: This function may receive untrusted input.
+
+ @param[in] OperationRequest TPM physical presence operation request.
+
+ @return Return Code for Get User Confirmation Status for Operation.
+**/
+UINT32
+EFIAPI
+Tcg2PhysicalPresenceLibGetUserConfirmationStatusFunction (
+ IN UINT32 OperationRequest
+ )
+{
+ EFI_STATUS Status;
+ UINTN DataSize;
+ EFI_TCG2_PHYSICAL_PRESENCE PpData;
+ EFI_TCG2_PHYSICAL_PRESENCE_FLAGS Flags;
+ BOOLEAN RequestConfirmed;
+
+ DEBUG ((EFI_D_INFO, "[TPM2] GetUserConfirmationStatusFunction, Request = %x\n", OperationRequest));
+
+ //
+ // Get the Physical Presence variable
+ //
+ DataSize = sizeof (EFI_TCG2_PHYSICAL_PRESENCE);
+ Status = mTcg2PpSmmVariable->SmmGetVariable (
+ TCG2_PHYSICAL_PRESENCE_VARIABLE,
+ &gEfiTcg2PhysicalPresenceGuid,
+ NULL,
+ &DataSize,
+ &PpData
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "[TPM2] Get PP variable failure! Status = %r\n", Status));
+ return TCG_PP_GET_USER_CONFIRMATION_BLOCKED_BY_BIOS_CONFIGURATION;
+ }
+ //
+ // Get the Physical Presence flags
+ //
+ DataSize = sizeof (EFI_TCG2_PHYSICAL_PRESENCE_FLAGS);
+ Status = mTcg2PpSmmVariable->SmmGetVariable (
+ TCG2_PHYSICAL_PRESENCE_FLAGS_VARIABLE,
+ &gEfiTcg2PhysicalPresenceGuid,
+ NULL,
+ &DataSize,
+ &Flags
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "[TPM2] Get PP flags failure! Status = %r\n", Status));
+ return TCG_PP_GET_USER_CONFIRMATION_BLOCKED_BY_BIOS_CONFIGURATION;
+ }
+
+ RequestConfirmed = FALSE;
+
+ switch (OperationRequest) {
+ case TCG2_PHYSICAL_PRESENCE_CLEAR:
+ case TCG2_PHYSICAL_PRESENCE_ENABLE_CLEAR:
+ case TCG2_PHYSICAL_PRESENCE_ENABLE_CLEAR_2:
+ case TCG2_PHYSICAL_PRESENCE_ENABLE_CLEAR_3:
+ if ((Flags.PPFlags & TCG2_BIOS_TPM_MANAGEMENT_FLAG_PP_REQUIRED_FOR_CLEAR) == 0) {
+ RequestConfirmed = TRUE;
+ }
+ break;
+
+ case TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_CLEAR_TRUE:
+ RequestConfirmed = TRUE;
+ break;
+
+ case TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_CLEAR_FALSE:
+ break;
+
+ case TCG2_PHYSICAL_PRESENCE_SET_PCR_BANKS:
+ if ((Flags.PPFlags & TCG2_BIOS_TPM_MANAGEMENT_FLAG_PP_REQUIRED_FOR_CHANGE_PCRS) == 0) {
+ RequestConfirmed = TRUE;
+ }
+ break;
+
+ case TCG2_PHYSICAL_PRESENCE_CHANGE_EPS:
+ if ((Flags.PPFlags & TCG2_BIOS_TPM_MANAGEMENT_FLAG_PP_REQUIRED_FOR_CHANGE_EPS) == 0) {
+ RequestConfirmed = TRUE;
+ }
+ break;
+
+ case TCG2_PHYSICAL_PRESENCE_LOG_ALL_DIGESTS:
+ RequestConfirmed = TRUE;
+ break;
+
+ case TCG2_PHYSICAL_PRESENCE_ENABLE_BLOCK_SID:
+ if ((Flags.PPFlags & TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_PP_REQUIRED_FOR_ENABLE_BLOCK_SID) == 0) {
+ RequestConfirmed = TRUE;
+ }
+ break;
+
+ case TCG2_PHYSICAL_PRESENCE_DISABLE_BLOCK_SID:
+ if ((Flags.PPFlags & TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_PP_REQUIRED_FOR_DISABLE_BLOCK_SID) == 0) {
+ RequestConfirmed = TRUE;
+ }
+ break;
+
+ case TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_ENABLE_BLOCK_SID_FUNC_TRUE:
+ case TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_DISABLE_BLOCK_SID_FUNC_TRUE:
+ RequestConfirmed = TRUE;
+ break;
+
+ case TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_ENABLE_BLOCK_SID_FUNC_FALSE:
+ case TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_DISABLE_BLOCK_SID_FUNC_FALSE:
+ break;
+
+ default:
+ if (OperationRequest <= TCG2_PHYSICAL_PRESENCE_NO_ACTION_MAX) {
+ RequestConfirmed = TRUE;
+ } else {
+ if (OperationRequest < TCG2_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION) {
+ return TCG_PP_GET_USER_CONFIRMATION_NOT_IMPLEMENTED;
+ }
+ }
+ break;
+ }
+
+ if (OperationRequest >= TCG2_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION) {
+ return Tcg2PpVendorLibGetUserConfirmationStatusFunction (OperationRequest, Flags.PPFlags);
+ }
+
+ if (RequestConfirmed) {
+ return TCG_PP_GET_USER_CONFIRMATION_ALLOWED_AND_PPUSER_NOT_REQUIRED;
+ } else {
+ return TCG_PP_GET_USER_CONFIRMATION_ALLOWED_AND_PPUSER_REQUIRED;
+ }
+}
+
+/**
+ The constructor function locates SmmVariable protocol.
+
+ It will ASSERT() if that operation fails and it will always return EFI_SUCCESS.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The constructor successfully added string package.
+ @retval Other value The constructor can't add string package.
+**/
+EFI_STATUS
+EFIAPI
+Tcg2PhysicalPresenceLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Locate SmmVariableProtocol.
+ //
+ Status = gSmst->SmmLocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID**)&mTcg2PpSmmVariable);
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
diff --git a/Core/SecurityPkg/Library/SmmTcg2PhysicalPresenceLib/SmmTcg2PhysicalPresenceLib.inf b/Core/SecurityPkg/Library/SmmTcg2PhysicalPresenceLib/SmmTcg2PhysicalPresenceLib.inf
new file mode 100644
index 0000000000..5fa84b1024
--- /dev/null
+++ b/Core/SecurityPkg/Library/SmmTcg2PhysicalPresenceLib/SmmTcg2PhysicalPresenceLib.inf
@@ -0,0 +1,57 @@
+## @file
+# Handle TPM 2.0 physical presence requests from OS.
+#
+# This library will handle TPM 2.0 physical presence request from OS.
+#
+# Caution: This module requires additional review when modified.
+# This driver will have external input - variable.
+# This external input must be validated carefully to avoid security issue.
+#
+# Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SmmTcg2PhysicalPresenceLib
+ MODULE_UNI_FILE = SmmTcg2PhysicalPresenceLib.uni
+ FILE_GUID = AAE02741-858B-4964-9887-CA870489D944
+ MODULE_TYPE = DXE_SMM_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = Tcg2PhysicalPresenceLib|DXE_SMM_DRIVER
+ CONSTRUCTOR = Tcg2PhysicalPresenceLibConstructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ SmmTcg2PhysicalPresenceLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+ DebugLib
+ Tcg2PpVendorLib
+ SmmServicesTableLib
+ BaseMemoryLib
+
+[Guids]
+ ## SOMETIMES_PRODUCES ## Variable:L"PhysicalPresence"
+ ## SOMETIMES_CONSUMES ## Variable:L"PhysicalPresence"
+ ## SOMETIMES_CONSUMES ## Variable:L"PhysicalPresenceFlags"
+ gEfiTcg2PhysicalPresenceGuid
+
+[Depex]
+ gEfiSmmVariableProtocolGuid \ No newline at end of file
diff --git a/Core/SecurityPkg/Library/SmmTcg2PhysicalPresenceLib/SmmTcg2PhysicalPresenceLib.uni b/Core/SecurityPkg/Library/SmmTcg2PhysicalPresenceLib/SmmTcg2PhysicalPresenceLib.uni
new file mode 100644
index 0000000000..268db455d9
--- /dev/null
+++ b/Core/SecurityPkg/Library/SmmTcg2PhysicalPresenceLib/SmmTcg2PhysicalPresenceLib.uni
@@ -0,0 +1,26 @@
+// /** @file
+// Handle TPM 2.0 physical presence requests from OS.
+//
+// This library will handle TPM 2.0 physical presence request from OS.
+//
+// Caution: This module requires additional review when modified.
+// This driver will have external input - variable.
+// This external input must be validated carefully to avoid security issue.
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Handle TPM 2.0 physical presence requests from OS"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library will handle TPM 2.0 physical presence request from OS.\n"
+ "Caution: This module requires additional review when modified. This driver will have external input - variable. This external input must be validated carefully to avoid security issue."
+
diff --git a/Core/SecurityPkg/Library/Tcg2PpVendorLibNull/Tcg2PpVendorLibNull.c b/Core/SecurityPkg/Library/Tcg2PpVendorLibNull/Tcg2PpVendorLibNull.c
new file mode 100644
index 0000000000..93cb312d90
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tcg2PpVendorLibNull/Tcg2PpVendorLibNull.c
@@ -0,0 +1,133 @@
+/** @file
+ NULL Tcg2 PP Vendor library instance that does not support any vendor specific PPI.
+
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Library/DebugLib.h>
+#include <Library/Tcg2PpVendorLib.h>
+
+/**
+ Check and execute the requested physical presence command.
+
+ This API should be invoked in BIOS boot phase to process pending request.
+
+ Caution: This function may receive untrusted input.
+
+ If OperationRequest < 128, then ASSERT().
+
+ @param[in] PlatformAuth platform auth value. NULL means no platform auth change.
+ @param[in] OperationRequest TPM physical presence operation request.
+ @param[in, out] ManagementFlags BIOS TPM Management Flags.
+ @param[out] ResetRequired If reset is required to vendor settings in effect.
+ True, it indicates the reset is required.
+ False, it indicates the reset is not required.
+
+ @return TPM Operation Response to OS Environment.
+**/
+UINT32
+EFIAPI
+Tcg2PpVendorLibExecutePendingRequest (
+ IN TPM2B_AUTH *PlatformAuth, OPTIONAL
+ IN UINT32 OperationRequest,
+ IN OUT UINT32 *ManagementFlags,
+ OUT BOOLEAN *ResetRequired
+ )
+{
+ ASSERT (OperationRequest >= TCG2_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION);
+ return TCG_PP_OPERATION_RESPONSE_BIOS_FAILURE;
+}
+
+/**
+ Check if there is a valid physical presence command request.
+
+ This API should be invoked in BIOS boot phase to process pending request.
+
+ Caution: This function may receive untrusted input.
+
+ If OperationRequest < 128, then ASSERT().
+
+ @param[in] OperationRequest TPM physical presence operation request.
+ @param[in] ManagementFlags BIOS TPM Management Flags.
+ @param[out] RequestConfirmed If the physical presence operation command required user confirm from UI.
+ True, it indicates the command doesn't require user confirm.
+ False, it indicates the command need user confirm from UI.
+
+ @retval TRUE Physical Presence operation command is valid.
+ @retval FALSE Physical Presence operation command is invalid.
+**/
+BOOLEAN
+EFIAPI
+Tcg2PpVendorLibHasValidRequest (
+ IN UINT32 OperationRequest,
+ IN UINT32 ManagementFlags,
+ OUT BOOLEAN *RequestConfirmed
+ )
+{
+ ASSERT (OperationRequest >= TCG2_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION);
+ return FALSE;
+}
+
+/**
+ The callback for TPM vendor specific physical presence which is called for
+ Submit TPM Operation Request to Pre-OS Environment and
+ Submit TPM Operation Request to Pre-OS Environment 2.
+
+ This API should be invoked in OS runtime phase to interface with ACPI method.
+
+ Caution: This function may receive untrusted input.
+
+ If OperationRequest < 128, then ASSERT().
+
+ @param[in] OperationRequest TPM physical presence operation request.
+ @param[in] ManagementFlags BIOS TPM Management Flags.
+ @param[in] RequestParameter Extra parameter from the passed package.
+
+ @return Return Code for Submit TPM Operation Request to Pre-OS Environment and
+ Submit TPM Operation Request to Pre-OS Environment 2.
+**/
+UINT32
+EFIAPI
+Tcg2PpVendorLibSubmitRequestToPreOSFunction (
+ IN UINT32 OperationRequest,
+ IN UINT32 ManagementFlags,
+ IN UINT32 RequestParameter
+ )
+{
+ ASSERT (OperationRequest >= TCG2_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION);
+ return TCG_PP_SUBMIT_REQUEST_TO_PREOS_NOT_IMPLEMENTED;
+}
+
+/**
+ The callback for TPM vendor specific physical presence which is called for
+ Get User Confirmation Status for Operation.
+
+ This API should be invoked in OS runtime phase to interface with ACPI method.
+
+ Caution: This function may receive untrusted input.
+
+ If OperationRequest < 128, then ASSERT().
+
+ @param[in] OperationRequest TPM physical presence operation request.
+ @param[in] ManagementFlags BIOS TPM Management Flags.
+
+ @return Return Code for Get User Confirmation Status for Operation.
+**/
+UINT32
+EFIAPI
+Tcg2PpVendorLibGetUserConfirmationStatusFunction (
+ IN UINT32 OperationRequest,
+ IN UINT32 ManagementFlags
+ )
+{
+ ASSERT (OperationRequest >= TCG2_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION);
+ return TCG_PP_GET_USER_CONFIRMATION_NOT_IMPLEMENTED;
+}
diff --git a/Core/SecurityPkg/Library/Tcg2PpVendorLibNull/Tcg2PpVendorLibNull.inf b/Core/SecurityPkg/Library/Tcg2PpVendorLibNull/Tcg2PpVendorLibNull.inf
new file mode 100644
index 0000000000..f953fe95a7
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tcg2PpVendorLibNull/Tcg2PpVendorLibNull.inf
@@ -0,0 +1,37 @@
+## @file
+# NULL Tcg PP Vendor library instance that does not support any vendor specific PPI
+#
+# Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = Tcg2PpVendorLibNull
+ MODULE_UNI_FILE = Tcg2PpVendorLibNull.uni
+ FILE_GUID = 51924AE9-BE81-4820-94BA-7C9546E702D0
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = Tcg2PpVendorLib|DXE_RUNTIME_DRIVER DXE_SMM_DRIVER DXE_DRIVER
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ Tcg2PpVendorLibNull.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+ DebugLib \ No newline at end of file
diff --git a/Core/SecurityPkg/Library/Tcg2PpVendorLibNull/Tcg2PpVendorLibNull.uni b/Core/SecurityPkg/Library/Tcg2PpVendorLibNull/Tcg2PpVendorLibNull.uni
new file mode 100644
index 0000000000..9423bac31d
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tcg2PpVendorLibNull/Tcg2PpVendorLibNull.uni
@@ -0,0 +1,18 @@
+// /** @file
+// NULL Tcg PP Vendor library instance that does not support any vendor specific PPI
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+#string STR_MODULE_ABSTRACT #language en-US "NULL Tcg PP Vendor library instance that does not support any vendor specific PPI"
+
+#string STR_MODULE_DESCRIPTION #language en-US "NULL Tcg PP Vendor library instance that does not support any vendor specific PPI."
+
diff --git a/Core/SecurityPkg/Library/TcgPpVendorLibNull/TcgPpVendorLibNull.c b/Core/SecurityPkg/Library/TcgPpVendorLibNull/TcgPpVendorLibNull.c
new file mode 100644
index 0000000000..ddd6d727cc
--- /dev/null
+++ b/Core/SecurityPkg/Library/TcgPpVendorLibNull/TcgPpVendorLibNull.c
@@ -0,0 +1,129 @@
+/** @file
+ NULL TCG PP Vendor library instance that does not support any vendor specific PPI.
+
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Library/DebugLib.h>
+#include <Library/TcgPpVendorLib.h>
+
+/**
+ Check and execute the requested physical presence command.
+
+ This API should be invoked in BIOS boot phase to process pending request.
+
+ Caution: This function may receive untrusted input.
+
+ If OperationRequest < 128, then ASSERT().
+
+ @param[in] OperationRequest TPM physical presence operation request.
+ @param[in, out] ManagementFlags BIOS TPM Management Flags.
+ @param[out] ResetRequired If reset is required to vendor settings in effect.
+ True, it indicates the reset is required.
+ False, it indicates the reset is not required.
+
+ @return TPM Operation Response to OS Environment.
+**/
+UINT32
+EFIAPI
+TcgPpVendorLibExecutePendingRequest (
+ IN UINT32 OperationRequest,
+ IN OUT UINT32 *ManagementFlags,
+ OUT BOOLEAN *ResetRequired
+ )
+{
+ ASSERT (OperationRequest >= TCG_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION);
+ return TCG_PP_OPERATION_RESPONSE_BIOS_FAILURE;
+}
+
+/**
+ Check if there is a valid physical presence command request.
+
+ This API should be invoked in BIOS boot phase to process pending request.
+
+ Caution: This function may receive untrusted input.
+
+ If OperationRequest < 128, then ASSERT().
+
+ @param[in] OperationRequest TPM physical presence operation request.
+ @param[in] ManagementFlags BIOS TPM Management Flags.
+ @param[out] RequestConfirmed If the physical presence operation command required user confirm from UI.
+ True, it indicates the command doesn't require user confirm.
+ False, it indicates the command need user confirm from UI.
+
+ @retval TRUE Physical Presence operation command is valid.
+ @retval FALSE Physical Presence operation command is invalid.
+**/
+BOOLEAN
+EFIAPI
+TcgPpVendorLibHasValidRequest (
+ IN UINT32 OperationRequest,
+ IN UINT32 ManagementFlags,
+ OUT BOOLEAN *RequestConfirmed
+ )
+{
+ ASSERT (OperationRequest >= TCG_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION);
+ return FALSE;
+}
+
+/**
+ The callback for TPM vendor specific physical presence which is called for
+ Submit TPM Operation Request to Pre-OS Environment and
+ Submit TPM Operation Request to Pre-OS Environment 2.
+
+ This API should be invoked in OS runtime phase to interface with ACPI method.
+
+ Caution: This function may receive untrusted input.
+
+ If OperationRequest < 128, then ASSERT().
+
+ @param[in] OperationRequest TPM physical presence operation request.
+ @param[in] ManagementFlags BIOS TPM Management Flags.
+
+ @return Return Code for Submit TPM Operation Request to Pre-OS Environment and
+ Submit TPM Operation Request to Pre-OS Environment 2.
+**/
+UINT32
+EFIAPI
+TcgPpVendorLibSubmitRequestToPreOSFunction (
+ IN UINT32 OperationRequest,
+ IN UINT32 ManagementFlags
+ )
+{
+ ASSERT (OperationRequest >= TCG_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION);
+ return TCG_PP_SUBMIT_REQUEST_TO_PREOS_NOT_IMPLEMENTED;
+}
+
+/**
+ The callback for TPM vendor specific physical presence which is called for
+ Get User Confirmation Status for Operation.
+
+ This API should be invoked in OS runtime phase to interface with ACPI method.
+
+ Caution: This function may receive untrusted input.
+
+ If OperationRequest < 128, then ASSERT().
+
+ @param[in] OperationRequest TPM physical presence operation request.
+ @param[in] ManagementFlags BIOS TPM Management Flags.
+
+ @return Return Code for Get User Confirmation Status for Operation.
+**/
+UINT32
+EFIAPI
+TcgPpVendorLibGetUserConfirmationStatusFunction (
+ IN UINT32 OperationRequest,
+ IN UINT32 ManagementFlags
+ )
+{
+ ASSERT (OperationRequest >= TCG_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION);
+ return TCG_PP_GET_USER_CONFIRMATION_NOT_IMPLEMENTED;
+}
diff --git a/Core/SecurityPkg/Library/TcgPpVendorLibNull/TcgPpVendorLibNull.inf b/Core/SecurityPkg/Library/TcgPpVendorLibNull/TcgPpVendorLibNull.inf
new file mode 100644
index 0000000000..9674386abd
--- /dev/null
+++ b/Core/SecurityPkg/Library/TcgPpVendorLibNull/TcgPpVendorLibNull.inf
@@ -0,0 +1,37 @@
+## @file
+# NULL TCG PP Vendor library instance that does not support any vendor specific PPI
+#
+# Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = TcgPpVendorLibNull
+ MODULE_UNI_FILE = TcgPpVendorLibNull.uni
+ FILE_GUID = 8489334D-4219-4CA1-9B42-1D46B0B75861
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = TcgPpVendorLib|DXE_RUNTIME_DRIVER DXE_SMM_DRIVER DXE_DRIVER
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ TcgPpVendorLibNull.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+ DebugLib \ No newline at end of file
diff --git a/Core/SecurityPkg/Library/TcgPpVendorLibNull/TcgPpVendorLibNull.uni b/Core/SecurityPkg/Library/TcgPpVendorLibNull/TcgPpVendorLibNull.uni
new file mode 100644
index 0000000000..2fd967cb97
--- /dev/null
+++ b/Core/SecurityPkg/Library/TcgPpVendorLibNull/TcgPpVendorLibNull.uni
@@ -0,0 +1,18 @@
+// /** @file
+// NULL TCG PP Vendor library instance that does not support any vendor specific PPI
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+#string STR_MODULE_ABSTRACT #language en-US "NULL TCG PP Vendor library instance that does not support any vendor specific PPI"
+
+#string STR_MODULE_DESCRIPTION #language en-US "NULL TCG PP Vendor library instance that does not support any vendor specific PPI."
+
diff --git a/Core/SecurityPkg/Library/TcgStorageCoreLib/TcgStorageCore.c b/Core/SecurityPkg/Library/TcgStorageCoreLib/TcgStorageCore.c
new file mode 100644
index 0000000000..76b25a3775
--- /dev/null
+++ b/Core/SecurityPkg/Library/TcgStorageCoreLib/TcgStorageCore.c
@@ -0,0 +1,1652 @@
+/** @file
+ Provide functions to provide tcg storage core spec related functions.
+
+Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Library/TcgStorageCoreLib.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+//#include <Library/PrintLib.h>
+
+/**
+ Required to be called before calling any other Tcg functions with the TCG_CREATE_STRUCT.
+ Initializes the packet variables to NULL. Additionally, the buffer will be memset.
+
+ @param [in/out] CreateStruct Structure to initialize
+ @param [in] Buffer Buffer allocated by client of library. It will contain the Tcg encoded packet. This cannot be null.
+ @param [in] BufferSize Size of buffer provided. It cannot be 0.
+
+ @retval Return the action result.
+**/
+TCG_RESULT
+EFIAPI
+TcgInitTcgCreateStruct(
+ TCG_CREATE_STRUCT *CreateStruct,
+ VOID *Buffer,
+ UINT32 BufferSize
+ )
+{
+ NULL_CHECK(CreateStruct);
+ NULL_CHECK(Buffer);
+
+ if (BufferSize == 0) {
+ DEBUG ((DEBUG_INFO, "BufferSize=0\n"));
+ return (TcgResultFailureZeroSize);
+ }
+
+ ZeroMem(Buffer, BufferSize);
+ CreateStruct->BufferSize = BufferSize;
+ CreateStruct->Buffer = Buffer;
+ CreateStruct->ComPacket = NULL;
+ CreateStruct->CurPacket = NULL;
+ CreateStruct->CurSubPacket = NULL;
+
+ return (TcgResultSuccess);
+}
+
+/**
+
+ Encodes the ComPacket header to the data structure.
+
+ @param[in/out] CreateStruct Structure to initialize
+ @param[in] ComId ComID of the Tcg ComPacket.
+ @param[in] ComIdExtension ComID Extension of the Tcg ComPacket.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgStartComPacket(
+ TCG_CREATE_STRUCT *CreateStruct,
+ UINT16 ComId,
+ UINT16 ComIdExtension
+ )
+{
+ NULL_CHECK(CreateStruct);
+
+ if (CreateStruct->ComPacket != NULL ||
+ CreateStruct->CurPacket != NULL ||
+ CreateStruct->CurSubPacket != NULL
+ ) {
+ DEBUG ((DEBUG_INFO, "unexpected state: ComPacket=%p CurPacket=%p CurSubPacket=%p\n", CreateStruct->ComPacket, CreateStruct->CurPacket,
+ CreateStruct->CurSubPacket));
+ return (TcgResultFailureInvalidAction);
+ }
+
+ if (sizeof(TCG_COM_PACKET) > CreateStruct->BufferSize) {
+ DEBUG ((DEBUG_INFO, "BufferSize=0x%X\n", CreateStruct->BufferSize));
+ return (TcgResultFailureBufferTooSmall);
+ }
+
+ CreateStruct->ComPacket = (TCG_COM_PACKET*)CreateStruct->Buffer;
+ CreateStruct->ComPacket->ComIDBE = SwapBytes16(ComId);
+ CreateStruct->ComPacket->ComIDExtensionBE = SwapBytes16(ComIdExtension);
+
+ return (TcgResultSuccess);
+}
+
+/**
+
+ Starts a new ComPacket in the Data structure.
+
+ @param [in/out] CreateStruct Structure used to add Tcg Packet
+ @param[in] Tsn Packet Tper session number
+ @param[in] Hsn Packet Host session number
+ @param[in] SeqNumber Packet Sequence Number
+ @param[in] AckType Packet Acknowledge Type
+ @param[in] Ack Packet Acknowledge
+
+**/
+TCG_RESULT
+EFIAPI
+TcgStartPacket(
+ TCG_CREATE_STRUCT *CreateStruct,
+ UINT32 Tsn,
+ UINT32 Hsn,
+ UINT32 SeqNumber,
+ UINT16 AckType,
+ UINT32 Ack
+ )
+{
+ UINT32 AddedSize;
+ NULL_CHECK(CreateStruct);
+
+ AddedSize = 0;
+
+ if (CreateStruct->ComPacket == NULL ||
+ CreateStruct->CurPacket != NULL ||
+ CreateStruct->CurSubPacket != NULL
+ ) {
+ DEBUG ((DEBUG_INFO, "unexpected state: ComPacket=%p CurPacket=%p CurSubPacket=%p\n", CreateStruct->ComPacket, CreateStruct->CurPacket, CreateStruct->CurSubPacket));
+ return (TcgResultFailureInvalidAction);
+ }
+
+ // update TCG_COM_PACKET and packet lengths
+ AddedSize = sizeof(TCG_PACKET);
+
+ if ((SwapBytes32(CreateStruct->ComPacket->LengthBE) + AddedSize) > CreateStruct->BufferSize) {
+ DEBUG ((DEBUG_INFO, "BufferSize=0x%X\n", CreateStruct->BufferSize));
+ return (TcgResultFailureBufferTooSmall);
+ }
+
+ CreateStruct->CurPacket = (TCG_PACKET*)(CreateStruct->ComPacket->Payload + SwapBytes32(CreateStruct->ComPacket->LengthBE));
+
+ CreateStruct->CurPacket->TperSessionNumberBE = SwapBytes32( Tsn );
+ CreateStruct->CurPacket->HostSessionNumberBE = SwapBytes32( Hsn );
+ CreateStruct->CurPacket->SequenceNumberBE = SwapBytes32( SeqNumber );
+ CreateStruct->CurPacket->AckTypeBE = SwapBytes16( AckType );
+ CreateStruct->CurPacket->AcknowledgementBE = SwapBytes32( Ack );
+
+ CreateStruct->CurPacket->LengthBE = 0;
+
+ // update TCG_COM_PACKET Length for next pointer
+ CreateStruct->ComPacket->LengthBE = SwapBytes32( SwapBytes32(CreateStruct->ComPacket->LengthBE) + AddedSize );
+
+ return (TcgResultSuccess);
+}
+
+/**
+
+ Starts a new SubPacket in the Data structure.
+
+ @param[in/out] CreateStruct Structure used to start Tcg SubPacket
+ @param[in] Kind SubPacket kind
+
+**/
+TCG_RESULT
+EFIAPI
+TcgStartSubPacket(
+ TCG_CREATE_STRUCT *CreateStruct,
+ UINT16 Kind
+ )
+{
+ UINT32 AddedSize;
+
+ NULL_CHECK(CreateStruct);
+
+ AddedSize = 0;
+
+ if (CreateStruct->ComPacket == NULL ||
+ CreateStruct->CurPacket == NULL ||
+ CreateStruct->CurSubPacket != NULL
+ ) {
+ DEBUG ((DEBUG_INFO, "unexpected state: ComPacket=%p CurPacket=%p CurSubPacket=%p\n", CreateStruct->ComPacket, CreateStruct->CurPacket, CreateStruct->CurSubPacket));
+ return (TcgResultFailureInvalidAction);
+ }
+
+ AddedSize = sizeof(TCG_SUB_PACKET);
+
+ if ((SwapBytes32(CreateStruct->ComPacket->LengthBE) + AddedSize) > CreateStruct->BufferSize) {
+ DEBUG ((DEBUG_INFO, "BufferSize=0x%X\n", CreateStruct->BufferSize));
+ return (TcgResultFailureBufferTooSmall);
+ }
+
+ CreateStruct->CurSubPacket = (TCG_SUB_PACKET*)(CreateStruct->CurPacket->Payload + SwapBytes32(CreateStruct->CurPacket->LengthBE));
+ CreateStruct->CurSubPacket->KindBE = SwapBytes16(Kind);
+
+ // update lengths
+ CreateStruct->CurSubPacket->LengthBE = 0;
+
+ // update TCG_COM_PACKET and packet lengths
+ CreateStruct->ComPacket->LengthBE = SwapBytes32(SwapBytes32(CreateStruct->ComPacket->LengthBE) + AddedSize);
+ CreateStruct->CurPacket->LengthBE = SwapBytes32(SwapBytes32(CreateStruct->CurPacket->LengthBE) + AddedSize);
+
+ return (TcgResultSuccess);
+}
+
+/**
+
+ Ends the current SubPacket in the Data structure. This function will also perform the 4-byte padding
+ required for Subpackets.
+
+ @param[in/out] CreateStruct Structure used to end the current Tcg SubPacket
+
+**/
+TCG_RESULT
+EFIAPI
+TcgEndSubPacket(
+ TCG_CREATE_STRUCT *CreateStruct
+ )
+{
+ UINT32 PadSize;
+
+ NULL_CHECK(CreateStruct);
+
+ PadSize = 0;
+
+ if (CreateStruct->ComPacket == NULL ||
+ CreateStruct->CurPacket == NULL ||
+ CreateStruct->CurSubPacket == NULL
+ ) {
+ DEBUG ((DEBUG_INFO, "unexpected state: ComPacket=%p CurPacket=%p CurSubPacket=%p\n", CreateStruct->ComPacket, CreateStruct->CurPacket, CreateStruct->CurSubPacket));
+ return (TcgResultFailureInvalidAction);
+ }
+
+ // align to 4-byte boundaries, so shift padding
+ // pad Size does not apply to subpacket Length
+ PadSize = TCG_SUBPACKET_ALIGNMENT - (SwapBytes32(CreateStruct->CurSubPacket->LengthBE) & (TCG_SUBPACKET_ALIGNMENT - 1));
+
+ if (PadSize == TCG_SUBPACKET_ALIGNMENT) {
+ PadSize = 0;
+ }
+
+ if ((SwapBytes32(CreateStruct->ComPacket->LengthBE) + PadSize) > CreateStruct->BufferSize) {
+ DEBUG ((DEBUG_INFO, "BufferSize=0x%X\n", CreateStruct->BufferSize));
+ return (TcgResultFailureBufferTooSmall);
+ }
+
+ CreateStruct->CurPacket->LengthBE = SwapBytes32(SwapBytes32(CreateStruct->CurPacket->LengthBE) + PadSize);
+ CreateStruct->ComPacket->LengthBE = SwapBytes32(SwapBytes32(CreateStruct->ComPacket->LengthBE) + PadSize);
+
+ CreateStruct->CurSubPacket = NULL;
+
+ return (TcgResultSuccess);
+}
+
+/**
+
+ Ends the current Packet in the Data structure.
+
+ @param[in/out] CreateStruct Structure used to end the current Tcg Packet
+
+**/
+TCG_RESULT
+EFIAPI
+TcgEndPacket(
+ TCG_CREATE_STRUCT *CreateStruct
+ )
+{
+ NULL_CHECK(CreateStruct);
+
+ if (CreateStruct->ComPacket == NULL ||
+ CreateStruct->CurPacket == NULL ||
+ CreateStruct->CurSubPacket != NULL
+ ) {
+ DEBUG ((DEBUG_INFO, "unexpected state: ComPacket=%p CurPacket=%p CurSubPacket=%p\n", CreateStruct->ComPacket, CreateStruct->CurPacket, CreateStruct->CurSubPacket));
+ return (TcgResultFailureInvalidAction);
+ }
+
+ CreateStruct->CurPacket = NULL;
+
+ return (TcgResultSuccess);
+}
+
+/**
+
+ Ends the ComPacket in the Data structure and ret
+
+ @param [in/out] CreateStruct Structure used to end the Tcg ComPacket
+ @param [in/out] Size Describes the Size of the entire ComPacket (Header and payload). Filled out by function.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgEndComPacket(
+ TCG_CREATE_STRUCT *CreateStruct,
+ UINT32 *Size
+ )
+{
+ NULL_CHECK(CreateStruct);
+ NULL_CHECK(Size);
+
+ if (CreateStruct->ComPacket == NULL ||
+ CreateStruct->CurPacket != NULL ||
+ CreateStruct->CurSubPacket != NULL
+ ) {
+ DEBUG ((DEBUG_INFO, "unexpected state: ComPacket=%p CurPacket=%p CurSubPacket=%p\n", CreateStruct->ComPacket, CreateStruct->CurPacket, CreateStruct->CurSubPacket));
+ return (TcgResultFailureInvalidAction);
+ }
+
+ *Size = SwapBytes32(CreateStruct->ComPacket->LengthBE) + sizeof(*CreateStruct->ComPacket);
+ CreateStruct->ComPacket = NULL;
+
+ return (TcgResultSuccess);
+}
+
+/**
+ Adds raw Data with optional Header
+
+ @param CreateStruct The create structure.
+ @param Header The header structure.
+ @param HeaderSize The header size.
+ @param Data The data need to add.
+ @param DataSize The data size.
+ @param ByteSwapData Whether byte or swap data.
+
+**/
+TCG_RESULT
+TcgAddRawTokenData(
+ TCG_CREATE_STRUCT *CreateStruct,
+ const VOID *Header,
+ UINT8 HeaderSize,
+ const VOID *Data,
+ UINT32 DataSize,
+ BOOLEAN ByteSwapData
+ )
+{
+ UINT32 AddedSize;
+ UINT8* Dest;
+ const UINT8* DataBytes;
+ UINT32 Index;
+
+ AddedSize = 0;
+ Index = 0;
+ Dest = NULL;
+
+ NULL_CHECK(CreateStruct);
+
+ if ((HeaderSize != 0 && Header == NULL) ||
+ (DataSize != 0 && Data == NULL)
+ ) {
+ DEBUG ((DEBUG_INFO, "HeaderSize=0x%X Header=%p DataSize=0x%X Data=%p\n", HeaderSize, Header, DataSize, Data));
+ return (TcgResultFailureNullPointer);
+ }
+
+ if (CreateStruct->ComPacket == NULL ||
+ CreateStruct->CurPacket == NULL ||
+ CreateStruct->CurSubPacket == NULL
+ ) {
+ DEBUG ((DEBUG_INFO, "unexpected state: ComPacket=%p CurPacket=%p CurSubPacket=%p\n", CreateStruct->ComPacket, CreateStruct->CurPacket, CreateStruct->CurSubPacket));
+ return (TcgResultFailureInvalidAction);
+ }
+
+ // verify there is enough Buffer Size
+ AddedSize = HeaderSize + DataSize;
+ if ((SwapBytes32(CreateStruct->ComPacket->LengthBE) + AddedSize) > CreateStruct->BufferSize) {
+ return (TcgResultFailureBufferTooSmall);
+ }
+
+ // Get a pointer to where the new bytes should go
+ Dest = CreateStruct->ComPacket->Payload + SwapBytes32(CreateStruct->ComPacket->LengthBE);
+
+ switch (HeaderSize) {
+ case sizeof(TCG_SIMPLE_TOKEN_SHORT_ATOM):
+ case sizeof(TCG_SIMPLE_TOKEN_MEDIUM_ATOM):
+ case sizeof(TCG_SIMPLE_TOKEN_LONG_ATOM):
+ CopyMem(Dest, Header, HeaderSize);
+ Dest += HeaderSize;
+ case 0: // no Header is valid
+ break;
+ // invalid Header Size
+ default:
+ DEBUG ((DEBUG_INFO, "unsupported HeaderSize=%u\n", HeaderSize));
+ return TcgResultFailure;
+ }
+
+ // copy the Data bytes
+ if (ByteSwapData) {
+ DataBytes = (const UINT8*)Data;
+ for (Index = 0; Index < DataSize; Index++) {
+ Dest[Index] = DataBytes[DataSize - 1 - Index];
+ }
+ } else {
+ CopyMem(Dest, Data, DataSize);
+ }
+
+ // Update all the packet sizes
+ CreateStruct->ComPacket->LengthBE = SwapBytes32(SwapBytes32(CreateStruct->ComPacket->LengthBE) + AddedSize);
+ CreateStruct->CurPacket->LengthBE = SwapBytes32(SwapBytes32(CreateStruct->CurPacket->LengthBE) + AddedSize);
+ CreateStruct->CurSubPacket->LengthBE = SwapBytes32(SwapBytes32(CreateStruct->CurSubPacket->LengthBE) + AddedSize);
+
+ return (TcgResultSuccess);
+}
+
+/**
+
+ Adds a single raw token byte to the Data structure.
+
+ @param[in/out] CreateStruct Structure used to add the byte
+ @param[in] Byte Byte to add
+
+**/
+TCG_RESULT
+EFIAPI
+TcgAddRawByte(
+ TCG_CREATE_STRUCT *CreateStruct,
+ UINT8 Byte
+ )
+{
+ return TcgAddRawTokenData(CreateStruct, NULL, 0, &Byte, 1, FALSE);
+}
+
+
+/**
+ simple tokens - atoms: tiny, short, medium, long and empty atoms.
+ tiny atom can be a signed or unsigned integer.
+ short, medium, long can be a signed or unsigned integer OR a complete or non-final byte sequence.
+
+ @param CreateStruct The create structure.
+ @param Data The data need to add.
+ @param DataSize The data size.
+ @param ByteOrInt, Data format is byte or int.
+ @param SignOrCont sign or cont.
+
+
+**/
+TCG_RESULT
+TcgAddAtom(
+ TCG_CREATE_STRUCT *CreateStruct,
+ const VOID *Data,
+ UINT32 DataSize,
+ UINT8 ByteOrInt,
+ UINT8 SignOrCont
+ )
+{
+ const UINT8* DataBytes;
+ TCG_SIMPLE_TOKEN_TINY_ATOM TinyAtom;
+ TCG_SIMPLE_TOKEN_SHORT_ATOM ShortAtom;
+ TCG_SIMPLE_TOKEN_MEDIUM_ATOM MediumAtom;
+ TCG_SIMPLE_TOKEN_LONG_ATOM LongAtom;
+
+ NULL_CHECK(CreateStruct);
+
+ if (DataSize == 0) {
+ if (ByteOrInt == TCG_ATOM_TYPE_INTEGER) {
+ DEBUG ((DEBUG_INFO, "0-Size integer not allowed\n"));
+ return TcgResultFailure;
+ }
+ } else {
+ // if DataSize != 0, Data must be valid
+ NULL_CHECK(Data);
+ }
+
+ // encode Data using the shortest possible atom
+ DataBytes = (const UINT8*)Data;
+ if ((DataSize == 1) &&
+ (ByteOrInt == TCG_ATOM_TYPE_INTEGER) &&
+ ((SignOrCont != 0 && ((TCG_TOKEN_TINYATOM_SIGNED_MIN_VALUE <= *(INT8*)Data) && (*(INT8*)Data <= TCG_TOKEN_TINYATOM_SIGNED_MAX_VALUE))) ||
+ (SignOrCont == 0 && ((*DataBytes <= TCG_TOKEN_TINYATOM_UNSIGNED_MAX_VALUE))))
+ ) {
+ TinyAtom.TinyAtomBits.IsZero = 0;
+ TinyAtom.TinyAtomBits.Sign = SignOrCont;
+ TinyAtom.TinyAtomBits.Data = *DataBytes & TCG_TOKEN_TINYATOM_UNSIGNED_MAX_VALUE;
+ return TcgAddRawTokenData(CreateStruct, NULL, 0, (UINT8*)&TinyAtom, sizeof(TCG_SIMPLE_TOKEN_TINY_ATOM), FALSE);
+ }
+
+ if (DataSize <= TCG_TOKEN_SHORTATOM_MAX_BYTE_SIZE) {
+ ShortAtom.ShortAtomBits.IsOne = 1;
+ ShortAtom.ShortAtomBits.IsZero = 0;
+ ShortAtom.ShortAtomBits.ByteOrInt = ByteOrInt;
+ ShortAtom.ShortAtomBits.SignOrCont = SignOrCont;
+ ShortAtom.ShortAtomBits.Length = DataSize & 0x0F;
+ return TcgAddRawTokenData(CreateStruct, &ShortAtom, sizeof(TCG_SIMPLE_TOKEN_SHORT_ATOM), Data, DataSize, ByteOrInt == TCG_ATOM_TYPE_INTEGER);
+ }
+
+ if (DataSize <= TCG_TOKEN_MEDIUMATOM_MAX_BYTE_SIZE) {
+ MediumAtom.MediumAtomBits.IsOne1 = 1;
+ MediumAtom.MediumAtomBits.IsOne2 = 1;
+ MediumAtom.MediumAtomBits.IsZero = 0;
+ MediumAtom.MediumAtomBits.ByteOrInt = ByteOrInt;
+ MediumAtom.MediumAtomBits.SignOrCont = SignOrCont;
+ MediumAtom.MediumAtomBits.LengthLow = DataSize & 0xFF;
+ MediumAtom.MediumAtomBits.LengthHigh = (DataSize >> TCG_MEDIUM_ATOM_LENGTH_HIGH_SHIFT) & TCG_MEDIUM_ATOM_LENGTH_HIGH_MASK;
+ return TcgAddRawTokenData(CreateStruct, &MediumAtom, sizeof(TCG_SIMPLE_TOKEN_MEDIUM_ATOM), Data, DataSize, ByteOrInt == TCG_ATOM_TYPE_INTEGER);
+ }
+
+ LongAtom.LongAtomBits.IsOne1 = 1;
+ LongAtom.LongAtomBits.IsOne2 = 1;
+ LongAtom.LongAtomBits.IsOne3 = 1;
+ LongAtom.LongAtomBits.IsZero = 0;
+ LongAtom.LongAtomBits.ByteOrInt = ByteOrInt;
+ LongAtom.LongAtomBits.SignOrCont = SignOrCont;
+ LongAtom.LongAtomBits.LengthLow = DataSize & 0xFF;
+ LongAtom.LongAtomBits.LengthMid = (DataSize >> TCG_LONG_ATOM_LENGTH_MID_SHIFT) & 0xFF;
+ LongAtom.LongAtomBits.LengthHigh = (DataSize >> TCG_LONG_ATOM_LENGTH_HIGH_SHIFT) & 0xFF;
+ return TcgAddRawTokenData(CreateStruct, &LongAtom, sizeof(TCG_SIMPLE_TOKEN_LONG_ATOM), Data, DataSize, ByteOrInt == TCG_ATOM_TYPE_INTEGER);
+}
+
+/**
+
+ Adds the Data parameter as a byte sequence to the Data structure.
+
+ @param[in/out] CreateStruct Structure used to add the byte sequence
+ @param[in] Data Byte sequence that will be encoded and copied into Data structure
+ @param[in] DataSize Length of Data provided
+ @param[in] Continued TRUE if byte sequence is continued or
+ FALSE if the Data contains the entire byte sequence to be encoded
+
+**/
+TCG_RESULT
+EFIAPI
+TcgAddByteSequence(
+ TCG_CREATE_STRUCT *CreateStruct,
+ const VOID *Data,
+ UINT32 DataSize,
+ BOOLEAN Continued
+ )
+{
+ return TcgAddAtom(CreateStruct, Data, DataSize, TCG_ATOM_TYPE_BYTE, Continued ? 1 : 0);
+}
+
+/**
+
+ Adds an arbitrary-Length integer to the Data structure.
+ The integer will be encoded using the shortest possible atom.
+
+ @param[in/out] CreateStruct Structure used to add the integer
+ @param[in] Data Integer in host byte order that will be encoded and copied into Data structure
+ @param[in] DataSize Length in bytes of the Data provided
+ @param[in] SignedInteger TRUE if the integer is signed or FALSE if the integer is unsigned
+
+**/
+TCG_RESULT
+EFIAPI
+TcgAddInteger(
+ TCG_CREATE_STRUCT *CreateStruct,
+ const VOID *Data,
+ UINT32 DataSize,
+ BOOLEAN SignedInteger
+ )
+{
+ const UINT8* DataBytes;
+ UINT32 ActualDataSize;
+ BOOLEAN ValueIsNegative;
+
+ NULL_CHECK(CreateStruct);
+ NULL_CHECK(Data);
+
+ if (DataSize == 0) {
+ DEBUG ((DEBUG_INFO, "invalid DataSize=0\n"));
+ return TcgResultFailure;
+ }
+
+ DataBytes = (const UINT8*)Data;
+
+ // integer should be represented by smallest atom possible
+ // so calculate real Data Size
+ ValueIsNegative = SignedInteger && DataBytes[ DataSize - 1 ] & 0x80;
+
+ // assumes native Data is little endian
+ // shorten Data to smallest byte representation
+ for (ActualDataSize = DataSize; ActualDataSize > 1; ActualDataSize--) {
+ // ignore sign extended FFs
+ if (ValueIsNegative && (DataBytes[ActualDataSize - 1] != 0xFF)) {
+ break;
+ } else if (!ValueIsNegative && (DataBytes[ActualDataSize - 1] != 0)) {
+ // ignore extended 00s
+ break;
+ }
+ }
+
+ return TcgAddAtom(CreateStruct, Data, ActualDataSize, TCG_ATOM_TYPE_INTEGER, SignedInteger ? 1 : 0);
+}
+
+/**
+ Adds an 8-bit unsigned integer to the Data structure.
+
+ @param[in/out] CreateStruct Structure used to add the integer
+ @param[in] Value Integer Value to add
+
+**/
+TCG_RESULT
+EFIAPI
+TcgAddUINT8(
+ TCG_CREATE_STRUCT *CreateStruct,
+ UINT8 Value
+ )
+{
+ return TcgAddInteger(CreateStruct, &Value, sizeof(Value), FALSE);
+}
+
+/**
+
+ Adds a 16-bit unsigned integer to the Data structure.
+
+ @param[in/out] CreateStruct Structure used to add the integer
+ @param[in] Value Integer Value to add
+
+**/
+TCG_RESULT
+EFIAPI
+TcgAddUINT16 (
+ TCG_CREATE_STRUCT *CreateStruct,
+ UINT16 Value
+ )
+{
+ return TcgAddInteger(CreateStruct, &Value, sizeof(Value), FALSE);
+}
+
+/**
+
+ Adds a 32-bit unsigned integer to the Data structure.
+
+ @param[in/out] CreateStruct Structure used to add the integer
+ @param[in] Value Integer Value to add
+
+**/
+TCG_RESULT
+EFIAPI
+TcgAddUINT32(
+ TCG_CREATE_STRUCT *CreateStruct,
+ UINT32 Value
+ )
+{
+ return TcgAddInteger(CreateStruct, &Value, sizeof(Value), FALSE);
+}
+
+
+/**
+
+ Adds a 64-bit unsigned integer to the Data structure.
+
+ @param[in/out] CreateStruct Structure used to add the integer
+ @param[in] Value Integer Value to add
+
+**/
+TCG_RESULT
+EFIAPI
+TcgAddUINT64(
+ TCG_CREATE_STRUCT *CreateStruct,
+ UINT64 Value
+ )
+{
+ return TcgAddInteger(CreateStruct, &Value, sizeof(Value), FALSE);
+}
+
+/**
+ Adds a BOOLEAN to the Data structure.
+
+ @param[in/out] CreateStruct Structure used to add the integer
+ @param[in] Value BOOLEAN Value to add
+
+**/
+TCG_RESULT
+EFIAPI
+TcgAddBOOLEAN(
+ TCG_CREATE_STRUCT *CreateStruct,
+ BOOLEAN Value
+ )
+{
+ return TcgAddInteger(CreateStruct, &Value, sizeof(Value), FALSE);
+}
+
+/**
+ Add tcg uid info.
+
+ @param [in/out] CreateStruct Structure used to add the integer
+ @param Uid Input uid info.
+
+ @retval return the action result.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgAddTcgUid(
+ TCG_CREATE_STRUCT *CreateStruct,
+ TCG_UID Uid
+ )
+{
+ return TcgAddByteSequence(CreateStruct, &Uid, sizeof(TCG_UID), FALSE);
+}
+
+/**
+ Add start list.
+
+ @param [in/out] CreateStruct Structure used to add the integer
+
+ @retval return the action result.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgAddStartList(
+ TCG_CREATE_STRUCT *CreateStruct
+ )
+{
+ return TcgAddRawByte(CreateStruct, TCG_TOKEN_STARTLIST);
+}
+
+/**
+ Add end list.
+
+ @param [in/out] CreateStruct Structure used to add the integer
+
+ @retval return the action result.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgAddEndList(
+ TCG_CREATE_STRUCT *CreateStruct
+ )
+{
+ return TcgAddRawByte(CreateStruct, TCG_TOKEN_ENDLIST);
+}
+
+/**
+ Add start name.
+
+ @param [in/out] CreateStruct Structure used to add the integer
+
+ @retval return the action result.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgAddStartName(
+ TCG_CREATE_STRUCT *CreateStruct
+ )
+{
+ return TcgAddRawByte(CreateStruct, TCG_TOKEN_STARTNAME);
+}
+
+/**
+ Add end name.
+
+ @param [in/out] CreateStruct Structure used to add the integer
+
+ @retval return the action result.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgAddEndName(
+ TCG_CREATE_STRUCT *CreateStruct
+ )
+{
+ return TcgAddRawByte(CreateStruct, TCG_TOKEN_ENDNAME);
+}
+
+/**
+ Add end call.
+
+ @param [in/out] CreateStruct Structure used to add the integer
+
+ @retval return the action result.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgAddCall(
+ TCG_CREATE_STRUCT *CreateStruct
+ )
+{
+ return TcgAddRawByte(CreateStruct, TCG_TOKEN_CALL);
+}
+
+/**
+ Add end of data.
+
+ @param [in/out] CreateStruct Structure used to add the integer
+
+ @retval return the action result.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgAddEndOfData(
+ TCG_CREATE_STRUCT *CreateStruct
+ )
+{
+ return TcgAddRawByte(CreateStruct, TCG_TOKEN_ENDDATA);
+}
+
+/**
+ Add end of session.
+
+ @param [in/out] CreateStruct Structure used to add the integer
+
+ @retval return the action result.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgAddEndOfSession(
+ TCG_CREATE_STRUCT *CreateStruct
+ )
+{
+ return TcgAddRawByte(CreateStruct, TCG_TOKEN_ENDSESSION);
+}
+
+/**
+ Add start transaction.
+
+ @param [in/out] CreateStruct Structure used to add the integer
+
+ @retval return the action result.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgAddStartTransaction(
+ TCG_CREATE_STRUCT *CreateStruct
+ )
+{
+ return TcgAddRawByte(CreateStruct, TCG_TOKEN_STARTTRANSACTION);
+}
+
+/**
+ Add end transaction.
+
+ @param [in/out] CreateStruct Structure used to add the integer
+
+ @retval return the action result.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgAddEndTransaction(
+ TCG_CREATE_STRUCT *CreateStruct
+ )
+{
+ return TcgAddRawByte(CreateStruct, TCG_TOKEN_ENDTRANSACTION);
+}
+
+/**
+ Initial the tcg parse stucture.
+
+ @param ParseStruct Input parse structure.
+ @param Buffer Input buffer data.
+ @param BufferSize Input buffer size.
+
+ @retval return the action result.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgInitTcgParseStruct(
+ TCG_PARSE_STRUCT *ParseStruct,
+ const VOID *Buffer,
+ UINT32 BufferSize
+ )
+{
+ UINT32 ComPacketLength;
+ UINT32 PacketLength;
+
+ NULL_CHECK(ParseStruct);
+ NULL_CHECK(Buffer);
+
+ if (BufferSize < sizeof(TCG_COM_PACKET)) {
+ return (TcgResultFailureBufferTooSmall);
+ }
+
+ ParseStruct->ComPacket = (TCG_COM_PACKET*)Buffer;
+
+ ComPacketLength = SwapBytes32(ParseStruct->ComPacket->LengthBE);
+
+ if ((BufferSize - sizeof(TCG_COM_PACKET)) < ComPacketLength) {
+ DEBUG ((DEBUG_INFO, "Buffer %u too small for ComPacket %u\n", BufferSize, ComPacketLength));
+ return (TcgResultFailureBufferTooSmall);
+ }
+
+ ParseStruct->BufferSize = BufferSize;
+ ParseStruct->Buffer = Buffer;
+
+ ParseStruct->CurPacket = NULL;
+ ParseStruct->CurSubPacket = NULL;
+ ParseStruct->CurPtr = NULL;
+
+ // if payload > 0, then must have a packet
+ if (ComPacketLength != 0) {
+ if (ComPacketLength < sizeof(TCG_PACKET)) {
+ DEBUG ((DEBUG_INFO, "ComPacket too small for Packet\n"));
+ return (TcgResultFailureBufferTooSmall);
+ }
+ ParseStruct->CurPacket = (TCG_PACKET*)ParseStruct->ComPacket->Payload;
+
+ PacketLength = SwapBytes32(ParseStruct->CurPacket->LengthBE);
+
+ if (PacketLength > 0) {
+ if (PacketLength < sizeof(TCG_SUB_PACKET)) {
+ DEBUG ((DEBUG_INFO, "Packet too small for SubPacket\n"));
+ return (TcgResultFailureBufferTooSmall);
+ }
+
+ ParseStruct->CurSubPacket = (TCG_SUB_PACKET*)ParseStruct->CurPacket->Payload;
+ }
+ }
+
+ //TODO should check for method status list at this point?
+
+ return (TcgResultSuccess);
+}
+
+/**
+ Get next token info.
+
+ @param ParseStruct Input parse structure info.
+ @param TcgToken return the tcg token info.
+
+ @retval return the action result.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgGetNextToken(
+ TCG_PARSE_STRUCT *ParseStruct,
+ TCG_TOKEN *TcgToken
+ )
+{
+ const UINT8* EndOfSubPacket;
+ UINT8* TokenEnd;
+ UINT8 Hdr;
+ TCG_SIMPLE_TOKEN_SHORT_ATOM* TmpShort;
+ const TCG_SIMPLE_TOKEN_MEDIUM_ATOM* TmpMed;
+ const TCG_SIMPLE_TOKEN_LONG_ATOM* TmpLong;
+
+ NULL_CHECK(ParseStruct);
+ NULL_CHECK(TcgToken);
+
+ if (ParseStruct->ComPacket == NULL ||
+ ParseStruct->CurPacket == NULL ||
+ ParseStruct->CurSubPacket == NULL
+ ) {
+ DEBUG ((DEBUG_INFO, "unexpected state: ComPacket=%p CurPacket=%p CurSubPacket=%p\n", ParseStruct->ComPacket, ParseStruct->CurPacket, ParseStruct->CurSubPacket));
+ return TcgResultFailureInvalidAction;
+ }
+
+ // initial call, start at sub packet
+ if (ParseStruct->CurPtr == NULL) {
+ ParseStruct->CurPtr = ParseStruct->CurSubPacket->Payload;
+ }
+
+ EndOfSubPacket = ParseStruct->CurSubPacket->Payload + SwapBytes32(ParseStruct->CurSubPacket->LengthBE);
+ TokenEnd = NULL;
+
+ // confirmed that subpacket Length falls within end of Buffer and TCG_COM_PACKET,
+ // so simply need to verify the loop stays within current subpacket
+ if (ParseStruct->CurPtr >= EndOfSubPacket) {
+ DEBUG ((DEBUG_INFO, "ParseStruct->CurPtr >= EndOfSubPacket\n"));
+ return (TcgResultFailureEndBuffer);
+ }
+
+ Hdr = *ParseStruct->CurPtr;
+ TcgToken->HdrStart = ParseStruct->CurPtr;
+
+ // Tiny Atom range
+ if (Hdr <= 0x7F) {
+ // tiny atom Header is only 1 byte, so don't need to verify Size before cast and access
+ TcgToken->Type = TcgTokenTypeTinyAtom;
+
+ TokenEnd = TcgToken->HdrStart + sizeof(TCG_SIMPLE_TOKEN_TINY_ATOM);
+
+ // verify caller will have enough Size to reference token
+ if (TokenEnd >= EndOfSubPacket) {
+ DEBUG ((DEBUG_INFO, "Tiny Atom TokenEnd >= EndOfSubPacket\n"));
+ return (TcgResultFailureEndBuffer);
+ }
+ }
+ // Short Atom Range
+ else if (0x80 <= Hdr && Hdr <= 0xBF) {
+ // short atom Header is only 1 byte, so don't need to verify Size before cast and access
+ TmpShort = (TCG_SIMPLE_TOKEN_SHORT_ATOM*)(ParseStruct->CurPtr);
+ TcgToken->Type = TcgTokenTypeShortAtom;
+
+ TokenEnd = (TcgToken->HdrStart + sizeof(TCG_SIMPLE_TOKEN_SHORT_ATOM) + TmpShort->ShortAtomBits.Length);
+
+ // verify caller will have enough Size to reference token
+ if (TokenEnd >= EndOfSubPacket) {
+ DEBUG ((DEBUG_INFO, "Short Atom TokenEnd >= EndOfSubPacket\n"));
+ return (TcgResultFailureEndBuffer);
+ }
+ }
+ // Medium Atom Range
+ else if (0xC0 <= Hdr && Hdr <= 0xDF) {
+ if (TcgToken->HdrStart + sizeof(TCG_SIMPLE_TOKEN_MEDIUM_ATOM) >= EndOfSubPacket) {
+ return (TcgResultFailureEndBuffer);
+ }
+ TmpMed = (const TCG_SIMPLE_TOKEN_MEDIUM_ATOM*)ParseStruct->CurPtr;
+ TcgToken->Type = TcgTokenTypeMediumAtom;
+ TokenEnd = TcgToken->HdrStart + sizeof(TCG_SIMPLE_TOKEN_MEDIUM_ATOM) +
+ ((TmpMed->MediumAtomBits.LengthHigh << TCG_MEDIUM_ATOM_LENGTH_HIGH_SHIFT) |
+ TmpMed->MediumAtomBits.LengthLow);
+
+ // verify caller will have enough Size to reference token
+ if (TokenEnd >= EndOfSubPacket) {
+ DEBUG ((DEBUG_INFO, "Medium Atom TokenEnd >= EndOfSubPacket\n"));
+ return (TcgResultFailureEndBuffer);
+ }
+ }
+ // Long Atom Range
+ else if (0xE0 <= Hdr && Hdr <= 0xE3) {
+ if (TcgToken->HdrStart + sizeof(TCG_SIMPLE_TOKEN_LONG_ATOM) >= EndOfSubPacket) {
+ return (TcgResultFailureEndBuffer);
+ }
+ TmpLong = (const TCG_SIMPLE_TOKEN_LONG_ATOM*)ParseStruct->CurPtr;
+ TcgToken->Type = TcgTokenTypeLongAtom;
+
+ TokenEnd = TcgToken->HdrStart + sizeof(TCG_SIMPLE_TOKEN_LONG_ATOM) +
+ ((TmpLong->LongAtomBits.LengthHigh << TCG_LONG_ATOM_LENGTH_HIGH_SHIFT) |
+ (TmpLong->LongAtomBits.LengthMid << TCG_LONG_ATOM_LENGTH_MID_SHIFT) |
+ TmpLong->LongAtomBits.LengthLow);
+
+ // verify caller will have enough Size to reference token
+ if (TokenEnd >= EndOfSubPacket) {
+ DEBUG ((DEBUG_INFO, "Long Atom TokenEnd >= EndOfSubPacket\n"));
+ return (TcgResultFailureEndBuffer);
+ }
+ } else {
+ // single byte tokens
+ switch (Hdr) {
+ case TCG_TOKEN_STARTLIST:
+ TcgToken->Type = TcgTokenTypeStartList;
+ break;
+ case TCG_TOKEN_ENDLIST:
+ TcgToken->Type = TcgTokenTypeEndList;
+ break;
+ case TCG_TOKEN_STARTNAME:
+ TcgToken->Type = TcgTokenTypeStartName;
+ break;
+ case TCG_TOKEN_ENDNAME:
+ TcgToken->Type = TcgTokenTypeEndName;
+ break;
+ case TCG_TOKEN_CALL:
+ TcgToken->Type = TcgTokenTypeCall;
+ break;
+ case TCG_TOKEN_ENDDATA:
+ TcgToken->Type = TcgTokenTypeEndOfData;
+ break;
+ case TCG_TOKEN_ENDSESSION:
+ TcgToken->Type = TcgTokenTypeEndOfSession;
+ break;
+ case TCG_TOKEN_STARTTRANSACTION:
+ TcgToken->Type = TcgTokenTypeStartTransaction;
+ break;
+ case TCG_TOKEN_ENDTRANSACTION:
+ TcgToken->Type = TcgTokenTypeEndTransaction;
+ break;
+ case TCG_TOKEN_EMPTY:
+ TcgToken->Type = TcgTokenTypeEmptyAtom;
+ break;
+ default:
+ DEBUG ((DEBUG_INFO, "WARNING: reserved token Type 0x%02X\n", Hdr));
+ TcgToken->Type = TcgTokenTypeReserved;
+ break;
+ }
+ ParseStruct->CurPtr++;
+ TokenEnd = TcgToken->HdrStart + 1;
+ }
+
+ // increment curptr for next call
+ ParseStruct->CurPtr = TokenEnd;
+ return (TcgResultSuccess);
+}
+
+/**
+ Get atom info.
+
+ @param TcgToken Input token info.
+ @param HeaderLength return the header length.
+ @param DataLength return the data length.
+ @param ByteOrInt return the atom Type.
+ @param SignOrCont return the sign or count info.
+
+ @retval return the action result.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgGetAtomInfo(
+ const TCG_TOKEN *TcgToken,
+ UINT32 *HeaderLength,
+ UINT32 *DataLength,
+ UINT8 *ByteOrInt,
+ UINT8 *SignOrCont
+ )
+{
+ TCG_SIMPLE_TOKEN_TINY_ATOM* TinyAtom;
+ TCG_SIMPLE_TOKEN_SHORT_ATOM* ShortAtom;
+ TCG_SIMPLE_TOKEN_MEDIUM_ATOM* MediumAtom;
+ TCG_SIMPLE_TOKEN_LONG_ATOM* LongAtom;
+
+ NULL_CHECK(TcgToken);
+ NULL_CHECK(HeaderLength);
+ NULL_CHECK(DataLength);
+ NULL_CHECK(ByteOrInt);
+ NULL_CHECK(SignOrCont);
+
+ switch (TcgToken->Type) {
+ case TcgTokenTypeTinyAtom: {
+ TinyAtom = (TCG_SIMPLE_TOKEN_TINY_ATOM*)TcgToken->HdrStart;
+ *ByteOrInt = TCG_ATOM_TYPE_INTEGER;
+ *SignOrCont = TinyAtom->TinyAtomBits.Sign;
+ *HeaderLength = 0;
+ *DataLength = 0; // tiny atom must be handled as a special case - Header and Data in the same byte
+ return TcgResultSuccess;
+ }
+
+ case TcgTokenTypeShortAtom: {
+ ShortAtom = (TCG_SIMPLE_TOKEN_SHORT_ATOM*)TcgToken->HdrStart;
+ *ByteOrInt = ShortAtom->ShortAtomBits.ByteOrInt;
+ *SignOrCont = ShortAtom->ShortAtomBits.SignOrCont;
+ *HeaderLength = sizeof(TCG_SIMPLE_TOKEN_SHORT_ATOM);
+ *DataLength = ShortAtom->ShortAtomBits.Length;
+ return TcgResultSuccess;
+ }
+
+ case TcgTokenTypeMediumAtom: {
+ MediumAtom = (TCG_SIMPLE_TOKEN_MEDIUM_ATOM*)TcgToken->HdrStart;
+ *ByteOrInt = MediumAtom->MediumAtomBits.ByteOrInt;
+ *SignOrCont = MediumAtom->MediumAtomBits.SignOrCont;
+ *HeaderLength = sizeof(TCG_SIMPLE_TOKEN_MEDIUM_ATOM);
+ *DataLength = (MediumAtom->MediumAtomBits.LengthHigh << TCG_MEDIUM_ATOM_LENGTH_HIGH_SHIFT) | MediumAtom->MediumAtomBits.LengthLow;
+ return TcgResultSuccess;
+ }
+
+ case TcgTokenTypeLongAtom: {
+ LongAtom = (TCG_SIMPLE_TOKEN_LONG_ATOM*)TcgToken->HdrStart;
+ *ByteOrInt = LongAtom->LongAtomBits.ByteOrInt;
+ *SignOrCont = LongAtom->LongAtomBits.SignOrCont;
+ *HeaderLength = sizeof(TCG_SIMPLE_TOKEN_LONG_ATOM);
+ *DataLength = (LongAtom->LongAtomBits.LengthHigh << TCG_LONG_ATOM_LENGTH_HIGH_SHIFT) |
+ (LongAtom->LongAtomBits.LengthMid << TCG_LONG_ATOM_LENGTH_MID_SHIFT) |
+ LongAtom->LongAtomBits.LengthLow;
+ return TcgResultSuccess;
+ }
+
+ default:
+ DEBUG ((DEBUG_INFO, "Token Type is not simple atom (%d)\n", TcgToken->Type));
+ return (TcgResultFailureInvalidType);
+ }
+}
+
+/**
+ Get token specified value.
+
+ @param TcgToken Input token info.
+ @param Value return the value.
+
+ @retval return the action result.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgGetTokenUINT64(
+ const TCG_TOKEN *TcgToken,
+ UINT64 *Value
+ )
+{
+ UINT32 HdrLength;
+ UINT32 DataLength;
+ UINT8 ByteOrInt;
+ UINT8 IsSigned;
+ TCG_SIMPLE_TOKEN_TINY_ATOM* TmpTiny;
+ const UINT8* Data;
+ UINT32 Index;
+
+ NULL_CHECK(TcgToken);
+ NULL_CHECK(Value);
+
+ Index = 0;
+ *Value = 0;
+ ERROR_CHECK(TcgGetAtomInfo(TcgToken, &HdrLength, &DataLength, &ByteOrInt, &IsSigned));
+
+ if (ByteOrInt != TCG_ATOM_TYPE_INTEGER) {
+ DEBUG ((DEBUG_INFO, "Invalid Type, expected integer not byte sequence\n"));
+ return TcgResultFailureInvalidType;
+ }
+
+ if (IsSigned != 0) {
+ DEBUG ((DEBUG_INFO, "Integer is signed, expected unsigned\n"));
+ return TcgResultFailureInvalidType;
+ }
+
+ // special case for tiny atom
+ // Header and Data are in one byte, so extract only the Data bitfield
+ if (TcgToken->Type == TcgTokenTypeTinyAtom) {
+ TmpTiny = (TCG_SIMPLE_TOKEN_TINY_ATOM*)TcgToken->HdrStart;
+ *Value = TmpTiny->TinyAtomBits.Data;
+ return TcgResultSuccess;
+ }
+
+ if (DataLength > sizeof(UINT64)) {
+ DEBUG ((DEBUG_INFO, "Length %d is greater than Size of UINT64\n", DataLength));
+ return TcgResultFailureBufferTooSmall;
+ }
+
+ // read big-endian integer
+ Data = TcgToken->HdrStart + HdrLength;
+ for (Index = 0; Index < DataLength; Index++) {
+ *Value = LShiftU64(*Value, 8) | Data[Index];
+ }
+
+ return TcgResultSuccess;
+}
+
+/**
+ Get token byte sequence.
+
+ @param TcgToken Input token info.
+ @param Length Input the length info.
+
+ @retval Return the value data.
+
+**/
+UINT8*
+EFIAPI
+TcgGetTokenByteSequence(
+ const TCG_TOKEN *TcgToken,
+ UINT32 *Length
+ )
+{
+ UINT32 HdrLength;
+ UINT8 ByteOrInt;
+ UINT8 SignOrCont;
+
+ if (TcgToken == NULL || Length == NULL) {
+ return NULL;
+ }
+
+ *Length = 0;
+ if (TcgGetAtomInfo(TcgToken, &HdrLength, Length, &ByteOrInt, &SignOrCont) != TcgResultSuccess) {
+ DEBUG ((DEBUG_INFO, "Failed to get simple token info\n"));
+ return NULL;
+ }
+
+ if (ByteOrInt != TCG_ATOM_TYPE_BYTE) {
+ DEBUG ((DEBUG_INFO, "Invalid Type, expected byte sequence not integer\n"));
+ return NULL;
+ }
+
+ return (TcgToken->HdrStart + HdrLength);
+}
+
+/**
+ Get next specify value.
+
+ @param ParseStruct Input parse structure.
+ @param Value Return vlaue.
+
+ @retval return the action result.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgGetNextUINT8(
+ TCG_PARSE_STRUCT *ParseStruct,
+ UINT8 *Value
+ )
+{
+ UINT64 Value64;
+ TCG_TOKEN Tok;
+
+ NULL_CHECK(Value);
+
+ ERROR_CHECK(TcgGetNextToken(ParseStruct, &Tok));
+ ERROR_CHECK(TcgGetTokenUINT64(&Tok, &Value64));
+
+ if (Value64 > MAX_UINT8) {
+ return TcgResultFailure;
+ }
+
+ *Value = (UINT8)Value64;
+
+ return TcgResultSuccess;
+}
+
+/**
+ Get next specify value.
+
+ @param ParseStruct Input parse structure.
+ @param Value Return vlaue.
+
+ @retval return the action result.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgGetNextUINT16(
+ TCG_PARSE_STRUCT *ParseStruct,
+ UINT16 *Value
+ )
+{
+ UINT64 Value64;
+ TCG_TOKEN Tok;
+
+ NULL_CHECK(Value);
+
+ ERROR_CHECK(TcgGetNextToken(ParseStruct, &Tok));
+ ERROR_CHECK(TcgGetTokenUINT64(&Tok, &Value64));
+
+ if (Value64 > MAX_UINT16) {
+ return TcgResultFailure;
+ }
+
+ *Value = (UINT16)Value64;
+
+ return TcgResultSuccess;
+}
+
+/**
+ Get next specify value.
+
+ @param ParseStruct Input parse structure.
+ @param Value Return vlaue.
+
+ @retval return the action result.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgGetNextUINT32(
+ TCG_PARSE_STRUCT *ParseStruct,
+ UINT32 *Value
+ )
+{
+ UINT64 Value64;
+ TCG_TOKEN Tok;
+
+ NULL_CHECK(Value);
+
+ ERROR_CHECK(TcgGetNextToken(ParseStruct, &Tok));
+ ERROR_CHECK(TcgGetTokenUINT64(&Tok, &Value64));
+
+ if (Value64 > MAX_UINT32) {
+ return TcgResultFailure;
+ }
+
+ *Value = (UINT32)Value64;
+
+ return TcgResultSuccess;
+}
+
+/**
+ Get next specify value.
+
+ @param ParseStruct Input parse structure.
+ @param Value Return vlaue.
+
+ @retval return the action result.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgGetNextUINT64(
+ TCG_PARSE_STRUCT *ParseStruct,
+ UINT64 *Value
+ )
+{
+ TCG_TOKEN Tok;
+ ERROR_CHECK(TcgGetNextToken(ParseStruct, &Tok));
+ ERROR_CHECK(TcgGetTokenUINT64(&Tok, Value));
+ return TcgResultSuccess;
+}
+
+/**
+ Get next specify value.
+
+ @param ParseStruct Input parse structure.
+ @param Value Return vlaue.
+
+ @retval return the action result.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgGetNextBOOLEAN(
+ TCG_PARSE_STRUCT *ParseStruct,
+ BOOLEAN *Value
+ )
+{
+ UINT64 Value64;
+ TCG_TOKEN Tok;
+
+ NULL_CHECK(Value);
+
+ ERROR_CHECK(TcgGetNextToken(ParseStruct, &Tok));
+ ERROR_CHECK(TcgGetTokenUINT64(&Tok, &Value64));
+
+ if (Value64 > 1) {
+ return TcgResultFailure;
+ }
+
+ *Value = (BOOLEAN)Value64;
+
+ return TcgResultSuccess;
+}
+
+/**
+ Get next tcg uid info.
+
+ @param ParseStruct Input parse structure.
+ @param Uid Get the uid info.
+
+ @retval return the action result.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgGetNextTcgUid(
+ TCG_PARSE_STRUCT *ParseStruct,
+ TCG_UID *Uid
+ )
+{
+ TCG_TOKEN Tok;
+ UINT32 Length;
+ const UINT8* ByteSeq;
+
+ NULL_CHECK(Uid);
+
+ ERROR_CHECK(TcgGetNextToken(ParseStruct, &Tok));
+ ByteSeq = TcgGetTokenByteSequence(&Tok, &Length);
+
+ if (Length != sizeof(TCG_UID)) {
+ DEBUG ((DEBUG_INFO, "Token Length %u != TCG_UID Size %u\n", Length, (UINT32)sizeof(TCG_UID)));
+ return TcgResultFailure;
+ }
+
+ ASSERT (ByteSeq != NULL);
+
+ CopyMem(Uid, ByteSeq, sizeof(TCG_UID));
+
+ return TcgResultSuccess;
+}
+
+/**
+ Get next byte sequence.
+
+ @param ParseStruct Input parse structure.
+ @param Data return the data.
+ @param Length return the length.
+
+ @retval return the action result.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgGetNextByteSequence(
+ TCG_PARSE_STRUCT *ParseStruct,
+ const VOID **Data,
+ UINT32 *Length
+ )
+{
+ TCG_TOKEN Tok;
+ const UINT8* Bs;
+
+ ERROR_CHECK(TcgGetNextToken(ParseStruct, &Tok));
+ Bs = TcgGetTokenByteSequence(&Tok, Length);
+
+ if (Bs == NULL) {
+ return TcgResultFailure;
+ }
+ *Data = Bs;
+ return TcgResultSuccess;
+}
+
+/**
+ Get next token Type.
+
+ @param ParseStruct Input parse structure.
+ @param Type Input the type need to check.
+
+ @retval return the action result.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgGetNextTokenType(
+ TCG_PARSE_STRUCT *ParseStruct,
+ TCG_TOKEN_TYPE Type
+ )
+{
+ TCG_TOKEN Tok;
+ ERROR_CHECK(TcgGetNextToken(ParseStruct, &Tok));
+ if (Tok.Type != Type) {
+ DEBUG ((DEBUG_INFO, "expected Type %u, got Type %u\n", Type, Tok.Type));
+ return TcgResultFailure;
+ }
+ return TcgResultSuccess;
+}
+
+/**
+ Get next start list.
+
+ @param ParseStruct Input parse structure.
+
+ @retval return the action result.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgGetNextStartList(
+ TCG_PARSE_STRUCT *ParseStruct
+ )
+{
+ return TcgGetNextTokenType(ParseStruct, TcgTokenTypeStartList);
+}
+
+/**
+ Get next end list.
+
+ @param ParseStruct Input parse structure.
+
+ @retval return the action result.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgGetNextEndList(
+ TCG_PARSE_STRUCT *ParseStruct
+ )
+{
+ return TcgGetNextTokenType(ParseStruct, TcgTokenTypeEndList);
+}
+
+/**
+ Get next start name.
+
+ @param ParseStruct Input parse structure.
+
+ @retval return the action result.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgGetNextStartName(
+ TCG_PARSE_STRUCT *ParseStruct
+ )
+{
+ return TcgGetNextTokenType(ParseStruct, TcgTokenTypeStartName);
+}
+
+/**
+ Get next end name.
+
+ @param ParseStruct Input parse structure.
+
+ @retval return the action result.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgGetNextEndName(
+ TCG_PARSE_STRUCT *ParseStruct
+ )
+{
+ return TcgGetNextTokenType(ParseStruct, TcgTokenTypeEndName);
+}
+
+/**
+ Get next call.
+
+ @param ParseStruct Input parse structure.
+
+ @retval return the action result.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgGetNextCall(
+ TCG_PARSE_STRUCT *ParseStruct
+ )
+{
+ return TcgGetNextTokenType(ParseStruct, TcgTokenTypeCall);
+}
+
+/**
+ Get next end data.
+
+ @param ParseStruct Input parse structure.
+
+ @retval return the action result.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgGetNextEndOfData(
+ TCG_PARSE_STRUCT *ParseStruct
+ )
+{
+ return TcgGetNextTokenType(ParseStruct, TcgTokenTypeEndOfData);
+}
+
+/**
+ Get next end of session.
+
+ @param ParseStruct Input parse structure.
+
+ @retval return the action result.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgGetNextEndOfSession(
+ TCG_PARSE_STRUCT *ParseStruct
+ )
+{
+ return TcgGetNextTokenType(ParseStruct, TcgTokenTypeEndOfSession);
+}
+
+/**
+ Get next start transaction.
+
+ @param ParseStruct Input parse structure.
+
+ @retval return the action result.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgGetNextStartTransaction(
+ TCG_PARSE_STRUCT *ParseStruct
+ )
+{
+ return TcgGetNextTokenType(ParseStruct, TcgTokenTypeStartTransaction);
+}
+
+/**
+ Get next end transaction.
+
+ @param ParseStruct Input parse structure.
+
+ @retval return the action result.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgGetNextEndTransaction(
+ TCG_PARSE_STRUCT *ParseStruct
+ )
+{
+ return TcgGetNextTokenType(ParseStruct, TcgTokenTypeEndTransaction);
+}
diff --git a/Core/SecurityPkg/Library/TcgStorageCoreLib/TcgStorageCoreLib.inf b/Core/SecurityPkg/Library/TcgStorageCoreLib/TcgStorageCoreLib.inf
new file mode 100644
index 0000000000..a80cb00a9c
--- /dev/null
+++ b/Core/SecurityPkg/Library/TcgStorageCoreLib/TcgStorageCoreLib.inf
@@ -0,0 +1,38 @@
+## @file
+# This is a Tcg Storage core library.
+#
+# This module is used to provide API used by Opal password solution.
+#
+# Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+[Defines]
+ INF_VERSION = 0x00010017
+ BASE_NAME = TcgStorageCoreLib
+ FILE_GUID = ad63b09b-1fc9-4789-af0c-5af8a3fb1f9c
+ VERSION_STRING = 1.0
+ MODULE_TYPE = BASE
+ LIBRARY_CLASS = TcgStorageCoreLib|DXE_DRIVER DXE_CORE DXE_SMM_DRIVER
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+
+[Packages]
+ MdePkg/MdePkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[Sources]
+ TcgStorageCore.c
+ TcgStorageUtil.c
diff --git a/Core/SecurityPkg/Library/TcgStorageCoreLib/TcgStorageUtil.c b/Core/SecurityPkg/Library/TcgStorageCoreLib/TcgStorageUtil.c
new file mode 100644
index 0000000000..286f5b6bda
--- /dev/null
+++ b/Core/SecurityPkg/Library/TcgStorageCoreLib/TcgStorageUtil.c
@@ -0,0 +1,907 @@
+/** @file
+ Provide functions to provide tcg storage core spec related functions.
+
+Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Library/TcgStorageCoreLib.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+
+typedef struct {
+ UINT16 FeatureCode;
+ TCG_LEVEL0_FEATURE_DESCRIPTOR_HEADER *Feature;
+ UINTN FeatureSize;
+} TCG_FIND_FEATURE_CTX;
+
+/**
+ Returns a human-readable string representing a method status return code.
+
+ @param[in] MethodStatus Method status to translate to a string
+
+
+ @retval return the string info.
+**/
+CHAR8*
+EFIAPI
+TcgMethodStatusString(
+ UINT8 MethodStatus
+ )
+{
+ switch (MethodStatus) {
+ #define C(status) case TCG_METHOD_STATUS_CODE_ ## status: return #status
+ C(SUCCESS);
+ C(NOT_AUTHORIZED);
+ C(OBSOLETE);
+ C(SP_BUSY);
+ C(SP_FAILED);
+ C(SP_DISABLED);
+ C(SP_FROZEN);
+ C(NO_SESSIONS_AVAILABLE);
+ C(UNIQUENESS_CONFLICT);
+ C(INSUFFICIENT_SPACE);
+ C(INSUFFICIENT_ROWS);
+ C(INVALID_PARAMETER);
+ C(OBSOLETE2);
+ C(OBSOLETE3);
+ C(TPER_MALFUNCTION);
+ C(TRANSACTION_FAILURE);
+ C(RESPONSE_OVERFLOW);
+ C(AUTHORITY_LOCKED_OUT);
+ C(FAIL);
+ #undef C
+ }
+ return "unknown";
+}
+
+
+/**
+ adds call token and method Header (invoking id, and method id).
+
+ @param CreateStruct The input create structure.
+ @param InvokingId Invoking id.
+ @param MethodId Method id.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgStartMethodCall(
+ TCG_CREATE_STRUCT *CreateStruct,
+ TCG_UID InvokingId,
+ TCG_UID MethodId
+ )
+{
+ NULL_CHECK(CreateStruct);
+
+ if (CreateStruct->ComPacket == NULL ||
+ CreateStruct->CurPacket == NULL ||
+ CreateStruct->CurSubPacket == NULL
+ ) {
+ DEBUG ((DEBUG_INFO, "unexpected state: ComPacket=%p CurPacket=%p CurSubPacket=%p\n", CreateStruct->ComPacket, CreateStruct->CurPacket, CreateStruct->CurSubPacket));
+ return (TcgResultFailureInvalidAction);
+ }
+
+ ERROR_CHECK(TcgAddCall(CreateStruct));
+ ERROR_CHECK(TcgAddTcgUid(CreateStruct, InvokingId));
+ ERROR_CHECK(TcgAddTcgUid(CreateStruct, MethodId));
+
+ return TcgResultSuccess;
+}
+
+/**
+ Adds START LIST token.
+
+ @param CreateStruct The input create structure.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgStartParameters(
+ TCG_CREATE_STRUCT *CreateStruct
+ )
+{
+ NULL_CHECK(CreateStruct);
+
+ if (CreateStruct->ComPacket == NULL ||
+ CreateStruct->CurPacket == NULL ||
+ CreateStruct->CurSubPacket == NULL
+ ) {
+ DEBUG ((DEBUG_INFO, "unexpected state: ComPacket=%p CurPacket=%p CurSubPacket=%p\n", CreateStruct->ComPacket, CreateStruct->CurPacket, CreateStruct->CurSubPacket));
+ return (TcgResultFailureInvalidAction);
+ }
+
+ return TcgAddStartList(CreateStruct);
+}
+
+/**
+ Adds END LIST token.
+
+ @param CreateStruct The input create structure.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgEndParameters(
+ TCG_CREATE_STRUCT *CreateStruct
+ )
+{
+ NULL_CHECK(CreateStruct);
+
+ if (CreateStruct->ComPacket == NULL ||
+ CreateStruct->CurPacket == NULL ||
+ CreateStruct->CurSubPacket == NULL
+ ) {
+ DEBUG ((DEBUG_INFO, "unexpected state: ComPacket=%p CurPacket=%p CurSubPacket=%p\n", CreateStruct->ComPacket, CreateStruct->CurPacket, CreateStruct->CurSubPacket));
+ return (TcgResultFailureInvalidAction);
+ }
+
+ return TcgAddEndList(CreateStruct);
+}
+
+/**
+ Adds END Data token and method list.
+
+ @param CreateStruct The input create structure.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgEndMethodCall(
+ TCG_CREATE_STRUCT *CreateStruct
+ )
+{
+ NULL_CHECK(CreateStruct);
+
+ if (CreateStruct->ComPacket == NULL ||
+ CreateStruct->CurPacket == NULL ||
+ CreateStruct->CurSubPacket == NULL
+ ) {
+ DEBUG ((DEBUG_INFO, "unexpected state: ComPacket=%p CurPacket=%p CurSubPacket=%p\n", CreateStruct->ComPacket, CreateStruct->CurPacket, CreateStruct->CurSubPacket));
+ return (TcgResultFailureInvalidAction);
+ }
+
+ ERROR_CHECK(TcgAddEndOfData(CreateStruct));
+
+ ERROR_CHECK(TcgAddStartList(CreateStruct));
+ ERROR_CHECK(TcgAddUINT8(CreateStruct, 0x00)); // expected to complete properly
+ ERROR_CHECK(TcgAddUINT8(CreateStruct, 0x00)); // reserved
+ ERROR_CHECK(TcgAddUINT8(CreateStruct, 0x00)); // reserved
+ ERROR_CHECK(TcgAddEndList(CreateStruct));
+
+ return TcgResultSuccess;
+}
+
+/**
+ Retrieves the comID and Extended comID of the ComPacket in the Tcg response.
+ It is intended to be used to confirm the received Tcg response is intended for user that received it.
+
+ @param [in] ParseStruct Structure used to parse received TCG response.
+ @param [in/out] ComId comID retrieved from received ComPacket.
+ @param [in/out] ComIdExtension Extended comID retrieved from received ComPacket
+
+**/
+TCG_RESULT
+EFIAPI
+TcgGetComIds(
+ const TCG_PARSE_STRUCT *ParseStruct,
+ UINT16 *ComId,
+ UINT16 *ComIdExtension
+ )
+{
+ NULL_CHECK(ParseStruct);
+ NULL_CHECK(ComId);
+ NULL_CHECK(ComIdExtension);
+
+ if (ParseStruct->ComPacket == NULL) {
+ DEBUG ((DEBUG_INFO, "unexpected state: ComPacket=%p\n", ParseStruct->ComPacket));
+ return TcgResultFailureInvalidAction;
+ }
+
+ *ComId = SwapBytes16(ParseStruct->ComPacket->ComIDBE);
+ *ComIdExtension = SwapBytes16(ParseStruct->ComPacket->ComIDExtensionBE);
+
+ return TcgResultSuccess;
+}
+
+/**
+ Checks if the ComIDs of the response match the expected values.
+
+ @param[in] ParseStruct Structure used to parse received TCG response
+ @param[in] ExpectedComId Expected comID
+ @param[in] ExpectedComIdExtension Expected extended comID
+
+**/
+TCG_RESULT
+EFIAPI
+TcgCheckComIds(
+ const TCG_PARSE_STRUCT *ParseStruct,
+ UINT16 ExpectedComId,
+ UINT16 ExpectedComIdExtension
+ )
+{
+ UINT16 ParseComId;
+ UINT16 ParseComIdExtension;
+
+ ERROR_CHECK(TcgGetComIds(ParseStruct, &ParseComId, &ParseComIdExtension));
+ if (ParseComId != ExpectedComId || ParseComIdExtension != ExpectedComIdExtension) {
+ DEBUG ((DEBUG_INFO, "Com ID: Actual 0x%02X Expected 0x%02X\n", ParseComId, ExpectedComId));
+ DEBUG ((DEBUG_INFO, "Extended Com ID: 0x%02X Expected 0x%02X\n", ParseComIdExtension, ExpectedComIdExtension));
+ return TcgResultFailure;
+ }
+ return TcgResultSuccess;
+}
+
+/**
+ Returns the method status of the current subpacket. Does not affect the current position
+ in the ComPacket. In other words, it can be called whenever you have a valid SubPacket.
+
+ @param [in/out] ParseStruct Structure used to parse received TCG response
+ @param [in/out] MethodStatus Method status retrieved of the current SubPacket
+
+**/
+TCG_RESULT
+EFIAPI
+TcgGetMethodStatus(
+ const TCG_PARSE_STRUCT *ParseStruct,
+ UINT8 *MethodStatus
+ )
+{
+ TCG_PARSE_STRUCT TmpParseStruct;
+ TCG_TOKEN TcgToken;
+ UINT8 Reserved1, Reserved2;
+
+ NULL_CHECK(ParseStruct);
+ NULL_CHECK(MethodStatus);
+
+ if (ParseStruct->ComPacket == NULL ||
+ ParseStruct->CurPacket == NULL ||
+ ParseStruct->CurSubPacket == NULL
+ ) {
+ DEBUG ((DEBUG_INFO, "unexpected state: ComPacket=%p CurPacket=%p CurSubPacket=%p\n", ParseStruct->ComPacket, ParseStruct->CurPacket, ParseStruct->CurSubPacket));
+ return TcgResultFailureInvalidAction;
+ }
+
+ // duplicate ParseStruct, then don't need to "reset" location cur ptr
+ CopyMem (&TmpParseStruct, ParseStruct, sizeof(TCG_PARSE_STRUCT));
+
+ // method status list exists after the end method call in the subpacket
+ // skip tokens until ENDDATA is found
+ do {
+ ERROR_CHECK(TcgGetNextToken(&TmpParseStruct, &TcgToken));
+ } while (TcgToken.Type != TcgTokenTypeEndOfData);
+
+ // only reach here if enddata is found
+ // at this point, the curptr is pointing at method status list beginning
+ ERROR_CHECK(TcgGetNextStartList(&TmpParseStruct));
+ ERROR_CHECK(TcgGetNextUINT8(&TmpParseStruct, MethodStatus));
+ ERROR_CHECK(TcgGetNextUINT8(&TmpParseStruct, &Reserved1));
+ ERROR_CHECK(TcgGetNextUINT8(&TmpParseStruct, &Reserved2));
+ ERROR_CHECK(TcgGetNextEndList(&TmpParseStruct));
+
+ if (Reserved1 != 0) {
+ DEBUG ((DEBUG_INFO, "Method status reserved1 = 0x%02X (expected 0)\n", Reserved1));
+ return TcgResultFailure;
+ }
+
+ if (Reserved2 != 0) {
+ DEBUG ((DEBUG_INFO, "Method status reserved2 = 0x%02X (expected 0)\n", Reserved1));
+ return TcgResultFailure;
+ }
+
+ return TcgResultSuccess;
+}
+
+/**
+ Return the toke type string info.
+
+ @param Type Input the type info.
+
+ @retval Return the string for this type.
+
+**/
+CHAR8*
+EFIAPI
+TcgTokenTypeString(
+ TCG_TOKEN_TYPE Type
+ )
+{
+ switch (Type) {
+ case TcgTokenTypeReserved: return "Reserved";
+ case TcgTokenTypeTinyAtom: return "Tiny Atom";
+ case TcgTokenTypeShortAtom: return "Short Atom";
+ case TcgTokenTypeMediumAtom: return "Medium Atom";
+ case TcgTokenTypeLongAtom: return "Long Atom";
+ case TcgTokenTypeStartList: return "Start List";
+ case TcgTokenTypeEndList: return "End List";
+ case TcgTokenTypeStartName: return "Start Name";
+ case TcgTokenTypeEndName: return "End Name";
+ case TcgTokenTypeCall: return "Call";
+ case TcgTokenTypeEndOfData: return "End of Data";
+ case TcgTokenTypeEndOfSession: return "End of Session";
+ case TcgTokenTypeStartTransaction: return "Start Transaction";
+ case TcgTokenTypeEndTransaction: return "End Transaction";
+ case TcgTokenTypeEmptyAtom: return "Empty atom";
+ }
+ return "Unknown";
+}
+
+
+/**
+
+ Adds Start Session call to the data structure. This creates the entire ComPacket structure and
+ returns the size of the entire compacket in the size parameter.
+
+ @param [in/out] CreateStruct Structure used to add the start session call
+ @param [in/out] Size Describes the size of the entire ComPacket (header and payload). Filled out by function.
+ @param [in] ComId ComID for the ComPacket
+ @param [in] ComIdExtension Extended ComID for the ComPacket
+ @param [in] HostSessionId Host Session ID
+ @param [in] SpId Security Provider to start session with
+ @param [in] Write Write option for start session. TRUE = start session requests write access
+ @param [in] HostChallengeLength Length of the host challenge. Length should be 0 if hostChallenge is NULL
+ @param [in] HostChallenge Host challenge for Host Signing Authority. If NULL, then no Host Challenge shall be sent.
+ @param [in] HostSigningAuthority Host Signing Authority used for start session. If NULL, then no Host Signing Authority shall be sent.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgCreateStartSession(
+ TCG_CREATE_STRUCT *CreateStruct,
+ UINT32 *Size,
+ UINT16 ComId,
+ UINT16 ComIdExtension,
+ UINT32 HostSessionId,
+ TCG_UID SpId,
+ BOOLEAN Write,
+ UINT32 HostChallengeLength,
+ const VOID *HostChallenge,
+ TCG_UID HostSigningAuthority
+ )
+{
+ ERROR_CHECK(TcgStartComPacket(CreateStruct, ComId, ComIdExtension));
+ ERROR_CHECK(TcgStartPacket(CreateStruct, 0x0, 0x0, 0x0, 0x0, 0x0)) ;
+ ERROR_CHECK(TcgStartSubPacket(CreateStruct, 0x0));
+ ERROR_CHECK(TcgStartMethodCall(CreateStruct, TCG_UID_SMUID, TCG_UID_SM_START_SESSION));
+ ERROR_CHECK(TcgStartParameters(CreateStruct));
+ ERROR_CHECK(TcgAddUINT32(CreateStruct, HostSessionId));
+ ERROR_CHECK(TcgAddTcgUid(CreateStruct, SpId));
+ ERROR_CHECK(TcgAddBOOLEAN(CreateStruct, Write));
+
+ // optional parameters
+ if (HostChallenge != NULL && HostChallengeLength != 0) {
+ ERROR_CHECK(TcgAddStartName(CreateStruct));
+ ERROR_CHECK(TcgAddUINT8(CreateStruct, 0x00)); //TODO Create Enum for Method Optional Parameters?
+ ERROR_CHECK(TcgAddByteSequence(CreateStruct, HostChallenge, HostChallengeLength, FALSE));
+ ERROR_CHECK(TcgAddEndName(CreateStruct));
+ }
+ // optional parameters
+ if (HostSigningAuthority != 0) {
+ ERROR_CHECK(TcgAddStartName(CreateStruct));
+ ERROR_CHECK(TcgAddUINT8(CreateStruct, 0x03)); //TODO Create Enum for Method Optional Parameters?
+ ERROR_CHECK(TcgAddTcgUid(CreateStruct, HostSigningAuthority));
+ ERROR_CHECK(TcgAddEndName(CreateStruct));
+ }
+
+ ERROR_CHECK(TcgEndParameters(CreateStruct));
+ ERROR_CHECK(TcgEndMethodCall(CreateStruct));
+ ERROR_CHECK(TcgEndSubPacket(CreateStruct));
+ ERROR_CHECK(TcgEndPacket(CreateStruct));
+ ERROR_CHECK(TcgEndComPacket(CreateStruct, Size));
+
+ return TcgResultSuccess;
+}
+
+/**
+ Parses the Sync Session response contained in the parseStruct to retrieve Tper session ID. If the Sync Session response
+ parameters do not match the comID, extended ComID and host session ID then a failure is returned.
+
+ @param[in/out] ParseStruct Structure used to parse received TCG response, contains Sync Session response.
+ @param[in] ComId Expected ComID that is compared to actual ComID of response
+ @param[in] ComIdExtension Expected Extended ComID that is compared to actual Extended ComID of response
+ @param[in] HostSessionId Expected Host Session ID that is compared to actual Host Session ID of response
+ @param[in/out] TperSessionId Tper Session ID retrieved from the Sync Session response.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgParseSyncSession(
+ const TCG_PARSE_STRUCT *ParseStruct,
+ UINT16 ComId,
+ UINT16 ComIdExtension,
+ UINT32 HostSessionId,
+ UINT32 *TperSessionId
+ )
+{
+ UINT8 MethodStatus;
+ TCG_PARSE_STRUCT TmpParseStruct;
+ UINT16 ParseComId;
+ UINT16 ParseExtComId;
+ TCG_UID InvokingUID;
+ TCG_UID MethodUID;
+ UINT32 RecvHostSessionId;
+
+ NULL_CHECK(ParseStruct);
+ NULL_CHECK(TperSessionId);
+
+ CopyMem (&TmpParseStruct, ParseStruct, sizeof(TCG_PARSE_STRUCT));
+
+ // verify method status is good
+ ERROR_CHECK(TcgGetMethodStatus(&TmpParseStruct, &MethodStatus));
+ METHOD_STATUS_ERROR_CHECK (MethodStatus, TcgResultFailure);
+
+ // verify comids
+ ERROR_CHECK(TcgGetComIds(&TmpParseStruct, &ParseComId, &ParseExtComId));
+
+ if ((ComId != ParseComId) || (ComIdExtension != ParseExtComId)) {
+ DEBUG ((DEBUG_INFO, "unmatched comid (exp: 0x%X recv: 0x%X) or comid extension (exp: 0x%X recv: 0x%X)\n", ComId, ParseComId, ComIdExtension, ParseExtComId));
+ return TcgResultFailure;
+ }
+ ERROR_CHECK(TcgGetNextCall(&TmpParseStruct));
+ ERROR_CHECK(TcgGetNextTcgUid(&TmpParseStruct, &InvokingUID));
+ ERROR_CHECK(TcgGetNextTcgUid(&TmpParseStruct, &MethodUID));
+ ERROR_CHECK(TcgGetNextStartList(&TmpParseStruct));
+ ERROR_CHECK(TcgGetNextUINT32(&TmpParseStruct, &RecvHostSessionId));
+ ERROR_CHECK(TcgGetNextUINT32(&TmpParseStruct, TperSessionId));
+ ERROR_CHECK(TcgGetNextEndList(&TmpParseStruct));
+ ERROR_CHECK(TcgGetNextEndOfData(&TmpParseStruct));
+
+ if (InvokingUID != TCG_UID_SMUID) {
+ DEBUG ((DEBUG_INFO, "Invoking UID did not match UID_SMUID\n"));
+ return TcgResultFailure;
+ }
+
+ if (MethodUID != TCG_UID_SM_SYNC_SESSION) {
+ DEBUG ((DEBUG_INFO, "Method UID did not match UID_SM_SYNC_SESSION\n"));
+ return TcgResultFailure;
+ }
+
+ if (HostSessionId != RecvHostSessionId) {
+ DEBUG ((DEBUG_INFO, "unmatched HostSessionId (exp: 0x%X recv: 0x%X)\n", HostSessionId, RecvHostSessionId));
+ return TcgResultFailure;
+ }
+
+ return TcgResultSuccess;
+}
+
+/**
+
+ Creates ComPacket with EndSession.
+ This assumes a start session has already been opened.
+
+ @param [in/out] CreateStruct Structure used to add Endsession
+ @param [in/out] Size Describes the size of the entire ComPacket (header and payload). Filled out by function.
+ @param [in] ComId ComID for the ComPacket
+ @param [in] ComIdExtension Extended ComID for the ComPacket
+ @param [in] HostSessionId Host Session ID for the Packet
+ @param [in] TpSessionId Tper Session ID for the Packet
+
+**/
+TCG_RESULT
+EFIAPI
+TcgCreateEndSession(
+ TCG_CREATE_STRUCT *CreateStruct,
+ UINT32 *Size,
+ UINT16 ComId,
+ UINT16 ComIdExtension,
+ UINT32 HostSessionId,
+ UINT32 TpSessionId
+ )
+{
+ ERROR_CHECK(TcgStartComPacket(CreateStruct, ComId, ComIdExtension));
+ ERROR_CHECK(TcgStartPacket(CreateStruct, TpSessionId, HostSessionId, 0x0, 0x0, 0x0));
+ ERROR_CHECK(TcgStartSubPacket(CreateStruct, 0x0));
+ ERROR_CHECK(TcgAddEndOfSession(CreateStruct));
+ ERROR_CHECK(TcgEndSubPacket(CreateStruct));
+ ERROR_CHECK(TcgEndPacket(CreateStruct));
+ ERROR_CHECK(TcgEndComPacket(CreateStruct, Size));
+
+ return TcgResultSuccess;
+}
+
+/**
+ Set start method.
+
+ @param CreateStruct Input create structure.
+ @param Row Input the row info.
+ @param ColumnNumber the column info.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgStartMethodSet(
+ TCG_CREATE_STRUCT *CreateStruct,
+ TCG_UID Row,
+ UINT32 ColumnNumber
+ )
+{
+ ERROR_CHECK(TcgStartMethodCall(CreateStruct, Row, TCG_UID_METHOD_SET));
+ ERROR_CHECK(TcgStartParameters(CreateStruct));
+ ERROR_CHECK(TcgAddStartName(CreateStruct));
+ ERROR_CHECK(TcgAddUINT8(CreateStruct, 0x01)); // "Values"
+ ERROR_CHECK(TcgAddStartList(CreateStruct));
+ ERROR_CHECK(TcgAddStartName(CreateStruct));
+ ERROR_CHECK(TcgAddUINT32(CreateStruct, ColumnNumber));
+ return TcgResultSuccess;
+}
+
+/**
+ Set end method.
+
+ @param CreateStruct Input create structure.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgEndMethodSet(
+ TCG_CREATE_STRUCT *CreateStruct
+ )
+{
+ ERROR_CHECK(TcgAddEndName(CreateStruct));
+ ERROR_CHECK(TcgAddEndList(CreateStruct));
+ ERROR_CHECK(TcgAddEndName(CreateStruct));
+ ERROR_CHECK(TcgEndParameters(CreateStruct));
+ ERROR_CHECK(TcgEndMethodCall(CreateStruct));
+ return TcgResultSuccess;
+}
+
+/**
+ Creates ComPacket with a Method call that sets the PIN column for the row specified.
+ This assumes a start session has already been opened with the desired SP.
+
+ @param [in/out] CreateStruct Structure used to add method call.
+ @param [in/out] Size Describes the size of the entire ComPacket (header and payload). Filled out by function.
+ @param [in] ComId ComID for the ComPacket
+ @param [in] ComIdExtension Extended ComID for the ComPacket
+ @param [in] TperSession Tper Session ID for the Packet
+ @param [in] HostSession Host Session ID for the Packet
+ @param [in] SidRow UID of row of current SP to set PIN column
+ @param [in] Password value of PIN to set
+ @param [in] PasswordSize Size of PIN
+
+**/
+TCG_RESULT
+EFIAPI
+TcgCreateSetCPin(
+ TCG_CREATE_STRUCT *CreateStruct,
+ UINT32 *Size,
+ UINT16 ComId,
+ UINT16 ComIdExtension,
+ UINT32 TperSession,
+ UINT32 HostSession,
+ TCG_UID SidRow,
+ const VOID *Password,
+ UINT32 PasswordSize
+ )
+{
+ // set new SID Password
+ ERROR_CHECK(TcgStartComPacket(CreateStruct, ComId, ComIdExtension));
+ ERROR_CHECK(TcgStartPacket(CreateStruct, TperSession, HostSession, 0x0, 0x0, 0x0));
+ ERROR_CHECK(TcgStartSubPacket(CreateStruct, 0x0));
+ ERROR_CHECK(TcgStartMethodSet(CreateStruct, SidRow, 0x03)); // "PIN"
+ ERROR_CHECK(TcgAddByteSequence(CreateStruct, Password, PasswordSize, FALSE));
+ ERROR_CHECK(TcgEndMethodSet(CreateStruct));
+ ERROR_CHECK(TcgEndSubPacket(CreateStruct));
+ ERROR_CHECK(TcgEndPacket(CreateStruct));
+ ERROR_CHECK(TcgEndComPacket(CreateStruct, Size));
+ return TcgResultSuccess;
+}
+
+/**
+ Creates ComPacket with a Method call that sets the "Enabled" column for the row specified using the value specified.
+ This assumes a start session has already been opened with the desired SP.
+
+ @param [in/out] CreateStruct Structure used to add method call
+ @param [in/out] Size Describes the size of the entire ComPacket (header and payload). Filled out by function.
+ @param [in] ComId ComID for the ComPacket
+ @param [in] ComIdExtension Extended ComID for the ComPacket
+ @param [in] TperSession Tper Session ID for the Packet
+ @param [in] HostSession Host Session ID for the Packet
+ @param [in] AuthorityUid Authority UID to modify the "Enabled" column for
+ @param [in] Enabled Value to set the "Enabled" column to
+
+**/
+TCG_RESULT
+EFIAPI
+TcgSetAuthorityEnabled(
+ TCG_CREATE_STRUCT *CreateStruct,
+ UINT32 *Size,
+ UINT16 ComId,
+ UINT16 ComIdExtension,
+ UINT32 TperSession,
+ UINT32 HostSession,
+ TCG_UID AuthorityUid,
+ BOOLEAN Enabled
+ )
+{
+ ERROR_CHECK(TcgStartComPacket(CreateStruct, ComId, ComIdExtension));
+ ERROR_CHECK(TcgStartPacket(CreateStruct, TperSession, HostSession, 0x0, 0x0, 0x0));
+ ERROR_CHECK(TcgStartSubPacket(CreateStruct, 0x0));
+ ERROR_CHECK(TcgStartMethodSet(CreateStruct, AuthorityUid, 0x05)); // "Enabled"
+ ERROR_CHECK(TcgAddBOOLEAN(CreateStruct, Enabled));
+ ERROR_CHECK(TcgEndMethodSet(CreateStruct));
+ ERROR_CHECK(TcgEndSubPacket(CreateStruct));
+ ERROR_CHECK(TcgEndPacket(CreateStruct));
+ ERROR_CHECK(TcgEndComPacket(CreateStruct, Size));
+ return TcgResultSuccess;
+}
+
+/**
+ Create set ace.
+
+ @param CreateStruct Input create structure.
+ @param Size size info.
+ @param ComId ComId info.
+ @param ComIdExtension ComId extension info.
+ @param TperSession Tper session data.
+ @param HostSession Host session data.
+ @param AceRow Ace row info.
+ @param Authority1 Authority 1 info.
+ @param LogicalOperator Logiccal operator info.
+ @param Authority2 Authority 2 info.
+
+ @retval Return the action result.
+
+**/
+TCG_RESULT
+EFIAPI
+TcgCreateSetAce(
+ TCG_CREATE_STRUCT *CreateStruct,
+ UINT32 *Size,
+ UINT16 ComId,
+ UINT16 ComIdExtension,
+ UINT32 TperSession,
+ UINT32 HostSession,
+ TCG_UID AceRow,
+ TCG_UID Authority1,
+ BOOLEAN LogicalOperator,
+ TCG_UID Authority2
+ )
+{
+ UINT8 HalfUidAuthorityObjectRef[4];
+ UINT8 HalfUidBooleanAce[4];
+
+ HalfUidAuthorityObjectRef[0] = 0x0;
+ HalfUidAuthorityObjectRef[1] = 0x0;
+ HalfUidAuthorityObjectRef[2] = 0xC;
+ HalfUidAuthorityObjectRef[3] = 0x5;
+
+ HalfUidBooleanAce[0] = 0x0;
+ HalfUidBooleanAce[1] = 0x0;
+ HalfUidBooleanAce[2] = 0x4;
+ HalfUidBooleanAce[3] = 0xE;
+
+ ERROR_CHECK(TcgStartComPacket(CreateStruct, ComId, ComIdExtension));
+ ERROR_CHECK(TcgStartPacket(CreateStruct, TperSession, HostSession, 0x0, 0x0, 0x0));
+ ERROR_CHECK(TcgStartSubPacket(CreateStruct, 0x0));
+ ERROR_CHECK(TcgStartMethodSet(CreateStruct, AceRow, 0x03)); // "BooleanExpr"
+ ERROR_CHECK(TcgAddStartList(CreateStruct));
+ ERROR_CHECK(TcgAddStartName(CreateStruct));
+ ERROR_CHECK(TcgAddByteSequence(CreateStruct, HalfUidAuthorityObjectRef, sizeof(HalfUidAuthorityObjectRef), FALSE));
+ ERROR_CHECK(TcgAddTcgUid(CreateStruct, Authority1));
+ ERROR_CHECK(TcgAddEndName(CreateStruct));
+ ERROR_CHECK(TcgAddStartName(CreateStruct));
+ ERROR_CHECK(TcgAddByteSequence(CreateStruct, HalfUidAuthorityObjectRef, sizeof(HalfUidAuthorityObjectRef), FALSE));
+ ERROR_CHECK(TcgAddTcgUid(CreateStruct, Authority2));
+ ERROR_CHECK(TcgAddEndName(CreateStruct));
+
+ ERROR_CHECK(TcgAddStartName(CreateStruct));
+ ERROR_CHECK(TcgAddByteSequence(CreateStruct, HalfUidBooleanAce, sizeof(HalfUidBooleanAce), FALSE));
+ ERROR_CHECK(TcgAddBOOLEAN(CreateStruct, LogicalOperator));
+ ERROR_CHECK(TcgAddEndName(CreateStruct));
+ ERROR_CHECK(TcgAddEndList(CreateStruct));
+ ERROR_CHECK(TcgEndMethodSet(CreateStruct));
+ ERROR_CHECK(TcgEndSubPacket(CreateStruct));
+ ERROR_CHECK(TcgEndPacket(CreateStruct));
+ ERROR_CHECK(TcgEndComPacket(CreateStruct, Size));
+ return TcgResultSuccess;
+}
+
+/**
+ Enum level 0 discovery.
+
+ @param DiscoveryHeader Discovery header.
+ @param Callback Callback function.
+ @param Context The context for the function.
+
+ @retval return true if the callback return TRUE, else return FALSE.
+
+**/
+BOOLEAN
+EFIAPI
+TcgEnumLevel0Discovery(
+ const TCG_LEVEL0_DISCOVERY_HEADER *DiscoveryHeader,
+ TCG_LEVEL0_ENUM_CALLBACK Callback,
+ VOID *Context
+ )
+{
+ UINT32 BytesLeft;
+ const UINT8 *DiscoveryBufferPtr;
+ UINT32 FeatLength;
+ TCG_LEVEL0_FEATURE_DESCRIPTOR_HEADER *Feat;
+
+ //
+ // Total bytes including descriptors but not including the Length field
+ //
+ BytesLeft = SwapBytes32(DiscoveryHeader->LengthBE);
+
+ //
+ // If discovery Header is not valid, exit
+ //
+ if (BytesLeft == 0) {
+ return FALSE;
+ }
+
+ //
+ // Subtract the Length of the Header, except the Length field, which is not included
+ //
+ BytesLeft -= (sizeof(TCG_LEVEL0_DISCOVERY_HEADER) - sizeof(DiscoveryHeader->LengthBE));
+
+ //
+ // Move ptr to first descriptor
+ //
+ DiscoveryBufferPtr = (const UINT8*)DiscoveryHeader + sizeof(TCG_LEVEL0_DISCOVERY_HEADER);
+
+ while (BytesLeft > sizeof(TCG_LEVEL0_FEATURE_DESCRIPTOR_HEADER)) {
+ //
+ // Pointer to beginning of descriptor (including common Header)
+ //
+ Feat = (TCG_LEVEL0_FEATURE_DESCRIPTOR_HEADER*)DiscoveryBufferPtr;
+
+ FeatLength = Feat->Length + sizeof(TCG_LEVEL0_FEATURE_DESCRIPTOR_HEADER);
+
+ //
+ // Not enough bytes left for Feature descriptor
+ //
+ if (BytesLeft < FeatLength) {
+ break;
+ }
+
+ //
+ // Report the Feature to the callback
+ //
+ if (Callback(DiscoveryHeader, Feat, FeatLength, Context)) {
+ return TRUE;
+ }
+
+ //
+ // Descriptor Length only describes Data after common Header
+ //
+ BytesLeft -= FeatLength;
+ DiscoveryBufferPtr += FeatLength;
+ }
+
+ return FALSE;
+}
+
+/**
+ The callback function for Get Feature function.
+
+ @param DiscoveryHeader Input discovery header.
+ @param Feature Input Feature.
+ @param FeatureSize Input Feature size.
+ @param Context The context.
+
+**/
+BOOLEAN
+EFIAPI
+TcgFindFeatureCallback(
+ const TCG_LEVEL0_DISCOVERY_HEADER *DiscoveryHeader,
+ TCG_LEVEL0_FEATURE_DESCRIPTOR_HEADER *Feature,
+ UINTN FeatureSize,
+ VOID *Context
+ )
+{
+ TCG_FIND_FEATURE_CTX* FindCtx;
+
+ FindCtx = (TCG_FIND_FEATURE_CTX*)Context;
+ if ( SwapBytes16( Feature->FeatureCode_BE ) == FindCtx->FeatureCode ) {
+ FindCtx->Feature = Feature;
+ FindCtx->FeatureSize = FeatureSize;
+ return TRUE; // done enumerating features
+ }
+ return FALSE; // continue enumerating
+}
+
+/**
+ Get Feature code from the header.
+
+ @param DiscoveryHeader The discovery header.
+ @param FeatureCode reutrn the Feature code.
+ @param FeatureSize return the Feature size.
+
+ @retval return the Feature code data.
+**/
+TCG_LEVEL0_FEATURE_DESCRIPTOR_HEADER*
+EFIAPI
+TcgGetFeature(
+ const TCG_LEVEL0_DISCOVERY_HEADER *DiscoveryHeader,
+ UINT16 FeatureCode,
+ UINTN *FeatureSize
+ )
+{
+ TCG_FIND_FEATURE_CTX FindCtx;
+
+ FindCtx.FeatureCode = FeatureCode;
+ FindCtx.Feature = NULL;
+ FindCtx.FeatureSize = 0;
+
+ TcgEnumLevel0Discovery(DiscoveryHeader, TcgFindFeatureCallback, &FindCtx);
+ if (FeatureSize != NULL) {
+ *FeatureSize = FindCtx.FeatureSize;
+ }
+ return FindCtx.Feature;
+}
+
+/**
+ Determines if the protocol provided is part of the provided supported protocol list.
+
+ @param[in] ProtocolList Supported protocol list to investigate
+ @param[in] Protocol Protocol value to determine if supported
+
+ @return TRUE = protocol is supported, FALSE = protocol is not supported
+**/
+BOOLEAN
+EFIAPI
+TcgIsProtocolSupported(
+ const TCG_SUPPORTED_SECURITY_PROTOCOLS *ProtocolList,
+ UINT16 Protocol
+ )
+{
+ UINT16 Index;
+ UINT16 ListLength;
+
+ ListLength = SwapBytes16(ProtocolList->ListLength_BE);
+
+ if (ListLength > sizeof(ProtocolList->List)) {
+ DEBUG ((DEBUG_INFO, "WARNING: list Length is larger than max allowed Value; truncating\n"));
+ ListLength = sizeof(ProtocolList->List);
+ }
+
+ for (Index = 0; Index < ListLength; Index++) {
+ if (ProtocolList->List[Index] == Protocol) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Check whether lock or not.
+
+ @param Discovery
+
+ @retval TRUE if lock, FALSE if not lock.
+**/
+BOOLEAN
+EFIAPI
+TcgIsLocked(
+ const TCG_LEVEL0_DISCOVERY_HEADER *Discovery
+ )
+{
+ UINTN Size;
+ TCG_LOCKING_FEATURE_DESCRIPTOR *LockDescriptor;
+
+ Size = 0;
+ LockDescriptor =(TCG_LOCKING_FEATURE_DESCRIPTOR*) TcgGetFeature (Discovery, TCG_FEATURE_LOCKING, &Size);
+
+ if (LockDescriptor != NULL && Size >= sizeof(*LockDescriptor)) {
+ DEBUG ((DEBUG_INFO, "locked: %d\n", LockDescriptor->Locked));
+ return LockDescriptor->Locked;
+ }
+
+ //
+ // Descriptor was not found
+ //
+ return FALSE;
+}
diff --git a/Core/SecurityPkg/Library/TcgStorageOpalLib/TcgStorageOpalCore.c b/Core/SecurityPkg/Library/TcgStorageOpalLib/TcgStorageOpalCore.c
new file mode 100644
index 0000000000..90cc51a24c
--- /dev/null
+++ b/Core/SecurityPkg/Library/TcgStorageOpalLib/TcgStorageOpalCore.c
@@ -0,0 +1,1665 @@
+/** @file
+ Public API for Opal Core library.
+
+Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Uefi.h>
+#include <Library/BaseLib.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/TcgStorageOpalLib.h>
+
+#pragma pack(1)
+typedef struct {
+ UINT8 HardwareReset : 1;
+ UINT8 Reserved : 7;
+} TCG_BLOCK_SID_CLEAR_EVENTS;
+#pragma pack()
+
+#define TRUSTED_COMMAND_TIMEOUT_NS ((UINT64) 5 * ((UINT64)(1000000)) * 1000) // 5 seconds
+#define BUFFER_SIZE 512
+
+/**
+ The function performs a Trusted Send of a Buffer containing a TCG_COM_PACKET.
+
+ @param[in] Sscp The input Ssc Protocol.
+ @param[in] MediaId The input Media id info used by Ssc Protocol.
+ @param[in] SecurityProtocol Security Protocol
+ @param[in] SpSpecific Security Protocol Specific
+ @param[in] TransferLength Transfer Length of Buffer (in bytes) - always a multiple of 512
+ @param[in] Buffer Address of Data to transfer
+ @param[in] BufferSize Full Size of Buffer, including space that may be used for padding.
+
+**/
+TCG_RESULT
+OpalTrustedSend(
+ EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *Sscp,
+ UINT32 MediaId,
+ UINT8 SecurityProtocol,
+ UINT16 SpSpecific,
+ UINTN TransferLength,
+ VOID *Buffer,
+ UINTN BufferSize
+ )
+{
+ UINTN TransferLength512;
+ EFI_STATUS Status;
+
+ //
+ // Round transferLength up to a 512-byte multiple
+ //
+ TransferLength512 = (TransferLength + 511) & ~(UINTN)511;
+
+ if (TransferLength512 > BufferSize) {
+ return TcgResultFailureBufferTooSmall;
+ }
+
+ ZeroMem((UINT8*)Buffer + TransferLength, TransferLength512 - TransferLength);
+
+ Status = Sscp->SendData(
+ Sscp,
+ MediaId,
+ TRUSTED_COMMAND_TIMEOUT_NS,
+ SecurityProtocol,
+ SwapBytes16(SpSpecific),
+ TransferLength512,
+ Buffer
+ );
+
+ return Status == EFI_SUCCESS ? TcgResultSuccess : TcgResultFailure;
+}
+
+/**
+
+ The function performs a Trusted Receive of a Buffer containing a TCG_COM_PACKET.
+
+ @param[in] Sscp The input Ssc Protocol.
+ @param[in] MediaId The input Media id info used by Ssc Protocol.
+ @param[in] SecurityProtocol Security Protocol
+ @param[in] SpSpecific Security Protocol Specific
+ @param[in] Buffer Address of Data to transfer
+ @param[in] BufferSize Full Size of Buffer, including space that may be used for padding.
+
+**/
+TCG_RESULT
+OpalTrustedRecv(
+ EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *Sscp,
+ UINT32 MediaId,
+ UINT8 SecurityProtocol,
+ UINT16 SpSpecific,
+ VOID *Buffer,
+ UINTN BufferSize
+ )
+{
+
+ UINTN TransferLength512;
+ UINT32 Tries;
+ TCG_COM_PACKET *ComPacket;
+ UINT32 Length;
+ UINT32 OutstandingData;
+ EFI_STATUS Status;
+ UINTN TransferSize;
+
+ //
+ // Round Buffer Size down to a 512-byte multiple
+ //
+ TransferLength512 = BufferSize & ~(UINTN)511;
+ Tries = 0;
+ ComPacket = NULL;
+ Length = 0;
+ OutstandingData = 0;
+
+ if (TransferLength512 < sizeof(TCG_COM_PACKET)) {
+ DEBUG ((DEBUG_INFO, "transferLength %u too small for ComPacket\n", TransferLength512));
+ return TcgResultFailureBufferTooSmall;
+ }
+
+ //
+ // Some devices respond with Length = 0 and OutstandingData = 1 to indicate that processing is not yet completed,
+ // so we need to retry the IF-RECV to get the actual Data.
+ // See TCG Core Spec v2 Table 45 IF-RECV ComPacket Field Values Summary
+ // This is an arbitrary number of retries, not from the spec.
+ // have a max timeout of 10 seconds, 5000 tries * 2ms = 10s
+ //
+ Tries = 5000;
+ while ((Tries--) > 0) {
+ ZeroMem( Buffer, BufferSize );
+ TransferSize = 0;
+
+ Status = Sscp->ReceiveData(
+ Sscp,
+ MediaId,
+ TRUSTED_COMMAND_TIMEOUT_NS,
+ SecurityProtocol,
+ SwapBytes16(SpSpecific),
+ TransferLength512,
+ Buffer,
+ &TransferSize
+ );
+
+ if (EFI_ERROR (Status)) {
+ return TcgResultFailure;
+ }
+
+ if (SecurityProtocol != TCG_OPAL_SECURITY_PROTOCOL_1 && SecurityProtocol != TCG_OPAL_SECURITY_PROTOCOL_2) {
+ return TcgResultSuccess;
+ }
+
+ if (SpSpecific == TCG_SP_SPECIFIC_PROTOCOL_LEVEL0_DISCOVERY) {
+ return TcgResultSuccess;
+ }
+
+ ComPacket = (TCG_COM_PACKET*) Buffer;
+ Length = SwapBytes32(ComPacket->LengthBE);
+ OutstandingData = SwapBytes32( ComPacket->OutstandingDataBE );
+
+ if (Length != 0 && OutstandingData == 0) {
+ return TcgResultSuccess;
+ }
+
+ //
+ // Delay for 2 ms
+ //
+ MicroSecondDelay (2000);
+ }
+
+ return TcgResultFailure;
+}
+
+/**
+ The function performs send, recv, check comIDs, check method status action.
+
+ @param[in] Session OPAL_SESSION related to this method..
+ @param[in] SendSize Transfer Length of Buffer (in bytes) - always a multiple of 512
+ @param[in] Buffer Address of Data to transfer
+ @param[in] BufferSize Full Size of Buffer, including space that may be used for padding.
+ @param[in] ParseStruct Structure used to parse received TCG response.
+ @param[in] MethodStatus Method status of last action performed. If action succeeded, it should be TCG_METHOD_STATUS_CODE_SUCCESS.
+
+**/
+TCG_RESULT
+EFIAPI
+OpalPerformMethod(
+ OPAL_SESSION *Session,
+ UINT32 SendSize,
+ VOID *Buffer,
+ UINT32 BufferSize,
+ TCG_PARSE_STRUCT *ParseStruct,
+ UINT8 *MethodStatus
+ )
+{
+ NULL_CHECK(Session);
+ NULL_CHECK(MethodStatus);
+
+ ERROR_CHECK(OpalTrustedSend(
+ Session->Sscp,
+ Session->MediaId,
+ TCG_OPAL_SECURITY_PROTOCOL_1,
+ Session->OpalBaseComId,
+ SendSize,
+ Buffer,
+ BufferSize
+ ));
+
+ ERROR_CHECK(OpalTrustedRecv(
+ Session->Sscp,
+ Session->MediaId,
+ TCG_OPAL_SECURITY_PROTOCOL_1,
+ Session->OpalBaseComId,
+ Buffer,
+ BufferSize
+ ));
+
+ ERROR_CHECK(TcgInitTcgParseStruct(ParseStruct, Buffer, BufferSize));
+ ERROR_CHECK(TcgCheckComIds(ParseStruct, Session->OpalBaseComId, Session->ComIdExtension));
+ ERROR_CHECK(TcgGetMethodStatus(ParseStruct, MethodStatus));
+
+ return TcgResultSuccess;
+}
+
+/**
+ Trig the block sid action.
+
+ @param[in] Session OPAL_SESSION related to this method..
+ @param[in] HardwareReset Whether need to do hardware reset.
+
+**/
+TCG_RESULT
+EFIAPI
+OpalBlockSid(
+ OPAL_SESSION *Session,
+ BOOLEAN HardwareReset
+ )
+{
+ UINT8 Buffer[BUFFER_SIZE];
+ TCG_BLOCK_SID_CLEAR_EVENTS *ClearEvents;
+
+ NULL_CHECK(Session);
+
+ //
+ // Set Hardware Reset bit
+ //
+ ClearEvents = (TCG_BLOCK_SID_CLEAR_EVENTS *) &Buffer[0];
+
+ ClearEvents->Reserved = 0;
+ ClearEvents->HardwareReset = HardwareReset;
+
+ return(OpalTrustedSend(
+ Session->Sscp,
+ Session->MediaId,
+ TCG_OPAL_SECURITY_PROTOCOL_2,
+ TCG_BLOCKSID_COMID, // hardcode ComID 0x0005
+ 1,
+ Buffer,
+ BUFFER_SIZE
+ ));
+}
+
+/**
+
+ Reverts device using Admin SP Revert method.
+
+ @param[in] AdminSpSession OPAL_SESSION with OPAL_UID_ADMIN_SP as OPAL_ADMIN_SP_PSID_AUTHORITY to perform PSID revert.
+
+**/
+TCG_RESULT
+EFIAPI
+OpalPsidRevert(
+ OPAL_SESSION *AdminSpSession
+ )
+{
+ //
+ // Now that base comid is known, start Session
+ // we'll attempt to start Session as PSID authority
+ // verify PSID Authority is defined in ADMIN SP authority table... is this possible?
+ //
+ TCG_CREATE_STRUCT CreateStruct;
+ TCG_PARSE_STRUCT ParseStruct;
+ UINT32 Size;
+ UINT8 Buffer[BUFFER_SIZE];
+ UINT8 MethodStatus;
+
+ NULL_CHECK(AdminSpSession);
+
+ //
+ // Send Revert action on Admin SP
+ //
+ ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buffer, BUFFER_SIZE));
+ ERROR_CHECK(TcgStartComPacket(&CreateStruct, AdminSpSession->OpalBaseComId, AdminSpSession->ComIdExtension));
+ ERROR_CHECK(TcgStartPacket(&CreateStruct, AdminSpSession->TperSessionId, AdminSpSession->HostSessionId, 0x0, 0x0, 0x0));
+ ERROR_CHECK(TcgStartSubPacket(&CreateStruct, 0x0));
+ ERROR_CHECK(TcgStartMethodCall(&CreateStruct, OPAL_UID_ADMIN_SP, OPAL_ADMIN_SP_REVERT_METHOD));
+ ERROR_CHECK(TcgStartParameters(&CreateStruct));
+ ERROR_CHECK(TcgEndParameters(&CreateStruct));
+ ERROR_CHECK(TcgEndMethodCall(&CreateStruct));
+ ERROR_CHECK(TcgEndSubPacket(&CreateStruct));
+ ERROR_CHECK(TcgEndPacket(&CreateStruct));
+ ERROR_CHECK(TcgEndComPacket(&CreateStruct, &Size));
+
+ //
+ // Send Revert Method Call
+ //
+ ERROR_CHECK(OpalPerformMethod(AdminSpSession, Size, Buffer, BUFFER_SIZE, &ParseStruct, &MethodStatus));
+ METHOD_STATUS_ERROR_CHECK(MethodStatus, TcgResultFailure);
+
+ return TcgResultSuccess;
+}
+
+/**
+
+ The function fills in the provided Buffer with the level 0 discovery Header
+ of the device specified.
+
+ @param[in] Session OPAL_SESSION data.
+ @param[in] BufferSize Size of Buffer provided (in bytes)
+ @param[in] BuffAddress Buffer address to fill with Level 0 Discovery response
+
+**/
+TCG_RESULT
+EFIAPI
+OpalRetrieveLevel0DiscoveryHeader(
+ OPAL_SESSION *Session,
+ UINTN BufferSize,
+ VOID *BuffAddress
+ )
+{
+ return (OpalTrustedRecv(
+ Session->Sscp,
+ Session->MediaId,
+ TCG_OPAL_SECURITY_PROTOCOL_1, // SP
+ TCG_SP_SPECIFIC_PROTOCOL_LEVEL0_DISCOVERY, // SP_Specific
+ BuffAddress,
+ BufferSize
+ ));
+}
+
+/**
+
+ The function fills in the provided Buffer with the supported protocol list
+ of the device specified.
+
+ @param[in] Session OPAL_SESSION data.
+ @param[in] BufferSize Size of Buffer provided (in bytes)
+ @param[in] BuffAddress Buffer address to fill with security protocol list
+
+**/
+TCG_RESULT
+EFIAPI
+OpalRetrieveSupportedProtocolList(
+ OPAL_SESSION *Session,
+ UINTN BufferSize,
+ VOID *BuffAddress
+ )
+{
+ return (OpalTrustedRecv(
+ Session->Sscp,
+ Session->MediaId,
+ TCG_SECURITY_PROTOCOL_INFO, // SP
+ TCG_SP_SPECIFIC_PROTOCOL_LIST, // SP_Specific
+ BuffAddress,
+ BufferSize
+ ));
+}
+
+/**
+ Starts a session with a security provider (SP).
+
+ If a session is started successfully, the caller must end the session with OpalEndSession when finished
+ performing Opal actions.
+
+ @param[in/out] Session OPAL_SESSION to initialize.
+ @param[in] SpId Security provider ID to start the session with.
+ @param[in] Write Whether the session should be read-only (FALSE) or read/write (TRUE).
+ @param[in] HostChallengeLength Length of the host challenge. Length should be 0 if hostChallenge is NULL
+ @param[in] HostChallenge Host challenge for Host Signing Authority. If NULL, then no Host Challenge will be sent.
+ @param[in] HostSigningAuthority Host Signing Authority used for start session. If NULL, then no Host Signing Authority will be sent.
+ @param[in/out] MethodStatus Status of the StartSession method; only valid if TcgResultSuccess is returned.
+
+ @return TcgResultSuccess indicates that the function completed without any internal errors.
+ The caller must inspect the MethodStatus field to determine whether the method completed successfully.
+
+**/
+TCG_RESULT
+EFIAPI
+OpalStartSession(
+ OPAL_SESSION *Session,
+ TCG_UID SpId,
+ BOOLEAN Write,
+ UINT32 HostChallengeLength,
+ const VOID *HostChallenge,
+ TCG_UID HostSigningAuthority,
+ UINT8 *MethodStatus
+ )
+{
+ TCG_CREATE_STRUCT CreateStruct;
+ TCG_PARSE_STRUCT ParseStruct;
+ UINT32 Size;
+ UINT8 Buf[BUFFER_SIZE];
+ UINT16 ComIdExtension;
+ UINT32 HostSessionId;
+
+ ComIdExtension = 0;
+ HostSessionId = 1;
+
+ NULL_CHECK(Session);
+ NULL_CHECK(MethodStatus);
+
+ Session->ComIdExtension = ComIdExtension;
+ Session->HostSessionId = HostSessionId;
+
+ ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf)));
+ ERROR_CHECK(TcgCreateStartSession(
+ &CreateStruct,
+ &Size,
+ Session->OpalBaseComId,
+ ComIdExtension,
+ HostSessionId,
+ SpId,
+ Write,
+ HostChallengeLength,
+ HostChallenge,
+ HostSigningAuthority
+ ));
+ ERROR_CHECK(OpalPerformMethod(Session, Size, Buf, sizeof(Buf), &ParseStruct, MethodStatus));
+ if (*MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) {
+ return TcgResultSuccess; // return early if method failed - user must check MethodStatus
+ }
+
+ if (TcgParseSyncSession(&ParseStruct, Session->OpalBaseComId, ComIdExtension, HostSessionId, &Session->TperSessionId) != TcgResultSuccess) {
+ OpalEndSession(Session);
+ return TcgResultFailure;
+ }
+
+ return TcgResultSuccess;
+}
+
+/**
+ Close a session opened with OpalStartSession.
+
+ @param[in/out] Session OPAL_SESSION to end.
+
+**/
+TCG_RESULT
+EFIAPI
+OpalEndSession(
+ OPAL_SESSION *Session
+ )
+{
+ UINT8 Buffer[BUFFER_SIZE];
+ TCG_CREATE_STRUCT CreateStruct;
+ UINT32 Size;
+ TCG_PARSE_STRUCT ParseStruct;
+
+ NULL_CHECK(Session);
+ ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buffer, sizeof(Buffer)));
+ ERROR_CHECK(TcgCreateEndSession(
+ &CreateStruct,
+ &Size,
+ Session->OpalBaseComId,
+ Session->ComIdExtension,
+ Session->HostSessionId,
+ Session->TperSessionId
+ ));
+
+ ERROR_CHECK(OpalTrustedSend(
+ Session->Sscp,
+ Session->MediaId,
+ TCG_OPAL_SECURITY_PROTOCOL_1,
+ Session->OpalBaseComId,
+ Size,
+ Buffer,
+ sizeof(Buffer)
+ ));
+
+ ERROR_CHECK(OpalTrustedRecv(
+ Session->Sscp,
+ Session->MediaId,
+ TCG_OPAL_SECURITY_PROTOCOL_1,
+ Session->OpalBaseComId,
+ Buffer,
+ sizeof(Buffer)
+ ));
+
+ ERROR_CHECK(TcgInitTcgParseStruct(&ParseStruct, Buffer, sizeof(Buffer)));
+ ERROR_CHECK(TcgCheckComIds(&ParseStruct, Session->OpalBaseComId, Session->ComIdExtension));
+
+ ERROR_CHECK(TcgGetNextEndOfSession(&ParseStruct));
+ return TcgResultSuccess;
+}
+
+/**
+
+ The function retrieves the MSID from the device specified
+
+ @param[in] AdminSpSession OPAL_SESSION with OPAL_UID_ADMIN_SP as OPAL_ADMIN_SP_PSID_AUTHORITY to perform PSID revert.
+ @param[in] MsidBufferSize Allocated Buffer Size (in bytes) for MSID allocated by caller
+ @param[in] Msid Variable Length byte sequence representing MSID of device
+ @param[in] MsidLength Actual Length of MSID retrieved from device
+
+**/
+TCG_RESULT
+EFIAPI
+OpalGetMsid(
+ OPAL_SESSION *AdminSpSession,
+ UINT32 MsidBufferSize,
+ UINT8 *Msid,
+ UINT32 *MsidLength
+ )
+{
+ //
+ // now that base comid is known, start Session
+ // we'll attempt to start Session as PSID authority
+ // verify PSID Authority is defined in ADMIN SP authority table... is this possible?
+ //
+ TCG_CREATE_STRUCT CreateStruct;
+ TCG_PARSE_STRUCT ParseStruct;
+ UINT32 Size;
+ UINT8 MethodStatus;
+ UINT32 Col;
+ const VOID *RecvMsid;
+ UINT8 Buffer[BUFFER_SIZE];
+
+ NULL_CHECK(AdminSpSession);
+ NULL_CHECK(Msid);
+ NULL_CHECK(MsidLength);
+
+ ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buffer, BUFFER_SIZE));
+ ERROR_CHECK(TcgStartComPacket(&CreateStruct, AdminSpSession->OpalBaseComId, AdminSpSession->ComIdExtension));
+ ERROR_CHECK(TcgStartPacket(&CreateStruct, AdminSpSession->TperSessionId, AdminSpSession->HostSessionId, 0x0, 0x0, 0x0));
+ ERROR_CHECK(TcgStartSubPacket(&CreateStruct, 0x0));
+ ERROR_CHECK(TcgStartMethodCall(&CreateStruct, OPAL_UID_ADMIN_SP_C_PIN_MSID, TCG_UID_METHOD_GET));
+ ERROR_CHECK(TcgStartParameters(&CreateStruct));
+ ERROR_CHECK(TcgAddStartList(&CreateStruct));
+ ERROR_CHECK(TcgAddStartName(&CreateStruct));
+ ERROR_CHECK(TcgAddUINT8(&CreateStruct, TCG_CELL_BLOCK_START_COLUMN_NAME));
+ ERROR_CHECK(TcgAddUINT8(&CreateStruct, OPAL_ADMIN_SP_PIN_COL));
+ ERROR_CHECK(TcgAddEndName(&CreateStruct));
+ ERROR_CHECK(TcgAddStartName(&CreateStruct));
+ ERROR_CHECK(TcgAddUINT8(&CreateStruct, TCG_CELL_BLOCK_END_COLUMN_NAME));
+ ERROR_CHECK(TcgAddUINT8(&CreateStruct, OPAL_ADMIN_SP_PIN_COL));
+ ERROR_CHECK(TcgAddEndName(&CreateStruct));
+ ERROR_CHECK(TcgAddEndList(&CreateStruct));
+ ERROR_CHECK(TcgEndParameters(&CreateStruct));
+ ERROR_CHECK(TcgEndMethodCall(&CreateStruct));
+ ERROR_CHECK(TcgEndSubPacket(&CreateStruct));
+ ERROR_CHECK(TcgEndPacket(&CreateStruct));
+ ERROR_CHECK(TcgEndComPacket(&CreateStruct, &Size));
+
+ //
+ // Send MSID Method Call
+ //
+ ERROR_CHECK(OpalPerformMethod(AdminSpSession, Size, Buffer, BUFFER_SIZE, &ParseStruct, &MethodStatus));
+ METHOD_STATUS_ERROR_CHECK(MethodStatus, TcgResultFailure);
+
+ ERROR_CHECK(TcgGetNextStartList(&ParseStruct));
+ ERROR_CHECK(TcgGetNextStartList(&ParseStruct));
+ ERROR_CHECK(TcgGetNextStartName(&ParseStruct));
+ ERROR_CHECK(TcgGetNextUINT32(&ParseStruct, &Col));
+ ERROR_CHECK(TcgGetNextByteSequence(&ParseStruct, &RecvMsid, MsidLength));
+ ERROR_CHECK(TcgGetNextEndName(&ParseStruct));
+ ERROR_CHECK(TcgGetNextEndList(&ParseStruct));
+ ERROR_CHECK(TcgGetNextEndList(&ParseStruct));
+ ERROR_CHECK(TcgGetNextEndOfData(&ParseStruct));
+
+ if (Col != OPAL_ADMIN_SP_PIN_COL) {
+ DEBUG ((DEBUG_INFO, "ERROR: got col %u, expected %u\n", Col, OPAL_ADMIN_SP_PIN_COL));
+ return TcgResultFailure;
+ }
+
+ if (RecvMsid == NULL) {
+ return TcgResultFailure;
+ }
+
+ if (MsidBufferSize < *MsidLength) {
+ DEBUG ((DEBUG_INFO, "Buffer too small MsidBufferSize: %d MsidLength: %d\n", MsidBufferSize, *MsidLength));
+ return TcgResultFailureBufferTooSmall;
+ }
+
+ //
+ // copy msid into Buffer
+ //
+ CopyMem(Msid, RecvMsid, *MsidLength);
+ return TcgResultSuccess;
+}
+
+/**
+
+ The function calls the Admin SP RevertSP method on the Locking SP. If KeepUserData is True, then the optional parameter
+ to keep the user Data is set to True, otherwise the optional parameter is not provided.
+
+ @param[in] LockingSpSession OPAL_SESSION with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_ADMIN1_AUTHORITY to revertSP
+ @param[in] KeepUserData Specifies whether or not to keep user Data when performing RevertSP action. True = keeps user Data.
+ @param[in/out] MethodStatus Method status of last action performed. If action succeeded, it should be TCG_METHOD_STATUS_CODE_SUCCESS.
+
+**/
+TCG_RESULT
+EFIAPI
+OpalAdminRevert(
+ OPAL_SESSION *LockingSpSession,
+ BOOLEAN KeepUserData,
+ UINT8 *MethodStatus
+ )
+{
+ UINT8 Buf[BUFFER_SIZE];
+ TCG_CREATE_STRUCT CreateStruct;
+ UINT32 Size;
+ TCG_PARSE_STRUCT ParseStruct;
+ TCG_RESULT Ret;
+
+ NULL_CHECK(LockingSpSession);
+ NULL_CHECK(MethodStatus);
+
+ //
+ // ReadLocked or WriteLocked must be False (per Opal spec) to guarantee revertSP can keep user Data
+ //
+ if (KeepUserData) {
+ //
+ // set readlocked and writelocked to false
+ //
+ Ret = OpalUpdateGlobalLockingRange(
+ LockingSpSession,
+ FALSE,
+ FALSE,
+ MethodStatus);
+
+ if (Ret != TcgResultSuccess || *MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) {
+ //
+ // bail out
+ //
+ return Ret;
+ }
+ }
+
+ ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf)));
+ ERROR_CHECK(TcgStartComPacket(&CreateStruct, LockingSpSession->OpalBaseComId, LockingSpSession->ComIdExtension));
+ ERROR_CHECK(TcgStartPacket(&CreateStruct, LockingSpSession->TperSessionId, LockingSpSession->HostSessionId, 0x0, 0x0, 0x0));
+ ERROR_CHECK(TcgStartSubPacket(&CreateStruct, 0x0));
+ ERROR_CHECK(TcgStartMethodCall(&CreateStruct, TCG_UID_THIS_SP, OPAL_LOCKING_SP_REVERTSP_METHOD));
+ ERROR_CHECK(TcgStartParameters(&CreateStruct));
+
+ if (KeepUserData) {
+ //
+ // optional parameter to keep Data after revert
+ //
+ ERROR_CHECK(TcgAddStartName(&CreateStruct));
+ ERROR_CHECK(TcgAddUINT32(&CreateStruct, 0x060000)); // weird Value but that's what spec says
+ ERROR_CHECK(TcgAddBOOLEAN(&CreateStruct, KeepUserData));
+ ERROR_CHECK(TcgAddEndName(&CreateStruct));
+ }
+
+ ERROR_CHECK(TcgEndParameters(&CreateStruct));
+ ERROR_CHECK(TcgEndMethodCall(&CreateStruct));
+ ERROR_CHECK(TcgEndSubPacket(&CreateStruct));
+ ERROR_CHECK(TcgEndPacket(&CreateStruct));
+ ERROR_CHECK(TcgEndComPacket(&CreateStruct, &Size));
+
+ //
+ // Send RevertSP method call
+ //
+ ERROR_CHECK(OpalPerformMethod(LockingSpSession, Size, Buf, sizeof(Buf), &ParseStruct, MethodStatus));
+
+ //
+ // Session is immediately ended by device after successful revertsp, so no need to end Session
+ //
+ if (*MethodStatus == TCG_METHOD_STATUS_CODE_SUCCESS) {
+ //
+ // Caller should take ownership again
+ //
+ return TcgResultSuccess;
+ } else {
+ //
+ // End Session
+ //
+ METHOD_STATUS_ERROR_CHECK(*MethodStatus, TcgResultSuccess); // exit with success on method failure - user must inspect MethodStatus
+ }
+
+ return TcgResultSuccess;
+}
+
+/**
+
+ The function activates the Locking SP.
+ Once activated, per Opal spec, the ADMIN SP SID PIN is copied over to the ADMIN1 LOCKING SP PIN.
+ If the Locking SP is already enabled, then TcgResultSuccess is returned and no action occurs.
+
+ @param[in] AdminSpSession OPAL_SESSION with OPAL_UID_ADMIN_SP as OPAL_ADMIN_SP_SID_AUTHORITY to activate Locking SP
+ @param[in/out] MethodStatus Method status of last action performed. If action succeeded, it should be TCG_METHOD_STATUS_CODE_SUCCESS.
+
+**/
+TCG_RESULT
+EFIAPI
+OpalActivateLockingSp(
+ OPAL_SESSION *AdminSpSession,
+ UINT8 *MethodStatus
+ )
+{
+ UINT8 Buf[BUFFER_SIZE];
+ TCG_CREATE_STRUCT CreateStruct;
+ UINT32 Size;
+ TCG_PARSE_STRUCT ParseStruct;
+
+ NULL_CHECK(AdminSpSession);
+ NULL_CHECK(MethodStatus);
+
+ //
+ // Call Activate method on Locking SP
+ //
+ ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf)));
+ ERROR_CHECK(TcgStartComPacket(&CreateStruct, AdminSpSession->OpalBaseComId, AdminSpSession->ComIdExtension));
+ ERROR_CHECK(TcgStartPacket(&CreateStruct, AdminSpSession->TperSessionId, AdminSpSession->HostSessionId, 0x0, 0x0, 0x0));
+ ERROR_CHECK(TcgStartSubPacket(&CreateStruct, 0x0));
+ ERROR_CHECK(TcgStartMethodCall(&CreateStruct, OPAL_UID_LOCKING_SP, OPAL_ADMIN_SP_ACTIVATE_METHOD));
+ ERROR_CHECK(TcgStartParameters(&CreateStruct));
+ ERROR_CHECK(TcgEndParameters(&CreateStruct));
+ ERROR_CHECK(TcgEndMethodCall(&CreateStruct));
+ ERROR_CHECK(TcgEndSubPacket(&CreateStruct));
+ ERROR_CHECK(TcgEndPacket(&CreateStruct));
+ ERROR_CHECK(TcgEndComPacket(&CreateStruct, &Size));
+
+ //
+ // Send Activate method call
+ //
+ ERROR_CHECK(OpalPerformMethod(AdminSpSession, Size, Buf, sizeof(Buf), &ParseStruct, MethodStatus));
+ METHOD_STATUS_ERROR_CHECK(*MethodStatus, TcgResultSuccess); // exit with success on method failure - user must inspect MethodStatus
+
+ return TcgResultSuccess;
+}
+
+/**
+
+ The function sets the PIN column of the specified cpinRowUid (authority) with the newPin Value.
+
+ @param[in/out] Session OPAL_SESSION to set password
+ @param[in] CpinRowUid UID of row (authority) to update PIN column
+ @param[in] NewPin New Pin to set for cpinRowUid specified
+ @param[in] NewPinLength Length in bytes of newPin
+ @param[in/out] MethodStatus Method status of last action performed. If action succeeded, it should be TCG_METHOD_STATUS_CODE_SUCCESS.
+
+**/
+TCG_RESULT
+EFIAPI
+OpalSetPassword(
+ OPAL_SESSION *Session,
+ TCG_UID CpinRowUid,
+ const VOID *NewPin,
+ UINT32 NewPinLength,
+ UINT8 *MethodStatus
+ )
+{
+ UINT8 Buf[BUFFER_SIZE];
+ TCG_CREATE_STRUCT CreateStruct;
+ TCG_PARSE_STRUCT ParseStruct;
+ UINT32 Size;
+
+ NULL_CHECK(Session);
+ NULL_CHECK(NewPin);
+ NULL_CHECK(MethodStatus);
+
+ ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf)));
+ ERROR_CHECK(TcgCreateSetCPin(
+ &CreateStruct,
+ &Size,
+ Session->OpalBaseComId,
+ Session->ComIdExtension,
+ Session->TperSessionId,
+ Session->HostSessionId,
+ CpinRowUid,
+ NewPin,
+ NewPinLength
+ ));
+
+ ERROR_CHECK(OpalPerformMethod(Session, Size, Buf, sizeof(Buf), &ParseStruct, MethodStatus));
+ // exit with success on method failure - user must inspect MethodStatus
+ METHOD_STATUS_ERROR_CHECK(*MethodStatus, TcgResultSuccess);
+
+ return TcgResultSuccess;
+}
+
+/**
+
+ The function sets the Enabled column to TRUE for the authorityUid provided and updates the PIN column for the cpinRowUid provided
+ using the newPin provided. AuthorityUid and cpinRowUid should describe the same authority.
+
+ @param[in] LockingSpSession OPAL_SESSION with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_ADMIN1_AUTHORITY to update
+ @param[in] CpinRowUid Row UID of C_PIN table of Locking SP to update PIN
+ @param[in] AuthorityUid UID of Locking SP authority to update Pin column with
+ @param[in] NewPin New Password used to set Pin column
+ @param[in] NewPinLength Length in bytes of new password
+ @param[in/out] MethodStatus Method status of last action performed. If action succeeded, it should be TCG_METHOD_STATUS_CODE_SUCCESS.
+
+**/
+TCG_RESULT
+EFIAPI
+OpalSetLockingSpAuthorityEnabledAndPin(
+ OPAL_SESSION *LockingSpSession,
+ TCG_UID CpinRowUid,
+ TCG_UID AuthorityUid,
+ const VOID *NewPin,
+ UINT32 NewPinLength,
+ UINT8 *MethodStatus
+ )
+{
+ UINT8 Buf[BUFFER_SIZE];
+ TCG_CREATE_STRUCT CreateStruct;
+ TCG_PARSE_STRUCT ParseStruct;
+ UINT32 Size;
+ TCG_UID ActiveKey;
+ TCG_RESULT Ret;
+
+ NULL_CHECK(LockingSpSession);
+ NULL_CHECK(NewPin);
+ NULL_CHECK(MethodStatus);
+
+ ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf)));
+ ERROR_CHECK(TcgSetAuthorityEnabled(
+ &CreateStruct,
+ &Size,
+ LockingSpSession->OpalBaseComId,
+ LockingSpSession->ComIdExtension,
+ LockingSpSession->TperSessionId,
+ LockingSpSession->HostSessionId,
+ AuthorityUid,
+ TRUE));
+
+ ERROR_CHECK(OpalPerformMethod(LockingSpSession, Size, Buf, sizeof(Buf), &ParseStruct, MethodStatus));
+
+ if (*MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) {
+ DEBUG ((DEBUG_INFO, "Send Set Authority error\n"));
+ return TcgResultFailure;
+ }
+
+ ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf)));
+
+ ERROR_CHECK(TcgCreateSetCPin(
+ &CreateStruct,
+ &Size,
+ LockingSpSession->OpalBaseComId,
+ LockingSpSession->ComIdExtension,
+ LockingSpSession->TperSessionId,
+ LockingSpSession->HostSessionId,
+ CpinRowUid,
+ NewPin,
+ NewPinLength));
+
+ ERROR_CHECK(OpalPerformMethod(LockingSpSession, Size, Buf, sizeof(Buf), &ParseStruct, MethodStatus));
+
+ //
+ // allow user1 to set global range to unlocked/locked by modifying ACE_Locking_GlobalRange_SetRdLocked/SetWrLocked
+ //
+ ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf)));
+ ERROR_CHECK(TcgCreateSetAce(
+ &CreateStruct,
+ &Size,
+ LockingSpSession->OpalBaseComId,
+ LockingSpSession->ComIdExtension,
+ LockingSpSession->TperSessionId,
+ LockingSpSession->HostSessionId,
+ OPAL_LOCKING_SP_ACE_LOCKING_GLOBALRANGE_SET_RDLOCKED,
+ OPAL_LOCKING_SP_USER1_AUTHORITY,
+ TCG_ACE_EXPRESSION_OR,
+ OPAL_LOCKING_SP_ADMINS_AUTHORITY
+ ));
+
+ ERROR_CHECK(OpalPerformMethod(LockingSpSession, Size, Buf, sizeof(Buf), &ParseStruct, MethodStatus));
+
+ if (*MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) {
+ DEBUG ((DEBUG_INFO, "Update ACE for RDLOCKED failed\n"));
+ return TcgResultFailure;
+ }
+
+ ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf)));
+ ERROR_CHECK(TcgCreateSetAce(
+ &CreateStruct,
+ &Size,
+ LockingSpSession->OpalBaseComId,
+ LockingSpSession->ComIdExtension,
+ LockingSpSession->TperSessionId,
+ LockingSpSession->HostSessionId,
+ OPAL_LOCKING_SP_ACE_LOCKING_GLOBALRANGE_SET_WRLOCKED,
+ OPAL_LOCKING_SP_USER1_AUTHORITY,
+ TCG_ACE_EXPRESSION_OR,
+ OPAL_LOCKING_SP_ADMINS_AUTHORITY
+ ));
+
+ ERROR_CHECK(OpalPerformMethod(LockingSpSession, Size, Buf, sizeof(Buf), &ParseStruct, MethodStatus));
+
+ if (*MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) {
+ DEBUG ((DEBUG_INFO, "Update ACE for WRLOCKED failed\n"));
+ return TcgResultFailure;
+ }
+
+ ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf)));
+ ERROR_CHECK(OpalCreateRetrieveGlobalLockingRangeActiveKey(LockingSpSession, &CreateStruct, &Size));
+ ERROR_CHECK(OpalPerformMethod(LockingSpSession, Size, Buf, sizeof(Buf), &ParseStruct, MethodStatus));
+
+ //
+ // For Pyrite type SSC, it not supports Active Key.
+ // So here add check logic before enable it.
+ //
+ Ret = OpalParseRetrieveGlobalLockingRangeActiveKey(&ParseStruct, &ActiveKey);
+ if (Ret == TcgResultSuccess) {
+ ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf)));
+ ERROR_CHECK(TcgCreateSetAce(
+ &CreateStruct,
+ &Size,
+ LockingSpSession->OpalBaseComId,
+ LockingSpSession->ComIdExtension,
+ LockingSpSession->TperSessionId,
+ LockingSpSession->HostSessionId,
+ (ActiveKey == OPAL_LOCKING_SP_K_AES_256_GLOBALRANGE_KEY) ? OPAL_LOCKING_SP_ACE_K_AES_256_GLOBALRANGE_GENKEY : OPAL_LOCKING_SP_ACE_K_AES_128_GLOBALRANGE_GENKEY,
+ OPAL_LOCKING_SP_USER1_AUTHORITY,
+ TCG_ACE_EXPRESSION_OR,
+ OPAL_LOCKING_SP_ADMINS_AUTHORITY
+ ));
+
+ ERROR_CHECK(OpalPerformMethod(LockingSpSession, Size, Buf, sizeof(Buf), &ParseStruct, MethodStatus));
+
+ if (*MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) {
+ DEBUG ((DEBUG_INFO, "Update ACE for GLOBALRANGE_GENKEY failed\n"));
+ //
+ // Disable user1 if all permissions are not granted.
+ //
+ return TcgResultFailure;
+ }
+ }
+
+ ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf)));
+ ERROR_CHECK(TcgCreateSetAce(
+ &CreateStruct,
+ &Size,
+ LockingSpSession->OpalBaseComId,
+ LockingSpSession->ComIdExtension,
+ LockingSpSession->TperSessionId,
+ LockingSpSession->HostSessionId,
+ OPAL_LOCKING_SP_ACE_LOCKING_GLOBALRANGE_GET_ALL,
+ OPAL_LOCKING_SP_USER1_AUTHORITY,
+ TCG_ACE_EXPRESSION_OR,
+ OPAL_LOCKING_SP_ADMINS_AUTHORITY
+ ));
+
+ ERROR_CHECK(OpalPerformMethod(LockingSpSession, Size, Buf, sizeof(Buf), &ParseStruct, MethodStatus));
+
+ if (*MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) {
+ DEBUG ((DEBUG_INFO, "Update ACE for OPAL_LOCKING_SP_ACE_LOCKING_GLOBALRANGE_GET_ALL failed\n"));
+ return TcgResultFailure;
+ }
+
+ return TcgResultSuccess;
+}
+
+/**
+
+ The function sets the Enabled column to FALSE for the USER1 authority.
+
+ @param[in] LockingSpSession OPAL_SESSION with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_ADMIN1_AUTHORITY to disable User1
+ @param[in/out] MethodStatus Method status of last action performed. If action succeeded, it should be TCG_METHOD_STATUS_CODE_SUCCESS.
+
+**/
+TCG_RESULT
+EFIAPI
+OpalDisableUser(
+ OPAL_SESSION *LockingSpSession,
+ UINT8 *MethodStatus
+ )
+{
+ UINT8 Buf[BUFFER_SIZE];
+ TCG_CREATE_STRUCT CreateStruct;
+ TCG_PARSE_STRUCT ParseStruct;
+ UINT32 Size;
+
+ NULL_CHECK(LockingSpSession);
+ NULL_CHECK(MethodStatus);
+
+ ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf)));
+ ERROR_CHECK(TcgSetAuthorityEnabled(
+ &CreateStruct,
+ &Size,
+ LockingSpSession->OpalBaseComId,
+ LockingSpSession->ComIdExtension,
+ LockingSpSession->TperSessionId,
+ LockingSpSession->HostSessionId,
+ OPAL_LOCKING_SP_USER1_AUTHORITY,
+ FALSE));
+
+ ERROR_CHECK(OpalPerformMethod(LockingSpSession, Size, Buf, sizeof(Buf), &ParseStruct, MethodStatus));
+
+ return TcgResultSuccess;
+}
+
+/**
+
+ The function retrieves the active key of the global locking range
+ and calls the GenKey method on the active key retrieved.
+
+ @param[in] LockingSpSession OPAL_SESSION with OPAL_UID_LOCKING_SP to generate key
+ @param[in/out] MethodStatus Method status of last action performed. If action succeeded, it should be TCG_METHOD_STATUS_CODE_SUCCESS.
+
+**/
+TCG_RESULT
+EFIAPI
+OpalGlobalLockingRangeGenKey(
+ OPAL_SESSION *LockingSpSession,
+ UINT8 *MethodStatus
+ )
+{
+ UINT8 Buf[BUFFER_SIZE];
+ TCG_CREATE_STRUCT CreateStruct;
+ TCG_PARSE_STRUCT ParseStruct;
+ UINT32 Size;
+ TCG_UID ActiveKey;
+
+ NULL_CHECK(LockingSpSession);
+ NULL_CHECK(MethodStatus);
+
+ ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf)));
+ //
+ // retrieve the activekey in order to know which globalrange key to generate
+ //
+ ERROR_CHECK(OpalCreateRetrieveGlobalLockingRangeActiveKey(LockingSpSession, &CreateStruct, &Size));
+ ERROR_CHECK(OpalPerformMethod(LockingSpSession, Size, Buf, sizeof(Buf), &ParseStruct, MethodStatus));
+
+ METHOD_STATUS_ERROR_CHECK(*MethodStatus, TcgResultSuccess);
+
+ ERROR_CHECK(OpalParseRetrieveGlobalLockingRangeActiveKey(&ParseStruct, &ActiveKey));
+
+ //
+ // call genkey on ActiveKey UID
+ //
+ ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf)));
+ ERROR_CHECK(TcgStartComPacket(&CreateStruct, LockingSpSession->OpalBaseComId, LockingSpSession->ComIdExtension));
+ ERROR_CHECK(TcgStartPacket(&CreateStruct, LockingSpSession->TperSessionId, LockingSpSession->HostSessionId, 0x0, 0x0, 0x0));
+ ERROR_CHECK(TcgStartSubPacket(&CreateStruct, 0x0));
+ ERROR_CHECK(TcgStartMethodCall(&CreateStruct, ActiveKey, TCG_UID_METHOD_GEN_KEY));
+ ERROR_CHECK(TcgStartParameters(&CreateStruct));
+ ERROR_CHECK(TcgEndParameters(&CreateStruct));
+ ERROR_CHECK(TcgEndMethodCall(&CreateStruct));
+ ERROR_CHECK(TcgEndSubPacket(&CreateStruct));
+ ERROR_CHECK(TcgEndPacket(&CreateStruct));
+ ERROR_CHECK(TcgEndComPacket(&CreateStruct, &Size));
+
+ ERROR_CHECK(OpalPerformMethod(LockingSpSession, Size, Buf, sizeof(Buf), &ParseStruct, MethodStatus));
+
+ return TcgResultSuccess;
+}
+
+/**
+
+ The function updates the ReadLocked and WriteLocked columns of the Global Locking Range.
+ This function is required for a user1 authority, since a user1 authority shall only have access to ReadLocked and WriteLocked columns
+ (not ReadLockEnabled and WriteLockEnabled columns).
+
+ @param[in] LockingSpSession OPAL_SESSION with OPAL_UID_LOCKING_SP to generate key
+ @param[in] ReadLocked Value to set ReadLocked column for Global Locking Range
+ @param[in] WriteLocked Value to set WriteLocked column for Global Locking Range
+ @param[in/out] MethodStatus Method status of last action performed. If action succeeded, it should be TCG_METHOD_STATUS_CODE_SUCCESS.
+
+**/
+TCG_RESULT
+EFIAPI
+OpalUpdateGlobalLockingRange(
+ OPAL_SESSION *LockingSpSession,
+ BOOLEAN ReadLocked,
+ BOOLEAN WriteLocked,
+ UINT8 *MethodStatus
+ )
+{
+ UINT8 Buf[BUFFER_SIZE];
+ TCG_CREATE_STRUCT CreateStruct;
+ TCG_PARSE_STRUCT ParseStruct;
+ UINT32 Size;
+
+ NULL_CHECK(LockingSpSession);
+ NULL_CHECK(MethodStatus);
+
+ ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf)));
+
+ //
+ // set global locking range values
+ //
+ ERROR_CHECK(TcgStartComPacket(&CreateStruct, LockingSpSession->OpalBaseComId, LockingSpSession->ComIdExtension));
+ ERROR_CHECK(TcgStartPacket(&CreateStruct, LockingSpSession->TperSessionId, LockingSpSession->HostSessionId, 0x0, 0x0, 0x0));
+ ERROR_CHECK(TcgStartSubPacket(&CreateStruct, 0x0));
+ ERROR_CHECK(TcgStartMethodCall(&CreateStruct, OPAL_LOCKING_SP_LOCKING_GLOBALRANGE, TCG_UID_METHOD_SET));
+ ERROR_CHECK(TcgStartParameters(&CreateStruct));
+ ERROR_CHECK(TcgAddStartName(&CreateStruct));
+ ERROR_CHECK(TcgAddUINT8(&CreateStruct, 0x01)); // "Values"
+ ERROR_CHECK(TcgAddStartList(&CreateStruct));
+
+ ERROR_CHECK(TcgAddStartName(&CreateStruct));
+ ERROR_CHECK(TcgAddUINT8(&CreateStruct, 0x07)); // "ReadLocked"
+ ERROR_CHECK(TcgAddBOOLEAN(&CreateStruct, ReadLocked));
+ ERROR_CHECK(TcgAddEndName(&CreateStruct));
+
+ ERROR_CHECK(TcgAddStartName(&CreateStruct));
+ ERROR_CHECK(TcgAddUINT8(&CreateStruct, 0x08)); // "WriteLocked"
+ ERROR_CHECK(TcgAddBOOLEAN(&CreateStruct, WriteLocked));
+ ERROR_CHECK(TcgAddEndName(&CreateStruct));
+
+ ERROR_CHECK(TcgAddEndList(&CreateStruct));
+ ERROR_CHECK(TcgAddEndName(&CreateStruct));
+ ERROR_CHECK(TcgEndParameters(&CreateStruct));
+ ERROR_CHECK(TcgEndMethodCall(&CreateStruct));
+ ERROR_CHECK(TcgEndSubPacket(&CreateStruct));
+ ERROR_CHECK(TcgEndPacket(&CreateStruct));
+ ERROR_CHECK(TcgEndComPacket(&CreateStruct, &Size));
+
+ ERROR_CHECK(OpalPerformMethod(LockingSpSession, Size, Buf, sizeof(Buf), &ParseStruct, MethodStatus));
+ METHOD_STATUS_ERROR_CHECK(*MethodStatus, TcgResultSuccess);
+
+ return TcgResultSuccess;
+}
+
+/**
+
+ The function updates the RangeStart, RangeLength, ReadLockedEnabled, WriteLockedEnabled, ReadLocked and WriteLocked columns
+ of the specified Locking Range. This function requires admin authority of a locking SP session.
+
+ @param[in] LockingSpSession OPAL_SESSION with OPAL_UID_LOCKING_SP to generate key
+ @param[in] LockingRangeUid Locking range UID to set values
+ @param[in] RangeStart Value to set RangeStart column for Locking Range
+ @param[in] RangeLength Value to set RangeLength column for Locking Range
+ @param[in] ReadLockEnabled Value to set readLockEnabled column for Locking Range
+ @param[in] WriteLockEnabled Value to set writeLockEnabled column for Locking Range
+ @param[in] ReadLocked Value to set ReadLocked column for Locking Range
+ @param[in] WriteLocked Value to set WriteLocked column for Locking Range
+ @param[in/out] MethodStatus Method status of last action performed. If action succeeded, it should be TCG_METHOD_STATUS_CODE_SUCCESS.
+
+**/
+TCG_RESULT
+EFIAPI
+OpalSetLockingRange(
+ OPAL_SESSION *LockingSpSession,
+ TCG_UID LockingRangeUid,
+ UINT64 RangeStart,
+ UINT64 RangeLength,
+ BOOLEAN ReadLockEnabled,
+ BOOLEAN WriteLockEnabled,
+ BOOLEAN ReadLocked,
+ BOOLEAN WriteLocked,
+ UINT8 *MethodStatus
+ )
+{
+ UINT8 Buf[BUFFER_SIZE];
+ TCG_CREATE_STRUCT CreateStruct;
+ TCG_PARSE_STRUCT ParseStruct;
+ UINT32 Size;
+
+ NULL_CHECK(LockingSpSession);
+ NULL_CHECK(MethodStatus);
+
+ ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf)));
+
+ //
+ // set locking range values
+ //
+ ERROR_CHECK(TcgStartComPacket(&CreateStruct, LockingSpSession->OpalBaseComId, LockingSpSession->ComIdExtension));
+ ERROR_CHECK(TcgStartPacket(&CreateStruct, LockingSpSession->TperSessionId, LockingSpSession->HostSessionId, 0x0, 0x0, 0x0));
+ ERROR_CHECK(TcgStartSubPacket(&CreateStruct, 0x0));
+ ERROR_CHECK(TcgStartMethodCall(&CreateStruct, LockingRangeUid, TCG_UID_METHOD_SET));
+ ERROR_CHECK(TcgStartParameters(&CreateStruct));
+ ERROR_CHECK(TcgAddStartName(&CreateStruct));
+ ERROR_CHECK(TcgAddUINT8(&CreateStruct, 0x01)); // "Values"
+ ERROR_CHECK(TcgAddStartList(&CreateStruct));
+
+ //
+ // range start and range Length only apply to non-global locking ranges
+ //
+ if (LockingRangeUid != OPAL_LOCKING_SP_LOCKING_GLOBALRANGE) {
+ ERROR_CHECK(TcgAddStartName(&CreateStruct));
+ ERROR_CHECK(TcgAddUINT8(&CreateStruct, 0x03)); // "RangeStart"
+ ERROR_CHECK(TcgAddUINT64(&CreateStruct, RangeStart));
+ ERROR_CHECK(TcgAddEndName(&CreateStruct));
+
+ ERROR_CHECK(TcgAddStartName(&CreateStruct));
+ ERROR_CHECK(TcgAddUINT8(&CreateStruct, 0x04)); // "RangeLength"
+ ERROR_CHECK(TcgAddUINT64(&CreateStruct, RangeLength));
+ ERROR_CHECK(TcgAddEndName(&CreateStruct));
+ }
+
+ ERROR_CHECK(TcgAddStartName(&CreateStruct));
+ ERROR_CHECK(TcgAddUINT8(&CreateStruct, 0x05)); // "ReadLockEnabled"
+ ERROR_CHECK(TcgAddBOOLEAN(&CreateStruct, ReadLockEnabled));
+ ERROR_CHECK(TcgAddEndName(&CreateStruct));
+
+ ERROR_CHECK(TcgAddStartName(&CreateStruct));
+ ERROR_CHECK(TcgAddUINT8(&CreateStruct, 0x06)); // "WriteLockEnabled"
+ ERROR_CHECK(TcgAddBOOLEAN(&CreateStruct, WriteLockEnabled));
+ ERROR_CHECK(TcgAddEndName(&CreateStruct));
+
+ ERROR_CHECK(TcgAddStartName(&CreateStruct));
+ ERROR_CHECK(TcgAddUINT8(&CreateStruct, 0x07)); // "ReadLocked"
+ ERROR_CHECK(TcgAddBOOLEAN(&CreateStruct, ReadLocked));
+ ERROR_CHECK(TcgAddEndName(&CreateStruct));
+
+ ERROR_CHECK(TcgAddStartName(&CreateStruct));
+ ERROR_CHECK(TcgAddUINT8(&CreateStruct, 0x08)); // "WriteLocked"
+ ERROR_CHECK(TcgAddBOOLEAN(&CreateStruct, WriteLocked));
+ ERROR_CHECK(TcgAddEndName(&CreateStruct));
+
+ ERROR_CHECK(TcgAddEndList(&CreateStruct));
+ ERROR_CHECK(TcgAddEndName(&CreateStruct));
+ ERROR_CHECK(TcgEndParameters(&CreateStruct));
+ ERROR_CHECK(TcgEndMethodCall(&CreateStruct));
+ ERROR_CHECK(TcgEndSubPacket(&CreateStruct));
+ ERROR_CHECK(TcgEndPacket(&CreateStruct));
+ ERROR_CHECK(TcgEndComPacket(&CreateStruct, &Size));
+
+ ERROR_CHECK(OpalPerformMethod(LockingSpSession, Size, Buf, sizeof(Buf), &ParseStruct, MethodStatus));
+ // Exit with success on method failure - user must inspect MethodStatus
+ METHOD_STATUS_ERROR_CHECK(*MethodStatus, TcgResultSuccess);
+
+ return TcgResultSuccess;
+}
+
+/**
+
+ The function populates the CreateStruct with a payload that will retrieve the global locking range active key.
+ It is intended to be called with a session that is already started with a valid credential.
+ The function does not send the payload.
+
+ @param[in] Session OPAL_SESSION to populate command for, needs ComId
+ @param[in/out] CreateStruct Structure to populate with encoded TCG command
+ @param[in/out] Size Size in bytes of the command created.
+
+**/
+TCG_RESULT
+EFIAPI
+OpalCreateRetrieveGlobalLockingRangeActiveKey(
+ const OPAL_SESSION *Session,
+ TCG_CREATE_STRUCT *CreateStruct,
+ UINT32 *Size
+ )
+{
+ NULL_CHECK(Session);
+ NULL_CHECK(CreateStruct);
+ NULL_CHECK(Size);
+
+ // Retrieve the activekey in order to know which globalrange key to generate
+ ERROR_CHECK(TcgStartComPacket(CreateStruct, Session->OpalBaseComId, Session->ComIdExtension));
+ ERROR_CHECK(TcgStartPacket(CreateStruct, Session->TperSessionId, Session->HostSessionId, 0x0, 0x0, 0x0));
+ ERROR_CHECK(TcgStartSubPacket(CreateStruct, 0x0));
+ ERROR_CHECK(TcgStartMethodCall(CreateStruct, OPAL_LOCKING_SP_LOCKING_GLOBALRANGE, TCG_UID_METHOD_GET));
+ ERROR_CHECK(TcgStartParameters(CreateStruct));
+ ERROR_CHECK(TcgAddStartList(CreateStruct));
+ ERROR_CHECK(TcgAddStartName(CreateStruct));
+ ERROR_CHECK(TcgAddUINT8(CreateStruct, TCG_CELL_BLOCK_START_COLUMN_NAME));
+ ERROR_CHECK(TcgAddUINT8(CreateStruct, 0x0A)); // ActiveKey
+ ERROR_CHECK(TcgAddEndName(CreateStruct));
+ ERROR_CHECK(TcgAddStartName(CreateStruct));
+ ERROR_CHECK(TcgAddUINT8(CreateStruct, TCG_CELL_BLOCK_END_COLUMN_NAME));
+ ERROR_CHECK(TcgAddUINT8(CreateStruct, 0x0A));
+ ERROR_CHECK(TcgAddEndName(CreateStruct));
+ ERROR_CHECK(TcgAddEndList(CreateStruct));
+ ERROR_CHECK(TcgEndParameters(CreateStruct));
+ ERROR_CHECK(TcgEndMethodCall(CreateStruct));
+ ERROR_CHECK(TcgEndSubPacket(CreateStruct));
+ ERROR_CHECK(TcgEndPacket(CreateStruct));
+ ERROR_CHECK(TcgEndComPacket(CreateStruct, Size));
+
+ return TcgResultSuccess;
+}
+
+/**
+
+ The function acquires the activeKey specified for the Global Locking Range from the ParseStruct.
+
+ @param[in] ParseStruct Structure that contains the device's response with the activekey
+ @param[in/out] ActiveKey The UID of the active key retrieved
+
+**/
+TCG_RESULT
+EFIAPI
+OpalParseRetrieveGlobalLockingRangeActiveKey(
+ TCG_PARSE_STRUCT *ParseStruct,
+ TCG_UID *ActiveKey
+ )
+{
+ UINT32 ColumnName;
+
+ NULL_CHECK(ParseStruct);
+ NULL_CHECK(ActiveKey);
+
+ // parse response
+ ERROR_CHECK(TcgGetNextStartList(ParseStruct));
+ ERROR_CHECK(TcgGetNextStartList(ParseStruct));
+ ERROR_CHECK(TcgGetNextStartName(ParseStruct));
+ ERROR_CHECK(TcgGetNextUINT32(ParseStruct, &ColumnName));
+ ERROR_CHECK(TcgGetNextTcgUid(ParseStruct, ActiveKey));
+ ERROR_CHECK(TcgGetNextEndName(ParseStruct));
+ ERROR_CHECK(TcgGetNextEndList(ParseStruct));
+ ERROR_CHECK(TcgGetNextEndList(ParseStruct));
+ ERROR_CHECK(TcgGetNextEndOfData(ParseStruct));
+
+ if (ColumnName != 0x0A) {
+ DEBUG ((DEBUG_INFO, "Unexpected column name %u (exp 0x0A)\n", ColumnName));
+ return TcgResultFailure;
+ }
+
+ if (*ActiveKey != OPAL_LOCKING_SP_K_AES_256_GLOBALRANGE_KEY && *ActiveKey != OPAL_LOCKING_SP_K_AES_128_GLOBALRANGE_KEY) {
+ DEBUG ((DEBUG_INFO, "Unexpected gen key %u (exp %u or %u)\n", *ActiveKey, OPAL_LOCKING_SP_K_AES_256_GLOBALRANGE_KEY, OPAL_LOCKING_SP_K_AES_128_GLOBALRANGE_KEY));
+ return TcgResultFailure;
+ }
+
+ return TcgResultSuccess;
+}
+
+/**
+
+ The function retrieves the TryLimit column for the specified rowUid (authority).
+
+ @param[in] LockingSpSession OPAL_SESSION with OPAL_UID_LOCKING_SP to retrieve try limit
+ @param[in] RowUid Row UID of the Locking SP C_PIN table to retrieve TryLimit column
+ @param[in/out] TryLimit Value from TryLimit column
+
+**/
+TCG_RESULT
+EFIAPI
+OpalGetTryLimit(
+ OPAL_SESSION *LockingSpSession,
+ TCG_UID RowUid,
+ UINT32 *TryLimit
+ )
+{
+ TCG_CREATE_STRUCT CreateStruct;
+ TCG_PARSE_STRUCT ParseStruct;
+ UINT32 Size;
+ UINT8 MethodStatus;
+ UINT8 Buf[BUFFER_SIZE];
+ UINT32 Col;
+
+ NULL_CHECK(LockingSpSession);
+ NULL_CHECK(TryLimit);
+
+ ERROR_CHECK(TcgInitTcgCreateStruct(&CreateStruct, Buf, sizeof(Buf)));
+ ERROR_CHECK(TcgStartComPacket(&CreateStruct, LockingSpSession->OpalBaseComId, LockingSpSession->ComIdExtension));
+ ERROR_CHECK(TcgStartPacket(&CreateStruct, LockingSpSession->TperSessionId, LockingSpSession->HostSessionId, 0x0, 0x0, 0x0));
+ ERROR_CHECK(TcgStartSubPacket(&CreateStruct, 0x0));
+ ERROR_CHECK(TcgStartMethodCall(&CreateStruct, RowUid, TCG_UID_METHOD_GET));
+ ERROR_CHECK(TcgStartParameters(&CreateStruct));
+ ERROR_CHECK(TcgAddStartList(&CreateStruct));
+ ERROR_CHECK(TcgAddStartName(&CreateStruct));
+ ERROR_CHECK(TcgAddUINT8(&CreateStruct, TCG_CELL_BLOCK_START_COLUMN_NAME));
+ ERROR_CHECK(TcgAddUINT8(&CreateStruct, OPAL_LOCKING_SP_C_PIN_TRYLIMIT_COL));
+ ERROR_CHECK(TcgAddEndName(&CreateStruct));
+ ERROR_CHECK(TcgAddStartName(&CreateStruct));
+ ERROR_CHECK(TcgAddUINT8(&CreateStruct, TCG_CELL_BLOCK_END_COLUMN_NAME));
+ ERROR_CHECK(TcgAddUINT8(&CreateStruct, OPAL_LOCKING_SP_C_PIN_TRYLIMIT_COL));
+ ERROR_CHECK(TcgAddEndName(&CreateStruct));
+ ERROR_CHECK(TcgAddEndList(&CreateStruct));
+ ERROR_CHECK(TcgEndParameters(&CreateStruct));
+ ERROR_CHECK(TcgEndMethodCall(&CreateStruct));
+ ERROR_CHECK(TcgEndSubPacket(&CreateStruct));
+ ERROR_CHECK(TcgEndPacket(&CreateStruct));
+ ERROR_CHECK(TcgEndComPacket(&CreateStruct, &Size));
+
+ ERROR_CHECK(OpalPerformMethod(LockingSpSession, Size, Buf, sizeof(Buf), &ParseStruct, &MethodStatus));
+ METHOD_STATUS_ERROR_CHECK(MethodStatus, TcgResultFailure);
+
+ ERROR_CHECK(TcgGetNextStartList(&ParseStruct));
+ ERROR_CHECK(TcgGetNextStartList(&ParseStruct));
+ ERROR_CHECK(TcgGetNextStartName(&ParseStruct));
+ ERROR_CHECK(TcgGetNextUINT32(&ParseStruct, &Col));
+ ERROR_CHECK(TcgGetNextUINT32(&ParseStruct, TryLimit));
+ ERROR_CHECK(TcgGetNextEndName(&ParseStruct));
+ ERROR_CHECK(TcgGetNextEndList(&ParseStruct));
+ ERROR_CHECK(TcgGetNextEndList(&ParseStruct));
+ ERROR_CHECK(TcgGetNextEndOfData(&ParseStruct));
+
+ if (Col != OPAL_LOCKING_SP_C_PIN_TRYLIMIT_COL) {
+ DEBUG ((DEBUG_INFO, "ERROR: got col %u, expected %u\n", Col, OPAL_LOCKING_SP_C_PIN_TRYLIMIT_COL));
+ return TcgResultFailure;
+ }
+
+ return TcgResultSuccess;
+}
+
+/**
+
+ Get the support attribute info.
+
+ @param[in] Session OPAL_SESSION with OPAL_UID_LOCKING_SP to retrieve info.
+ @param[out] SupportedAttributes Return the support attribute info.
+ @param[out] OpalBaseComId Return the base com id info.
+
+**/
+TCG_RESULT
+EFIAPI
+OpalGetSupportedAttributesInfo(
+ IN OPAL_SESSION *Session,
+ OUT OPAL_DISK_SUPPORT_ATTRIBUTE *SupportedAttributes,
+ OUT UINT16 *OpalBaseComId
+ )
+{
+ UINT8 Buffer[BUFFER_SIZE];
+ TCG_SUPPORTED_SECURITY_PROTOCOLS *SupportedProtocols;
+ TCG_LEVEL0_DISCOVERY_HEADER *DiscoveryHeader;
+ OPAL_LEVEL0_FEATURE_DESCRIPTOR *Feat;
+ UINTN Size;
+
+ NULL_CHECK(Session);
+ NULL_CHECK(SupportedAttributes);
+ NULL_CHECK(OpalBaseComId);
+
+ ZeroMem(Buffer, BUFFER_SIZE);
+ ASSERT(sizeof(Buffer) >= sizeof(TCG_SUPPORTED_SECURITY_PROTOCOLS));
+
+ //
+ // Retrieve supported protocols verify security protocol 1 is supported
+ //
+ SupportedProtocols = (TCG_SUPPORTED_SECURITY_PROTOCOLS*) Buffer;
+
+ //
+ // Get list of supported protocols
+ //
+ if (OpalRetrieveSupportedProtocolList (Session, sizeof(TCG_SUPPORTED_SECURITY_PROTOCOLS), SupportedProtocols) == TcgResultFailure) {
+ DEBUG ((DEBUG_INFO, "OpalRetrieveSupportedProtocolList failed\n"));
+ return TcgResultFailure;
+ }
+
+ SupportedAttributes->Sp1 = TcgIsProtocolSupported (SupportedProtocols, TCG_OPAL_SECURITY_PROTOCOL_1);
+ SupportedAttributes->Sp2 = TcgIsProtocolSupported (SupportedProtocols, TCG_OPAL_SECURITY_PROTOCOL_2);
+ SupportedAttributes->SpIeee1667 = TcgIsProtocolSupported (SupportedProtocols, TCG_SECURITY_PROTOCOL_IEEE_1667);
+
+ DEBUG ((DEBUG_INFO, "Supported Protocols: Sp1 %d Sp2: %d SpIeee1667 %d \n",
+ SupportedAttributes->Sp1,
+ SupportedAttributes->Sp2,
+ SupportedAttributes->SpIeee1667
+ ));
+
+ //
+ // Perform level 0 discovery and assign desired feature info to Opal Disk structure
+ //
+ ZeroMem (Buffer, BUFFER_SIZE);
+ if (OpalRetrieveLevel0DiscoveryHeader (Session, BUFFER_SIZE, Buffer) == TcgResultFailure) {
+ DEBUG ((DEBUG_INFO, "OpalRetrieveLevel0DiscoveryHeader failed\n"));
+ return TcgResultFailure;
+ }
+
+ //
+ // Check for required feature descriptors
+ //
+ DiscoveryHeader = (TCG_LEVEL0_DISCOVERY_HEADER*) Buffer;
+
+ Size = 0;
+ Feat = (OPAL_LEVEL0_FEATURE_DESCRIPTOR*) TcgGetFeature (DiscoveryHeader, TCG_FEATURE_OPAL_SSC_V2_0_0, &Size);
+ SupportedAttributes->OpalSsc2 = (Feat != NULL);
+
+ *OpalBaseComId = TCG_RESERVED_COMID;
+
+ //
+ // Check Opal SCC V2 has valid settings for SID C_PIN on revert
+ //
+ if (SupportedAttributes->OpalSsc2 && Size >= sizeof (OPAL_SSCV2_FEATURE_DESCRIPTOR)) {
+ //
+ // Want opposite polarity b/c Value is greater than a bit, but we only care about non-zero vs zero
+ //
+ SupportedAttributes->InitCpinIndicator = (Feat->OpalSscV2.InitialCPINSIDPIN == 0);
+ SupportedAttributes->CpinUponRevert = (Feat->OpalSscV2.CPINSIDPINRevertBehavior == 0);
+ DEBUG ((DEBUG_INFO, "Opal SSC V2 InitCpinIndicator %d CpinUponRevert %d \n",
+ SupportedAttributes->InitCpinIndicator,
+ SupportedAttributes->CpinUponRevert
+ ));
+ *OpalBaseComId = SwapBytes16 (Feat->OpalSscV2.BaseComdIdBE);
+ }
+
+ Size = 0;
+ Feat = (OPAL_LEVEL0_FEATURE_DESCRIPTOR*) TcgGetFeature (DiscoveryHeader, TCG_FEATURE_OPAL_SSC_LITE, &Size);
+ SupportedAttributes->OpalSscLite = (Feat != NULL);
+
+ if (Feat != NULL && Size >= sizeof (OPAL_SSCLITE_FEATURE_DESCRIPTOR)) {
+ if (*OpalBaseComId == TCG_RESERVED_COMID) {
+ //
+ // Pin values used always match up with ComId used
+ //
+ *OpalBaseComId = SwapBytes16 (Feat->OpalSscLite.BaseComdIdBE);
+ SupportedAttributes->InitCpinIndicator = (Feat->OpalSscV2.InitialCPINSIDPIN == 0);
+ SupportedAttributes->CpinUponRevert = (Feat->OpalSscV2.CPINSIDPINRevertBehavior == 0);
+ DEBUG ((DEBUG_INFO, "Opal SSC Lite InitCpinIndicator %d CpinUponRevert %d \n",
+ SupportedAttributes->InitCpinIndicator,
+ SupportedAttributes->CpinUponRevert
+ ));
+ }
+ }
+
+ Size = 0;
+ Feat = (OPAL_LEVEL0_FEATURE_DESCRIPTOR*) TcgGetFeature (DiscoveryHeader, TCG_FEATURE_PYRITE_SSC, &Size);
+ SupportedAttributes->PyriteSsc = (Feat != NULL);
+ if (Feat != NULL && Size >= sizeof (PYRITE_SSC_FEATURE_DESCRIPTOR)) {
+ if (*OpalBaseComId == TCG_RESERVED_COMID) {
+ *OpalBaseComId = SwapBytes16 (Feat->PyriteSsc.BaseComdIdBE);
+ SupportedAttributes->InitCpinIndicator = (Feat->PyriteSsc.InitialCPINSIDPIN == 0);
+ SupportedAttributes->CpinUponRevert = (Feat->PyriteSsc.CPINSIDPINRevertBehavior == 0);
+ DEBUG ((DEBUG_INFO, "Pyrite SSC InitCpinIndicator %d CpinUponRevert %d \n",
+ SupportedAttributes->InitCpinIndicator,
+ SupportedAttributes->CpinUponRevert
+ ));
+ }
+ }
+
+ Size = 0;
+ Feat = (OPAL_LEVEL0_FEATURE_DESCRIPTOR*) TcgGetFeature (DiscoveryHeader, TCG_FEATURE_OPAL_SSC_V1_0_0, &Size);
+ SupportedAttributes->OpalSsc1 = (Feat != NULL);
+ if (Feat != NULL && Size >= sizeof (OPAL_SSCV1_FEATURE_DESCRIPTOR)) {
+ if (*OpalBaseComId == TCG_RESERVED_COMID) {
+ *OpalBaseComId = SwapBytes16 (Feat->OpalSscV1.BaseComdIdBE);
+ }
+ }
+
+ Size = 0;
+ Feat = (OPAL_LEVEL0_FEATURE_DESCRIPTOR*) TcgGetFeature (DiscoveryHeader, TCG_FEATURE_LOCKING, &Size);
+ if (Feat != NULL && Size >= sizeof (TCG_LOCKING_FEATURE_DESCRIPTOR)) {
+ SupportedAttributes->MediaEncryption = Feat->Locking.MediaEncryption;
+ }
+
+ Size = 0;
+ Feat = (OPAL_LEVEL0_FEATURE_DESCRIPTOR*) TcgGetFeature (DiscoveryHeader, TCG_FEATURE_BLOCK_SID, &Size);
+ if (Feat != NULL && Size >= sizeof (TCG_BLOCK_SID_FEATURE_DESCRIPTOR)) {
+ SupportedAttributes->BlockSid = TRUE;
+ }
+
+ DEBUG ((DEBUG_INFO, "Base COMID 0x%04X \n", *OpalBaseComId));
+
+
+ return TcgResultSuccess;
+}
+
+/**
+
+ Get the support attribute info.
+
+ @param[in] Session OPAL_SESSION with OPAL_UID_LOCKING_SP to retrieve info.
+ @param[in/out] LockingFeature Return the Locking info.
+
+**/
+TCG_RESULT
+EFIAPI
+OpalGetLockingInfo(
+ OPAL_SESSION *Session,
+ TCG_LOCKING_FEATURE_DESCRIPTOR *LockingFeature
+ )
+{
+ UINT8 Buffer[BUFFER_SIZE];
+ TCG_LEVEL0_DISCOVERY_HEADER *DiscoveryHeader;
+ OPAL_LEVEL0_FEATURE_DESCRIPTOR *Feat;
+ UINTN Size;
+
+ NULL_CHECK(Session);
+ NULL_CHECK(LockingFeature);
+
+ ZeroMem(Buffer, BUFFER_SIZE);
+ ASSERT(sizeof(Buffer) >= sizeof(TCG_SUPPORTED_SECURITY_PROTOCOLS));
+
+ if (OpalRetrieveLevel0DiscoveryHeader (Session, BUFFER_SIZE, Buffer) == TcgResultFailure) {
+ DEBUG ((DEBUG_INFO, "OpalRetrieveLevel0DiscoveryHeader failed\n"));
+ return TcgResultFailure;
+ }
+ DiscoveryHeader = (TCG_LEVEL0_DISCOVERY_HEADER*) Buffer;
+
+ Size = 0;
+ Feat = (OPAL_LEVEL0_FEATURE_DESCRIPTOR*) TcgGetFeature (DiscoveryHeader, TCG_FEATURE_LOCKING, &Size);
+ if (Feat != NULL && Size >= sizeof (TCG_LOCKING_FEATURE_DESCRIPTOR)) {
+ CopyMem (LockingFeature, &Feat->Locking, sizeof (TCG_LOCKING_FEATURE_DESCRIPTOR));
+ }
+
+ return TcgResultSuccess;
+}
+
+/**
+
+ The function determines whether or not all of the requirements for the Opal Feature (not full specification)
+ are met by the specified device.
+
+ @param[in] SupportedAttributes Opal device attribute.
+
+**/
+BOOLEAN
+EFIAPI
+OpalFeatureSupported(
+ OPAL_DISK_SUPPORT_ATTRIBUTE *SupportedAttributes
+ )
+{
+ NULL_CHECK(SupportedAttributes);
+
+ if (SupportedAttributes->Sp1 == 0) {
+ return FALSE;
+ }
+
+ if (SupportedAttributes->OpalSscLite == 0 &&
+ SupportedAttributes->OpalSsc1 == 0 &&
+ SupportedAttributes->OpalSsc2 == 0 &&
+ SupportedAttributes->PyriteSsc == 0
+ ) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+
+ The function returns whether or not the device is Opal Enabled.
+ TRUE means that the device is partially or fully locked.
+ This will perform a Level 0 Discovery and parse the locking feature descriptor
+
+ @param[in] SupportedAttributes Opal device attribute.
+ @param[in] LockingFeature Opal device locking status.
+
+
+**/
+BOOLEAN
+EFIAPI
+OpalFeatureEnabled(
+ OPAL_DISK_SUPPORT_ATTRIBUTE *SupportedAttributes,
+ TCG_LOCKING_FEATURE_DESCRIPTOR *LockingFeature
+ )
+{
+ NULL_CHECK(SupportedAttributes);
+ NULL_CHECK(LockingFeature);
+
+ if (!OpalFeatureSupported (SupportedAttributes)) {
+ return FALSE;
+ }
+
+ if (LockingFeature->LockingSupported && LockingFeature->LockingEnabled) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+
+ The function returns whether or not the device is Opal Locked.
+ TRUE means that the device is partially or fully locked.
+ This will perform a Level 0 Discovery and parse the locking feature descriptor
+
+ @param[in] SupportedAttributes Opal device attribute.
+ @param[in] LockingFeature Opal device locking status.
+
+**/
+BOOLEAN
+OpalDeviceLocked(
+ OPAL_DISK_SUPPORT_ATTRIBUTE *SupportedAttributes,
+ TCG_LOCKING_FEATURE_DESCRIPTOR *LockingFeature
+ )
+{
+ NULL_CHECK(SupportedAttributes);
+ NULL_CHECK(LockingFeature);
+
+ if (!OpalFeatureEnabled (SupportedAttributes, LockingFeature)) {
+ return FALSE;
+ }
+
+ return LockingFeature->Locked;
+}
+
diff --git a/Core/SecurityPkg/Library/TcgStorageOpalLib/TcgStorageOpalLib.inf b/Core/SecurityPkg/Library/TcgStorageOpalLib/TcgStorageOpalLib.inf
new file mode 100644
index 0000000000..ec26111ee2
--- /dev/null
+++ b/Core/SecurityPkg/Library/TcgStorageOpalLib/TcgStorageOpalLib.inf
@@ -0,0 +1,47 @@
+## @file
+# This is a Tcg storage Opal library.
+#
+# This module is used to provide API used by Opal password solution.
+#
+# Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+[Defines]
+ INF_VERSION = 0x00010017
+ BASE_NAME = TcgStorageOpalLib
+ FILE_GUID = F8B56221-FD5D-4215-B578-C3574AD1E253
+ VERSION_STRING = 1.0
+ MODULE_TYPE = BASE
+ LIBRARY_CLASS = TcgStorageOpalLib|DXE_DRIVER DXE_CORE DXE_SMM_DRIVER
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ TcgStorageOpalCore.c
+ TcgStorageOpalUtil.c
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ PrintLib
+ DebugLib
+ TimerLib
+ TcgStorageCoreLib
+ UefiLib
+
+[Packages]
+ MdePkg/MdePkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[Protocols]
+ gEfiStorageSecurityCommandProtocolGuid ## CONSUMES
diff --git a/Core/SecurityPkg/Library/TcgStorageOpalLib/TcgStorageOpalUtil.c b/Core/SecurityPkg/Library/TcgStorageOpalLib/TcgStorageOpalUtil.c
new file mode 100644
index 0000000000..f77fbe25c1
--- /dev/null
+++ b/Core/SecurityPkg/Library/TcgStorageOpalLib/TcgStorageOpalUtil.c
@@ -0,0 +1,914 @@
+/** @file
+ Public API for Opal Core library.
+
+Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+#include <Uefi.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/TcgStorageOpalLib.h>
+
+
+/**
+ Creates a session with OPAL_UID_ADMIN_SP as OPAL_ADMIN_SP_PSID_AUTHORITY, then reverts device using Admin SP Revert method.
+
+ @param[in] Session, The session info for one opal device.
+ @param[in] Psid PSID of device to revert.
+ @param[in] PsidLength Length of PSID in bytes.
+
+**/
+TCG_RESULT
+EFIAPI
+OpalUtilPsidRevert(
+ OPAL_SESSION *Session,
+ const VOID *Psid,
+ UINT32 PsidLength
+ )
+{
+ UINT8 MethodStatus;
+ TCG_RESULT Ret;
+
+ NULL_CHECK(Session);
+ NULL_CHECK(Psid);
+
+ Ret = OpalStartSession(
+ Session,
+ OPAL_UID_ADMIN_SP,
+ TRUE,
+ PsidLength,
+ Psid,
+ OPAL_ADMIN_SP_PSID_AUTHORITY,
+ &MethodStatus);
+ if (Ret == TcgResultSuccess && MethodStatus == TCG_METHOD_STATUS_CODE_SUCCESS) {
+ Ret = OpalPsidRevert(Session);
+ if (Ret != TcgResultSuccess) {
+ //
+ // If revert was successful, session was already ended by TPer, so only end session on failure
+ //
+ OpalEndSession(Session);
+ }
+ }
+
+ if (MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) {
+ Ret = TcgResultFailure;
+ }
+
+ return Ret;
+}
+
+/**
+ Opens a session with OPAL_UID_ADMIN_SP as OPAL_ADMIN_SP_SID_AUTHORITY,
+ sets the OPAL_UID_ADMIN_SP_C_PIN_SID column with the new password,
+ and activates the locking SP to copy SID PIN to Admin1 Locking SP PIN
+
+ @param[in] Session, The session info for one opal device.
+ @param[in] GeneratedSid Generated SID of disk
+ @param[in] SidLength Length of generatedSid in bytes
+ @param[in] Password New admin password to set
+ @param[in] PassLength Length of password in bytes
+
+**/
+TCG_RESULT
+EFIAPI
+OpalUtilSetAdminPasswordAsSid(
+ OPAL_SESSION *Session,
+ const VOID *GeneratedSid,
+ UINT32 SidLength,
+ const VOID *Password,
+ UINT32 PassLength
+ )
+{
+ UINT8 MethodStatus;
+ TCG_RESULT Ret;
+
+ NULL_CHECK(Session);
+ NULL_CHECK(GeneratedSid);
+ NULL_CHECK(Password);
+
+ Ret = OpalStartSession(
+ Session,
+ OPAL_UID_ADMIN_SP,
+ TRUE,
+ SidLength,
+ GeneratedSid,
+ OPAL_ADMIN_SP_SID_AUTHORITY,
+ &MethodStatus
+ );
+ if (Ret != TcgResultSuccess || MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) {
+ DEBUG ((DEBUG_INFO, "start session with admin SP as SID authority failed: Ret=%d MethodStatus=%u\n", Ret, MethodStatus));
+ goto done;
+ }
+
+ //
+ // 1. Update SID = new Password
+ //
+ Ret = OpalSetPassword(
+ Session,
+ OPAL_UID_ADMIN_SP_C_PIN_SID,
+ Password,
+ PassLength,
+ &MethodStatus
+ );
+
+ if (Ret != TcgResultSuccess || MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) {
+ OpalEndSession(Session);
+ DEBUG ((DEBUG_INFO, "set Password failed: Ret=%d MethodStatus=%u\n", Ret, MethodStatus));
+ goto done;
+ }
+
+ //
+ // 2. Activate locking SP
+ //
+ Ret = OpalActivateLockingSp(Session, &MethodStatus);
+ OpalEndSession(Session);
+ if (Ret != TcgResultSuccess || MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) {
+ DEBUG ((DEBUG_INFO, "activate locking SP failed: Ret=%d MethodStatus=%u\n", Ret, MethodStatus));
+ goto done;
+ }
+
+done:
+ if (MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) {
+ Ret = TcgResultFailure;
+ }
+ return Ret;
+}
+
+/**
+
+ Opens a session with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_ADMIN1_AUTHORITY,
+ and updates the specified locking range with the provided column values
+
+ @param[in] Session, The session info for one opal device.
+ @param[in] Password New admin password to set
+ @param[in] PassLength Length of password in bytes
+ @param[in] LockingRangeUid Locking range UID to set values
+ @param[in] RangeStart Value to set RangeStart column for Locking Range
+ @param[in] RangeLength Value to set RangeLength column for Locking Range
+ @param[in] ReadLockEnabled Value to set readLockEnabled column for Locking Range
+ @param[in] WriteLockEnabled Value to set writeLockEnabled column for Locking Range
+ @param[in] ReadLocked Value to set ReadLocked column for Locking Range
+ @param[in] WriteLocked Value to set WriteLocked column for Locking Range
+
+**/
+TCG_RESULT
+EFIAPI
+OpalUtilSetOpalLockingRange(
+ OPAL_SESSION *Session,
+ const VOID *Password,
+ UINT32 PassLength,
+ TCG_UID LockingRangeUid,
+ UINT64 RangeStart,
+ UINT64 RangeLength,
+ BOOLEAN ReadLockEnabled,
+ BOOLEAN WriteLockEnabled,
+ BOOLEAN ReadLocked,
+ BOOLEAN WriteLocked
+ )
+{
+ UINT8 MethodStatus;
+ TCG_RESULT Ret;
+
+ NULL_CHECK(Session);
+ NULL_CHECK(Password);
+
+ //
+ // Start session with Locking SP using current admin Password
+ //
+ Ret = OpalStartSession(
+ Session,
+ OPAL_UID_LOCKING_SP,
+ TRUE,
+ PassLength,
+ Password,
+ OPAL_LOCKING_SP_ADMIN1_AUTHORITY,
+ &MethodStatus);
+ if ((Ret != TcgResultSuccess) || (MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS)) {
+ DEBUG ((DEBUG_INFO, "start session with locking SP failed: Ret=%d MethodStatus=%u\n", Ret, MethodStatus));
+ goto done;
+ }
+
+ //
+ // Enable locking range
+ //
+ Ret = OpalSetLockingRange(
+ Session,
+ LockingRangeUid,
+ RangeStart,
+ RangeLength,
+ ReadLockEnabled,
+ WriteLockEnabled,
+ ReadLocked,
+ WriteLocked,
+ &MethodStatus);
+
+ OpalEndSession(Session);
+ if (Ret != TcgResultSuccess || MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) {
+ DEBUG ((DEBUG_INFO, "set locking range failed: Ret=%d MethodStatus=0x%x\n", Ret, MethodStatus));
+ }
+
+done:
+ if (MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) {
+ Ret = TcgResultFailure;
+ }
+ return Ret;
+}
+
+/**
+ Opens a session with OPAL_UID_ADMIN_SP as OPAL_ADMIN_SP_SID_AUTHORITY,
+ sets OPAL_UID_ADMIN_SP_C_PIN_SID with the new password,
+ and sets OPAL_LOCKING_SP_C_PIN_ADMIN1 with the new password.
+
+ @param[in] Session, The session info for one opal device.
+ @param[in] OldPassword Current admin password
+ @param[in] OldPasswordLength Length of current admin password in bytes
+ @param[in] NewPassword New admin password to set
+ @param[in] NewPasswordLength Length of new password in bytes
+
+**/
+TCG_RESULT
+EFIAPI
+OpalUtilSetAdminPassword(
+ OPAL_SESSION *Session,
+ const VOID *OldPassword,
+ UINT32 OldPasswordLength,
+ const VOID *NewPassword,
+ UINT32 NewPasswordLength
+ )
+{
+ TCG_RESULT Ret;
+ UINT8 MethodStatus;
+
+ NULL_CHECK(Session);
+ NULL_CHECK(OldPassword);
+ NULL_CHECK(NewPassword);
+
+ //
+ // Unknown ownership
+ //
+ Ret = OpalStartSession(
+ Session,
+ OPAL_UID_ADMIN_SP,
+ TRUE,
+ OldPasswordLength,
+ OldPassword,
+ OPAL_ADMIN_SP_SID_AUTHORITY,
+ &MethodStatus
+ );
+ if (Ret != TcgResultSuccess || MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) {
+ DEBUG ((DEBUG_INFO, "start session with admin SP using old Password failed\n"));
+ goto done;
+ }
+
+ //
+ // Update SID = new pw
+ //
+ Ret = OpalSetPassword(Session, OPAL_UID_ADMIN_SP_C_PIN_SID, NewPassword, NewPasswordLength, &MethodStatus);
+ OpalEndSession(Session);
+ if (Ret != TcgResultSuccess || MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) {
+ DEBUG ((DEBUG_INFO, "set new admin SP Password failed\n"));
+ goto done;
+ }
+
+ Ret = OpalStartSession(
+ Session,
+ OPAL_UID_LOCKING_SP,
+ TRUE,
+ OldPasswordLength,
+ OldPassword,
+ OPAL_LOCKING_SP_ADMIN1_AUTHORITY,
+ &MethodStatus
+ );
+ if (Ret != TcgResultSuccess || MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) {
+ DEBUG ((DEBUG_INFO, "start session with locking SP using old Password failed\n"));
+ goto done;
+ }
+
+ //
+ // Update admin locking SP to new pw
+ //
+ Ret = OpalSetPassword(Session, OPAL_LOCKING_SP_C_PIN_ADMIN1, NewPassword, NewPasswordLength, &MethodStatus);
+ OpalEndSession(Session);
+ if (Ret != TcgResultSuccess || MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) {
+ DEBUG ((DEBUG_INFO, "set new locking SP Password failed\n"));
+ goto done;
+ }
+
+done:
+ if (MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) {
+ Ret = TcgResultFailure;
+ }
+ return Ret;
+}
+
+/**
+ Starts a session with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_USER1_AUTHORITY or OPAL_LOCKING_SP_ADMIN1_AUTHORITY
+ and sets the User1 SP authority to enabled and sets the User1 password.
+
+ @param[in] Session, The session info for one opal device.
+ @param[in] OldPassword Current admin password
+ @param[in] OldPasswordLength Length of current admin password in bytes
+ @param[in] NewPassword New admin password to set
+ @param[in] NewPasswordLength Length of new password in bytes
+
+**/
+TCG_RESULT
+EFIAPI
+OpalUtilSetUserPassword(
+ OPAL_SESSION *Session,
+ const VOID *OldPassword,
+ UINT32 OldPasswordLength,
+ const VOID *NewPassword,
+ UINT32 NewPasswordLength
+ )
+{
+ UINT8 MethodStatus;
+ TCG_RESULT Ret;
+
+ NULL_CHECK(Session);
+ NULL_CHECK(OldPassword);
+ NULL_CHECK(NewPassword);
+
+ //
+ // See if updating user1 authority
+ //
+ Ret = OpalStartSession(
+ Session,
+ OPAL_UID_LOCKING_SP,
+ TRUE,
+ OldPasswordLength,
+ OldPassword,
+ OPAL_LOCKING_SP_USER1_AUTHORITY,
+ &MethodStatus
+ );
+ if (Ret == TcgResultSuccess && MethodStatus == TCG_METHOD_STATUS_CODE_SUCCESS) {
+ Ret = OpalSetPassword(
+ Session,
+ OPAL_LOCKING_SP_C_PIN_USER1,
+ NewPassword,
+ NewPasswordLength,
+ &MethodStatus
+ );
+ OpalEndSession(Session);
+ if (Ret == TcgResultSuccess && MethodStatus == TCG_METHOD_STATUS_CODE_SUCCESS) {
+ return Ret;
+ }
+ }
+
+ //
+ // Setting Password for first time or setting Password as admin
+ //
+
+ //
+ // Start session with Locking SP using current admin Password
+ //
+ Ret = OpalStartSession(
+ Session,
+ OPAL_UID_LOCKING_SP,
+ TRUE,
+ OldPasswordLength,
+ OldPassword,
+ OPAL_LOCKING_SP_ADMIN1_AUTHORITY,
+ &MethodStatus
+ );
+ if (Ret != TcgResultSuccess || MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) {
+ DEBUG ((DEBUG_INFO, "StartSession with locking SP as admin1 authority failed\n"));
+ goto done;
+ }
+
+ //
+ // Enable User1 and set its PIN
+ //
+ Ret = OpalSetLockingSpAuthorityEnabledAndPin(
+ Session,
+ OPAL_LOCKING_SP_C_PIN_USER1,
+ OPAL_LOCKING_SP_USER1_AUTHORITY,
+ NewPassword,
+ NewPasswordLength,
+ &MethodStatus
+ );
+ OpalEndSession(Session);
+ if (Ret != TcgResultSuccess || MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) {
+ DEBUG ((DEBUG_INFO, "OpalSetLockingSpAuthorityEnabledAndPin failed\n"));
+ goto done;
+ }
+
+done:
+ if (MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) {
+ Ret = TcgResultFailure;
+ }
+ return Ret;
+}
+
+/**
+ Verify whether user input the correct password.
+
+ @param[in] Session, The session info for one opal device.
+ @param[in] Password Admin password
+ @param[in] PasswordLength Length of password in bytes
+ @param[in/out] HostSigningAuthority Use the Host signing authority type.
+
+**/
+TCG_RESULT
+EFIAPI
+OpalUtilVerifyPassword (
+ OPAL_SESSION *Session,
+ const VOID *Password,
+ UINT32 PasswordLength,
+ TCG_UID HostSigningAuthority
+ )
+{
+ TCG_RESULT Ret;
+ UINT8 MethodStatus;
+
+ NULL_CHECK(Session);
+ NULL_CHECK(Password);
+
+ Ret = OpalStartSession(
+ Session,
+ OPAL_UID_LOCKING_SP,
+ TRUE,
+ PasswordLength,
+ Password,
+ HostSigningAuthority,
+ &MethodStatus);
+ if (Ret == TcgResultSuccess && MethodStatus == TCG_METHOD_STATUS_CODE_SUCCESS) {
+ OpalEndSession(Session);
+ return TcgResultSuccess;
+ }
+
+ return TcgResultFailure;
+}
+
+/**
+ Starts a session with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_USER1_AUTHORITY or OPAL_LOCKING_SP_ADMIN1_AUTHORITY
+ and generates a new global locking range key to erase the Data.
+
+ @param[in] Session, The session info for one opal device.
+ @param[in] Password Admin or user password
+ @param[in] PasswordLength Length of password in bytes
+ @param[in/out] PasswordFailed indicates if password failed (start session didn't work)
+
+**/
+TCG_RESULT
+EFIAPI
+OpalUtilSecureErase(
+ OPAL_SESSION *Session,
+ const VOID *Password,
+ UINT32 PasswordLength,
+ BOOLEAN *PasswordFailed
+ )
+{
+ UINT8 MethodStatus;
+ TCG_RESULT Ret;
+
+ NULL_CHECK(Session);
+ NULL_CHECK(Password);
+ NULL_CHECK(PasswordFailed);
+
+ //
+ // Try to generate a new key with admin1
+ //
+ Ret = OpalStartSession(
+ Session,
+ OPAL_UID_LOCKING_SP,
+ TRUE,
+ PasswordLength,
+ Password,
+ OPAL_LOCKING_SP_ADMIN1_AUTHORITY,
+ &MethodStatus
+ );
+
+ if (Ret == TcgResultSuccess && MethodStatus == TCG_METHOD_STATUS_CODE_SUCCESS) {
+ Ret = OpalGlobalLockingRangeGenKey(Session, &MethodStatus);
+ *PasswordFailed = FALSE;
+ OpalEndSession(Session);
+ } else {
+ //
+ // Try to generate a new key with user1
+ //
+ Ret = OpalStartSession(
+ Session,
+ OPAL_UID_LOCKING_SP,
+ TRUE,
+ PasswordLength,
+ Password,
+ OPAL_LOCKING_SP_USER1_AUTHORITY,
+ &MethodStatus
+ );
+
+ if (Ret == TcgResultSuccess && MethodStatus == TCG_METHOD_STATUS_CODE_SUCCESS) {
+ Ret = OpalGlobalLockingRangeGenKey(Session, &MethodStatus);
+ *PasswordFailed = FALSE;
+ OpalEndSession(Session);
+ } else {
+ *PasswordFailed = TRUE;
+ }
+ }
+
+ if (MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) {
+ Ret = TcgResultFailure;
+ }
+ return Ret;
+}
+
+/**
+ Starts a session with OPAL_UID_LOCKING_SP as OPAL_LOCKING_SP_ADMIN1_AUTHORITY and disables the User1 authority.
+
+ @param[in] Session, The session info for one opal device.
+ @param[in] Password Admin password
+ @param[in] PasswordLength Length of password in bytes
+ @param[in/out] PasswordFailed indicates if password failed (start session didn't work)
+
+**/
+TCG_RESULT
+EFIAPI
+OpalUtilDisableUser(
+ OPAL_SESSION *Session,
+ const VOID *Password,
+ UINT32 PasswordLength,
+ BOOLEAN *PasswordFailed
+ )
+{
+ UINT8 MethodStatus;
+ TCG_RESULT Ret;
+
+ NULL_CHECK(Session);
+ NULL_CHECK(Password);
+ NULL_CHECK(PasswordFailed);
+
+ //
+ // Start session with Locking SP using current admin Password
+ //
+ Ret = OpalStartSession(
+ Session,
+ OPAL_UID_LOCKING_SP,
+ TRUE,
+ PasswordLength,
+ Password,
+ OPAL_LOCKING_SP_ADMIN1_AUTHORITY,
+ &MethodStatus
+ );
+ if (Ret != TcgResultSuccess || MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) {
+ DEBUG ((DEBUG_INFO, "StartSession with Locking SP as Admin1 failed\n"));
+ *PasswordFailed = TRUE;
+ goto done;
+ }
+
+ *PasswordFailed = FALSE;
+ Ret = OpalDisableUser(Session, &MethodStatus);
+ OpalEndSession(Session);
+
+done:
+ if (MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) {
+ Ret = TcgResultFailure;
+ }
+ return Ret;
+}
+
+/**
+ Opens a session with OPAL_UID_ADMIN_SP as OPAL_ADMIN_SP_PSID_AUTHORITY, then reverts the device using the RevertSP method.
+
+ @param[in] Session, The session info for one opal device.
+ @param[in] KeepUserData TRUE to keep existing Data on the disk, or FALSE to erase it
+ @param[in] Password Admin password
+ @param[in] PasswordLength Length of password in bytes
+ @param[in/out] PasswordFailed indicates if password failed (start session didn't work)
+ @param[in] Msid Msid info.
+ @param[in] MsidLength Msid data length.
+
+**/
+TCG_RESULT
+EFIAPI
+OpalUtilRevert(
+ OPAL_SESSION *Session,
+ BOOLEAN KeepUserData,
+ const VOID *Password,
+ UINT32 PasswordLength,
+ BOOLEAN *PasswordFailed,
+ UINT8 *Msid,
+ UINT32 MsidLength
+ )
+{
+ UINT8 MethodStatus;
+ TCG_RESULT Ret;
+
+ NULL_CHECK(Session);
+ NULL_CHECK(Msid);
+ NULL_CHECK(Password);
+ NULL_CHECK(PasswordFailed);
+
+ Ret = OpalStartSession(
+ Session,
+ OPAL_UID_LOCKING_SP,
+ TRUE,
+ PasswordLength,
+ Password,
+ OPAL_LOCKING_SP_ADMIN1_AUTHORITY,
+ &MethodStatus
+ );
+
+ if (Ret != TcgResultSuccess || MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) {
+ DEBUG ((DEBUG_INFO, "error starting session: Ret=%d, MethodStatus=%u\n", Ret, MethodStatus));
+ *PasswordFailed = TRUE;
+ goto done;
+ }
+
+ *PasswordFailed = FALSE;
+ //
+ // Try to revert with admin1
+ //
+ Ret = OpalAdminRevert(Session, KeepUserData, &MethodStatus);
+ if (Ret != TcgResultSuccess || MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) {
+ //
+ // Device ends the session on successful revert, so only call OpalEndSession when fail.
+ //
+ DEBUG ((DEBUG_INFO, "OpalAdminRevert as admin failed\n"));
+ OpalEndSession(Session);
+ }
+
+ Ret = OpalUtilSetSIDtoMSID (Session, Password, PasswordLength, Msid, MsidLength);
+
+done:
+ if (MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) {
+ Ret = TcgResultFailure;
+ }
+ return Ret;
+}
+
+/**
+ After revert success, set SID to MSID.
+
+ @param Session, The session info for one opal device.
+ @param Password, Input password info.
+ @param PasswordLength, Input password length.
+ @param Msid Msid info.
+ @param MsidLength Msid data length.
+
+**/
+TCG_RESULT
+EFIAPI
+OpalUtilSetSIDtoMSID (
+ OPAL_SESSION *Session,
+ const VOID *Password,
+ UINT32 PasswordLength,
+ UINT8 *Msid,
+ UINT32 MsidLength
+ )
+{
+ TCG_RESULT Ret;
+ UINT8 MethodStatus;
+
+ NULL_CHECK(Session);
+ NULL_CHECK(Msid);
+ NULL_CHECK(Password);
+
+ //
+ // Start session with admin sp to update SID to MSID
+ //
+ Ret = OpalStartSession(
+ Session,
+ OPAL_UID_ADMIN_SP,
+ TRUE,
+ PasswordLength,
+ Password,
+ OPAL_ADMIN_SP_SID_AUTHORITY,
+ &MethodStatus
+ );
+ if (Ret != TcgResultSuccess || MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) {
+ goto done;
+ }
+
+ //
+ // Update SID pin
+ //
+ Ret = OpalSetPassword(Session, OPAL_UID_ADMIN_SP_C_PIN_SID, Msid, MsidLength, &MethodStatus);
+ OpalEndSession(Session);
+
+done:
+ if (MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) {
+ Ret = TcgResultFailure;
+ }
+
+ return Ret;
+}
+
+/**
+ Update global locking range.
+
+ @param Session, The session info for one opal device.
+ @param Password, Input password info.
+ @param PasswordLength, Input password length.
+ @param ReadLocked, Read lock info.
+ @param WriteLocked write lock info.
+
+**/
+TCG_RESULT
+EFIAPI
+OpalUtilUpdateGlobalLockingRange(
+ OPAL_SESSION *Session,
+ const VOID *Password,
+ UINT32 PasswordLength,
+ BOOLEAN ReadLocked,
+ BOOLEAN WriteLocked
+ )
+{
+ UINT8 MethodStatus;
+ TCG_RESULT Ret;
+
+ NULL_CHECK(Session);
+ NULL_CHECK(Password);
+
+ //
+ // Try to start session with Locking SP as admin1 authority
+ //
+ Ret = OpalStartSession(
+ Session,
+ OPAL_UID_LOCKING_SP,
+ TRUE,
+ PasswordLength,
+ Password,
+ OPAL_LOCKING_SP_ADMIN1_AUTHORITY,
+ &MethodStatus
+ );
+ if (Ret == TcgResultSuccess && MethodStatus == TCG_METHOD_STATUS_CODE_SUCCESS) {
+ Ret = OpalUpdateGlobalLockingRange(
+ Session,
+ ReadLocked,
+ WriteLocked,
+ &MethodStatus
+ );
+ OpalEndSession(Session);
+ if (Ret == TcgResultSuccess && MethodStatus == TCG_METHOD_STATUS_CODE_SUCCESS) {
+ goto done;
+ }
+ }
+
+ if (MethodStatus == TCG_METHOD_STATUS_CODE_AUTHORITY_LOCKED_OUT) {
+ DEBUG ((DEBUG_INFO, "unlock as admin failed with AUTHORITY_LOCKED_OUT\n"));
+ goto done;
+ }
+
+ //
+ // Try user1 authority
+ //
+ Ret = OpalStartSession(
+ Session,
+ OPAL_UID_LOCKING_SP,
+ TRUE,
+ PasswordLength,
+ Password,
+ OPAL_LOCKING_SP_USER1_AUTHORITY,
+ &MethodStatus
+ );
+ if (Ret != TcgResultSuccess || MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) {
+ DEBUG ((DEBUG_INFO, "StartSession with Locking SP as User1 failed\n"));
+ goto done;
+ }
+
+ Ret = OpalUpdateGlobalLockingRange(Session, ReadLocked, WriteLocked, &MethodStatus);
+ OpalEndSession(Session);
+
+done:
+ if (MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) {
+ Ret = TcgResultFailure;
+ }
+ return Ret;
+}
+
+/**
+ Update global locking range.
+
+ @param Session, The session info for one opal device.
+ @param Msid, The data buffer to save Msid info.
+ @param MsidBufferLength, The data buffer length for Msid.
+ @param MsidLength, The actual data length for Msid.
+
+**/
+TCG_RESULT
+EFIAPI
+OpalUtilGetMsid(
+ OPAL_SESSION *Session,
+ UINT8 *Msid,
+ UINT32 MsidBufferLength,
+ UINT32 *MsidLength
+ )
+{
+ UINT8 MethodStatus;
+ TCG_RESULT Ret;
+
+ NULL_CHECK(Session);
+ NULL_CHECK(Msid);
+ NULL_CHECK(MsidLength);
+
+ Ret = OpalStartSession(
+ Session,
+ OPAL_UID_ADMIN_SP,
+ TRUE,
+ 0,
+ NULL,
+ TCG_UID_NULL,
+ &MethodStatus
+ );
+ if ((Ret == TcgResultSuccess) && (MethodStatus == TCG_METHOD_STATUS_CODE_SUCCESS)) {
+ Ret = OpalGetMsid (Session, MsidBufferLength, Msid, MsidLength);
+ OpalEndSession (Session);
+ }
+
+ if (MethodStatus != TCG_METHOD_STATUS_CODE_SUCCESS) {
+ Ret = TcgResultFailure;
+ }
+
+ return Ret;
+}
+
+/**
+
+ The function determines who owns the device by attempting to start a session with different credentials.
+ If the SID PIN matches the MSID PIN, the no one owns the device.
+ If the SID PIN matches the ourSidPin, then "Us" owns the device. Otherwise it is unknown.
+
+
+ @param[in] Session The session info for one opal device.
+ @param Msid, The Msid info.
+ @param MsidLength, The data length for Msid.
+
+**/
+OPAL_OWNER_SHIP
+EFIAPI
+OpalUtilDetermineOwnership(
+ OPAL_SESSION *Session,
+ UINT8 *Msid,
+ UINT32 MsidLength
+ )
+{
+ UINT8 MethodStatus;
+ TCG_RESULT Ret;
+ OPAL_OWNER_SHIP Owner;
+
+ if ((Session == NULL) || (Msid == NULL)) {
+ return OpalOwnershipUnknown;
+ }
+
+ Owner = OpalOwnershipUnknown;
+ //
+ // Start Session as SID_UID with ADMIN_SP using MSID PIN
+ //
+ Ret = OpalStartSession(
+ Session,
+ OPAL_UID_ADMIN_SP,
+ TRUE,
+ MsidLength,
+ Msid,
+ OPAL_ADMIN_SP_SID_AUTHORITY,
+ &MethodStatus);
+ if ((Ret == TcgResultSuccess) && (MethodStatus == TCG_METHOD_STATUS_CODE_SUCCESS)) {
+ //
+ // now we know that SID PIN == MSID PIN
+ //
+ Owner = OpalOwnershipNobody;
+
+ OpalEndSession(Session);
+ }
+
+ return Owner;
+}
+
+/**
+
+ The function returns if admin password exists.
+
+ @param[in] OwnerShip The owner ship of the opal device.
+ @param[in] LockingFeature The locking info of the opal device.
+
+ @retval TRUE Admin password existed.
+ @retval FALSE Admin password not existed.
+
+**/
+BOOLEAN
+EFIAPI
+OpalUtilAdminPasswordExists(
+ IN UINT16 OwnerShip,
+ IN TCG_LOCKING_FEATURE_DESCRIPTOR *LockingFeature
+ )
+{
+ NULL_CHECK(LockingFeature);
+
+ // if it is Unknown who owns the device
+ // then someone has set password previously through our UI
+ // because the SID would no longer match the generated SID (ownership us)
+ // or someone has set password using 3rd party software
+
+ //
+ // Locking sp enabled is checked b/c it must be enabled to change the PIN of the Admin1.
+ //
+ return (OwnerShip == OpalOwnershipUnknown && LockingFeature->LockingEnabled);
+}
+
diff --git a/Core/SecurityPkg/Library/Tpm12CommandLib/Tpm12CommandLib.inf b/Core/SecurityPkg/Library/Tpm12CommandLib/Tpm12CommandLib.inf
new file mode 100644
index 0000000000..f5dbb721b8
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm12CommandLib/Tpm12CommandLib.inf
@@ -0,0 +1,50 @@
+## @file
+# Provides some TPM 1.2 commands
+#
+# This library is used by other modules to send TPM 1.2 command.
+#
+# Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = Tpm12CommandLib
+ MODULE_UNI_FILE = Tpm12CommandLib.uni
+ FILE_GUID = C595047C-70B3-4731-99CC-A014E956D7A7
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = Tpm12CommandLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF
+#
+
+[Sources]
+ Tpm12Startup.c
+ Tpm12Ownership.c
+ Tpm12NvStorage.c
+ Tpm12GetCapability.c
+ Tpm12Pcr.c
+ Tpm12PhysicalPresence.c
+ Tpm12SelfTest.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ IoLib
+ TimerLib
+ DebugLib
+ Tpm12DeviceLib
diff --git a/Core/SecurityPkg/Library/Tpm12CommandLib/Tpm12CommandLib.uni b/Core/SecurityPkg/Library/Tpm12CommandLib/Tpm12CommandLib.uni
new file mode 100644
index 0000000000..5aeb1b2c5c
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm12CommandLib/Tpm12CommandLib.uni
@@ -0,0 +1,21 @@
+// /** @file
+// Provides some TPM 1.2 commands
+//
+// This library is used by other modules to send TPM 1.2 command.
+//
+// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides some TPM 1.2 command functions"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library is used by other modules to send TPM 1.2 command."
+
diff --git a/Core/SecurityPkg/Library/Tpm12CommandLib/Tpm12GetCapability.c b/Core/SecurityPkg/Library/Tpm12CommandLib/Tpm12GetCapability.c
new file mode 100644
index 0000000000..c6eb9e1050
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm12CommandLib/Tpm12GetCapability.c
@@ -0,0 +1,137 @@
+/** @file
+ Implement TPM1.2 Get Capabilities related commands.
+
+Copyright (c) 2016 - 2017, Intel Corporation. All rights reserved. <BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiPei.h>
+#include <Library/Tpm12CommandLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/Tpm12DeviceLib.h>
+
+#pragma pack(1)
+
+typedef struct {
+ TPM_RQU_COMMAND_HDR Hdr;
+ UINT32 Capability;
+ UINT32 CapabilityFlagSize;
+ UINT32 CapabilityFlag;
+} TPM_CMD_GET_CAPABILITY;
+
+typedef struct {
+ TPM_RSP_COMMAND_HDR Hdr;
+ UINT32 ResponseSize;
+ TPM_PERMANENT_FLAGS Flags;
+} TPM_RSP_GET_CAPABILITY_PERMANENT_FLAGS;
+
+typedef struct {
+ TPM_RSP_COMMAND_HDR Hdr;
+ UINT32 ResponseSize;
+ TPM_STCLEAR_FLAGS Flags;
+} TPM_RSP_GET_CAPABILITY_STCLEAR_FLAGS;
+
+#pragma pack()
+
+/**
+Get TPM capability permanent flags.
+
+@param[out] TpmPermanentFlags Pointer to the buffer for returned flag structure.
+
+@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
+EFIAPI
+Tpm12GetCapabilityFlagPermanent (
+ OUT TPM_PERMANENT_FLAGS *TpmPermanentFlags
+ )
+{
+ EFI_STATUS Status;
+ TPM_CMD_GET_CAPABILITY Command;
+ TPM_RSP_GET_CAPABILITY_PERMANENT_FLAGS Response;
+ UINT32 Length;
+
+ //
+ // send Tpm command TPM_ORD_GetCapability
+ //
+ Command.Hdr.tag = SwapBytes16 (TPM_TAG_RQU_COMMAND);
+ Command.Hdr.paramSize = SwapBytes32 (sizeof (Command));
+ Command.Hdr.ordinal = SwapBytes32 (TPM_ORD_GetCapability);
+ Command.Capability = SwapBytes32 (TPM_CAP_FLAG);
+ Command.CapabilityFlagSize = SwapBytes32 (sizeof (TPM_CAP_FLAG_PERMANENT));
+ Command.CapabilityFlag = SwapBytes32 (TPM_CAP_FLAG_PERMANENT);
+ Length = sizeof (Response);
+ Status = Tpm12SubmitCommand (sizeof (Command), (UINT8 *)&Command, &Length, (UINT8 *)&Response);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (SwapBytes32 (Response.Hdr.returnCode) != TPM_SUCCESS) {
+ DEBUG ((DEBUG_ERROR, "Tpm12GetCapabilityFlagPermanent: Response Code error! 0x%08x\r\n", SwapBytes32 (Response.Hdr.returnCode)));
+ return EFI_DEVICE_ERROR;
+ }
+
+ ZeroMem (TpmPermanentFlags, sizeof (*TpmPermanentFlags));
+ CopyMem (TpmPermanentFlags, &Response.Flags, MIN (sizeof (*TpmPermanentFlags), Response.ResponseSize));
+
+ return Status;
+}
+
+/**
+Get TPM capability volatile flags.
+
+@param[out] VolatileFlags Pointer to the buffer for returned flag structure.
+
+@retval EFI_SUCCESS Operation completed successfully.
+@retval EFI_DEVICE_ERROR The command was unsuccessful.
+
+**/
+EFI_STATUS
+EFIAPI
+Tpm12GetCapabilityFlagVolatile (
+ OUT TPM_STCLEAR_FLAGS *VolatileFlags
+ )
+{
+ EFI_STATUS Status;
+ TPM_CMD_GET_CAPABILITY Command;
+ TPM_RSP_GET_CAPABILITY_STCLEAR_FLAGS Response;
+ UINT32 Length;
+
+ //
+ // send Tpm command TPM_ORD_GetCapability
+ //
+ Command.Hdr.tag = SwapBytes16 (TPM_TAG_RQU_COMMAND);
+ Command.Hdr.paramSize = SwapBytes32 (sizeof (Command));
+ Command.Hdr.ordinal = SwapBytes32 (TPM_ORD_GetCapability);
+ Command.Capability = SwapBytes32 (TPM_CAP_FLAG);
+ Command.CapabilityFlagSize = SwapBytes32 (sizeof (TPM_CAP_FLAG_VOLATILE));
+ Command.CapabilityFlag = SwapBytes32 (TPM_CAP_FLAG_VOLATILE);
+ Length = sizeof (Response);
+ Status = Tpm12SubmitCommand (sizeof (Command), (UINT8 *)&Command, &Length, (UINT8 *)&Response);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (SwapBytes32 (Response.Hdr.returnCode) != TPM_SUCCESS) {
+ DEBUG ((DEBUG_ERROR, "Tpm12GetCapabilityFlagVolatile: Response Code error! 0x%08x\r\n", SwapBytes32 (Response.Hdr.returnCode)));
+ return EFI_DEVICE_ERROR;
+ }
+
+ ZeroMem (VolatileFlags, sizeof (*VolatileFlags));
+ CopyMem (VolatileFlags, &Response.Flags, MIN (sizeof (*VolatileFlags), Response.ResponseSize));
+
+ return Status;
+}
diff --git a/Core/SecurityPkg/Library/Tpm12CommandLib/Tpm12NvStorage.c b/Core/SecurityPkg/Library/Tpm12CommandLib/Tpm12NvStorage.c
new file mode 100644
index 0000000000..e176b00f6b
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm12CommandLib/Tpm12NvStorage.c
@@ -0,0 +1,234 @@
+/** @file
+ Implement TPM1.2 NV storage related command.
+
+Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved. <BR>
+(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiPei.h>
+#include <Library/Tpm12CommandLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/Tpm12DeviceLib.h>
+
+//
+// Max TPM NV value length
+//
+#define TPMNVVALUELENGTH 1024
+
+#pragma pack(1)
+
+typedef struct {
+ TPM_RQU_COMMAND_HDR Hdr;
+ TPM12_NV_DATA_PUBLIC PubInfo;
+ TPM_ENCAUTH EncAuth;
+} TPM_CMD_NV_DEFINE_SPACE;
+
+typedef struct {
+ TPM_RQU_COMMAND_HDR Hdr;
+ TPM_NV_INDEX NvIndex;
+ UINT32 Offset;
+ UINT32 DataSize;
+} TPM_CMD_NV_READ_VALUE;
+
+typedef struct {
+ TPM_RSP_COMMAND_HDR Hdr;
+ UINT32 DataSize;
+ UINT8 Data[TPMNVVALUELENGTH];
+} TPM_RSP_NV_READ_VALUE;
+
+typedef struct {
+ TPM_RQU_COMMAND_HDR Hdr;
+ TPM_NV_INDEX NvIndex;
+ UINT32 Offset;
+ UINT32 DataSize;
+ UINT8 Data[TPMNVVALUELENGTH];
+} TPM_CMD_NV_WRITE_VALUE;
+
+#pragma pack()
+
+/**
+ Send NV DefineSpace command to TPM1.2.
+
+ @param PubInfo The public parameters of the NV area.
+ @param EncAuth The encrypted AuthData, only valid if the attributes require subsequent authorization.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+Tpm12NvDefineSpace (
+ IN TPM12_NV_DATA_PUBLIC *PubInfo,
+ IN TPM_ENCAUTH *EncAuth
+ )
+{
+ EFI_STATUS Status;
+ TPM_CMD_NV_DEFINE_SPACE Command;
+ TPM_RSP_COMMAND_HDR Response;
+ UINT32 Length;
+
+ //
+ // send Tpm command TPM_ORD_NV_DefineSpace
+ //
+ Command.Hdr.tag = SwapBytes16 (TPM_TAG_RQU_COMMAND);
+ Command.Hdr.paramSize = SwapBytes32 (sizeof (Command));
+ Command.Hdr.ordinal = SwapBytes32 (TPM_ORD_NV_DefineSpace);
+ Command.PubInfo.tag = SwapBytes16 (PubInfo->tag);
+ Command.PubInfo.nvIndex = SwapBytes32 (PubInfo->nvIndex);
+ Command.PubInfo.pcrInfoRead.pcrSelection.sizeOfSelect = SwapBytes16 (PubInfo->pcrInfoRead.pcrSelection.sizeOfSelect);
+ Command.PubInfo.pcrInfoRead.pcrSelection.pcrSelect[0] = PubInfo->pcrInfoRead.pcrSelection.pcrSelect[0];
+ Command.PubInfo.pcrInfoRead.pcrSelection.pcrSelect[1] = PubInfo->pcrInfoRead.pcrSelection.pcrSelect[1];
+ Command.PubInfo.pcrInfoRead.pcrSelection.pcrSelect[2] = PubInfo->pcrInfoRead.pcrSelection.pcrSelect[2];
+ Command.PubInfo.pcrInfoRead.localityAtRelease = PubInfo->pcrInfoRead.localityAtRelease;
+ CopyMem (&Command.PubInfo.pcrInfoRead.digestAtRelease, &PubInfo->pcrInfoRead.digestAtRelease, sizeof(PubInfo->pcrInfoRead.digestAtRelease));
+ Command.PubInfo.pcrInfoWrite.pcrSelection.sizeOfSelect = SwapBytes16 (PubInfo->pcrInfoWrite.pcrSelection.sizeOfSelect);
+ Command.PubInfo.pcrInfoWrite.pcrSelection.pcrSelect[0] = PubInfo->pcrInfoWrite.pcrSelection.pcrSelect[0];
+ Command.PubInfo.pcrInfoWrite.pcrSelection.pcrSelect[1] = PubInfo->pcrInfoWrite.pcrSelection.pcrSelect[1];
+ Command.PubInfo.pcrInfoWrite.pcrSelection.pcrSelect[2] = PubInfo->pcrInfoWrite.pcrSelection.pcrSelect[2];
+ Command.PubInfo.pcrInfoWrite.localityAtRelease = PubInfo->pcrInfoWrite.localityAtRelease;
+ CopyMem (&Command.PubInfo.pcrInfoWrite.digestAtRelease, &PubInfo->pcrInfoWrite.digestAtRelease, sizeof(PubInfo->pcrInfoWrite.digestAtRelease));
+ Command.PubInfo.permission.tag = SwapBytes16 (PubInfo->permission.tag);
+ Command.PubInfo.permission.attributes = SwapBytes32 (PubInfo->permission.attributes);
+ Command.PubInfo.bReadSTClear = PubInfo->bReadSTClear;
+ Command.PubInfo.bWriteSTClear = PubInfo->bWriteSTClear;
+ Command.PubInfo.bWriteDefine = PubInfo->bWriteDefine;
+ Command.PubInfo.dataSize = SwapBytes32 (PubInfo->dataSize);
+ CopyMem (&Command.EncAuth, EncAuth, sizeof(*EncAuth));
+ Length = sizeof (Response);
+ Status = Tpm12SubmitCommand (sizeof (Command), (UINT8 *)&Command, &Length, (UINT8 *)&Response);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ DEBUG ((DEBUG_INFO, "Tpm12NvDefineSpace - ReturnCode = %x\n", SwapBytes32 (Response.returnCode)));
+ switch (SwapBytes32 (Response.returnCode)) {
+ case TPM_SUCCESS:
+ return EFI_SUCCESS;
+ default:
+ return EFI_DEVICE_ERROR;
+ }
+}
+
+/**
+ Send NV ReadValue command to TPM1.2.
+
+ @param NvIndex The index of the area to set.
+ @param Offset The offset into the area.
+ @param DataSize The size of the data area.
+ @param Data The data to set the area to.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+Tpm12NvReadValue (
+ IN TPM_NV_INDEX NvIndex,
+ IN UINT32 Offset,
+ IN OUT UINT32 *DataSize,
+ OUT UINT8 *Data
+ )
+{
+ EFI_STATUS Status;
+ TPM_CMD_NV_READ_VALUE Command;
+ TPM_RSP_NV_READ_VALUE Response;
+ UINT32 Length;
+
+ //
+ // send Tpm command TPM_ORD_NV_ReadValue
+ //
+ Command.Hdr.tag = SwapBytes16 (TPM_TAG_RQU_COMMAND);
+ Command.Hdr.paramSize = SwapBytes32 (sizeof (Command));
+ Command.Hdr.ordinal = SwapBytes32 (TPM_ORD_NV_ReadValue);
+ Command.NvIndex = SwapBytes32 (NvIndex);
+ Command.Offset = SwapBytes32 (Offset);
+ Command.DataSize = SwapBytes32 (*DataSize);
+ Length = sizeof (Response);
+ Status = Tpm12SubmitCommand (sizeof (Command), (UINT8 *)&Command, &Length, (UINT8 *)&Response);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ DEBUG ((DEBUG_INFO, "Tpm12NvReadValue - ReturnCode = %x\n", SwapBytes32 (Response.Hdr.returnCode)));
+ switch (SwapBytes32 (Response.Hdr.returnCode)) {
+ case TPM_SUCCESS:
+ break;
+ default:
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Return the response
+ //
+ if (SwapBytes32 (Response.DataSize) > *DataSize) {
+ return EFI_BUFFER_TOO_SMALL;
+ }
+ *DataSize = SwapBytes32 (Response.DataSize);
+ ZeroMem (Data, *DataSize);
+ CopyMem (Data, &Response.Data, *DataSize);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Send NV WriteValue command to TPM1.2.
+
+ @param NvIndex The index of the area to set.
+ @param Offset The offset into the NV Area.
+ @param DataSize The size of the data parameter.
+ @param Data The data to set the area to.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+Tpm12NvWriteValue (
+ IN TPM_NV_INDEX NvIndex,
+ IN UINT32 Offset,
+ IN UINT32 DataSize,
+ IN UINT8 *Data
+ )
+{
+ EFI_STATUS Status;
+ TPM_CMD_NV_WRITE_VALUE Command;
+ UINT32 CommandLength;
+ TPM_RSP_COMMAND_HDR Response;
+ UINT32 ResponseLength;
+
+ if (DataSize > sizeof (Command.Data)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // send Tpm command TPM_ORD_NV_WriteValue
+ //
+ Command.Hdr.tag = SwapBytes16 (TPM_TAG_RQU_COMMAND);
+ CommandLength = sizeof (Command) - sizeof(Command.Data) + DataSize;
+ Command.Hdr.paramSize = SwapBytes32 (CommandLength);
+ Command.Hdr.ordinal = SwapBytes32 (TPM_ORD_NV_WriteValue);
+ Command.NvIndex = SwapBytes32 (NvIndex);
+ Command.Offset = SwapBytes32 (Offset);
+ Command.DataSize = SwapBytes32 (DataSize);
+ CopyMem (Command.Data, Data, DataSize);
+ ResponseLength = sizeof (Response);
+ Status = Tpm12SubmitCommand (CommandLength, (UINT8 *)&Command, &ResponseLength, (UINT8 *)&Response);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ DEBUG ((DEBUG_INFO, "Tpm12NvWritedValue - ReturnCode = %x\n", SwapBytes32 (Response.returnCode)));
+ switch (SwapBytes32 (Response.returnCode)) {
+ case TPM_SUCCESS:
+ return EFI_SUCCESS;
+ default:
+ return EFI_DEVICE_ERROR;
+ }
+}
diff --git a/Core/SecurityPkg/Library/Tpm12CommandLib/Tpm12Ownership.c b/Core/SecurityPkg/Library/Tpm12CommandLib/Tpm12Ownership.c
new file mode 100644
index 0000000000..0b1bf5c536
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm12CommandLib/Tpm12Ownership.c
@@ -0,0 +1,55 @@
+/** @file
+ Implement TPM1.2 Ownership related command.
+
+Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved. <BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiPei.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/BaseLib.h>
+#include <Library/Tpm12DeviceLib.h>
+
+/**
+ Send ForceClear command to TPM1.2.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+Tpm12ForceClear (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ TPM_RQU_COMMAND_HDR Command;
+ TPM_RSP_COMMAND_HDR Response;
+ UINT32 Length;
+
+ //
+ // send Tpm command TPM_ORD_ForceClear
+ //
+ Command.tag = SwapBytes16 (TPM_TAG_RQU_COMMAND);
+ Command.paramSize = SwapBytes32 (sizeof (Command));
+ Command.ordinal = SwapBytes32 (TPM_ORD_ForceClear);
+ Length = sizeof (Response);
+
+ Status = Tpm12SubmitCommand (sizeof (Command), (UINT8 *)&Command, &Length, (UINT8 *)&Response);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ switch (SwapBytes32 (Response.returnCode)) {
+ case TPM_SUCCESS:
+ return EFI_SUCCESS;
+ default:
+ return EFI_DEVICE_ERROR;
+ }
+} \ No newline at end of file
diff --git a/Core/SecurityPkg/Library/Tpm12CommandLib/Tpm12Pcr.c b/Core/SecurityPkg/Library/Tpm12CommandLib/Tpm12Pcr.c
new file mode 100644
index 0000000000..18d5b96e6f
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm12CommandLib/Tpm12Pcr.c
@@ -0,0 +1,87 @@
+/** @file
+ Implement TPM1.2 PCR related commands.
+
+Copyright (c) 2016, Intel Corporation. All rights reserved. <BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiPei.h>
+#include <Library/Tpm12CommandLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/Tpm12DeviceLib.h>
+
+#pragma pack(1)
+
+typedef struct {
+ TPM_RQU_COMMAND_HDR Hdr;
+ TPM_PCRINDEX PcrIndex;
+ TPM_DIGEST TpmDigest;
+} TPM_CMD_EXTEND;
+
+typedef struct {
+ TPM_RSP_COMMAND_HDR Hdr;
+ TPM_DIGEST TpmDigest;
+} TPM_RSP_EXTEND;
+
+#pragma pack()
+
+/**
+Extend a TPM PCR.
+
+@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
+EFIAPI
+Tpm12Extend (
+ IN TPM_DIGEST *DigestToExtend,
+ IN TPM_PCRINDEX PcrIndex,
+ OUT TPM_DIGEST *NewPcrValue
+ )
+{
+ EFI_STATUS Status;
+ TPM_CMD_EXTEND Command;
+ TPM_RSP_EXTEND Response;
+ UINT32 Length;
+
+ //
+ // send Tpm command TPM_ORD_Extend
+ //
+ Command.Hdr.tag = SwapBytes16 (TPM_TAG_RQU_COMMAND);
+ Command.Hdr.paramSize = SwapBytes32 (sizeof (Command));
+ Command.Hdr.ordinal = SwapBytes32 (TPM_ORD_Extend);
+ Command.PcrIndex = SwapBytes32 (PcrIndex);
+ CopyMem (&Command.TpmDigest, DigestToExtend, sizeof (Command.TpmDigest));
+ Length = sizeof (Response);
+ Status = Tpm12SubmitCommand (sizeof (Command), (UINT8 *)&Command, &Length, (UINT8 *)&Response);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (SwapBytes32(Response.Hdr.returnCode) != TPM_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "Tpm12Extend: Response Code error! 0x%08x\r\n", SwapBytes32(Response.Hdr.returnCode)));
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (NewPcrValue != NULL) {
+ CopyMem (NewPcrValue, &Response.TpmDigest, sizeof (*NewPcrValue));
+ }
+
+ return Status;
+}
diff --git a/Core/SecurityPkg/Library/Tpm12CommandLib/Tpm12PhysicalPresence.c b/Core/SecurityPkg/Library/Tpm12CommandLib/Tpm12PhysicalPresence.c
new file mode 100644
index 0000000000..d8d1998d4b
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm12CommandLib/Tpm12PhysicalPresence.c
@@ -0,0 +1,72 @@
+/** @file
+ Implement TPM1.2 Physical Presence related command.
+
+Copyright (c) 2016, Intel Corporation. All rights reserved. <BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiPei.h>
+#include <Library/Tpm12CommandLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/Tpm12DeviceLib.h>
+
+#pragma pack(1)
+
+typedef struct {
+ TPM_RQU_COMMAND_HDR Hdr;
+ TPM_PHYSICAL_PRESENCE PhysicalPresence;
+} TPM_CMD_PHYSICAL_PRESENCE;
+
+#pragma pack()
+
+/**
+Send TSC_PhysicalPresence command to TPM.
+
+@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
+EFIAPI
+Tpm12PhysicalPresence (
+ IN TPM_PHYSICAL_PRESENCE PhysicalPresence
+ )
+{
+ EFI_STATUS Status;
+ TPM_CMD_PHYSICAL_PRESENCE Command;
+ TPM_RSP_COMMAND_HDR Response;
+ UINT32 Length;
+
+ //
+ // send Tpm command TSC_ORD_PhysicalPresence
+ //
+ Command.Hdr.tag = SwapBytes16 (TPM_TAG_RQU_COMMAND);
+ Command.Hdr.paramSize = SwapBytes32 (sizeof (Command));
+ Command.Hdr.ordinal = SwapBytes32 (TSC_ORD_PhysicalPresence);
+ Command.PhysicalPresence = SwapBytes16 (PhysicalPresence);
+ Length = sizeof (Response);
+
+ Status = Tpm12SubmitCommand (sizeof (Command), (UINT8 *)&Command, &Length, (UINT8 *)&Response);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (SwapBytes32(Response.returnCode) != TPM_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "Tpm12PhysicalPresence: Response Code error! 0x%08x\r\n", SwapBytes32(Response.returnCode)));
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Core/SecurityPkg/Library/Tpm12CommandLib/Tpm12SelfTest.c b/Core/SecurityPkg/Library/Tpm12CommandLib/Tpm12SelfTest.c
new file mode 100644
index 0000000000..579fed722b
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm12CommandLib/Tpm12SelfTest.c
@@ -0,0 +1,60 @@
+/** @file
+ Implement TPM1.2 NV Self Test related commands.
+
+Copyright (c) 2016 - 2017, Intel Corporation. All rights reserved. <BR>
+(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiPei.h>
+#include <Library/Tpm12CommandLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/Tpm12DeviceLib.h>
+
+/**
+Send TPM_ContinueSelfTest command to TPM.
+
+@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
+EFIAPI
+Tpm12ContinueSelfTest (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ TPM_RQU_COMMAND_HDR Command;
+ TPM_RSP_COMMAND_HDR Response;
+ UINT32 Length;
+
+ //
+ // send Tpm command TPM_ORD_ContinueSelfTest
+ //
+ Command.tag = SwapBytes16 (TPM_TAG_RQU_COMMAND);
+ Command.paramSize = SwapBytes32 (sizeof (Command));
+ Command.ordinal = SwapBytes32 (TPM_ORD_ContinueSelfTest);
+ Length = sizeof (Response);
+ Status = Tpm12SubmitCommand (sizeof (Command), (UINT8 *)&Command, &Length, (UINT8 *)&Response);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (SwapBytes32 (Response.returnCode) != TPM_SUCCESS) {
+ DEBUG ((DEBUG_ERROR, "Tpm12ContinueSelfTest: Response Code error! 0x%08x\r\n", SwapBytes32 (Response.returnCode)));
+ return EFI_DEVICE_ERROR;
+ }
+
+ return Status;
+}
diff --git a/Core/SecurityPkg/Library/Tpm12CommandLib/Tpm12Startup.c b/Core/SecurityPkg/Library/Tpm12CommandLib/Tpm12Startup.c
new file mode 100644
index 0000000000..098dd28dc1
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm12CommandLib/Tpm12Startup.c
@@ -0,0 +1,109 @@
+/** @file
+ Implement TPM1.2 Startup related command.
+
+Copyright (c) 2013, Intel Corporation. All rights reserved. <BR>
+(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiPei.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/BaseLib.h>
+#include <Library/Tpm12DeviceLib.h>
+#include <Library/DebugLib.h>
+
+#pragma pack(1)
+
+typedef struct {
+ TPM_RQU_COMMAND_HDR Hdr;
+ TPM_STARTUP_TYPE TpmSt;
+} TPM_CMD_START_UP;
+
+#pragma pack()
+
+/**
+ Send Startup command to TPM1.2.
+
+ @param TpmSt Startup Type.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+Tpm12Startup (
+ IN TPM_STARTUP_TYPE TpmSt
+ )
+{
+ EFI_STATUS Status;
+ TPM_CMD_START_UP Command;
+ TPM_RSP_COMMAND_HDR Response;
+ UINT32 Length;
+
+ //
+ // send Tpm command TPM_ORD_Startup
+ //
+ Command.Hdr.tag = SwapBytes16 (TPM_TAG_RQU_COMMAND);
+ Command.Hdr.paramSize = SwapBytes32 (sizeof (Command));
+ Command.Hdr.ordinal = SwapBytes32 (TPM_ORD_Startup);
+ Command.TpmSt = SwapBytes16 (TpmSt);
+ Length = sizeof (Response);
+ Status = Tpm12SubmitCommand (sizeof (Command), (UINT8 *)&Command, &Length, (UINT8 *)&Response);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ switch (SwapBytes32(Response.returnCode)) {
+ case TPM_SUCCESS:
+ DEBUG ((DEBUG_INFO, "TPM12Startup: TPM_SUCCESS\n"));
+ return EFI_SUCCESS;
+ case TPM_INVALID_POSTINIT:
+ // In warm reset, TPM may response TPM_INVALID_POSTINIT
+ DEBUG ((DEBUG_INFO, "TPM12Startup: TPM_INVALID_POSTINIT\n"));
+ return EFI_SUCCESS;
+ default:
+ return EFI_DEVICE_ERROR;
+ }
+}
+
+/**
+ Send SaveState command to TPM1.2.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+Tpm12SaveState (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ TPM_RQU_COMMAND_HDR Command;
+ TPM_RSP_COMMAND_HDR Response;
+ UINT32 Length;
+
+ //
+ // send Tpm command TPM_ORD_SaveState
+ //
+ Command.tag = SwapBytes16 (TPM_TAG_RQU_COMMAND);
+ Command.paramSize = SwapBytes32 (sizeof (Command));
+ Command.ordinal = SwapBytes32 (TPM_ORD_SaveState);
+ Length = sizeof (Response);
+ Status = Tpm12SubmitCommand (sizeof (Command), (UINT8 *)&Command, &Length, (UINT8 *)&Response);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ switch (SwapBytes32 (Response.returnCode)) {
+ case TPM_SUCCESS:
+ return EFI_SUCCESS;
+ default:
+ return EFI_DEVICE_ERROR;
+ }
+}
diff --git a/Core/SecurityPkg/Library/Tpm12DeviceLibDTpm/Tpm12DeviceLibDTpm.inf b/Core/SecurityPkg/Library/Tpm12DeviceLibDTpm/Tpm12DeviceLibDTpm.inf
new file mode 100644
index 0000000000..30b399499e
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm12DeviceLibDTpm/Tpm12DeviceLibDTpm.inf
@@ -0,0 +1,48 @@
+## @file
+# Provides TPM 1.2 TIS functions
+#
+# This library implements TIS (TPM Interface Specification) functions which is
+# used for every TPM 1.2 command. Choosing this library means platform uses and
+# only uses TPM 1.2 device.
+#
+# Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = Tpm12DeviceLibDTpm
+ MODULE_UNI_FILE = Tpm12DeviceLibDTpm.uni
+ FILE_GUID = BC2B7672-A48B-4d58-B39E-AEE3707B5A23
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = Tpm12DeviceLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF
+#
+
+[Sources]
+ Tpm12Tis.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ IoLib
+ TimerLib
+ DebugLib
+
+[Pcd]
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpmBaseAddress ## CONSUMES \ No newline at end of file
diff --git a/Core/SecurityPkg/Library/Tpm12DeviceLibDTpm/Tpm12DeviceLibDTpm.uni b/Core/SecurityPkg/Library/Tpm12DeviceLibDTpm/Tpm12DeviceLibDTpm.uni
new file mode 100644
index 0000000000..dd98a407ee
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm12DeviceLibDTpm/Tpm12DeviceLibDTpm.uni
@@ -0,0 +1,23 @@
+// /** @file
+// Provides TPM 1.2 TIS functions
+//
+// This library implements TIS (TPM Interface Specification) functions which is
+// used for every TPM 1.2 command. Choosing this library means platform uses and
+// only uses TPM 1.2 device.
+//
+// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides TPM 1.2 TIS functions"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library implements TIS (TPM Interface Specification) functions which is used for every TPM 1.2 command. Choosing this library means platform uses and only uses TPM 1.2 device."
+
diff --git a/Core/SecurityPkg/Library/Tpm12DeviceLibDTpm/Tpm12Tis.c b/Core/SecurityPkg/Library/Tpm12DeviceLibDTpm/Tpm12Tis.c
new file mode 100644
index 0000000000..c392b4b215
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm12DeviceLibDTpm/Tpm12Tis.c
@@ -0,0 +1,550 @@
+/** @file
+ TIS (TPM Interface Specification) functions used by TPM1.2.
+
+Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.<BR>
+(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Uefi.h>
+#include <IndustryStandard/Tpm12.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/IoLib.h>
+#include <Library/TimerLib.h>
+#include <Library/DebugLib.h>
+#include <Library/Tpm12CommandLib.h>
+#include <Library/PcdLib.h>
+
+#include <IndustryStandard/TpmPtp.h>
+#include <IndustryStandard/TpmTis.h>
+
+typedef enum {
+ PtpInterfaceTis,
+ PtpInterfaceFifo,
+ PtpInterfaceCrb,
+ PtpInterfaceMax,
+} PTP_INTERFACE_TYPE;
+
+//
+// Max TPM command/reponse length
+//
+#define TPMCMDBUFLENGTH 1024
+
+/**
+ 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
+Tpm12TisPcPresenceCheck (
+ IN TIS_PC_REGISTERS_PTR TisReg
+ )
+{
+ UINT8 RegRead;
+
+ RegRead = MmioRead8 ((UINTN)&TisReg->Access);
+ return (BOOLEAN)(RegRead != (UINT8)-1);
+}
+
+/**
+ Return PTP interface type.
+
+ @param[in] Register Pointer to PTP register.
+
+ @return PTP interface type.
+**/
+PTP_INTERFACE_TYPE
+Tpm12GetPtpInterface (
+ IN VOID *Register
+ )
+{
+ PTP_CRB_INTERFACE_IDENTIFIER InterfaceId;
+ PTP_FIFO_INTERFACE_CAPABILITY InterfaceCapability;
+
+ if (!Tpm12TisPcPresenceCheck (Register)) {
+ return PtpInterfaceMax;
+ }
+ //
+ // Check interface id
+ //
+ InterfaceId.Uint32 = MmioRead32 ((UINTN)&((PTP_CRB_REGISTERS *)Register)->InterfaceId);
+ InterfaceCapability.Uint32 = MmioRead32 ((UINTN)&((PTP_FIFO_REGISTERS *)Register)->InterfaceCapability);
+
+ if ((InterfaceId.Bits.InterfaceType == PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_CRB) &&
+ (InterfaceId.Bits.InterfaceVersion == PTP_INTERFACE_IDENTIFIER_INTERFACE_VERSION_CRB) &&
+ (InterfaceId.Bits.CapCRB != 0)) {
+ return PtpInterfaceCrb;
+ }
+ if ((InterfaceId.Bits.InterfaceType == PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_FIFO) &&
+ (InterfaceId.Bits.InterfaceVersion == PTP_INTERFACE_IDENTIFIER_INTERFACE_VERSION_FIFO) &&
+ (InterfaceId.Bits.CapFIFO != 0) &&
+ (InterfaceCapability.Bits.InterfaceVersion == INTERFACE_CAPABILITY_INTERFACE_VERSION_PTP)) {
+ return PtpInterfaceFifo;
+ }
+ return PtpInterfaceTis;
+}
+
+/**
+ 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
+Tpm12TisPcWaitRegisterBits (
+ 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
+Tpm12TisPcReadBurstCount (
+ 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
+Tpm12TisPcPrepareCommand (
+ 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 = Tpm12TisPcWaitRegisterBits (
+ &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_A.
+
+ @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
+Tpm12TisPcRequestUseTpm (
+ IN TIS_PC_REGISTERS_PTR TisReg
+ )
+{
+ EFI_STATUS Status;
+
+ if (TisReg == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!Tpm12TisPcPresenceCheck (TisReg)) {
+ return EFI_NOT_FOUND;
+ }
+
+ MmioWrite8((UINTN)&TisReg->Access, TIS_PC_ACC_RQUUSE);
+ Status = Tpm12TisPcWaitRegisterBits (
+ &TisReg->Access,
+ (UINT8)(TIS_PC_ACC_ACTIVE |TIS_PC_VALID),
+ 0,
+ TIS_TIMEOUT_A
+ );
+ return Status;
+}
+
+/**
+ Send a command to TPM for execution and return response data.
+
+ @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_BUFFER_TOO_SMALL Response data buffer is too small.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+ @retval EFI_UNSUPPORTED Unsupported TPM version
+
+**/
+EFI_STATUS
+Tpm12TisTpmCommand (
+ 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;
+ UINT16 RspTag;
+
+ DEBUG_CODE (
+ UINTN DebugSize;
+
+ DEBUG ((EFI_D_VERBOSE, "Tpm12TisTpmCommand Send - "));
+ if (SizeIn > 0x100) {
+ DebugSize = 0x40;
+ } else {
+ DebugSize = SizeIn;
+ }
+ for (Index = 0; Index < DebugSize; Index++) {
+ DEBUG ((EFI_D_VERBOSE, "%02x ", BufferIn[Index]));
+ }
+ if (DebugSize != SizeIn) {
+ DEBUG ((EFI_D_VERBOSE, "...... "));
+ for (Index = SizeIn - 0x20; Index < SizeIn; Index++) {
+ DEBUG ((EFI_D_VERBOSE, "%02x ", BufferIn[Index]));
+ }
+ }
+ DEBUG ((EFI_D_VERBOSE, "\n"));
+ );
+ TpmOutSize = 0;
+
+ Status = Tpm12TisPcPrepareCommand (TisReg);
+ if (EFI_ERROR (Status)){
+ DEBUG ((DEBUG_ERROR, "Tpm12 is not ready for command!\n"));
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Send the command data to Tpm
+ //
+ Index = 0;
+ while (Index < SizeIn) {
+ Status = Tpm12TisPcReadBurstCount (TisReg, &BurstCount);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ 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 = Tpm12TisPcWaitRegisterBits (
+ &TisReg->Status,
+ (UINT8) TIS_PC_VALID,
+ TIS_PC_STS_EXPECT,
+ TIS_TIMEOUT_C
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Tpm12 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 = Tpm12TisPcWaitRegisterBits (
+ &TisReg->Status,
+ (UINT8) (TIS_PC_VALID | TIS_PC_STS_DATA),
+ 0,
+ TIS_TIMEOUT_B
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Wait for Tpm12 response data time out!!\n"));
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+ //
+ // Get response data header
+ //
+ Index = 0;
+ BurstCount = 0;
+ while (Index < sizeof (TPM_RSP_COMMAND_HDR)) {
+ Status = Tpm12TisPcReadBurstCount (TisReg, &BurstCount);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+ for (; BurstCount > 0; BurstCount--) {
+ *(BufferOut + Index) = MmioRead8 ((UINTN)&TisReg->DataFifo);
+ Index++;
+ if (Index == sizeof (TPM_RSP_COMMAND_HDR)) break;
+ }
+ }
+ DEBUG_CODE (
+ DEBUG ((EFI_D_VERBOSE, "Tpm12TisTpmCommand ReceiveHeader - "));
+ for (Index = 0; Index < sizeof (TPM_RSP_COMMAND_HDR); Index++) {
+ DEBUG ((EFI_D_VERBOSE, "%02x ", BufferOut[Index]));
+ }
+ DEBUG ((EFI_D_VERBOSE, "\n"));
+ );
+ //
+ // Check the response data header (tag, parasize and returncode)
+ //
+ CopyMem (&Data16, BufferOut, sizeof (UINT16));
+ RspTag = SwapBytes16 (Data16);
+ if (RspTag != TPM_TAG_RSP_COMMAND && RspTag != TPM_TAG_RSP_AUTH1_COMMAND && RspTag != TPM_TAG_RSP_AUTH2_COMMAND) {
+ DEBUG ((EFI_D_ERROR, "TPM12: Response tag error - current tag value is %x\n", RspTag));
+ Status = EFI_UNSUPPORTED;
+ 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 = Tpm12TisPcReadBurstCount (TisReg, &BurstCount);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+ }
+Exit:
+ DEBUG_CODE (
+ DEBUG ((EFI_D_VERBOSE, "Tpm12TisTpmCommand Receive - "));
+ for (Index = 0; Index < TpmOutSize; Index++) {
+ DEBUG ((EFI_D_VERBOSE, "%02x ", BufferOut[Index]));
+ }
+ DEBUG ((EFI_D_VERBOSE, "\n"));
+ );
+ MmioWrite8((UINTN)&TisReg->Status, TIS_PC_STS_READY);
+ return Status;
+}
+
+/**
+ This service enables the sending of commands to the TPM12.
+
+ @param[in] InputParameterBlockSize Size of the TPM12 input parameter block.
+ @param[in] InputParameterBlock Pointer to the TPM12 input parameter block.
+ @param[in,out] OutputParameterBlockSize Size of the TPM12 output parameter block.
+ @param[in] OutputParameterBlock Pointer to the TPM12 output parameter block.
+
+ @retval EFI_SUCCESS The command byte stream was successfully sent to the device and a response was successfully received.
+ @retval EFI_DEVICE_ERROR The command was not successfully sent to the device or a response was not successfully received from the device.
+ @retval EFI_BUFFER_TOO_SMALL The output parameter block is too small.
+**/
+EFI_STATUS
+EFIAPI
+Tpm12SubmitCommand (
+ IN UINT32 InputParameterBlockSize,
+ IN UINT8 *InputParameterBlock,
+ IN OUT UINT32 *OutputParameterBlockSize,
+ IN UINT8 *OutputParameterBlock
+ )
+{
+ PTP_INTERFACE_TYPE PtpInterface;
+
+ //
+ // Special handle for TPM1.2 to check PTP too, because PTP/TIS share same register address.
+ //
+ PtpInterface = Tpm12GetPtpInterface ((VOID *) (UINTN) PcdGet64 (PcdTpmBaseAddress));
+ switch (PtpInterface) {
+ case PtpInterfaceFifo:
+ case PtpInterfaceTis:
+ return Tpm12TisTpmCommand (
+ (TIS_PC_REGISTERS_PTR) (UINTN) PcdGet64 (PcdTpmBaseAddress),
+ InputParameterBlock,
+ InputParameterBlockSize,
+ OutputParameterBlock,
+ OutputParameterBlockSize
+ );
+ case PtpInterfaceCrb:
+ //
+ // No need to support CRB because it is only accept TPM2 command.
+ //
+ default:
+ return EFI_DEVICE_ERROR;
+ }
+
+}
+
+/**
+ 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
+Tpm12PtpCrbWaitRegisterBits (
+ IN UINT32 *Register,
+ IN UINT32 BitSet,
+ IN UINT32 BitClear,
+ IN UINT32 TimeOut
+ )
+{
+ UINT32 RegRead;
+ UINT32 WaitTime;
+
+ for (WaitTime = 0; WaitTime < TimeOut; WaitTime += 30){
+ RegRead = MmioRead32 ((UINTN)Register);
+ if ((RegRead & BitSet) == BitSet && (RegRead & BitClear) == 0) {
+ return EFI_SUCCESS;
+ }
+ MicroSecondDelay (30);
+ }
+ return EFI_TIMEOUT;
+}
+
+/**
+ Get the control of TPM chip.
+
+ @param[in] CrbReg Pointer to CRB register.
+
+ @retval EFI_SUCCESS Get the control of TPM chip.
+ @retval EFI_INVALID_PARAMETER CrbReg is NULL.
+ @retval EFI_NOT_FOUND TPM chip doesn't exit.
+ @retval EFI_TIMEOUT Can't get the TPM control in time.
+**/
+EFI_STATUS
+Tpm12PtpCrbRequestUseTpm (
+ IN PTP_CRB_REGISTERS_PTR CrbReg
+ )
+{
+ EFI_STATUS Status;
+
+ MmioWrite32((UINTN)&CrbReg->LocalityControl, PTP_CRB_LOCALITY_CONTROL_REQUEST_ACCESS);
+ Status = Tpm12PtpCrbWaitRegisterBits (
+ &CrbReg->LocalityStatus,
+ PTP_CRB_LOCALITY_STATUS_GRANTED,
+ 0,
+ PTP_TIMEOUT_A
+ );
+ return Status;
+}
+
+/**
+ This service requests use TPM12.
+
+ @retval EFI_SUCCESS Get the control of TPM12 chip.
+ @retval EFI_NOT_FOUND TPM12 not found.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+Tpm12RequestUseTpm (
+ VOID
+ )
+{
+ PTP_INTERFACE_TYPE PtpInterface;
+
+ //
+ // Special handle for TPM1.2 to check PTP too, because PTP/TIS share same register address.
+ // Some other program might leverage this function to check the existence of TPM chip.
+ //
+ PtpInterface = Tpm12GetPtpInterface ((VOID *) (UINTN) PcdGet64 (PcdTpmBaseAddress));
+ switch (PtpInterface) {
+ case PtpInterfaceCrb:
+ return Tpm12PtpCrbRequestUseTpm ((PTP_CRB_REGISTERS_PTR) (UINTN) PcdGet64 (PcdTpmBaseAddress));
+ case PtpInterfaceFifo:
+ case PtpInterfaceTis:
+ return Tpm12TisPcRequestUseTpm ((TIS_PC_REGISTERS_PTR) (UINTN) PcdGet64 (PcdTpmBaseAddress));
+ default:
+ return EFI_NOT_FOUND;
+ }
+}
diff --git a/Core/SecurityPkg/Library/Tpm12DeviceLibTcg/Tpm12DeviceLibTcg.c b/Core/SecurityPkg/Library/Tpm12DeviceLibTcg/Tpm12DeviceLibTcg.c
new file mode 100644
index 0000000000..126ec06cbd
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm12DeviceLibTcg/Tpm12DeviceLibTcg.c
@@ -0,0 +1,108 @@
+/** @file
+ This library is TPM12 TCG protocol lib.
+
+Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved. <BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Uefi.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/Tpm12DeviceLib.h>
+#include <Protocol/TcgService.h>
+#include <IndustryStandard/Tpm12.h>
+
+EFI_TCG_PROTOCOL *mTcgProtocol = NULL;
+
+/**
+ This service enables the sending of commands to the TPM12.
+
+ @param[in] InputParameterBlockSize Size of the TPM12 input parameter block.
+ @param[in] InputParameterBlock Pointer to the TPM12 input parameter block.
+ @param[in,out] OutputParameterBlockSize Size of the TPM12 output parameter block.
+ @param[in] OutputParameterBlock Pointer to the TPM12 output parameter block.
+
+ @retval EFI_SUCCESS The command byte stream was successfully sent to the device and a response was successfully received.
+ @retval EFI_DEVICE_ERROR The command was not successfully sent to the device or a response was not successfully received from the device.
+ @retval EFI_BUFFER_TOO_SMALL The output parameter block is too small.
+**/
+EFI_STATUS
+EFIAPI
+Tpm12SubmitCommand (
+ IN UINT32 InputParameterBlockSize,
+ IN UINT8 *InputParameterBlock,
+ IN OUT UINT32 *OutputParameterBlockSize,
+ IN UINT8 *OutputParameterBlock
+ )
+{
+ EFI_STATUS Status;
+ TPM_RSP_COMMAND_HDR *Header;
+
+ if (mTcgProtocol == NULL) {
+ Status = gBS->LocateProtocol (&gEfiTcgProtocolGuid, NULL, (VOID **) &mTcgProtocol);
+ if (EFI_ERROR (Status)) {
+ //
+ // TCG protocol is not installed. So, TPM12 is not present.
+ //
+ DEBUG ((EFI_D_ERROR, "Tpm12SubmitCommand - TCG - %r\n", Status));
+ return EFI_NOT_FOUND;
+ }
+ }
+ //
+ // Assume when TCG Protocol is ready, RequestUseTpm already done.
+ //
+ Status = mTcgProtocol->PassThroughToTpm (
+ mTcgProtocol,
+ InputParameterBlockSize,
+ InputParameterBlock,
+ *OutputParameterBlockSize,
+ OutputParameterBlock
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Header = (TPM_RSP_COMMAND_HDR *)OutputParameterBlock;
+ *OutputParameterBlockSize = SwapBytes32 (Header->paramSize);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This service requests use TPM12.
+
+ @retval EFI_SUCCESS Get the control of TPM12 chip.
+ @retval EFI_NOT_FOUND TPM12 not found.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+Tpm12RequestUseTpm (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+
+ if (mTcgProtocol == NULL) {
+ Status = gBS->LocateProtocol (&gEfiTcgProtocolGuid, NULL, (VOID **) &mTcgProtocol);
+ if (EFI_ERROR (Status)) {
+ //
+ // TCG protocol is not installed. So, TPM12 is not present.
+ //
+ DEBUG ((EFI_D_ERROR, "Tpm12RequestUseTpm - TCG - %r\n", Status));
+ return EFI_NOT_FOUND;
+ }
+ }
+ //
+ // Assume when TCG Protocol is ready, RequestUseTpm already done.
+ //
+ return EFI_SUCCESS;
+}
diff --git a/Core/SecurityPkg/Library/Tpm12DeviceLibTcg/Tpm12DeviceLibTcg.inf b/Core/SecurityPkg/Library/Tpm12DeviceLibTcg/Tpm12DeviceLibTcg.inf
new file mode 100644
index 0000000000..76ea4924a4
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm12DeviceLibTcg/Tpm12DeviceLibTcg.inf
@@ -0,0 +1,46 @@
+## @file
+# Provides function interfaces to communicate with TPM 1.2 device
+#
+# This library helps to use TPM 1.2 device in library function API
+# based on TCG protocol.
+#
+# Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = Tpm12DeviceLibTcg
+ MODULE_UNI_FILE = Tpm12DeviceLibTcg.uni
+ FILE_GUID = 4D8B77D9-E923-48f8-B070-4053D78B7E56
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = Tpm12DeviceLib|DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SAL_DRIVER UEFI_APPLICATION UEFI_DRIVER
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF
+#
+
+[Sources]
+ Tpm12DeviceLibTcg.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ UefiBootServicesTableLib
+
+[Protocols]
+ gEfiTcgProtocolGuid ## CONSUMES
diff --git a/Core/SecurityPkg/Library/Tpm12DeviceLibTcg/Tpm12DeviceLibTcg.uni b/Core/SecurityPkg/Library/Tpm12DeviceLibTcg/Tpm12DeviceLibTcg.uni
new file mode 100644
index 0000000000..23242658d1
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm12DeviceLibTcg/Tpm12DeviceLibTcg.uni
@@ -0,0 +1,22 @@
+// /** @file
+// Provides function interfaces to communicate with TPM 1.2 device
+//
+// This library helps to use TPM 1.2 device in library function API
+// based on TCG protocol.
+//
+// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides function interfaces to communicate with TPM 1.2 device"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library helps to use TPM 1.2 device in library function API based on TCG protocol."
+
diff --git a/Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2Capability.c b/Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2Capability.c
new file mode 100644
index 0000000000..79e80fb7a9
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2Capability.c
@@ -0,0 +1,833 @@
+/** @file
+ Implement TPM2 Capability related command.
+
+Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved. <BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <IndustryStandard/UefiTcgPlatform.h>
+#include <Library/Tpm2CommandLib.h>
+#include <Library/Tpm2DeviceLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+
+#pragma pack(1)
+
+typedef struct {
+ TPM2_COMMAND_HEADER Header;
+ TPM_CAP Capability;
+ UINT32 Property;
+ UINT32 PropertyCount;
+} TPM2_GET_CAPABILITY_COMMAND;
+
+typedef struct {
+ TPM2_RESPONSE_HEADER Header;
+ TPMI_YES_NO MoreData;
+ TPMS_CAPABILITY_DATA CapabilityData;
+} TPM2_GET_CAPABILITY_RESPONSE;
+
+typedef struct {
+ TPM2_COMMAND_HEADER Header;
+ TPMT_PUBLIC_PARMS Parameters;
+} TPM2_TEST_PARMS_COMMAND;
+
+typedef struct {
+ TPM2_RESPONSE_HEADER Header;
+} TPM2_TEST_PARMS_RESPONSE;
+
+#pragma pack()
+
+/**
+ This command returns various information regarding the TPM and its current state.
+
+ The capability parameter determines the category of data returned. The property parameter
+ selects the first value of the selected category to be returned. If there is no property
+ that corresponds to the value of property, the next higher value is returned, if it exists.
+ The moreData parameter will have a value of YES if there are more values of the requested
+ type that were not returned.
+ If no next capability exists, the TPM will return a zero-length list and moreData will have
+ a value of NO.
+
+ NOTE:
+ To simplify this function, leave returned CapabilityData for caller to unpack since there are
+ many capability categories and only few categories will be used in firmware. It means the caller
+ need swap the byte order for the feilds in CapabilityData.
+
+ @param[in] Capability Group selection; determines the format of the response.
+ @param[in] Property Further definition of information.
+ @param[in] PropertyCount Number of properties of the indicated type to return.
+ @param[out] MoreData Flag to indicate if there are more values of this type.
+ @param[out] CapabilityData The capability data.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2GetCapability (
+ IN TPM_CAP Capability,
+ IN UINT32 Property,
+ IN UINT32 PropertyCount,
+ OUT TPMI_YES_NO *MoreData,
+ OUT TPMS_CAPABILITY_DATA *CapabilityData
+ )
+{
+ EFI_STATUS Status;
+ TPM2_GET_CAPABILITY_COMMAND SendBuffer;
+ TPM2_GET_CAPABILITY_RESPONSE RecvBuffer;
+ UINT32 SendBufferSize;
+ UINT32 RecvBufferSize;
+
+ //
+ // Construct command
+ //
+ SendBuffer.Header.tag = SwapBytes16(TPM_ST_NO_SESSIONS);
+ SendBuffer.Header.commandCode = SwapBytes32(TPM_CC_GetCapability);
+
+ SendBuffer.Capability = SwapBytes32 (Capability);
+ SendBuffer.Property = SwapBytes32 (Property);
+ SendBuffer.PropertyCount = SwapBytes32 (PropertyCount);
+
+ SendBufferSize = (UINT32) sizeof (SendBuffer);
+ SendBuffer.Header.paramSize = SwapBytes32 (SendBufferSize);
+
+ //
+ // send Tpm command
+ //
+ RecvBufferSize = sizeof (RecvBuffer);
+ Status = Tpm2SubmitCommand (SendBufferSize, (UINT8 *)&SendBuffer, &RecvBufferSize, (UINT8 *)&RecvBuffer );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (RecvBufferSize <= sizeof (TPM2_RESPONSE_HEADER) + sizeof (UINT8)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Return the response
+ //
+ *MoreData = RecvBuffer.MoreData;
+ //
+ // Does not unpack all possiable property here, the caller should unpack it and note the byte order.
+ //
+ CopyMem (CapabilityData, &RecvBuffer.CapabilityData, RecvBufferSize - sizeof (TPM2_RESPONSE_HEADER) - sizeof (UINT8));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This command returns the information of TPM Family.
+
+ This function parse the value got from TPM2_GetCapability and return the Family.
+
+ @param[out] Family The Family of TPM. (a 4-octet character string)
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2GetCapabilityFamily (
+ OUT CHAR8 *Family
+ )
+{
+ TPMS_CAPABILITY_DATA TpmCap;
+ TPMI_YES_NO MoreData;
+ EFI_STATUS Status;
+
+ Status = Tpm2GetCapability (
+ TPM_CAP_TPM_PROPERTIES,
+ TPM_PT_FAMILY_INDICATOR,
+ 1,
+ &MoreData,
+ &TpmCap
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ CopyMem (Family, &TpmCap.data.tpmProperties.tpmProperty->value, 4);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This command returns the information of TPM manufacture ID.
+
+ This function parse the value got from TPM2_GetCapability and return the TPM manufacture ID.
+
+ @param[out] ManufactureId The manufacture ID of TPM.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2GetCapabilityManufactureID (
+ OUT UINT32 *ManufactureId
+ )
+{
+ TPMS_CAPABILITY_DATA TpmCap;
+ TPMI_YES_NO MoreData;
+ EFI_STATUS Status;
+
+ Status = Tpm2GetCapability (
+ TPM_CAP_TPM_PROPERTIES,
+ TPM_PT_MANUFACTURER,
+ 1,
+ &MoreData,
+ &TpmCap
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ *ManufactureId = TpmCap.data.tpmProperties.tpmProperty->value;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This command returns the information of TPM FirmwareVersion.
+
+ This function parse the value got from TPM2_GetCapability and return the TPM FirmwareVersion.
+
+ @param[out] FirmwareVersion1 The FirmwareVersion1.
+ @param[out] FirmwareVersion2 The FirmwareVersion2.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2GetCapabilityFirmwareVersion (
+ OUT UINT32 *FirmwareVersion1,
+ OUT UINT32 *FirmwareVersion2
+ )
+{
+ TPMS_CAPABILITY_DATA TpmCap;
+ TPMI_YES_NO MoreData;
+ EFI_STATUS Status;
+
+ Status = Tpm2GetCapability (
+ TPM_CAP_TPM_PROPERTIES,
+ TPM_PT_FIRMWARE_VERSION_1,
+ 1,
+ &MoreData,
+ &TpmCap
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ *FirmwareVersion1 = SwapBytes32 (TpmCap.data.tpmProperties.tpmProperty->value);
+
+ Status = Tpm2GetCapability (
+ TPM_CAP_TPM_PROPERTIES,
+ TPM_PT_FIRMWARE_VERSION_2,
+ 1,
+ &MoreData,
+ &TpmCap
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ *FirmwareVersion2 = SwapBytes32 (TpmCap.data.tpmProperties.tpmProperty->value);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This command returns the information of the maximum value for commandSize and responseSize in a command.
+
+ This function parse the value got from TPM2_GetCapability and return the max command size and response size
+
+ @param[out] MaxCommandSize The maximum value for commandSize in a command.
+ @param[out] MaxResponseSize The maximum value for responseSize in a command.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2GetCapabilityMaxCommandResponseSize (
+ OUT UINT32 *MaxCommandSize,
+ OUT UINT32 *MaxResponseSize
+ )
+{
+ TPMS_CAPABILITY_DATA TpmCap;
+ TPMI_YES_NO MoreData;
+ EFI_STATUS Status;
+
+ Status = Tpm2GetCapability (
+ TPM_CAP_TPM_PROPERTIES,
+ TPM_PT_MAX_COMMAND_SIZE,
+ 1,
+ &MoreData,
+ &TpmCap
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ *MaxCommandSize = SwapBytes32 (TpmCap.data.tpmProperties.tpmProperty->value);
+
+ Status = Tpm2GetCapability (
+ TPM_CAP_TPM_PROPERTIES,
+ TPM_PT_MAX_RESPONSE_SIZE,
+ 1,
+ &MoreData,
+ &TpmCap
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ *MaxResponseSize = SwapBytes32 (TpmCap.data.tpmProperties.tpmProperty->value);
+ return EFI_SUCCESS;
+}
+
+/**
+ This command returns Returns a list of TPMS_ALG_PROPERTIES. Each entry is an
+ algorithm ID and a set of properties of the algorithm.
+
+ This function parse the value got from TPM2_GetCapability and return the list.
+
+ @param[out] AlgList List of algorithm.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2GetCapabilitySupportedAlg (
+ OUT TPML_ALG_PROPERTY *AlgList
+ )
+{
+ TPMS_CAPABILITY_DATA TpmCap;
+ TPMI_YES_NO MoreData;
+ UINTN Index;
+ EFI_STATUS Status;
+
+ Status = Tpm2GetCapability (
+ TPM_CAP_ALGS,
+ 1,
+ MAX_CAP_ALGS,
+ &MoreData,
+ &TpmCap
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ CopyMem (AlgList, &TpmCap.data.algorithms, sizeof (TPML_ALG_PROPERTY));
+
+ AlgList->count = SwapBytes32 (AlgList->count);
+ for (Index = 0; Index < AlgList->count; Index++) {
+ AlgList->algProperties[Index].alg = SwapBytes16 (AlgList->algProperties[Index].alg);
+ WriteUnaligned32 ((UINT32 *)&AlgList->algProperties[Index].algProperties, SwapBytes32 (ReadUnaligned32 ((UINT32 *)&AlgList->algProperties[Index].algProperties)));
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This command returns the information of TPM LockoutCounter.
+
+ This function parse the value got from TPM2_GetCapability and return the LockoutCounter.
+
+ @param[out] LockoutCounter The LockoutCounter of TPM.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2GetCapabilityLockoutCounter (
+ OUT UINT32 *LockoutCounter
+ )
+{
+ TPMS_CAPABILITY_DATA TpmCap;
+ TPMI_YES_NO MoreData;
+ EFI_STATUS Status;
+
+ Status = Tpm2GetCapability (
+ TPM_CAP_TPM_PROPERTIES,
+ TPM_PT_LOCKOUT_COUNTER,
+ 1,
+ &MoreData,
+ &TpmCap
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ *LockoutCounter = SwapBytes32 (TpmCap.data.tpmProperties.tpmProperty->value);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This command returns the information of TPM LockoutInterval.
+
+ This function parse the value got from TPM2_GetCapability and return the LockoutInterval.
+
+ @param[out] LockoutInterval The LockoutInterval of TPM.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2GetCapabilityLockoutInterval (
+ OUT UINT32 *LockoutInterval
+ )
+{
+ TPMS_CAPABILITY_DATA TpmCap;
+ TPMI_YES_NO MoreData;
+ EFI_STATUS Status;
+
+ Status = Tpm2GetCapability (
+ TPM_CAP_TPM_PROPERTIES,
+ TPM_PT_LOCKOUT_INTERVAL,
+ 1,
+ &MoreData,
+ &TpmCap
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ *LockoutInterval = SwapBytes32 (TpmCap.data.tpmProperties.tpmProperty->value);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This command returns the information of TPM InputBufferSize.
+
+ This function parse the value got from TPM2_GetCapability and return the InputBufferSize.
+
+ @param[out] InputBufferSize The InputBufferSize of TPM.
+ the maximum size of a parameter (typically, a TPM2B_MAX_BUFFER)
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2GetCapabilityInputBufferSize (
+ OUT UINT32 *InputBufferSize
+ )
+{
+ TPMS_CAPABILITY_DATA TpmCap;
+ TPMI_YES_NO MoreData;
+ EFI_STATUS Status;
+
+ Status = Tpm2GetCapability (
+ TPM_CAP_TPM_PROPERTIES,
+ TPM_PT_INPUT_BUFFER,
+ 1,
+ &MoreData,
+ &TpmCap
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ *InputBufferSize = SwapBytes32 (TpmCap.data.tpmProperties.tpmProperty->value);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This command returns the information of TPM PCRs.
+
+ This function parse the value got from TPM2_GetCapability and return the PcrSelection.
+
+ @param[out] Pcrs The Pcr Selection
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2GetCapabilityPcrs (
+ OUT TPML_PCR_SELECTION *Pcrs
+ )
+{
+ TPMS_CAPABILITY_DATA TpmCap;
+ TPMI_YES_NO MoreData;
+ EFI_STATUS Status;
+ UINTN Index;
+
+ Status = Tpm2GetCapability (
+ TPM_CAP_PCRS,
+ 0,
+ 1,
+ &MoreData,
+ &TpmCap
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Pcrs->count = SwapBytes32 (TpmCap.data.assignedPCR.count);
+ for (Index = 0; Index < Pcrs->count; Index++) {
+ Pcrs->pcrSelections[Index].hash = SwapBytes16 (TpmCap.data.assignedPCR.pcrSelections[Index].hash);
+ Pcrs->pcrSelections[Index].sizeofSelect = TpmCap.data.assignedPCR.pcrSelections[Index].sizeofSelect;
+ CopyMem (Pcrs->pcrSelections[Index].pcrSelect, TpmCap.data.assignedPCR.pcrSelections[Index].pcrSelect, Pcrs->pcrSelections[Index].sizeofSelect);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function will query the TPM to determine which hashing algorithms
+ are supported and which PCR banks are currently active.
+
+ @param[out] TpmHashAlgorithmBitmap A bitmask containing the algorithms supported by the TPM.
+ @param[out] ActivePcrBanks A bitmask containing the PCRs currently allocated.
+
+ @retval EFI_SUCCESS TPM was successfully queried and return values can be trusted.
+ @retval Others An error occurred, likely in communication with the TPM.
+
+**/
+EFI_STATUS
+EFIAPI
+Tpm2GetCapabilitySupportedAndActivePcrs (
+ OUT UINT32 *TpmHashAlgorithmBitmap,
+ OUT UINT32 *ActivePcrBanks
+ )
+{
+ EFI_STATUS Status;
+ TPML_PCR_SELECTION Pcrs;
+ UINTN Index;
+
+ //
+ // Get supported PCR and current Active PCRs.
+ //
+ Status = Tpm2GetCapabilityPcrs (&Pcrs);
+
+ //
+ // If error, assume that we have at least SHA-1 (and return the error.)
+ //
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "GetSupportedAndActivePcrs - Tpm2GetCapabilityPcrs fail!\n"));
+ *TpmHashAlgorithmBitmap = HASH_ALG_SHA1;
+ *ActivePcrBanks = HASH_ALG_SHA1;
+ }
+ //
+ // Otherwise, process the return data to determine what algorithms are supported
+ // and currently allocated.
+ //
+ else {
+ DEBUG ((EFI_D_INFO, "GetSupportedAndActivePcrs - Count = %08x\n", Pcrs.count));
+ *TpmHashAlgorithmBitmap = 0;
+ *ActivePcrBanks = 0;
+ for (Index = 0; Index < Pcrs.count; Index++) {
+ switch (Pcrs.pcrSelections[Index].hash) {
+ case TPM_ALG_SHA1:
+ DEBUG ((EFI_D_VERBOSE, "GetSupportedAndActivePcrs - HASH_ALG_SHA1 present.\n"));
+ *TpmHashAlgorithmBitmap |= HASH_ALG_SHA1;
+ if (!IsZeroBuffer (Pcrs.pcrSelections[Index].pcrSelect, Pcrs.pcrSelections[Index].sizeofSelect)) {
+ DEBUG ((EFI_D_VERBOSE, "GetSupportedAndActivePcrs - HASH_ALG_SHA1 active.\n"));
+ *ActivePcrBanks |= HASH_ALG_SHA1;
+ }
+ break;
+ case TPM_ALG_SHA256:
+ DEBUG ((EFI_D_VERBOSE, "GetSupportedAndActivePcrs - HASH_ALG_SHA256 present.\n"));
+ *TpmHashAlgorithmBitmap |= HASH_ALG_SHA256;
+ if (!IsZeroBuffer (Pcrs.pcrSelections[Index].pcrSelect, Pcrs.pcrSelections[Index].sizeofSelect)) {
+ DEBUG ((EFI_D_VERBOSE, "GetSupportedAndActivePcrs - HASH_ALG_SHA256 active.\n"));
+ *ActivePcrBanks |= HASH_ALG_SHA256;
+ }
+ break;
+ case TPM_ALG_SHA384:
+ DEBUG ((EFI_D_VERBOSE, "GetSupportedAndActivePcrs - HASH_ALG_SHA384 present.\n"));
+ *TpmHashAlgorithmBitmap |= HASH_ALG_SHA384;
+ if (!IsZeroBuffer (Pcrs.pcrSelections[Index].pcrSelect, Pcrs.pcrSelections[Index].sizeofSelect)) {
+ DEBUG ((EFI_D_VERBOSE, "GetSupportedAndActivePcrs - HASH_ALG_SHA384 active.\n"));
+ *ActivePcrBanks |= HASH_ALG_SHA384;
+ }
+ break;
+ case TPM_ALG_SHA512:
+ DEBUG ((EFI_D_VERBOSE, "GetSupportedAndActivePcrs - HASH_ALG_SHA512 present.\n"));
+ *TpmHashAlgorithmBitmap |= HASH_ALG_SHA512;
+ if (!IsZeroBuffer (Pcrs.pcrSelections[Index].pcrSelect, Pcrs.pcrSelections[Index].sizeofSelect)) {
+ DEBUG ((EFI_D_VERBOSE, "GetSupportedAndActivePcrs - HASH_ALG_SHA512 active.\n"));
+ *ActivePcrBanks |= HASH_ALG_SHA512;
+ }
+ break;
+ case TPM_ALG_SM3_256:
+ DEBUG ((EFI_D_VERBOSE, "GetSupportedAndActivePcrs - HASH_ALG_SM3_256 present.\n"));
+ *TpmHashAlgorithmBitmap |= HASH_ALG_SM3_256;
+ if (!IsZeroBuffer (Pcrs.pcrSelections[Index].pcrSelect, Pcrs.pcrSelections[Index].sizeofSelect)) {
+ DEBUG ((EFI_D_VERBOSE, "GetSupportedAndActivePcrs - HASH_ALG_SM3_256 active.\n"));
+ *ActivePcrBanks |= HASH_ALG_SM3_256;
+ }
+ break;
+ }
+ }
+ }
+
+ return Status;
+}
+
+/**
+ This command returns the information of TPM AlgorithmSet.
+
+ This function parse the value got from TPM2_GetCapability and return the AlgorithmSet.
+
+ @param[out] AlgorithmSet The AlgorithmSet of TPM.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2GetCapabilityAlgorithmSet (
+ OUT UINT32 *AlgorithmSet
+ )
+{
+ TPMS_CAPABILITY_DATA TpmCap;
+ TPMI_YES_NO MoreData;
+ EFI_STATUS Status;
+
+ Status = Tpm2GetCapability (
+ TPM_CAP_TPM_PROPERTIES,
+ TPM_PT_ALGORITHM_SET,
+ 1,
+ &MoreData,
+ &TpmCap
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ *AlgorithmSet = SwapBytes32 (TpmCap.data.tpmProperties.tpmProperty->value);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This command is used to check to see if specific combinations of algorithm parameters are supported.
+
+ @param[in] Parameters Algorithm parameters to be validated
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2TestParms (
+ IN TPMT_PUBLIC_PARMS *Parameters
+ )
+{
+ EFI_STATUS Status;
+ TPM2_TEST_PARMS_COMMAND SendBuffer;
+ TPM2_TEST_PARMS_RESPONSE RecvBuffer;
+ UINT32 SendBufferSize;
+ UINT32 RecvBufferSize;
+ UINT8 *Buffer;
+
+ //
+ // Construct command
+ //
+ SendBuffer.Header.tag = SwapBytes16(TPM_ST_NO_SESSIONS);
+ SendBuffer.Header.commandCode = SwapBytes32(TPM_CC_TestParms);
+
+ Buffer = (UINT8 *)&SendBuffer.Parameters;
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->type));
+ Buffer += sizeof(UINT16);
+ switch (Parameters->type) {
+ case TPM_ALG_KEYEDHASH:
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.keyedHashDetail.scheme.scheme));
+ Buffer += sizeof(UINT16);
+ switch (Parameters->parameters.keyedHashDetail.scheme.scheme) {
+ case TPM_ALG_HMAC:
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.keyedHashDetail.scheme.details.hmac.hashAlg));
+ Buffer += sizeof(UINT16);
+ break;
+ case TPM_ALG_XOR:
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.keyedHashDetail.scheme.details.xor.hashAlg));
+ Buffer += sizeof(UINT16);
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.keyedHashDetail.scheme.details.xor.kdf));
+ Buffer += sizeof(UINT16);
+ break;
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+ case TPM_ALG_SYMCIPHER:
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.symDetail.algorithm));
+ Buffer += sizeof(UINT16);
+ switch (Parameters->parameters.symDetail.algorithm) {
+ case TPM_ALG_AES:
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.symDetail.keyBits.aes));
+ Buffer += sizeof(UINT16);
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.symDetail.mode.aes));
+ Buffer += sizeof(UINT16);
+ break;
+ case TPM_ALG_SM4:
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.symDetail.keyBits.SM4));
+ Buffer += sizeof(UINT16);
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.symDetail.mode.SM4));
+ Buffer += sizeof(UINT16);
+ break;
+ case TPM_ALG_XOR:
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.symDetail.keyBits.xor));
+ Buffer += sizeof(UINT16);
+ break;
+ case TPM_ALG_NULL:
+ break;
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+ break;
+ case TPM_ALG_RSA:
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.rsaDetail.symmetric.algorithm));
+ Buffer += sizeof(UINT16);
+ switch (Parameters->parameters.rsaDetail.symmetric.algorithm) {
+ case TPM_ALG_AES:
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.rsaDetail.symmetric.keyBits.aes));
+ Buffer += sizeof(UINT16);
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.rsaDetail.symmetric.mode.aes));
+ Buffer += sizeof(UINT16);
+ break;
+ case TPM_ALG_SM4:
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.rsaDetail.symmetric.keyBits.SM4));
+ Buffer += sizeof(UINT16);
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.rsaDetail.symmetric.mode.SM4));
+ Buffer += sizeof(UINT16);
+ break;
+ case TPM_ALG_NULL:
+ break;
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.rsaDetail.scheme.scheme));
+ Buffer += sizeof(UINT16);
+ switch (Parameters->parameters.rsaDetail.scheme.scheme) {
+ case TPM_ALG_RSASSA:
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.rsaDetail.scheme.details.rsassa.hashAlg));
+ Buffer += sizeof(UINT16);
+ break;
+ case TPM_ALG_RSAPSS:
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.rsaDetail.scheme.details.rsapss.hashAlg));
+ Buffer += sizeof(UINT16);
+ break;
+ case TPM_ALG_RSAES:
+ break;
+ case TPM_ALG_OAEP:
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.rsaDetail.scheme.details.oaep.hashAlg));
+ Buffer += sizeof(UINT16);
+ break;
+ case TPM_ALG_NULL:
+ break;
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.rsaDetail.keyBits));
+ Buffer += sizeof(UINT16);
+ WriteUnaligned32 ((UINT32 *)Buffer, SwapBytes32 (Parameters->parameters.rsaDetail.exponent));
+ Buffer += sizeof(UINT32);
+ break;
+ case TPM_ALG_ECC:
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.eccDetail.symmetric.algorithm));
+ Buffer += sizeof(UINT16);
+ switch (Parameters->parameters.eccDetail.symmetric.algorithm) {
+ case TPM_ALG_AES:
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.eccDetail.symmetric.keyBits.aes));
+ Buffer += sizeof(UINT16);
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.eccDetail.symmetric.mode.aes));
+ Buffer += sizeof(UINT16);
+ break;
+ case TPM_ALG_SM4:
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.eccDetail.symmetric.keyBits.SM4));
+ Buffer += sizeof(UINT16);
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.eccDetail.symmetric.mode.SM4));
+ Buffer += sizeof(UINT16);
+ break;
+ case TPM_ALG_NULL:
+ break;
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.eccDetail.scheme.scheme));
+ Buffer += sizeof(UINT16);
+ switch (Parameters->parameters.eccDetail.scheme.scheme) {
+ case TPM_ALG_ECDSA:
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.eccDetail.scheme.details.ecdsa.hashAlg));
+ Buffer += sizeof(UINT16);
+ break;
+ case TPM_ALG_ECDAA:
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.eccDetail.scheme.details.ecdaa.hashAlg));
+ Buffer += sizeof(UINT16);
+ break;
+ case TPM_ALG_ECSCHNORR:
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.eccDetail.scheme.details.ecSchnorr.hashAlg));
+ Buffer += sizeof(UINT16);
+ break;
+ case TPM_ALG_ECDH:
+ break;
+ case TPM_ALG_NULL:
+ break;
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.eccDetail.curveID));
+ Buffer += sizeof(UINT16);
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.eccDetail.kdf.scheme));
+ Buffer += sizeof(UINT16);
+ switch (Parameters->parameters.eccDetail.kdf.scheme) {
+ case TPM_ALG_MGF1:
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.eccDetail.kdf.details.mgf1.hashAlg));
+ Buffer += sizeof(UINT16);
+ break;
+ case TPM_ALG_KDF1_SP800_108:
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.eccDetail.kdf.details.kdf1_sp800_108.hashAlg));
+ Buffer += sizeof(UINT16);
+ break;
+ case TPM_ALG_KDF1_SP800_56a:
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.eccDetail.kdf.details.kdf1_SP800_56a.hashAlg));
+ Buffer += sizeof(UINT16);
+ break;
+ case TPM_ALG_KDF2:
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Parameters->parameters.eccDetail.kdf.details.kdf2.hashAlg));
+ Buffer += sizeof(UINT16);
+ break;
+ case TPM_ALG_NULL:
+ break;
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+ break;
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+
+ SendBufferSize = (UINT32)((UINTN)Buffer - (UINTN)&SendBuffer);
+ SendBuffer.Header.paramSize = SwapBytes32 (SendBufferSize);
+
+ //
+ // send Tpm command
+ //
+ RecvBufferSize = sizeof (RecvBuffer);
+ Status = Tpm2SubmitCommand (SendBufferSize, (UINT8 *)&SendBuffer, &RecvBufferSize, (UINT8 *)&RecvBuffer);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER)) {
+ DEBUG ((EFI_D_ERROR, "Tpm2TestParms - RecvBufferSize Error - %x\n", RecvBufferSize));
+ return EFI_DEVICE_ERROR;
+ }
+ if (SwapBytes32(RecvBuffer.Header.responseCode) != TPM_RC_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "Tpm2TestParms - responseCode - %x\n", SwapBytes32(RecvBuffer.Header.responseCode)));
+ return EFI_UNSUPPORTED;
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2CommandLib.inf b/Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2CommandLib.inf
new file mode 100644
index 0000000000..481a878671
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2CommandLib.inf
@@ -0,0 +1,55 @@
+## @file
+# Provides some TPM 2.0 commands
+#
+# This library is used by other modules to send TPM 2.0 command.
+#
+# Copyright (c) 2013 - 2017, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = Tpm2CommandLib
+ MODULE_UNI_FILE = Tpm2CommandLib.uni
+ FILE_GUID = 2F572F32-8BE5-4868-BD1D-7438AD97DC27
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = Tpm2CommandLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF
+#
+
+[Sources]
+ Tpm2Capability.c
+ Tpm2Sequences.c
+ Tpm2Integrity.c
+ Tpm2Hierarchy.c
+ Tpm2NVStorage.c
+ Tpm2Startup.c
+ Tpm2Session.c
+ Tpm2Context.c
+ Tpm2EnhancedAuthorization.c
+ Tpm2Test.c
+ Tpm2DictionaryAttack.c
+ Tpm2Object.c
+ Tpm2Miscellaneous.c
+ Tpm2Help.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ Tpm2DeviceLib
diff --git a/Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2CommandLib.uni b/Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2CommandLib.uni
new file mode 100644
index 0000000000..9009e32787
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2CommandLib.uni
@@ -0,0 +1,21 @@
+// /** @file
+// Provides some TPM 2.0 commands
+//
+// This library is used by other modules to send TPM 2.0 command.
+//
+// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides some TPM 2.0 command functions"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library is used by other modules to send TPM 2.0 command."
+
diff --git a/Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2Context.c b/Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2Context.c
new file mode 100644
index 0000000000..02a250127a
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2Context.c
@@ -0,0 +1,86 @@
+/** @file
+ Implement TPM2 Context related command.
+
+Copyright (c) 2014, Intel Corporation. All rights reserved. <BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <IndustryStandard/UefiTcgPlatform.h>
+#include <Library/Tpm2CommandLib.h>
+#include <Library/Tpm2DeviceLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+
+#pragma pack(1)
+
+typedef struct {
+ TPM2_COMMAND_HEADER Header;
+ TPMI_DH_CONTEXT FlushHandle;
+} TPM2_FLUSH_CONTEXT_COMMAND;
+
+typedef struct {
+ TPM2_RESPONSE_HEADER Header;
+} TPM2_FLUSH_CONTEXT_RESPONSE;
+
+#pragma pack()
+
+/**
+ This command causes all context associated with a loaded object or session to be removed from TPM memory.
+
+ @param[in] FlushHandle The handle of the item to flush.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2FlushContext (
+ IN TPMI_DH_CONTEXT FlushHandle
+ )
+{
+ EFI_STATUS Status;
+ TPM2_FLUSH_CONTEXT_COMMAND SendBuffer;
+ TPM2_FLUSH_CONTEXT_RESPONSE RecvBuffer;
+ UINT32 SendBufferSize;
+ UINT32 RecvBufferSize;
+
+ //
+ // Construct command
+ //
+ SendBuffer.Header.tag = SwapBytes16(TPM_ST_NO_SESSIONS);
+ SendBuffer.Header.commandCode = SwapBytes32(TPM_CC_FlushContext);
+
+ SendBuffer.FlushHandle = SwapBytes32 (FlushHandle);
+
+ SendBufferSize = (UINT32) sizeof (SendBuffer);
+ SendBuffer.Header.paramSize = SwapBytes32 (SendBufferSize);
+
+ //
+ // send Tpm command
+ //
+ RecvBufferSize = sizeof (RecvBuffer);
+ Status = Tpm2SubmitCommand (SendBufferSize, (UINT8 *)&SendBuffer, &RecvBufferSize, (UINT8 *)&RecvBuffer);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER)) {
+ DEBUG ((EFI_D_ERROR, "Tpm2FlushContext - RecvBufferSize Error - %x\n", RecvBufferSize));
+ return EFI_DEVICE_ERROR;
+ }
+ if (SwapBytes32(RecvBuffer.Header.responseCode) != TPM_RC_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "Tpm2FlushContext - responseCode - %x\n", SwapBytes32(RecvBuffer.Header.responseCode)));
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
diff --git a/Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2DictionaryAttack.c b/Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2DictionaryAttack.c
new file mode 100644
index 0000000000..3198b8a4b8
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2DictionaryAttack.c
@@ -0,0 +1,219 @@
+/** @file
+ Implement TPM2 DictionaryAttack related command.
+
+Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved. <BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <IndustryStandard/UefiTcgPlatform.h>
+#include <Library/Tpm2CommandLib.h>
+#include <Library/Tpm2DeviceLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+
+#pragma pack(1)
+
+typedef struct {
+ TPM2_COMMAND_HEADER Header;
+ TPMI_RH_LOCKOUT LockHandle;
+ UINT32 AuthSessionSize;
+ TPMS_AUTH_COMMAND AuthSession;
+} TPM2_DICTIONARY_ATTACK_LOCK_RESET_COMMAND;
+
+typedef struct {
+ TPM2_RESPONSE_HEADER Header;
+ UINT32 AuthSessionSize;
+ TPMS_AUTH_RESPONSE AuthSession;
+} TPM2_DICTIONARY_ATTACK_LOCK_RESET_RESPONSE;
+
+typedef struct {
+ TPM2_COMMAND_HEADER Header;
+ TPMI_RH_LOCKOUT LockHandle;
+ UINT32 AuthSessionSize;
+ TPMS_AUTH_COMMAND AuthSession;
+ UINT32 NewMaxTries;
+ UINT32 NewRecoveryTime;
+ UINT32 LockoutRecovery;
+} TPM2_DICTIONARY_ATTACK_PARAMETERS_COMMAND;
+
+typedef struct {
+ TPM2_RESPONSE_HEADER Header;
+ UINT32 AuthSessionSize;
+ TPMS_AUTH_RESPONSE AuthSession;
+} TPM2_DICTIONARY_ATTACK_PARAMETERS_RESPONSE;
+
+#pragma pack()
+
+/**
+ This command cancels the effect of a TPM lockout due to a number of successive authorization failures.
+ If this command is properly authorized, the lockout counter is set to zero.
+
+ @param[in] LockHandle TPM_RH_LOCKOUT
+ @param[in] AuthSession Auth Session context
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2DictionaryAttackLockReset (
+ IN TPMI_RH_LOCKOUT LockHandle,
+ IN TPMS_AUTH_COMMAND *AuthSession
+ )
+{
+ EFI_STATUS Status;
+ TPM2_DICTIONARY_ATTACK_LOCK_RESET_COMMAND SendBuffer;
+ TPM2_DICTIONARY_ATTACK_LOCK_RESET_RESPONSE RecvBuffer;
+ UINT32 SendBufferSize;
+ UINT32 RecvBufferSize;
+ UINT8 *Buffer;
+ UINT32 SessionInfoSize;
+
+ //
+ // Construct command
+ //
+ SendBuffer.Header.tag = SwapBytes16(TPM_ST_SESSIONS);
+ SendBuffer.Header.commandCode = SwapBytes32(TPM_CC_DictionaryAttackLockReset);
+
+ SendBuffer.LockHandle = SwapBytes32 (LockHandle);
+
+ //
+ // Add in Auth session
+ //
+ Buffer = (UINT8 *)&SendBuffer.AuthSession;
+
+ // sessionInfoSize
+ SessionInfoSize = CopyAuthSessionCommand (AuthSession, Buffer);
+ Buffer += SessionInfoSize;
+ SendBuffer.AuthSessionSize = SwapBytes32(SessionInfoSize);
+
+ SendBufferSize = (UINT32)((UINTN)Buffer - (UINTN)&SendBuffer);
+ SendBuffer.Header.paramSize = SwapBytes32 (SendBufferSize);
+
+ //
+ // send Tpm command
+ //
+ RecvBufferSize = sizeof (RecvBuffer);
+ Status = Tpm2SubmitCommand (SendBufferSize, (UINT8 *)&SendBuffer, &RecvBufferSize, (UINT8 *)&RecvBuffer);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER)) {
+ DEBUG ((EFI_D_ERROR, "Tpm2DictionaryAttackLockReset - RecvBufferSize Error - %x\n", RecvBufferSize));
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+ if (SwapBytes32(RecvBuffer.Header.responseCode) != TPM_RC_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "Tpm2DictionaryAttackLockReset - responseCode - %x\n", SwapBytes32(RecvBuffer.Header.responseCode)));
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+Done:
+ //
+ // Clear AuthSession Content
+ //
+ ZeroMem (&SendBuffer, sizeof(SendBuffer));
+ ZeroMem (&RecvBuffer, sizeof(RecvBuffer));
+ return Status;
+}
+
+/**
+ This command cancels the effect of a TPM lockout due to a number of successive authorization failures.
+ If this command is properly authorized, the lockout counter is set to zero.
+
+ @param[in] LockHandle TPM_RH_LOCKOUT
+ @param[in] AuthSession Auth Session context
+ @param[in] NewMaxTries Count of authorization failures before the lockout is imposed
+ @param[in] NewRecoveryTime Time in seconds before the authorization failure count is automatically decremented
+ @param[in] LockoutRecovery Time in seconds after a lockoutAuth failure before use of lockoutAuth is allowed
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2DictionaryAttackParameters (
+ IN TPMI_RH_LOCKOUT LockHandle,
+ IN TPMS_AUTH_COMMAND *AuthSession,
+ IN UINT32 NewMaxTries,
+ IN UINT32 NewRecoveryTime,
+ IN UINT32 LockoutRecovery
+ )
+{
+ EFI_STATUS Status;
+ TPM2_DICTIONARY_ATTACK_PARAMETERS_COMMAND SendBuffer;
+ TPM2_DICTIONARY_ATTACK_PARAMETERS_RESPONSE RecvBuffer;
+ UINT32 SendBufferSize;
+ UINT32 RecvBufferSize;
+ UINT8 *Buffer;
+ UINT32 SessionInfoSize;
+
+ //
+ // Construct command
+ //
+ SendBuffer.Header.tag = SwapBytes16(TPM_ST_SESSIONS);
+ SendBuffer.Header.commandCode = SwapBytes32(TPM_CC_DictionaryAttackParameters);
+
+ SendBuffer.LockHandle = SwapBytes32 (LockHandle);
+
+ //
+ // Add in Auth session
+ //
+ Buffer = (UINT8 *)&SendBuffer.AuthSession;
+
+ // sessionInfoSize
+ SessionInfoSize = CopyAuthSessionCommand (AuthSession, Buffer);
+ Buffer += SessionInfoSize;
+ SendBuffer.AuthSessionSize = SwapBytes32(SessionInfoSize);
+
+ //
+ // Real data
+ //
+ WriteUnaligned32 ((UINT32 *)Buffer, SwapBytes32(NewMaxTries));
+ Buffer += sizeof(UINT32);
+ WriteUnaligned32 ((UINT32 *)Buffer, SwapBytes32(NewRecoveryTime));
+ Buffer += sizeof(UINT32);
+ WriteUnaligned32 ((UINT32 *)Buffer, SwapBytes32(LockoutRecovery));
+ Buffer += sizeof(UINT32);
+
+ SendBufferSize = (UINT32)((UINTN)Buffer - (UINTN)&SendBuffer);
+ SendBuffer.Header.paramSize = SwapBytes32 (SendBufferSize);
+
+ //
+ // send Tpm command
+ //
+ RecvBufferSize = sizeof (RecvBuffer);
+ Status = Tpm2SubmitCommand (SendBufferSize, (UINT8 *)&SendBuffer, &RecvBufferSize, (UINT8 *)&RecvBuffer);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER)) {
+ DEBUG ((EFI_D_ERROR, "Tpm2DictionaryAttackParameters - RecvBufferSize Error - %x\n", RecvBufferSize));
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+ if (SwapBytes32(RecvBuffer.Header.responseCode) != TPM_RC_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "Tpm2DictionaryAttackParameters - responseCode - %x\n", SwapBytes32(RecvBuffer.Header.responseCode)));
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+Done:
+ //
+ // Clear AuthSession Content
+ //
+ ZeroMem (&SendBufferSize, sizeof(SendBufferSize));
+ ZeroMem (&RecvBuffer, sizeof(RecvBuffer));
+ return Status;
+}
diff --git a/Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2EnhancedAuthorization.c b/Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2EnhancedAuthorization.c
new file mode 100644
index 0000000000..6f6b3693f8
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2EnhancedAuthorization.c
@@ -0,0 +1,385 @@
+/** @file
+ Implement TPM2 EnhancedAuthorization related command.
+
+Copyright (c) 2014 - 2016, Intel Corporation. All rights reserved. <BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <IndustryStandard/UefiTcgPlatform.h>
+#include <Library/Tpm2CommandLib.h>
+#include <Library/Tpm2DeviceLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+
+#pragma pack(1)
+
+typedef struct {
+ TPM2_COMMAND_HEADER Header;
+ TPMI_DH_ENTITY AuthHandle;
+ TPMI_SH_POLICY PolicySession;
+ UINT32 AuthSessionSize;
+ TPMS_AUTH_COMMAND AuthSession;
+ TPM2B_NONCE NonceTPM;
+ TPM2B_DIGEST CpHashA;
+ TPM2B_NONCE PolicyRef;
+ INT32 Expiration;
+} TPM2_POLICY_SECRET_COMMAND;
+
+typedef struct {
+ TPM2_RESPONSE_HEADER Header;
+ UINT32 AuthSessionSize;
+ TPM2B_TIMEOUT Timeout;
+ TPMT_TK_AUTH PolicyTicket;
+ TPMS_AUTH_RESPONSE AuthSession;
+} TPM2_POLICY_SECRET_RESPONSE;
+
+typedef struct {
+ TPM2_COMMAND_HEADER Header;
+ TPMI_SH_POLICY PolicySession;
+ TPML_DIGEST HashList;
+} TPM2_POLICY_OR_COMMAND;
+
+typedef struct {
+ TPM2_RESPONSE_HEADER Header;
+} TPM2_POLICY_OR_RESPONSE;
+
+typedef struct {
+ TPM2_COMMAND_HEADER Header;
+ TPMI_SH_POLICY PolicySession;
+ TPM_CC Code;
+} TPM2_POLICY_COMMAND_CODE_COMMAND;
+
+typedef struct {
+ TPM2_RESPONSE_HEADER Header;
+} TPM2_POLICY_COMMAND_CODE_RESPONSE;
+
+typedef struct {
+ TPM2_COMMAND_HEADER Header;
+ TPMI_SH_POLICY PolicySession;
+} TPM2_POLICY_GET_DIGEST_COMMAND;
+
+typedef struct {
+ TPM2_RESPONSE_HEADER Header;
+ TPM2B_DIGEST PolicyHash;
+} TPM2_POLICY_GET_DIGEST_RESPONSE;
+
+#pragma pack()
+
+/**
+ This command includes a secret-based authorization to a policy.
+ The caller proves knowledge of the secret value using an authorization
+ session using the authValue associated with authHandle.
+
+ @param[in] AuthHandle Handle for an entity providing the authorization
+ @param[in] PolicySession Handle for the policy session being extended.
+ @param[in] AuthSession Auth Session context
+ @param[in] NonceTPM The policy nonce for the session.
+ @param[in] CpHashA Digest of the command parameters to which this authorization is limited.
+ @param[in] PolicyRef A reference to a policy relating to the authorization.
+ @param[in] Expiration Time when authorization will expire, measured in seconds from the time that nonceTPM was generated.
+ @param[out] Timeout Time value used to indicate to the TPM when the ticket expires.
+ @param[out] PolicyTicket A ticket that includes a value indicating when the authorization expires.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2PolicySecret (
+ IN TPMI_DH_ENTITY AuthHandle,
+ IN TPMI_SH_POLICY PolicySession,
+ IN TPMS_AUTH_COMMAND *AuthSession, OPTIONAL
+ IN TPM2B_NONCE *NonceTPM,
+ IN TPM2B_DIGEST *CpHashA,
+ IN TPM2B_NONCE *PolicyRef,
+ IN INT32 Expiration,
+ OUT TPM2B_TIMEOUT *Timeout,
+ OUT TPMT_TK_AUTH *PolicyTicket
+ )
+{
+ EFI_STATUS Status;
+ TPM2_POLICY_SECRET_COMMAND SendBuffer;
+ TPM2_POLICY_SECRET_RESPONSE RecvBuffer;
+ UINT32 SendBufferSize;
+ UINT32 RecvBufferSize;
+ UINT8 *Buffer;
+ UINT32 SessionInfoSize;
+
+ //
+ // Construct command
+ //
+ SendBuffer.Header.tag = SwapBytes16(TPM_ST_SESSIONS);
+ SendBuffer.Header.commandCode = SwapBytes32(TPM_CC_PolicySecret);
+ SendBuffer.AuthHandle = SwapBytes32 (AuthHandle);
+ SendBuffer.PolicySession = SwapBytes32 (PolicySession);
+
+ //
+ // Add in Auth session
+ //
+ Buffer = (UINT8 *)&SendBuffer.AuthSession;
+
+ // sessionInfoSize
+ SessionInfoSize = CopyAuthSessionCommand (AuthSession, Buffer);
+ Buffer += SessionInfoSize;
+ SendBuffer.AuthSessionSize = SwapBytes32(SessionInfoSize);
+
+ //
+ // Real data
+ //
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16(NonceTPM->size));
+ Buffer += sizeof(UINT16);
+ CopyMem (Buffer, NonceTPM->buffer, NonceTPM->size);
+ Buffer += NonceTPM->size;
+
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16(CpHashA->size));
+ Buffer += sizeof(UINT16);
+ CopyMem (Buffer, CpHashA->buffer, CpHashA->size);
+ Buffer += CpHashA->size;
+
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16(PolicyRef->size));
+ Buffer += sizeof(UINT16);
+ CopyMem (Buffer, PolicyRef->buffer, PolicyRef->size);
+ Buffer += PolicyRef->size;
+
+ WriteUnaligned32 ((UINT32 *)Buffer, SwapBytes32((UINT32)Expiration));
+ Buffer += sizeof(UINT32);
+
+ SendBufferSize = (UINT32)((UINTN)Buffer - (UINTN)&SendBuffer);
+ SendBuffer.Header.paramSize = SwapBytes32 (SendBufferSize);
+
+ //
+ // send Tpm command
+ //
+ RecvBufferSize = sizeof (RecvBuffer);
+ Status = Tpm2SubmitCommand (SendBufferSize, (UINT8 *)&SendBuffer, &RecvBufferSize, (UINT8 *)&RecvBuffer);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER)) {
+ DEBUG ((EFI_D_ERROR, "Tpm2PolicySecret - RecvBufferSize Error - %x\n", RecvBufferSize));
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+ if (SwapBytes32(RecvBuffer.Header.responseCode) != TPM_RC_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "Tpm2PolicySecret - responseCode - %x\n", SwapBytes32(RecvBuffer.Header.responseCode)));
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+ //
+ // Return the response
+ //
+ Buffer = (UINT8 *)&RecvBuffer.Timeout;
+ Timeout->size = SwapBytes16(ReadUnaligned16 ((UINT16 *)Buffer));
+ Buffer += sizeof(UINT16);
+ CopyMem (Timeout->buffer, Buffer, Timeout->size);
+
+ PolicyTicket->tag = SwapBytes16(ReadUnaligned16 ((UINT16 *)Buffer));
+ Buffer += sizeof(UINT16);
+ PolicyTicket->hierarchy = SwapBytes32(ReadUnaligned32 ((UINT32 *)Buffer));
+ Buffer += sizeof(UINT32);
+ PolicyTicket->digest.size = SwapBytes16(ReadUnaligned16 ((UINT16 *)Buffer));
+ Buffer += sizeof(UINT16);
+ CopyMem (PolicyTicket->digest.buffer, Buffer, PolicyTicket->digest.size);
+
+Done:
+ //
+ // Clear AuthSession Content
+ //
+ ZeroMem (&SendBuffer, sizeof(SendBuffer));
+ ZeroMem (&RecvBuffer, sizeof(RecvBuffer));
+ return Status;
+}
+
+/**
+ This command allows options in authorizations without requiring that the TPM evaluate all of the options.
+ If a policy may be satisfied by different sets of conditions, the TPM need only evaluate one set that
+ satisfies the policy. This command will indicate that one of the required sets of conditions has been
+ satisfied.
+
+ @param[in] PolicySession Handle for the policy session being extended.
+ @param[in] HashList the list of hashes to check for a match.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2PolicyOR (
+ IN TPMI_SH_POLICY PolicySession,
+ IN TPML_DIGEST *HashList
+ )
+{
+ EFI_STATUS Status;
+ TPM2_POLICY_OR_COMMAND SendBuffer;
+ TPM2_POLICY_OR_RESPONSE RecvBuffer;
+ UINT32 SendBufferSize;
+ UINT32 RecvBufferSize;
+ UINT8 *Buffer;
+ UINTN Index;
+
+ //
+ // Construct command
+ //
+ SendBuffer.Header.tag = SwapBytes16(TPM_ST_NO_SESSIONS);
+ SendBuffer.Header.commandCode = SwapBytes32(TPM_CC_PolicyOR);
+
+ SendBuffer.PolicySession = SwapBytes32 (PolicySession);
+ Buffer = (UINT8 *)&SendBuffer.HashList;
+ WriteUnaligned32 ((UINT32 *)Buffer, SwapBytes32 (HashList->count));
+ Buffer += sizeof(UINT32);
+ for (Index = 0; Index < HashList->count; Index++) {
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (HashList->digests[Index].size));
+ Buffer += sizeof(UINT16);
+ CopyMem (Buffer, HashList->digests[Index].buffer, HashList->digests[Index].size);
+ Buffer += HashList->digests[Index].size;
+ }
+
+ SendBufferSize = (UINT32)((UINTN)Buffer - (UINTN)&SendBuffer);
+ SendBuffer.Header.paramSize = SwapBytes32 (SendBufferSize);
+
+ //
+ // send Tpm command
+ //
+ RecvBufferSize = sizeof (RecvBuffer);
+ Status = Tpm2SubmitCommand (SendBufferSize, (UINT8 *)&SendBuffer, &RecvBufferSize, (UINT8 *)&RecvBuffer);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER)) {
+ DEBUG ((EFI_D_ERROR, "Tpm2PolicyOR - RecvBufferSize Error - %x\n", RecvBufferSize));
+ return EFI_DEVICE_ERROR;
+ }
+ if (SwapBytes32(RecvBuffer.Header.responseCode) != TPM_RC_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "Tpm2PolicyOR - responseCode - %x\n", SwapBytes32(RecvBuffer.Header.responseCode)));
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This command indicates that the authorization will be limited to a specific command code.
+
+ @param[in] PolicySession Handle for the policy session being extended.
+ @param[in] Code The allowed commandCode.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2PolicyCommandCode (
+ IN TPMI_SH_POLICY PolicySession,
+ IN TPM_CC Code
+ )
+{
+ EFI_STATUS Status;
+ TPM2_POLICY_COMMAND_CODE_COMMAND SendBuffer;
+ TPM2_POLICY_COMMAND_CODE_RESPONSE RecvBuffer;
+ UINT32 SendBufferSize;
+ UINT32 RecvBufferSize;
+
+ //
+ // Construct command
+ //
+ SendBuffer.Header.tag = SwapBytes16(TPM_ST_NO_SESSIONS);
+ SendBuffer.Header.commandCode = SwapBytes32(TPM_CC_PolicyCommandCode);
+
+ SendBuffer.PolicySession = SwapBytes32 (PolicySession);
+ SendBuffer.Code = SwapBytes32 (Code);
+
+ SendBufferSize = (UINT32) sizeof (SendBuffer);
+ SendBuffer.Header.paramSize = SwapBytes32 (SendBufferSize);
+
+ //
+ // send Tpm command
+ //
+ RecvBufferSize = sizeof (RecvBuffer);
+ Status = Tpm2SubmitCommand (SendBufferSize, (UINT8 *)&SendBuffer, &RecvBufferSize, (UINT8 *)&RecvBuffer);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER)) {
+ DEBUG ((EFI_D_ERROR, "Tpm2PolicyCommandCode - RecvBufferSize Error - %x\n", RecvBufferSize));
+ return EFI_DEVICE_ERROR;
+ }
+ if (SwapBytes32(RecvBuffer.Header.responseCode) != TPM_RC_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "Tpm2PolicyCommandCode - responseCode - %x\n", SwapBytes32(RecvBuffer.Header.responseCode)));
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This command returns the current policyDigest of the session. This command allows the TPM
+ to be used to perform the actions required to precompute the authPolicy for an object.
+
+ @param[in] PolicySession Handle for the policy session.
+ @param[out] PolicyHash the current value of the policyHash of policySession.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2PolicyGetDigest (
+ IN TPMI_SH_POLICY PolicySession,
+ OUT TPM2B_DIGEST *PolicyHash
+ )
+{
+ EFI_STATUS Status;
+ TPM2_POLICY_GET_DIGEST_COMMAND SendBuffer;
+ TPM2_POLICY_GET_DIGEST_RESPONSE RecvBuffer;
+ UINT32 SendBufferSize;
+ UINT32 RecvBufferSize;
+
+ //
+ // Construct command
+ //
+ SendBuffer.Header.tag = SwapBytes16(TPM_ST_NO_SESSIONS);
+ SendBuffer.Header.commandCode = SwapBytes32(TPM_CC_PolicyGetDigest);
+
+ SendBuffer.PolicySession = SwapBytes32 (PolicySession);
+
+ SendBufferSize = (UINT32) sizeof (SendBuffer);
+ SendBuffer.Header.paramSize = SwapBytes32 (SendBufferSize);
+
+ //
+ // send Tpm command
+ //
+ RecvBufferSize = sizeof (RecvBuffer);
+ Status = Tpm2SubmitCommand (SendBufferSize, (UINT8 *)&SendBuffer, &RecvBufferSize, (UINT8 *)&RecvBuffer);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER)) {
+ DEBUG ((EFI_D_ERROR, "Tpm2PolicyGetDigest - RecvBufferSize Error - %x\n", RecvBufferSize));
+ return EFI_DEVICE_ERROR;
+ }
+ if (SwapBytes32(RecvBuffer.Header.responseCode) != TPM_RC_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "Tpm2PolicyGetDigest - responseCode - %x\n", SwapBytes32(RecvBuffer.Header.responseCode)));
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Return the response
+ //
+ PolicyHash->size = SwapBytes16 (RecvBuffer.PolicyHash.size);
+ CopyMem (PolicyHash->buffer, &RecvBuffer.PolicyHash.buffer, PolicyHash->size);
+
+ return EFI_SUCCESS;
+}
diff --git a/Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2Help.c b/Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2Help.c
new file mode 100644
index 0000000000..180f360830
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2Help.c
@@ -0,0 +1,341 @@
+/** @file
+ Implement TPM2 help.
+
+Copyright (c) 2013 - 2017, Intel Corporation. All rights reserved. <BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <IndustryStandard/UefiTcgPlatform.h>
+#include <Library/Tpm2CommandLib.h>
+#include <Library/Tpm2DeviceLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+
+typedef struct {
+ TPMI_ALG_HASH HashAlgo;
+ UINT16 HashSize;
+ UINT32 HashMask;
+} INTERNAL_HASH_INFO;
+
+STATIC INTERNAL_HASH_INFO mHashInfo[] = {
+ {TPM_ALG_SHA1, SHA1_DIGEST_SIZE, HASH_ALG_SHA1},
+ {TPM_ALG_SHA256, SHA256_DIGEST_SIZE, HASH_ALG_SHA256},
+ {TPM_ALG_SM3_256, SM3_256_DIGEST_SIZE, HASH_ALG_SM3_256},
+ {TPM_ALG_SHA384, SHA384_DIGEST_SIZE, HASH_ALG_SHA384},
+ {TPM_ALG_SHA512, SHA512_DIGEST_SIZE, HASH_ALG_SHA512},
+};
+
+/**
+ Return size of digest.
+
+ @param[in] HashAlgo Hash algorithm
+
+ @return size of digest
+**/
+UINT16
+EFIAPI
+GetHashSizeFromAlgo (
+ IN TPMI_ALG_HASH HashAlgo
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < sizeof(mHashInfo)/sizeof(mHashInfo[0]); Index++) {
+ if (mHashInfo[Index].HashAlgo == HashAlgo) {
+ return mHashInfo[Index].HashSize;
+ }
+ }
+ return 0;
+}
+
+/**
+ Get hash mask from algorithm.
+
+ @param[in] HashAlgo Hash algorithm
+
+ @return Hash mask
+**/
+UINT32
+EFIAPI
+GetHashMaskFromAlgo (
+ IN TPMI_ALG_HASH HashAlgo
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < sizeof(mHashInfo)/sizeof(mHashInfo[0]); Index++) {
+ if (mHashInfo[Index].HashAlgo == HashAlgo) {
+ return mHashInfo[Index].HashMask;
+ }
+ }
+ return 0;
+}
+
+/**
+ Copy AuthSessionIn to TPM2 command buffer.
+
+ @param [in] AuthSessionIn Input AuthSession data
+ @param [out] AuthSessionOut Output AuthSession data in TPM2 command buffer
+
+ @return AuthSession size
+**/
+UINT32
+EFIAPI
+CopyAuthSessionCommand (
+ IN TPMS_AUTH_COMMAND *AuthSessionIn, OPTIONAL
+ OUT UINT8 *AuthSessionOut
+ )
+{
+ UINT8 *Buffer;
+
+ Buffer = (UINT8 *)AuthSessionOut;
+
+ //
+ // Add in Auth session
+ //
+ if (AuthSessionIn != NULL) {
+ // sessionHandle
+ WriteUnaligned32 ((UINT32 *)Buffer, SwapBytes32(AuthSessionIn->sessionHandle));
+ Buffer += sizeof(UINT32);
+
+ // nonce
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (AuthSessionIn->nonce.size));
+ Buffer += sizeof(UINT16);
+
+ CopyMem (Buffer, AuthSessionIn->nonce.buffer, AuthSessionIn->nonce.size);
+ Buffer += AuthSessionIn->nonce.size;
+
+ // sessionAttributes
+ *(UINT8 *)Buffer = *(UINT8 *)&AuthSessionIn->sessionAttributes;
+ Buffer++;
+
+ // hmac
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (AuthSessionIn->hmac.size));
+ Buffer += sizeof(UINT16);
+
+ CopyMem (Buffer, AuthSessionIn->hmac.buffer, AuthSessionIn->hmac.size);
+ Buffer += AuthSessionIn->hmac.size;
+ } else {
+ // sessionHandle
+ WriteUnaligned32 ((UINT32 *)Buffer, SwapBytes32(TPM_RS_PW));
+ Buffer += sizeof(UINT32);
+
+ // nonce = nullNonce
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16(0));
+ Buffer += sizeof(UINT16);
+
+ // sessionAttributes = 0
+ *(UINT8 *)Buffer = 0x00;
+ Buffer++;
+
+ // hmac = nullAuth
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16(0));
+ Buffer += sizeof(UINT16);
+ }
+
+ return (UINT32)((UINTN)Buffer - (UINTN)AuthSessionOut);
+}
+
+/**
+ Copy AuthSessionIn from TPM2 response buffer.
+
+ @param [in] AuthSessionIn Input AuthSession data in TPM2 response buffer
+ @param [out] AuthSessionOut Output AuthSession data
+
+ @return AuthSession size
+**/
+UINT32
+EFIAPI
+CopyAuthSessionResponse (
+ IN UINT8 *AuthSessionIn,
+ OUT TPMS_AUTH_RESPONSE *AuthSessionOut OPTIONAL
+ )
+{
+ UINT8 *Buffer;
+ TPMS_AUTH_RESPONSE LocalAuthSessionOut;
+
+ if (AuthSessionOut == NULL) {
+ AuthSessionOut = &LocalAuthSessionOut;
+ }
+
+ Buffer = (UINT8 *)AuthSessionIn;
+
+ // nonce
+ AuthSessionOut->nonce.size = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer));
+ Buffer += sizeof(UINT16);
+
+ CopyMem (AuthSessionOut->nonce.buffer, Buffer, AuthSessionOut->nonce.size);
+ Buffer += AuthSessionOut->nonce.size;
+
+ // sessionAttributes
+ *(UINT8 *)&AuthSessionOut->sessionAttributes = *(UINT8 *)Buffer;
+ Buffer++;
+
+ // hmac
+ AuthSessionOut->hmac.size = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer));
+ Buffer += sizeof(UINT16);
+
+ CopyMem (AuthSessionOut->hmac.buffer, Buffer, AuthSessionOut->hmac.size);
+ Buffer += AuthSessionOut->hmac.size;
+
+ return (UINT32)((UINTN)Buffer - (UINTN)AuthSessionIn);
+}
+
+/**
+ Return if hash alg is supported in HashAlgorithmMask.
+
+ @param HashAlg Hash algorithm to be checked.
+ @param HashAlgorithmMask Bitfield of allowed hash algorithms.
+
+ @retval TRUE Hash algorithm is supported.
+ @retval FALSE Hash algorithm is not supported.
+**/
+BOOLEAN
+EFIAPI
+IsHashAlgSupportedInHashAlgorithmMask(
+ IN TPMI_ALG_HASH HashAlg,
+ IN UINT32 HashAlgorithmMask
+ )
+{
+ switch (HashAlg) {
+ case TPM_ALG_SHA1:
+ if ((HashAlgorithmMask & HASH_ALG_SHA1) != 0) {
+ return TRUE;
+ }
+ break;
+ case TPM_ALG_SHA256:
+ if ((HashAlgorithmMask & HASH_ALG_SHA256) != 0) {
+ return TRUE;
+ }
+ break;
+ case TPM_ALG_SHA384:
+ if ((HashAlgorithmMask & HASH_ALG_SHA384) != 0) {
+ return TRUE;
+ }
+ break;
+ case TPM_ALG_SHA512:
+ if ((HashAlgorithmMask & HASH_ALG_SHA512) != 0) {
+ return TRUE;
+ }
+ break;
+ case TPM_ALG_SM3_256:
+ if ((HashAlgorithmMask & HASH_ALG_SM3_256) != 0) {
+ return TRUE;
+ }
+ break;
+ }
+
+ return FALSE;
+}
+
+/**
+ Copy TPML_DIGEST_VALUES into a buffer
+
+ @param[in,out] Buffer Buffer to hold copied TPML_DIGEST_VALUES compact binary.
+ @param[in] DigestList TPML_DIGEST_VALUES to be copied.
+ @param[in] HashAlgorithmMask HASH bits corresponding to the desired digests to copy.
+
+ @return The end of buffer to hold TPML_DIGEST_VALUES.
+**/
+VOID *
+EFIAPI
+CopyDigestListToBuffer (
+ IN OUT VOID *Buffer,
+ IN TPML_DIGEST_VALUES *DigestList,
+ IN UINT32 HashAlgorithmMask
+ )
+{
+ UINTN Index;
+ UINT16 DigestSize;
+ UINT32 DigestListCount;
+ UINT32 *DigestListCountPtr;
+
+ DigestListCountPtr = (UINT32 *) Buffer;
+ DigestListCount = 0;
+ Buffer = (UINT8 *)Buffer + sizeof(DigestList->count);
+ for (Index = 0; Index < DigestList->count; Index++) {
+ if (!IsHashAlgSupportedInHashAlgorithmMask(DigestList->digests[Index].hashAlg, HashAlgorithmMask)) {
+ DEBUG ((EFI_D_ERROR, "WARNING: TPM2 Event log has HashAlg unsupported by PCR bank (0x%x)\n", DigestList->digests[Index].hashAlg));
+ continue;
+ }
+ CopyMem (Buffer, &DigestList->digests[Index].hashAlg, sizeof(DigestList->digests[Index].hashAlg));
+ Buffer = (UINT8 *)Buffer + sizeof(DigestList->digests[Index].hashAlg);
+ DigestSize = GetHashSizeFromAlgo (DigestList->digests[Index].hashAlg);
+ CopyMem (Buffer, &DigestList->digests[Index].digest, DigestSize);
+ Buffer = (UINT8 *)Buffer + DigestSize;
+ DigestListCount++;
+ }
+ WriteUnaligned32 (DigestListCountPtr, DigestListCount);
+
+ return Buffer;
+}
+
+/**
+ Get TPML_DIGEST_VALUES data size.
+
+ @param[in] DigestList TPML_DIGEST_VALUES data.
+
+ @return TPML_DIGEST_VALUES data size.
+**/
+UINT32
+EFIAPI
+GetDigestListSize (
+ IN TPML_DIGEST_VALUES *DigestList
+ )
+{
+ UINTN Index;
+ UINT16 DigestSize;
+ UINT32 TotalSize;
+
+ TotalSize = sizeof(DigestList->count);
+ for (Index = 0; Index < DigestList->count; Index++) {
+ DigestSize = GetHashSizeFromAlgo (DigestList->digests[Index].hashAlg);
+ TotalSize += sizeof(DigestList->digests[Index].hashAlg) + DigestSize;
+ }
+
+ return TotalSize;
+}
+
+/**
+ This function get digest from digest list.
+
+ @param[in] HashAlg Digest algorithm
+ @param[in] DigestList Digest list
+ @param[out] Digest Digest
+
+ @retval EFI_SUCCESS Digest is found and returned.
+ @retval EFI_NOT_FOUND Digest is not found.
+**/
+EFI_STATUS
+EFIAPI
+GetDigestFromDigestList (
+ IN TPMI_ALG_HASH HashAlg,
+ IN TPML_DIGEST_VALUES *DigestList,
+ OUT VOID *Digest
+ )
+{
+ UINTN Index;
+ UINT16 DigestSize;
+
+ DigestSize = GetHashSizeFromAlgo (HashAlg);
+ for (Index = 0; Index < DigestList->count; Index++) {
+ if (DigestList->digests[Index].hashAlg == HashAlg) {
+ CopyMem (
+ Digest,
+ &DigestList->digests[Index].digest,
+ DigestSize
+ );
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
diff --git a/Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2Hierarchy.c b/Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2Hierarchy.c
new file mode 100644
index 0000000000..9bfbdad394
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2Hierarchy.c
@@ -0,0 +1,803 @@
+/** @file
+ Implement TPM2 Hierarchy related command.
+
+Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved. <BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <IndustryStandard/UefiTcgPlatform.h>
+#include <Library/Tpm2CommandLib.h>
+#include <Library/Tpm2DeviceLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+
+#pragma pack(1)
+
+typedef struct {
+ TPM2_COMMAND_HEADER Header;
+ TPMI_RH_HIERARCHY_AUTH AuthHandle;
+ UINT32 AuthSessionSize;
+ TPMS_AUTH_COMMAND AuthSession;
+ TPM2B_DIGEST AuthPolicy;
+ TPMI_ALG_HASH HashAlg;
+} TPM2_SET_PRIMARY_POLICY_COMMAND;
+
+typedef struct {
+ TPM2_RESPONSE_HEADER Header;
+ UINT32 AuthSessionSize;
+ TPMS_AUTH_RESPONSE AuthSession;
+} TPM2_SET_PRIMARY_POLICY_RESPONSE;
+
+typedef struct {
+ TPM2_COMMAND_HEADER Header;
+ TPMI_RH_CLEAR AuthHandle;
+ UINT32 AuthorizationSize;
+ TPMS_AUTH_COMMAND AuthSession;
+} TPM2_CLEAR_COMMAND;
+
+typedef struct {
+ TPM2_RESPONSE_HEADER Header;
+ UINT32 ParameterSize;
+ TPMS_AUTH_RESPONSE AuthSession;
+} TPM2_CLEAR_RESPONSE;
+
+typedef struct {
+ TPM2_COMMAND_HEADER Header;
+ TPMI_RH_CLEAR AuthHandle;
+ UINT32 AuthorizationSize;
+ TPMS_AUTH_COMMAND AuthSession;
+ TPMI_YES_NO Disable;
+} TPM2_CLEAR_CONTROL_COMMAND;
+
+typedef struct {
+ TPM2_RESPONSE_HEADER Header;
+ UINT32 ParameterSize;
+ TPMS_AUTH_RESPONSE AuthSession;
+} TPM2_CLEAR_CONTROL_RESPONSE;
+
+typedef struct {
+ TPM2_COMMAND_HEADER Header;
+ TPMI_RH_HIERARCHY_AUTH AuthHandle;
+ UINT32 AuthorizationSize;
+ TPMS_AUTH_COMMAND AuthSession;
+ TPM2B_AUTH NewAuth;
+} TPM2_HIERARCHY_CHANGE_AUTH_COMMAND;
+
+typedef struct {
+ TPM2_RESPONSE_HEADER Header;
+ UINT32 ParameterSize;
+ TPMS_AUTH_RESPONSE AuthSession;
+} TPM2_HIERARCHY_CHANGE_AUTH_RESPONSE;
+
+typedef struct {
+ TPM2_COMMAND_HEADER Header;
+ TPMI_RH_PLATFORM AuthHandle;
+ UINT32 AuthorizationSize;
+ TPMS_AUTH_COMMAND AuthSession;
+} TPM2_CHANGE_EPS_COMMAND;
+
+typedef struct {
+ TPM2_RESPONSE_HEADER Header;
+ UINT32 ParameterSize;
+ TPMS_AUTH_RESPONSE AuthSession;
+} TPM2_CHANGE_EPS_RESPONSE;
+
+typedef struct {
+ TPM2_COMMAND_HEADER Header;
+ TPMI_RH_PLATFORM AuthHandle;
+ UINT32 AuthorizationSize;
+ TPMS_AUTH_COMMAND AuthSession;
+} TPM2_CHANGE_PPS_COMMAND;
+
+typedef struct {
+ TPM2_RESPONSE_HEADER Header;
+ UINT32 ParameterSize;
+ TPMS_AUTH_RESPONSE AuthSession;
+} TPM2_CHANGE_PPS_RESPONSE;
+
+typedef struct {
+ TPM2_COMMAND_HEADER Header;
+ TPMI_RH_HIERARCHY AuthHandle;
+ UINT32 AuthorizationSize;
+ TPMS_AUTH_COMMAND AuthSession;
+ TPMI_RH_HIERARCHY Hierarchy;
+ TPMI_YES_NO State;
+} TPM2_HIERARCHY_CONTROL_COMMAND;
+
+typedef struct {
+ TPM2_RESPONSE_HEADER Header;
+ UINT32 ParameterSize;
+ TPMS_AUTH_RESPONSE AuthSession;
+} TPM2_HIERARCHY_CONTROL_RESPONSE;
+
+#pragma pack()
+
+/**
+ This command allows setting of the authorization policy for the platform hierarchy (platformPolicy), the
+ storage hierarchy (ownerPolicy), and and the endorsement hierarchy (endorsementPolicy).
+
+ @param[in] AuthHandle TPM_RH_ENDORSEMENT, TPM_RH_OWNER or TPM_RH_PLATFORM+{PP} parameters to be validated
+ @param[in] AuthSession Auth Session context
+ @param[in] AuthPolicy An authorization policy hash
+ @param[in] HashAlg The hash algorithm to use for the policy
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2SetPrimaryPolicy (
+ IN TPMI_RH_HIERARCHY_AUTH AuthHandle,
+ IN TPMS_AUTH_COMMAND *AuthSession,
+ IN TPM2B_DIGEST *AuthPolicy,
+ IN TPMI_ALG_HASH HashAlg
+ )
+{
+ EFI_STATUS Status;
+ TPM2_SET_PRIMARY_POLICY_COMMAND SendBuffer;
+ TPM2_SET_PRIMARY_POLICY_RESPONSE RecvBuffer;
+ UINT32 SendBufferSize;
+ UINT32 RecvBufferSize;
+ UINT8 *Buffer;
+ UINT32 SessionInfoSize;
+
+ //
+ // Construct command
+ //
+ SendBuffer.Header.tag = SwapBytes16(TPM_ST_SESSIONS);
+ SendBuffer.Header.commandCode = SwapBytes32(TPM_CC_SetPrimaryPolicy);
+
+ SendBuffer.AuthHandle = SwapBytes32 (AuthHandle);
+
+ //
+ // Add in Auth session
+ //
+ Buffer = (UINT8 *)&SendBuffer.AuthSession;
+
+ // sessionInfoSize
+ SessionInfoSize = CopyAuthSessionCommand (AuthSession, Buffer);
+ Buffer += SessionInfoSize;
+ SendBuffer.AuthSessionSize = SwapBytes32(SessionInfoSize);
+
+ //
+ // Real data
+ //
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16(AuthPolicy->size));
+ Buffer += sizeof(UINT16);
+ CopyMem (Buffer, AuthPolicy->buffer, AuthPolicy->size);
+ Buffer += AuthPolicy->size;
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16(HashAlg));
+ Buffer += sizeof(UINT16);
+
+ SendBufferSize = (UINT32)((UINTN)Buffer - (UINTN)&SendBuffer);
+ SendBuffer.Header.paramSize = SwapBytes32 (SendBufferSize);
+
+ //
+ // send Tpm command
+ //
+ RecvBufferSize = sizeof (RecvBuffer);
+ Status = Tpm2SubmitCommand (SendBufferSize, (UINT8 *)&SendBuffer, &RecvBufferSize, (UINT8 *)&RecvBuffer);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER)) {
+ DEBUG ((EFI_D_ERROR, "Tpm2SetPrimaryPolicy - RecvBufferSize Error - %x\n", RecvBufferSize));
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+ if (SwapBytes32(RecvBuffer.Header.responseCode) != TPM_RC_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "Tpm2SetPrimaryPolicy - responseCode - %x\n", SwapBytes32(RecvBuffer.Header.responseCode)));
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+Done:
+ //
+ // Clear AuthSession Content
+ //
+ ZeroMem (&SendBuffer, sizeof(SendBuffer));
+ ZeroMem (&RecvBuffer, sizeof(RecvBuffer));
+ return Status;
+}
+
+/**
+ This command removes all TPM context associated with a specific Owner.
+
+ @param[in] AuthHandle TPM_RH_LOCKOUT or TPM_RH_PLATFORM+{PP}
+ @param[in] AuthSession Auth Session context
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2Clear (
+ IN TPMI_RH_CLEAR AuthHandle,
+ IN TPMS_AUTH_COMMAND *AuthSession OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ TPM2_CLEAR_COMMAND Cmd;
+ TPM2_CLEAR_RESPONSE Res;
+ UINT32 ResultBufSize;
+ UINT32 CmdSize;
+ UINT32 RespSize;
+ UINT8 *Buffer;
+ UINT32 SessionInfoSize;
+
+ Cmd.Header.tag = SwapBytes16(TPM_ST_SESSIONS);
+ Cmd.Header.commandCode = SwapBytes32(TPM_CC_Clear);
+ Cmd.AuthHandle = SwapBytes32(AuthHandle);
+
+ //
+ // Add in Auth session
+ //
+ Buffer = (UINT8 *)&Cmd.AuthSession;
+
+ // sessionInfoSize
+ SessionInfoSize = CopyAuthSessionCommand (AuthSession, Buffer);
+ Buffer += SessionInfoSize;
+ Cmd.AuthorizationSize = SwapBytes32(SessionInfoSize);
+
+ CmdSize = (UINT32)(Buffer - (UINT8 *)&Cmd);
+ Cmd.Header.paramSize = SwapBytes32(CmdSize);
+
+ ResultBufSize = sizeof(Res);
+ Status = Tpm2SubmitCommand (CmdSize, (UINT8 *)&Cmd, &ResultBufSize, (UINT8 *)&Res);
+ if (EFI_ERROR(Status)) {
+ goto Done;
+ }
+
+ if (ResultBufSize > sizeof(Res)) {
+ DEBUG ((EFI_D_ERROR, "Clear: Failed ExecuteCommand: Buffer Too Small\r\n"));
+ Status = EFI_BUFFER_TOO_SMALL;
+ goto Done;
+ }
+
+ //
+ // Validate response headers
+ //
+ RespSize = SwapBytes32(Res.Header.paramSize);
+ if (RespSize > sizeof(Res)) {
+ DEBUG ((EFI_D_ERROR, "Clear: Response size too large! %d\r\n", RespSize));
+ Status = EFI_BUFFER_TOO_SMALL;
+ goto Done;
+ }
+
+ //
+ // Fail if command failed
+ //
+ if (SwapBytes32(Res.Header.responseCode) != TPM_RC_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "Clear: Response Code error! 0x%08x\r\n", SwapBytes32(Res.Header.responseCode)));
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+ //
+ // Unmarshal the response
+ //
+
+ // None
+Done:
+ //
+ // Clear AuthSession Content
+ //
+ ZeroMem (&Cmd, sizeof(Cmd));
+ ZeroMem (&Res, sizeof(Res));
+ return Status;
+}
+
+/**
+ Disables and enables the execution of TPM2_Clear().
+
+ @param[in] AuthHandle TPM_RH_LOCKOUT or TPM_RH_PLATFORM+{PP}
+ @param[in] AuthSession Auth Session context
+ @param[in] Disable YES if the disableOwnerClear flag is to be SET,
+ NO if the flag is to be CLEAR.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2ClearControl (
+ IN TPMI_RH_CLEAR AuthHandle,
+ IN TPMS_AUTH_COMMAND *AuthSession, OPTIONAL
+ IN TPMI_YES_NO Disable
+ )
+{
+ EFI_STATUS Status;
+ TPM2_CLEAR_CONTROL_COMMAND Cmd;
+ TPM2_CLEAR_CONTROL_RESPONSE Res;
+ UINT32 ResultBufSize;
+ UINT32 CmdSize;
+ UINT32 RespSize;
+ UINT8 *Buffer;
+ UINT32 SessionInfoSize;
+
+ Cmd.Header.tag = SwapBytes16(TPM_ST_SESSIONS);
+ Cmd.Header.commandCode = SwapBytes32(TPM_CC_ClearControl);
+ Cmd.AuthHandle = SwapBytes32(AuthHandle);
+
+ //
+ // Add in Auth session
+ //
+ Buffer = (UINT8 *)&Cmd.AuthSession;
+
+ // sessionInfoSize
+ SessionInfoSize = CopyAuthSessionCommand (AuthSession, Buffer);
+ Buffer += SessionInfoSize;
+ Cmd.AuthorizationSize = SwapBytes32(SessionInfoSize);
+
+ // disable
+ *(UINT8 *)Buffer = Disable;
+ Buffer++;
+
+ CmdSize = (UINT32)(Buffer - (UINT8 *)&Cmd);
+ Cmd.Header.paramSize = SwapBytes32(CmdSize);
+
+ ResultBufSize = sizeof(Res);
+ Status = Tpm2SubmitCommand (CmdSize, (UINT8 *)&Cmd, &ResultBufSize, (UINT8 *)&Res);
+ if (EFI_ERROR(Status)) {
+ goto Done;
+ }
+
+ if (ResultBufSize > sizeof(Res)) {
+ DEBUG ((EFI_D_ERROR, "ClearControl: Failed ExecuteCommand: Buffer Too Small\r\n"));
+ Status = EFI_BUFFER_TOO_SMALL;
+ goto Done;
+ }
+
+ //
+ // Validate response headers
+ //
+ RespSize = SwapBytes32(Res.Header.paramSize);
+ if (RespSize > sizeof(Res)) {
+ DEBUG ((EFI_D_ERROR, "ClearControl: Response size too large! %d\r\n", RespSize));
+ Status = EFI_BUFFER_TOO_SMALL;
+ goto Done;
+ }
+
+ //
+ // Fail if command failed
+ //
+ if (SwapBytes32(Res.Header.responseCode) != TPM_RC_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "ClearControl: Response Code error! 0x%08x\r\n", SwapBytes32(Res.Header.responseCode)));
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+ //
+ // Unmarshal the response
+ //
+
+ // None
+Done:
+ //
+ // Clear AuthSession Content
+ //
+ ZeroMem (&Cmd, sizeof(Cmd));
+ ZeroMem (&Res, sizeof(Res));
+ return Status;
+}
+
+/**
+ This command allows the authorization secret for a hierarchy or lockout to be changed using the current
+ authorization value as the command authorization.
+
+ @param[in] AuthHandle TPM_RH_LOCKOUT, TPM_RH_ENDORSEMENT, TPM_RH_OWNER or TPM_RH_PLATFORM+{PP}
+ @param[in] AuthSession Auth Session context
+ @param[in] NewAuth New authorization secret
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2HierarchyChangeAuth (
+ IN TPMI_RH_HIERARCHY_AUTH AuthHandle,
+ IN TPMS_AUTH_COMMAND *AuthSession,
+ IN TPM2B_AUTH *NewAuth
+ )
+{
+ EFI_STATUS Status;
+ TPM2_HIERARCHY_CHANGE_AUTH_COMMAND Cmd;
+ TPM2_HIERARCHY_CHANGE_AUTH_RESPONSE Res;
+ UINT32 CmdSize;
+ UINT32 RespSize;
+ UINT8 *Buffer;
+ UINT32 SessionInfoSize;
+ UINT8 *ResultBuf;
+ UINT32 ResultBufSize;
+
+ //
+ // Construct command
+ //
+ Cmd.Header.tag = SwapBytes16(TPM_ST_SESSIONS);
+ Cmd.Header.paramSize = SwapBytes32(sizeof(Cmd));
+ Cmd.Header.commandCode = SwapBytes32(TPM_CC_HierarchyChangeAuth);
+ Cmd.AuthHandle = SwapBytes32(AuthHandle);
+
+ //
+ // Add in Auth session
+ //
+ Buffer = (UINT8 *)&Cmd.AuthSession;
+
+ // sessionInfoSize
+ SessionInfoSize = CopyAuthSessionCommand (AuthSession, Buffer);
+ Buffer += SessionInfoSize;
+ Cmd.AuthorizationSize = SwapBytes32(SessionInfoSize);
+
+ // New Authorization size
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16(NewAuth->size));
+ Buffer += sizeof(UINT16);
+
+ // New Authorizeation
+ CopyMem(Buffer, NewAuth->buffer, NewAuth->size);
+ Buffer += NewAuth->size;
+
+ CmdSize = (UINT32)(Buffer - (UINT8 *)&Cmd);
+ Cmd.Header.paramSize = SwapBytes32(CmdSize);
+
+ ResultBuf = (UINT8 *) &Res;
+ ResultBufSize = sizeof(Res);
+
+ //
+ // Call the TPM
+ //
+ Status = Tpm2SubmitCommand (
+ CmdSize,
+ (UINT8 *)&Cmd,
+ &ResultBufSize,
+ ResultBuf
+ );
+ if (EFI_ERROR(Status)) {
+ goto Done;
+ }
+
+ if (ResultBufSize > sizeof(Res)) {
+ DEBUG ((EFI_D_ERROR, "HierarchyChangeAuth: Failed ExecuteCommand: Buffer Too Small\r\n"));
+ Status = EFI_BUFFER_TOO_SMALL;
+ goto Done;
+ }
+
+ //
+ // Validate response headers
+ //
+ RespSize = SwapBytes32(Res.Header.paramSize);
+ if (RespSize > sizeof(Res)) {
+ DEBUG ((EFI_D_ERROR, "HierarchyChangeAuth: Response size too large! %d\r\n", RespSize));
+ Status = EFI_BUFFER_TOO_SMALL;
+ goto Done;
+ }
+
+ //
+ // Fail if command failed
+ //
+ if (SwapBytes32(Res.Header.responseCode) != TPM_RC_SUCCESS) {
+ DEBUG((EFI_D_ERROR,"HierarchyChangeAuth: Response Code error! 0x%08x\r\n", SwapBytes32(Res.Header.responseCode)));
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+Done:
+ //
+ // Clear AuthSession Content
+ //
+ ZeroMem (&Cmd, sizeof(Cmd));
+ ZeroMem (&Res, sizeof(Res));
+ return Status;
+}
+
+/**
+ This replaces the current EPS with a value from the RNG and sets the Endorsement hierarchy controls to
+ their default initialization values.
+
+ @param[in] AuthHandle TPM_RH_PLATFORM+{PP}
+ @param[in] AuthSession Auth Session context
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2ChangeEPS (
+ IN TPMI_RH_PLATFORM AuthHandle,
+ IN TPMS_AUTH_COMMAND *AuthSession
+ )
+{
+ EFI_STATUS Status;
+ TPM2_CHANGE_EPS_COMMAND Cmd;
+ TPM2_CHANGE_EPS_RESPONSE Res;
+ UINT32 CmdSize;
+ UINT32 RespSize;
+ UINT8 *Buffer;
+ UINT32 SessionInfoSize;
+ UINT8 *ResultBuf;
+ UINT32 ResultBufSize;
+
+ //
+ // Construct command
+ //
+ Cmd.Header.tag = SwapBytes16(TPM_ST_SESSIONS);
+ Cmd.Header.paramSize = SwapBytes32(sizeof(Cmd));
+ Cmd.Header.commandCode = SwapBytes32(TPM_CC_ChangeEPS);
+ Cmd.AuthHandle = SwapBytes32(AuthHandle);
+
+ //
+ // Add in Auth session
+ //
+ Buffer = (UINT8 *)&Cmd.AuthSession;
+
+ // sessionInfoSize
+ SessionInfoSize = CopyAuthSessionCommand (AuthSession, Buffer);
+ Buffer += SessionInfoSize;
+ Cmd.AuthorizationSize = SwapBytes32(SessionInfoSize);
+
+ CmdSize = (UINT32)(Buffer - (UINT8 *)&Cmd);
+ Cmd.Header.paramSize = SwapBytes32(CmdSize);
+
+ ResultBuf = (UINT8 *) &Res;
+ ResultBufSize = sizeof(Res);
+
+ //
+ // Call the TPM
+ //
+ Status = Tpm2SubmitCommand (
+ CmdSize,
+ (UINT8 *)&Cmd,
+ &ResultBufSize,
+ ResultBuf
+ );
+ if (EFI_ERROR(Status)) {
+ goto Done;
+ }
+
+ if (ResultBufSize > sizeof(Res)) {
+ DEBUG ((EFI_D_ERROR, "ChangeEPS: Failed ExecuteCommand: Buffer Too Small\r\n"));
+ Status = EFI_BUFFER_TOO_SMALL;
+ goto Done;
+ }
+
+ //
+ // Validate response headers
+ //
+ RespSize = SwapBytes32(Res.Header.paramSize);
+ if (RespSize > sizeof(Res)) {
+ DEBUG ((EFI_D_ERROR, "ChangeEPS: Response size too large! %d\r\n", RespSize));
+ Status = EFI_BUFFER_TOO_SMALL;
+ goto Done;
+ }
+
+ //
+ // Fail if command failed
+ //
+ if (SwapBytes32(Res.Header.responseCode) != TPM_RC_SUCCESS) {
+ DEBUG((EFI_D_ERROR,"ChangeEPS: Response Code error! 0x%08x\r\n", SwapBytes32(Res.Header.responseCode)));
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+Done:
+ //
+ // Clear AuthSession Content
+ //
+ ZeroMem (&Cmd, sizeof(Cmd));
+ ZeroMem (&Res, sizeof(Res));
+ return Status;
+}
+
+/**
+ This replaces the current PPS with a value from the RNG and sets platformPolicy to the default
+ initialization value (the Empty Buffer).
+
+ @param[in] AuthHandle TPM_RH_PLATFORM+{PP}
+ @param[in] AuthSession Auth Session context
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2ChangePPS (
+ IN TPMI_RH_PLATFORM AuthHandle,
+ IN TPMS_AUTH_COMMAND *AuthSession
+ )
+{
+ EFI_STATUS Status;
+ TPM2_CHANGE_PPS_COMMAND Cmd;
+ TPM2_CHANGE_PPS_RESPONSE Res;
+ UINT32 CmdSize;
+ UINT32 RespSize;
+ UINT8 *Buffer;
+ UINT32 SessionInfoSize;
+ UINT8 *ResultBuf;
+ UINT32 ResultBufSize;
+
+ //
+ // Construct command
+ //
+ Cmd.Header.tag = SwapBytes16(TPM_ST_SESSIONS);
+ Cmd.Header.paramSize = SwapBytes32(sizeof(Cmd));
+ Cmd.Header.commandCode = SwapBytes32(TPM_CC_ChangePPS);
+ Cmd.AuthHandle = SwapBytes32(AuthHandle);
+
+ //
+ // Add in Auth session
+ //
+ Buffer = (UINT8 *)&Cmd.AuthSession;
+
+ // sessionInfoSize
+ SessionInfoSize = CopyAuthSessionCommand (AuthSession, Buffer);
+ Buffer += SessionInfoSize;
+ Cmd.AuthorizationSize = SwapBytes32(SessionInfoSize);
+
+ CmdSize = (UINT32)(Buffer - (UINT8 *)&Cmd);
+ Cmd.Header.paramSize = SwapBytes32(CmdSize);
+
+ ResultBuf = (UINT8 *) &Res;
+ ResultBufSize = sizeof(Res);
+
+ //
+ // Call the TPM
+ //
+ Status = Tpm2SubmitCommand (
+ CmdSize,
+ (UINT8 *)&Cmd,
+ &ResultBufSize,
+ ResultBuf
+ );
+ if (EFI_ERROR(Status)) {
+ goto Done;
+ }
+
+ if (ResultBufSize > sizeof(Res)) {
+ DEBUG ((EFI_D_ERROR, "ChangePPS: Failed ExecuteCommand: Buffer Too Small\r\n"));
+ Status = EFI_BUFFER_TOO_SMALL;
+ goto Done;
+ }
+
+ //
+ // Validate response headers
+ //
+ RespSize = SwapBytes32(Res.Header.paramSize);
+ if (RespSize > sizeof(Res)) {
+ DEBUG ((EFI_D_ERROR, "ChangePPS: Response size too large! %d\r\n", RespSize));
+ Status = EFI_BUFFER_TOO_SMALL;
+ goto Done;
+ }
+
+ //
+ // Fail if command failed
+ //
+ if (SwapBytes32(Res.Header.responseCode) != TPM_RC_SUCCESS) {
+ DEBUG((EFI_D_ERROR,"ChangePPS: Response Code error! 0x%08x\r\n", SwapBytes32(Res.Header.responseCode)));
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+Done:
+ //
+ // Clear AuthSession Content
+ //
+ ZeroMem (&Cmd, sizeof(Cmd));
+ ZeroMem (&Res, sizeof(Res));
+ return Status;
+}
+
+/**
+ This command enables and disables use of a hierarchy.
+
+ @param[in] AuthHandle TPM_RH_ENDORSEMENT, TPM_RH_OWNER or TPM_RH_PLATFORM+{PP}
+ @param[in] AuthSession Auth Session context
+ @param[in] Hierarchy Hierarchy of the enable being modified
+ @param[in] State YES if the enable should be SET,
+ NO if the enable should be CLEAR
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2HierarchyControl (
+ IN TPMI_RH_HIERARCHY AuthHandle,
+ IN TPMS_AUTH_COMMAND *AuthSession,
+ IN TPMI_RH_HIERARCHY Hierarchy,
+ IN TPMI_YES_NO State
+ )
+{
+ EFI_STATUS Status;
+ TPM2_HIERARCHY_CONTROL_COMMAND Cmd;
+ TPM2_HIERARCHY_CONTROL_RESPONSE Res;
+ UINT32 CmdSize;
+ UINT32 RespSize;
+ UINT8 *Buffer;
+ UINT32 SessionInfoSize;
+ UINT8 *ResultBuf;
+ UINT32 ResultBufSize;
+
+ //
+ // Construct command
+ //
+ Cmd.Header.tag = SwapBytes16(TPM_ST_SESSIONS);
+ Cmd.Header.paramSize = SwapBytes32(sizeof(Cmd));
+ Cmd.Header.commandCode = SwapBytes32(TPM_CC_HierarchyControl);
+ Cmd.AuthHandle = SwapBytes32(AuthHandle);
+
+ //
+ // Add in Auth session
+ //
+ Buffer = (UINT8 *)&Cmd.AuthSession;
+
+ // sessionInfoSize
+ SessionInfoSize = CopyAuthSessionCommand (AuthSession, Buffer);
+ Buffer += SessionInfoSize;
+ Cmd.AuthorizationSize = SwapBytes32(SessionInfoSize);
+
+ WriteUnaligned32 ((UINT32 *)Buffer, SwapBytes32(Hierarchy));
+ Buffer += sizeof(UINT32);
+
+ *(UINT8 *)Buffer = State;
+ Buffer++;
+
+ CmdSize = (UINT32)(Buffer - (UINT8 *)&Cmd);
+ Cmd.Header.paramSize = SwapBytes32(CmdSize);
+
+ ResultBuf = (UINT8 *) &Res;
+ ResultBufSize = sizeof(Res);
+
+ //
+ // Call the TPM
+ //
+ Status = Tpm2SubmitCommand (
+ CmdSize,
+ (UINT8 *)&Cmd,
+ &ResultBufSize,
+ ResultBuf
+ );
+ if (EFI_ERROR(Status)) {
+ goto Done;
+ }
+
+ if (ResultBufSize > sizeof(Res)) {
+ DEBUG ((EFI_D_ERROR, "HierarchyControl: Failed ExecuteCommand: Buffer Too Small\r\n"));
+ Status = EFI_BUFFER_TOO_SMALL;
+ goto Done;
+ }
+
+ //
+ // Validate response headers
+ //
+ RespSize = SwapBytes32(Res.Header.paramSize);
+ if (RespSize > sizeof(Res)) {
+ DEBUG ((EFI_D_ERROR, "HierarchyControl: Response size too large! %d\r\n", RespSize));
+ Status = EFI_BUFFER_TOO_SMALL;
+ goto Done;
+ }
+
+ //
+ // Fail if command failed
+ //
+ if (SwapBytes32(Res.Header.responseCode) != TPM_RC_SUCCESS) {
+ DEBUG((EFI_D_ERROR,"HierarchyControl: Response Code error! 0x%08x\r\n", SwapBytes32(Res.Header.responseCode)));
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+Done:
+ //
+ // Clear AuthSession Content
+ //
+ ZeroMem (&Cmd, sizeof(Cmd));
+ ZeroMem (&Res, sizeof(Res));
+ return Status;
+}
diff --git a/Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2Integrity.c b/Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2Integrity.c
new file mode 100644
index 0000000000..8eacfe6c13
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2Integrity.c
@@ -0,0 +1,671 @@
+/** @file
+ Implement TPM2 Integrity related command.
+
+Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved. <BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <IndustryStandard/UefiTcgPlatform.h>
+#include <Library/Tpm2CommandLib.h>
+#include <Library/Tpm2DeviceLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+
+#pragma pack(1)
+
+typedef struct {
+ TPM2_COMMAND_HEADER Header;
+ TPMI_DH_PCR PcrHandle;
+ UINT32 AuthorizationSize;
+ TPMS_AUTH_COMMAND AuthSessionPcr;
+ TPML_DIGEST_VALUES DigestValues;
+} TPM2_PCR_EXTEND_COMMAND;
+
+typedef struct {
+ TPM2_RESPONSE_HEADER Header;
+ UINT32 ParameterSize;
+ TPMS_AUTH_RESPONSE AuthSessionPcr;
+} TPM2_PCR_EXTEND_RESPONSE;
+
+typedef struct {
+ TPM2_COMMAND_HEADER Header;
+ TPMI_DH_PCR PcrHandle;
+ UINT32 AuthorizationSize;
+ TPMS_AUTH_COMMAND AuthSessionPcr;
+ TPM2B_EVENT EventData;
+} TPM2_PCR_EVENT_COMMAND;
+
+typedef struct {
+ TPM2_RESPONSE_HEADER Header;
+ UINT32 ParameterSize;
+ TPML_DIGEST_VALUES Digests;
+ TPMS_AUTH_RESPONSE AuthSessionPcr;
+} TPM2_PCR_EVENT_RESPONSE;
+
+typedef struct {
+ TPM2_COMMAND_HEADER Header;
+ TPML_PCR_SELECTION PcrSelectionIn;
+} TPM2_PCR_READ_COMMAND;
+
+typedef struct {
+ TPM2_RESPONSE_HEADER Header;
+ UINT32 PcrUpdateCounter;
+ TPML_PCR_SELECTION PcrSelectionOut;
+ TPML_DIGEST PcrValues;
+} TPM2_PCR_READ_RESPONSE;
+
+typedef struct {
+ TPM2_COMMAND_HEADER Header;
+ TPMI_RH_PLATFORM AuthHandle;
+ UINT32 AuthSessionSize;
+ TPMS_AUTH_COMMAND AuthSession;
+ TPML_PCR_SELECTION PcrAllocation;
+} TPM2_PCR_ALLOCATE_COMMAND;
+
+typedef struct {
+ TPM2_RESPONSE_HEADER Header;
+ UINT32 AuthSessionSize;
+ TPMI_YES_NO AllocationSuccess;
+ UINT32 MaxPCR;
+ UINT32 SizeNeeded;
+ UINT32 SizeAvailable;
+ TPMS_AUTH_RESPONSE AuthSession;
+} TPM2_PCR_ALLOCATE_RESPONSE;
+
+#pragma pack()
+
+/**
+ This command is used to cause an update to the indicated PCR.
+ The digests parameter contains one or more tagged digest value identified by an algorithm ID.
+ For each digest, the PCR associated with pcrHandle is Extended into the bank identified by the tag (hashAlg).
+
+ @param[in] PcrHandle Handle of the PCR
+ @param[in] Digests List of tagged digest values to be extended
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2PcrExtend (
+ IN TPMI_DH_PCR PcrHandle,
+ IN TPML_DIGEST_VALUES *Digests
+ )
+{
+ EFI_STATUS Status;
+ TPM2_PCR_EXTEND_COMMAND Cmd;
+ TPM2_PCR_EXTEND_RESPONSE Res;
+ UINT32 CmdSize;
+ UINT32 RespSize;
+ UINT32 ResultBufSize;
+ UINT8 *Buffer;
+ UINTN Index;
+ UINT32 SessionInfoSize;
+ UINT16 DigestSize;
+
+ Cmd.Header.tag = SwapBytes16(TPM_ST_SESSIONS);
+ Cmd.Header.commandCode = SwapBytes32(TPM_CC_PCR_Extend);
+ Cmd.PcrHandle = SwapBytes32(PcrHandle);
+
+
+ //
+ // Add in Auth session
+ //
+ Buffer = (UINT8 *)&Cmd.AuthSessionPcr;
+
+ // sessionInfoSize
+ SessionInfoSize = CopyAuthSessionCommand (NULL, Buffer);
+ Buffer += SessionInfoSize;
+ Cmd.AuthorizationSize = SwapBytes32(SessionInfoSize);
+
+ //Digest Count
+ WriteUnaligned32 ((UINT32 *)Buffer, SwapBytes32(Digests->count));
+ Buffer += sizeof(UINT32);
+
+ //Digest
+ for (Index = 0; Index < Digests->count; Index++) {
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16(Digests->digests[Index].hashAlg));
+ Buffer += sizeof(UINT16);
+ DigestSize = GetHashSizeFromAlgo (Digests->digests[Index].hashAlg);
+ if (DigestSize == 0) {
+ DEBUG ((EFI_D_ERROR, "Unknown hash algorithm %d\r\n", Digests->digests[Index].hashAlg));
+ return EFI_DEVICE_ERROR;
+ }
+ CopyMem(
+ Buffer,
+ &Digests->digests[Index].digest,
+ DigestSize
+ );
+ Buffer += DigestSize;
+ }
+
+ CmdSize = (UINT32)((UINTN)Buffer - (UINTN)&Cmd);
+ Cmd.Header.paramSize = SwapBytes32(CmdSize);
+
+ ResultBufSize = sizeof(Res);
+ Status = Tpm2SubmitCommand (CmdSize, (UINT8 *)&Cmd, &ResultBufSize, (UINT8 *)&Res);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ if (ResultBufSize > sizeof(Res)) {
+ DEBUG ((EFI_D_ERROR, "Tpm2PcrExtend: Failed ExecuteCommand: Buffer Too Small\r\n"));
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ //
+ // Validate response headers
+ //
+ RespSize = SwapBytes32(Res.Header.paramSize);
+ if (RespSize > sizeof(Res)) {
+ DEBUG ((EFI_D_ERROR, "Tpm2PcrExtend: Response size too large! %d\r\n", RespSize));
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ //
+ // Fail if command failed
+ //
+ if (SwapBytes32(Res.Header.responseCode) != TPM_RC_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "Tpm2PcrExtend: Response Code error! 0x%08x\r\n", SwapBytes32(Res.Header.responseCode)));
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Unmarshal the response
+ //
+
+ // None
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This command is used to cause an update to the indicated PCR.
+ The data in eventData is hashed using the hash algorithm associated with each bank in which the
+ indicated PCR has been allocated. After the data is hashed, the digests list is returned. If the pcrHandle
+ references an implemented PCR and not TPM_ALG_NULL, digests list is processed as in
+ TPM2_PCR_Extend().
+ A TPM shall support an Event.size of zero through 1,024 inclusive.
+
+ @param[in] PcrHandle Handle of the PCR
+ @param[in] EventData Event data in sized buffer
+ @param[out] Digests List of digest
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2PcrEvent (
+ IN TPMI_DH_PCR PcrHandle,
+ IN TPM2B_EVENT *EventData,
+ OUT TPML_DIGEST_VALUES *Digests
+ )
+{
+ EFI_STATUS Status;
+ TPM2_PCR_EVENT_COMMAND Cmd;
+ TPM2_PCR_EVENT_RESPONSE Res;
+ UINT32 CmdSize;
+ UINT32 RespSize;
+ UINT32 ResultBufSize;
+ UINT8 *Buffer;
+ UINTN Index;
+ UINT32 SessionInfoSize;
+ UINT16 DigestSize;
+
+ Cmd.Header.tag = SwapBytes16(TPM_ST_SESSIONS);
+ Cmd.Header.commandCode = SwapBytes32(TPM_CC_PCR_Event);
+ Cmd.PcrHandle = SwapBytes32(PcrHandle);
+
+ //
+ // Add in Auth session
+ //
+ Buffer = (UINT8 *)&Cmd.AuthSessionPcr;
+
+ // sessionInfoSize
+ SessionInfoSize = CopyAuthSessionCommand (NULL, Buffer);
+ Buffer += SessionInfoSize;
+ Cmd.AuthorizationSize = SwapBytes32(SessionInfoSize);
+
+ // Event
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16(EventData->size));
+ Buffer += sizeof(UINT16);
+
+ CopyMem (Buffer, EventData->buffer, EventData->size);
+ Buffer += EventData->size;
+
+ CmdSize = (UINT32)((UINTN)Buffer - (UINTN)&Cmd);
+ Cmd.Header.paramSize = SwapBytes32(CmdSize);
+
+ ResultBufSize = sizeof(Res);
+ Status = Tpm2SubmitCommand (CmdSize, (UINT8 *)&Cmd, &ResultBufSize, (UINT8 *)&Res);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ if (ResultBufSize > sizeof(Res)) {
+ DEBUG ((EFI_D_ERROR, "Tpm2PcrEvent: Failed ExecuteCommand: Buffer Too Small\r\n"));
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ //
+ // Validate response headers
+ //
+ RespSize = SwapBytes32(Res.Header.paramSize);
+ if (RespSize > sizeof(Res)) {
+ DEBUG ((EFI_D_ERROR, "Tpm2PcrEvent: Response size too large! %d\r\n", RespSize));
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ //
+ // Fail if command failed
+ //
+ if (SwapBytes32(Res.Header.responseCode) != TPM_RC_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "Tpm2PcrEvent: Response Code error! 0x%08x\r\n", SwapBytes32(Res.Header.responseCode)));
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Unmarshal the response
+ //
+ Buffer = (UINT8 *)&Res.Digests;
+
+ Digests->count = SwapBytes32 (ReadUnaligned32 ((UINT32 *)Buffer));
+ Buffer += sizeof(UINT32);
+ for (Index = 0; Index < Digests->count; Index++) {
+ Digests->digests[Index].hashAlg = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer));
+ Buffer += sizeof(UINT16);
+ DigestSize = GetHashSizeFromAlgo (Digests->digests[Index].hashAlg);
+ if (DigestSize == 0) {
+ DEBUG ((EFI_D_ERROR, "Unknown hash algorithm %d\r\n", Digests->digests[Index].hashAlg));
+ return EFI_DEVICE_ERROR;
+ }
+ CopyMem(
+ &Digests->digests[Index].digest,
+ Buffer,
+ DigestSize
+ );
+ Buffer += DigestSize;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This command returns the values of all PCR specified in pcrSelect.
+
+ @param[in] PcrSelectionIn The selection of PCR to read.
+ @param[out] PcrUpdateCounter The current value of the PCR update counter.
+ @param[out] PcrSelectionOut The PCR in the returned list.
+ @param[out] PcrValues The contents of the PCR indicated in pcrSelect.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2PcrRead (
+ IN TPML_PCR_SELECTION *PcrSelectionIn,
+ OUT UINT32 *PcrUpdateCounter,
+ OUT TPML_PCR_SELECTION *PcrSelectionOut,
+ OUT TPML_DIGEST *PcrValues
+ )
+{
+ EFI_STATUS Status;
+ TPM2_PCR_READ_COMMAND SendBuffer;
+ TPM2_PCR_READ_RESPONSE RecvBuffer;
+ UINT32 SendBufferSize;
+ UINT32 RecvBufferSize;
+ UINTN Index;
+ TPML_DIGEST *PcrValuesOut;
+ TPM2B_DIGEST *Digests;
+
+ //
+ // Construct command
+ //
+ SendBuffer.Header.tag = SwapBytes16(TPM_ST_NO_SESSIONS);
+ SendBuffer.Header.commandCode = SwapBytes32(TPM_CC_PCR_Read);
+
+ SendBuffer.PcrSelectionIn.count = SwapBytes32(PcrSelectionIn->count);
+ for (Index = 0; Index < PcrSelectionIn->count; Index++) {
+ SendBuffer.PcrSelectionIn.pcrSelections[Index].hash = SwapBytes16(PcrSelectionIn->pcrSelections[Index].hash);
+ SendBuffer.PcrSelectionIn.pcrSelections[Index].sizeofSelect = PcrSelectionIn->pcrSelections[Index].sizeofSelect;
+ CopyMem (&SendBuffer.PcrSelectionIn.pcrSelections[Index].pcrSelect, &PcrSelectionIn->pcrSelections[Index].pcrSelect, SendBuffer.PcrSelectionIn.pcrSelections[Index].sizeofSelect);
+ }
+
+ SendBufferSize = sizeof(SendBuffer.Header) + sizeof(SendBuffer.PcrSelectionIn.count) + sizeof(SendBuffer.PcrSelectionIn.pcrSelections[0]) * PcrSelectionIn->count;
+ SendBuffer.Header.paramSize = SwapBytes32 (SendBufferSize);
+
+ //
+ // send Tpm command
+ //
+ RecvBufferSize = sizeof (RecvBuffer);
+ Status = Tpm2SubmitCommand (SendBufferSize, (UINT8 *)&SendBuffer, &RecvBufferSize, (UINT8 *)&RecvBuffer);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER)) {
+ DEBUG ((EFI_D_ERROR, "Tpm2PcrRead - RecvBufferSize Error - %x\n", RecvBufferSize));
+ return EFI_DEVICE_ERROR;
+ }
+ if (SwapBytes32(RecvBuffer.Header.responseCode) != TPM_RC_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "Tpm2PcrRead - responseCode - %x\n", SwapBytes32(RecvBuffer.Header.responseCode)));
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Return the response
+ //
+
+ //
+ // PcrUpdateCounter
+ //
+ if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER) + sizeof(RecvBuffer.PcrUpdateCounter)) {
+ DEBUG ((EFI_D_ERROR, "Tpm2PcrRead - RecvBufferSize Error - %x\n", RecvBufferSize));
+ return EFI_DEVICE_ERROR;
+ }
+ *PcrUpdateCounter = SwapBytes32(RecvBuffer.PcrUpdateCounter);
+
+ //
+ // PcrSelectionOut
+ //
+ if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER) + sizeof(RecvBuffer.PcrUpdateCounter) + sizeof(RecvBuffer.PcrSelectionOut.count)) {
+ DEBUG ((EFI_D_ERROR, "Tpm2PcrRead - RecvBufferSize Error - %x\n", RecvBufferSize));
+ return EFI_DEVICE_ERROR;
+ }
+ PcrSelectionOut->count = SwapBytes32(RecvBuffer.PcrSelectionOut.count);
+ if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER) + sizeof(RecvBuffer.PcrUpdateCounter) + sizeof(RecvBuffer.PcrSelectionOut.count) + sizeof(RecvBuffer.PcrSelectionOut.pcrSelections[0]) * PcrSelectionOut->count) {
+ DEBUG ((EFI_D_ERROR, "Tpm2PcrRead - RecvBufferSize Error - %x\n", RecvBufferSize));
+ return EFI_DEVICE_ERROR;
+ }
+ for (Index = 0; Index < PcrSelectionOut->count; Index++) {
+ PcrSelectionOut->pcrSelections[Index].hash = SwapBytes16(RecvBuffer.PcrSelectionOut.pcrSelections[Index].hash);
+ PcrSelectionOut->pcrSelections[Index].sizeofSelect = RecvBuffer.PcrSelectionOut.pcrSelections[Index].sizeofSelect;
+ CopyMem (&PcrSelectionOut->pcrSelections[Index].pcrSelect, &RecvBuffer.PcrSelectionOut.pcrSelections[Index].pcrSelect, PcrSelectionOut->pcrSelections[Index].sizeofSelect);
+ }
+
+ //
+ // PcrValues
+ //
+ PcrValuesOut = (TPML_DIGEST *)((UINT8 *)&RecvBuffer + sizeof (TPM2_RESPONSE_HEADER) + sizeof(RecvBuffer.PcrUpdateCounter) + sizeof(RecvBuffer.PcrSelectionOut.count) + sizeof(RecvBuffer.PcrSelectionOut.pcrSelections[0]) * PcrSelectionOut->count);
+ PcrValues->count = SwapBytes32(PcrValuesOut->count);
+ Digests = PcrValuesOut->digests;
+ for (Index = 0; Index < PcrValues->count; Index++) {
+ PcrValues->digests[Index].size = SwapBytes16(Digests->size);
+ CopyMem (&PcrValues->digests[Index].buffer, &Digests->buffer, PcrValues->digests[Index].size);
+ Digests = (TPM2B_DIGEST *)((UINT8 *)Digests + sizeof(Digests->size) + PcrValues->digests[Index].size);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This command is used to set the desired PCR allocation of PCR and algorithms.
+
+ @param[in] AuthHandle TPM_RH_PLATFORM+{PP}
+ @param[in] AuthSession Auth Session context
+ @param[in] PcrAllocation The requested allocation
+ @param[out] AllocationSuccess YES if the allocation succeeded
+ @param[out] MaxPCR maximum number of PCR that may be in a bank
+ @param[out] SizeNeeded number of octets required to satisfy the request
+ @param[out] SizeAvailable Number of octets available. Computed before the allocation
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2PcrAllocate (
+ IN TPMI_RH_PLATFORM AuthHandle,
+ IN TPMS_AUTH_COMMAND *AuthSession,
+ IN TPML_PCR_SELECTION *PcrAllocation,
+ OUT TPMI_YES_NO *AllocationSuccess,
+ OUT UINT32 *MaxPCR,
+ OUT UINT32 *SizeNeeded,
+ OUT UINT32 *SizeAvailable
+ )
+{
+ EFI_STATUS Status;
+ TPM2_PCR_ALLOCATE_COMMAND Cmd;
+ TPM2_PCR_ALLOCATE_RESPONSE Res;
+ UINT32 CmdSize;
+ UINT32 RespSize;
+ UINT8 *Buffer;
+ UINT32 SessionInfoSize;
+ UINT8 *ResultBuf;
+ UINT32 ResultBufSize;
+ UINTN Index;
+
+ //
+ // Construct command
+ //
+ Cmd.Header.tag = SwapBytes16(TPM_ST_SESSIONS);
+ Cmd.Header.paramSize = SwapBytes32(sizeof(Cmd));
+ Cmd.Header.commandCode = SwapBytes32(TPM_CC_PCR_Allocate);
+ Cmd.AuthHandle = SwapBytes32(AuthHandle);
+
+ //
+ // Add in Auth session
+ //
+ Buffer = (UINT8 *)&Cmd.AuthSession;
+
+ // sessionInfoSize
+ SessionInfoSize = CopyAuthSessionCommand (AuthSession, Buffer);
+ Buffer += SessionInfoSize;
+ Cmd.AuthSessionSize = SwapBytes32(SessionInfoSize);
+
+ // Count
+ WriteUnaligned32 ((UINT32 *)Buffer, SwapBytes32(PcrAllocation->count));
+ Buffer += sizeof(UINT32);
+ for (Index = 0; Index < PcrAllocation->count; Index++) {
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16(PcrAllocation->pcrSelections[Index].hash));
+ Buffer += sizeof(UINT16);
+ *(UINT8 *)Buffer = PcrAllocation->pcrSelections[Index].sizeofSelect;
+ Buffer++;
+ CopyMem (Buffer, PcrAllocation->pcrSelections[Index].pcrSelect, PcrAllocation->pcrSelections[Index].sizeofSelect);
+ Buffer += PcrAllocation->pcrSelections[Index].sizeofSelect;
+ }
+
+ CmdSize = (UINT32)(Buffer - (UINT8 *)&Cmd);
+ Cmd.Header.paramSize = SwapBytes32(CmdSize);
+
+ ResultBuf = (UINT8 *) &Res;
+ ResultBufSize = sizeof(Res);
+
+ //
+ // Call the TPM
+ //
+ Status = Tpm2SubmitCommand (
+ CmdSize,
+ (UINT8 *)&Cmd,
+ &ResultBufSize,
+ ResultBuf
+ );
+ if (EFI_ERROR(Status)) {
+ goto Done;
+ }
+
+ if (ResultBufSize > sizeof(Res)) {
+ DEBUG ((EFI_D_ERROR, "Tpm2PcrAllocate: Failed ExecuteCommand: Buffer Too Small\r\n"));
+ Status = EFI_BUFFER_TOO_SMALL;
+ goto Done;
+ }
+
+ //
+ // Validate response headers
+ //
+ RespSize = SwapBytes32(Res.Header.paramSize);
+ if (RespSize > sizeof(Res)) {
+ DEBUG ((EFI_D_ERROR, "Tpm2PcrAllocate: Response size too large! %d\r\n", RespSize));
+ Status = EFI_BUFFER_TOO_SMALL;
+ goto Done;
+ }
+
+ //
+ // Fail if command failed
+ //
+ if (SwapBytes32(Res.Header.responseCode) != TPM_RC_SUCCESS) {
+ DEBUG((EFI_D_ERROR,"Tpm2PcrAllocate: Response Code error! 0x%08x\r\n", SwapBytes32(Res.Header.responseCode)));
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+ //
+ // Return the response
+ //
+ *AllocationSuccess = Res.AllocationSuccess;
+ *MaxPCR = SwapBytes32(Res.MaxPCR);
+ *SizeNeeded = SwapBytes32(Res.SizeNeeded);
+ *SizeAvailable = SwapBytes32(Res.SizeAvailable);
+
+Done:
+ //
+ // Clear AuthSession Content
+ //
+ ZeroMem (&Cmd, sizeof(Cmd));
+ ZeroMem (&Res, sizeof(Res));
+ return Status;
+}
+
+/**
+ Alloc PCR data.
+
+ @param[in] PlatformAuth platform auth value. NULL means no platform auth change.
+ @param[in] SupportedPCRBanks Supported PCR banks
+ @param[in] PCRBanks PCR banks
+
+ @retval EFI_SUCCESS Operation completed successfully.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2PcrAllocateBanks (
+ IN TPM2B_AUTH *PlatformAuth, OPTIONAL
+ IN UINT32 SupportedPCRBanks,
+ IN UINT32 PCRBanks
+ )
+{
+ EFI_STATUS Status;
+ TPMS_AUTH_COMMAND *AuthSession;
+ TPMS_AUTH_COMMAND LocalAuthSession;
+ TPML_PCR_SELECTION PcrAllocation;
+ TPMI_YES_NO AllocationSuccess;
+ UINT32 MaxPCR;
+ UINT32 SizeNeeded;
+ UINT32 SizeAvailable;
+
+ if (PlatformAuth == NULL) {
+ AuthSession = NULL;
+ } else {
+ AuthSession = &LocalAuthSession;
+ ZeroMem (&LocalAuthSession, sizeof(LocalAuthSession));
+ LocalAuthSession.sessionHandle = TPM_RS_PW;
+ LocalAuthSession.hmac.size = PlatformAuth->size;
+ CopyMem (LocalAuthSession.hmac.buffer, PlatformAuth->buffer, PlatformAuth->size);
+ }
+
+ //
+ // Fill input
+ //
+ ZeroMem (&PcrAllocation, sizeof(PcrAllocation));
+ if ((HASH_ALG_SHA1 & SupportedPCRBanks) != 0) {
+ PcrAllocation.pcrSelections[PcrAllocation.count].hash = TPM_ALG_SHA1;
+ PcrAllocation.pcrSelections[PcrAllocation.count].sizeofSelect = PCR_SELECT_MAX;
+ if ((HASH_ALG_SHA1 & PCRBanks) != 0) {
+ PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[0] = 0xFF;
+ PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[1] = 0xFF;
+ PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[2] = 0xFF;
+ } else {
+ PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[0] = 0x00;
+ PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[1] = 0x00;
+ PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[2] = 0x00;
+ }
+ PcrAllocation.count++;
+ }
+ if ((HASH_ALG_SHA256 & SupportedPCRBanks) != 0) {
+ PcrAllocation.pcrSelections[PcrAllocation.count].hash = TPM_ALG_SHA256;
+ PcrAllocation.pcrSelections[PcrAllocation.count].sizeofSelect = PCR_SELECT_MAX;
+ if ((HASH_ALG_SHA256 & PCRBanks) != 0) {
+ PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[0] = 0xFF;
+ PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[1] = 0xFF;
+ PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[2] = 0xFF;
+ } else {
+ PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[0] = 0x00;
+ PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[1] = 0x00;
+ PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[2] = 0x00;
+ }
+ PcrAllocation.count++;
+ }
+ if ((HASH_ALG_SHA384 & SupportedPCRBanks) != 0) {
+ PcrAllocation.pcrSelections[PcrAllocation.count].hash = TPM_ALG_SHA384;
+ PcrAllocation.pcrSelections[PcrAllocation.count].sizeofSelect = PCR_SELECT_MAX;
+ if ((HASH_ALG_SHA384 & PCRBanks) != 0) {
+ PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[0] = 0xFF;
+ PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[1] = 0xFF;
+ PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[2] = 0xFF;
+ } else {
+ PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[0] = 0x00;
+ PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[1] = 0x00;
+ PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[2] = 0x00;
+ }
+ PcrAllocation.count++;
+ }
+ if ((HASH_ALG_SHA512 & SupportedPCRBanks) != 0) {
+ PcrAllocation.pcrSelections[PcrAllocation.count].hash = TPM_ALG_SHA512;
+ PcrAllocation.pcrSelections[PcrAllocation.count].sizeofSelect = PCR_SELECT_MAX;
+ if ((HASH_ALG_SHA512 & PCRBanks) != 0) {
+ PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[0] = 0xFF;
+ PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[1] = 0xFF;
+ PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[2] = 0xFF;
+ } else {
+ PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[0] = 0x00;
+ PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[1] = 0x00;
+ PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[2] = 0x00;
+ }
+ PcrAllocation.count++;
+ }
+ if ((HASH_ALG_SM3_256 & SupportedPCRBanks) != 0) {
+ PcrAllocation.pcrSelections[PcrAllocation.count].hash = TPM_ALG_SM3_256;
+ PcrAllocation.pcrSelections[PcrAllocation.count].sizeofSelect = PCR_SELECT_MAX;
+ if ((HASH_ALG_SM3_256 & PCRBanks) != 0) {
+ PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[0] = 0xFF;
+ PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[1] = 0xFF;
+ PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[2] = 0xFF;
+ } else {
+ PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[0] = 0x00;
+ PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[1] = 0x00;
+ PcrAllocation.pcrSelections[PcrAllocation.count].pcrSelect[2] = 0x00;
+ }
+ PcrAllocation.count++;
+ }
+ Status = Tpm2PcrAllocate (
+ TPM_RH_PLATFORM,
+ AuthSession,
+ &PcrAllocation,
+ &AllocationSuccess,
+ &MaxPCR,
+ &SizeNeeded,
+ &SizeAvailable
+ );
+ DEBUG ((EFI_D_INFO, "Tpm2PcrAllocateBanks call Tpm2PcrAllocate - %r\n", Status));
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ DEBUG ((EFI_D_INFO, "AllocationSuccess - %02x\n", AllocationSuccess));
+ DEBUG ((EFI_D_INFO, "MaxPCR - %08x\n", MaxPCR));
+ DEBUG ((EFI_D_INFO, "SizeNeeded - %08x\n", SizeNeeded));
+ DEBUG ((EFI_D_INFO, "SizeAvailable - %08x\n", SizeAvailable));
+
+Done:
+ ZeroMem(&LocalAuthSession.hmac, sizeof(LocalAuthSession.hmac));
+ return Status;
+} \ No newline at end of file
diff --git a/Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2Miscellaneous.c b/Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2Miscellaneous.c
new file mode 100644
index 0000000000..5bd870fb9e
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2Miscellaneous.c
@@ -0,0 +1,122 @@
+/** @file
+ Implement TPM2 Miscellanenous related command.
+
+Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved. <BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <IndustryStandard/UefiTcgPlatform.h>
+#include <Library/Tpm2CommandLib.h>
+#include <Library/Tpm2DeviceLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+
+#pragma pack(1)
+
+typedef struct {
+ TPM2_COMMAND_HEADER Header;
+ TPMI_RH_HIERARCHY_AUTH AuthHandle;
+ UINT32 AuthSessionSize;
+ TPMS_AUTH_COMMAND AuthSession;
+ UINT32 AlgorithmSet;
+} TPM2_SET_ALGORITHM_SET_COMMAND;
+
+typedef struct {
+ TPM2_RESPONSE_HEADER Header;
+ UINT32 AuthSessionSize;
+ TPMS_AUTH_RESPONSE AuthSession;
+} TPM2_SET_ALGORITHM_SET_RESPONSE;
+
+#pragma pack()
+
+/**
+ This command allows the platform to change the set of algorithms that are used by the TPM.
+ The algorithmSet setting is a vendor-dependent value.
+
+ @param[in] AuthHandle TPM_RH_PLATFORM
+ @param[in] AuthSession Auth Session context
+ @param[in] AlgorithmSet A TPM vendor-dependent value indicating the
+ algorithm set selection
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2SetAlgorithmSet (
+ IN TPMI_RH_PLATFORM AuthHandle,
+ IN TPMS_AUTH_COMMAND *AuthSession,
+ IN UINT32 AlgorithmSet
+ )
+{
+ EFI_STATUS Status;
+ TPM2_SET_ALGORITHM_SET_COMMAND SendBuffer;
+ TPM2_SET_ALGORITHM_SET_RESPONSE RecvBuffer;
+ UINT32 SendBufferSize;
+ UINT32 RecvBufferSize;
+ UINT8 *Buffer;
+ UINT32 SessionInfoSize;
+
+ //
+ // Construct command
+ //
+ SendBuffer.Header.tag = SwapBytes16(TPM_ST_SESSIONS);
+ SendBuffer.Header.commandCode = SwapBytes32(TPM_CC_SetAlgorithmSet);
+
+ SendBuffer.AuthHandle = SwapBytes32 (AuthHandle);
+
+ //
+ // Add in Auth session
+ //
+ Buffer = (UINT8 *)&SendBuffer.AuthSession;
+
+ // sessionInfoSize
+ SessionInfoSize = CopyAuthSessionCommand (AuthSession, Buffer);
+ Buffer += SessionInfoSize;
+ SendBuffer.AuthSessionSize = SwapBytes32(SessionInfoSize);
+
+ //
+ // Real data
+ //
+ WriteUnaligned32 ((UINT32 *)Buffer, SwapBytes32(AlgorithmSet));
+ Buffer += sizeof(UINT32);
+
+ SendBufferSize = (UINT32)((UINTN)Buffer - (UINTN)&SendBuffer);
+ SendBuffer.Header.paramSize = SwapBytes32 (SendBufferSize);
+
+ //
+ // send Tpm command
+ //
+ RecvBufferSize = sizeof (RecvBuffer);
+ Status = Tpm2SubmitCommand (SendBufferSize, (UINT8 *)&SendBuffer, &RecvBufferSize, (UINT8 *)&RecvBuffer);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER)) {
+ DEBUG ((EFI_D_ERROR, "Tpm2SetAlgorithmSet - RecvBufferSize Error - %x\n", RecvBufferSize));
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+ if (SwapBytes32(RecvBuffer.Header.responseCode) != TPM_RC_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "Tpm2SetAlgorithmSet - responseCode - %x\n", SwapBytes32(RecvBuffer.Header.responseCode)));
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+Done:
+ //
+ // Clear AuthSession Content
+ //
+ ZeroMem (&SendBuffer, sizeof(SendBuffer));
+ ZeroMem (&RecvBuffer, sizeof(RecvBuffer));
+ return Status;
+}
diff --git a/Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2NVStorage.c b/Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2NVStorage.c
new file mode 100644
index 0000000000..9508022132
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2NVStorage.c
@@ -0,0 +1,1033 @@
+/** @file
+ Implement TPM2 NVStorage related command.
+
+Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved. <BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <IndustryStandard/UefiTcgPlatform.h>
+#include <Library/Tpm2CommandLib.h>
+#include <Library/Tpm2DeviceLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+
+#pragma pack(1)
+
+#define RC_NV_ReadPublic_nvIndex (TPM_RC_H + TPM_RC_1)
+
+#define RC_NV_DefineSpace_authHandle (TPM_RC_H + TPM_RC_1)
+#define RC_NV_DefineSpace_auth (TPM_RC_P + TPM_RC_1)
+#define RC_NV_DefineSpace_publicInfo (TPM_RC_P + TPM_RC_2)
+
+#define RC_NV_UndefineSpace_authHandle (TPM_RC_H + TPM_RC_1)
+#define RC_NV_UndefineSpace_nvIndex (TPM_RC_H + TPM_RC_2)
+
+#define RC_NV_Read_authHandle (TPM_RC_H + TPM_RC_1)
+#define RC_NV_Read_nvIndex (TPM_RC_H + TPM_RC_2)
+#define RC_NV_Read_size (TPM_RC_P + TPM_RC_1)
+#define RC_NV_Read_offset (TPM_RC_P + TPM_RC_2)
+
+#define RC_NV_Write_authHandle (TPM_RC_H + TPM_RC_1)
+#define RC_NV_Write_nvIndex (TPM_RC_H + TPM_RC_2)
+#define RC_NV_Write_data (TPM_RC_P + TPM_RC_1)
+#define RC_NV_Write_offset (TPM_RC_P + TPM_RC_2)
+
+typedef struct {
+ TPM2_COMMAND_HEADER Header;
+ TPMI_RH_NV_INDEX NvIndex;
+} TPM2_NV_READPUBLIC_COMMAND;
+
+typedef struct {
+ TPM2_RESPONSE_HEADER Header;
+ TPM2B_NV_PUBLIC NvPublic;
+ TPM2B_NAME NvName;
+} TPM2_NV_READPUBLIC_RESPONSE;
+
+typedef struct {
+ TPM2_COMMAND_HEADER Header;
+ TPMI_RH_PROVISION AuthHandle;
+ UINT32 AuthSessionSize;
+ TPMS_AUTH_COMMAND AuthSession;
+ TPM2B_AUTH Auth;
+ TPM2B_NV_PUBLIC NvPublic;
+} TPM2_NV_DEFINESPACE_COMMAND;
+
+typedef struct {
+ TPM2_RESPONSE_HEADER Header;
+ UINT32 AuthSessionSize;
+ TPMS_AUTH_RESPONSE AuthSession;
+} TPM2_NV_DEFINESPACE_RESPONSE;
+
+typedef struct {
+ TPM2_COMMAND_HEADER Header;
+ TPMI_RH_PROVISION AuthHandle;
+ TPMI_RH_NV_INDEX NvIndex;
+ UINT32 AuthSessionSize;
+ TPMS_AUTH_COMMAND AuthSession;
+} TPM2_NV_UNDEFINESPACE_COMMAND;
+
+typedef struct {
+ TPM2_RESPONSE_HEADER Header;
+ UINT32 AuthSessionSize;
+ TPMS_AUTH_RESPONSE AuthSession;
+} TPM2_NV_UNDEFINESPACE_RESPONSE;
+
+typedef struct {
+ TPM2_COMMAND_HEADER Header;
+ TPMI_RH_NV_AUTH AuthHandle;
+ TPMI_RH_NV_INDEX NvIndex;
+ UINT32 AuthSessionSize;
+ TPMS_AUTH_COMMAND AuthSession;
+ UINT16 Size;
+ UINT16 Offset;
+} TPM2_NV_READ_COMMAND;
+
+typedef struct {
+ TPM2_RESPONSE_HEADER Header;
+ UINT32 AuthSessionSize;
+ TPM2B_MAX_BUFFER Data;
+ TPMS_AUTH_RESPONSE AuthSession;
+} TPM2_NV_READ_RESPONSE;
+
+typedef struct {
+ TPM2_COMMAND_HEADER Header;
+ TPMI_RH_NV_AUTH AuthHandle;
+ TPMI_RH_NV_INDEX NvIndex;
+ UINT32 AuthSessionSize;
+ TPMS_AUTH_COMMAND AuthSession;
+ TPM2B_MAX_BUFFER Data;
+ UINT16 Offset;
+} TPM2_NV_WRITE_COMMAND;
+
+typedef struct {
+ TPM2_RESPONSE_HEADER Header;
+ UINT32 AuthSessionSize;
+ TPMS_AUTH_RESPONSE AuthSession;
+} TPM2_NV_WRITE_RESPONSE;
+
+typedef struct {
+ TPM2_COMMAND_HEADER Header;
+ TPMI_RH_NV_AUTH AuthHandle;
+ TPMI_RH_NV_INDEX NvIndex;
+ UINT32 AuthSessionSize;
+ TPMS_AUTH_COMMAND AuthSession;
+} TPM2_NV_READLOCK_COMMAND;
+
+typedef struct {
+ TPM2_RESPONSE_HEADER Header;
+ UINT32 AuthSessionSize;
+ TPMS_AUTH_RESPONSE AuthSession;
+} TPM2_NV_READLOCK_RESPONSE;
+
+typedef struct {
+ TPM2_COMMAND_HEADER Header;
+ TPMI_RH_NV_AUTH AuthHandle;
+ TPMI_RH_NV_INDEX NvIndex;
+ UINT32 AuthSessionSize;
+ TPMS_AUTH_COMMAND AuthSession;
+} TPM2_NV_WRITELOCK_COMMAND;
+
+typedef struct {
+ TPM2_RESPONSE_HEADER Header;
+ UINT32 AuthSessionSize;
+ TPMS_AUTH_RESPONSE AuthSession;
+} TPM2_NV_WRITELOCK_RESPONSE;
+
+typedef struct {
+ TPM2_COMMAND_HEADER Header;
+ TPMI_RH_PROVISION AuthHandle;
+ UINT32 AuthSessionSize;
+ TPMS_AUTH_COMMAND AuthSession;
+} TPM2_NV_GLOBALWRITELOCK_COMMAND;
+
+typedef struct {
+ TPM2_RESPONSE_HEADER Header;
+ UINT32 AuthSessionSize;
+ TPMS_AUTH_RESPONSE AuthSession;
+} TPM2_NV_GLOBALWRITELOCK_RESPONSE;
+
+#pragma pack()
+
+/**
+ This command is used to read the public area and Name of an NV Index.
+
+ @param[in] NvIndex The NV Index.
+ @param[out] NvPublic The public area of the index.
+ @param[out] NvName The Name of the nvIndex.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+ @retval EFI_NOT_FOUND The command was returned successfully, but NvIndex is not found.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2NvReadPublic (
+ IN TPMI_RH_NV_INDEX NvIndex,
+ OUT TPM2B_NV_PUBLIC *NvPublic,
+ OUT TPM2B_NAME *NvName
+ )
+{
+ EFI_STATUS Status;
+ TPM2_NV_READPUBLIC_COMMAND SendBuffer;
+ TPM2_NV_READPUBLIC_RESPONSE RecvBuffer;
+ UINT32 SendBufferSize;
+ UINT32 RecvBufferSize;
+ UINT16 NvPublicSize;
+ UINT16 NvNameSize;
+ UINT8 *Buffer;
+ TPM_RC ResponseCode;
+
+ //
+ // Construct command
+ //
+ SendBuffer.Header.tag = SwapBytes16(TPM_ST_NO_SESSIONS);
+ SendBuffer.Header.commandCode = SwapBytes32(TPM_CC_NV_ReadPublic);
+
+ SendBuffer.NvIndex = SwapBytes32 (NvIndex);
+
+ SendBufferSize = (UINT32) sizeof (SendBuffer);
+ SendBuffer.Header.paramSize = SwapBytes32 (SendBufferSize);
+
+ //
+ // send Tpm command
+ //
+ RecvBufferSize = sizeof (RecvBuffer);
+ Status = Tpm2SubmitCommand (SendBufferSize, (UINT8 *)&SendBuffer, &RecvBufferSize, (UINT8 *)&RecvBuffer);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER)) {
+ DEBUG ((EFI_D_ERROR, "Tpm2NvReadPublic - RecvBufferSize Error - %x\n", RecvBufferSize));
+ return EFI_DEVICE_ERROR;
+ }
+ ResponseCode = SwapBytes32(RecvBuffer.Header.responseCode);
+ if (ResponseCode != TPM_RC_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "Tpm2NvReadPublic - responseCode - %x\n", SwapBytes32(RecvBuffer.Header.responseCode)));
+ }
+ switch (ResponseCode) {
+ case TPM_RC_SUCCESS:
+ // return data
+ break;
+ case TPM_RC_HANDLE + RC_NV_ReadPublic_nvIndex: // TPM_RC_NV_DEFINED:
+ return EFI_NOT_FOUND;
+ case TPM_RC_VALUE + RC_NV_ReadPublic_nvIndex:
+ return EFI_INVALID_PARAMETER;
+ default:
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (RecvBufferSize <= sizeof (TPM2_RESPONSE_HEADER) + sizeof (UINT16) + sizeof(UINT16)) {
+ DEBUG ((EFI_D_ERROR, "Tpm2NvReadPublic - RecvBufferSize Error - %x\n", RecvBufferSize));
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Basic check
+ //
+ NvPublicSize = SwapBytes16 (RecvBuffer.NvPublic.size);
+ NvNameSize = SwapBytes16 (ReadUnaligned16 ((UINT16 *)((UINT8 *)&RecvBuffer + sizeof(TPM2_RESPONSE_HEADER) + sizeof(UINT16) + NvPublicSize)));
+
+ if (RecvBufferSize != sizeof(TPM2_RESPONSE_HEADER) + sizeof(UINT16) + NvPublicSize + sizeof(UINT16) + NvNameSize) {
+ DEBUG ((EFI_D_ERROR, "Tpm2NvReadPublic - RecvBufferSize Error - NvPublicSize %x, NvNameSize %x\n", RecvBufferSize, NvNameSize));
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Return the response
+ //
+ CopyMem (NvPublic, &RecvBuffer.NvPublic, sizeof(UINT16) + NvPublicSize);
+ NvPublic->size = NvPublicSize;
+ NvPublic->nvPublic.nvIndex = SwapBytes32 (NvPublic->nvPublic.nvIndex);
+ NvPublic->nvPublic.nameAlg = SwapBytes16 (NvPublic->nvPublic.nameAlg);
+ WriteUnaligned32 ((UINT32 *)&NvPublic->nvPublic.attributes, SwapBytes32 (ReadUnaligned32 ((UINT32 *)&NvPublic->nvPublic.attributes)));
+ NvPublic->nvPublic.authPolicy.size = SwapBytes16 (NvPublic->nvPublic.authPolicy.size);
+ Buffer = (UINT8 *)&RecvBuffer.NvPublic.nvPublic.authPolicy;
+ Buffer += sizeof(UINT16) + NvPublic->nvPublic.authPolicy.size;
+ NvPublic->nvPublic.dataSize = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer));
+
+ CopyMem (NvName->name, (UINT8 *)&RecvBuffer + sizeof(TPM2_RESPONSE_HEADER) + sizeof(UINT16) + NvPublicSize + sizeof(UINT16), NvNameSize);
+ NvName->size = NvNameSize;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This command defines the attributes of an NV Index and causes the TPM to
+ reserve space to hold the data associated with the index.
+ If a definition already exists at the index, the TPM will return TPM_RC_NV_DEFINED.
+
+ @param[in] AuthHandle TPM_RH_OWNER or TPM_RH_PLATFORM+{PP}.
+ @param[in] AuthSession Auth Session context
+ @param[in] Auth The authorization data.
+ @param[in] NvPublic The public area of the index.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+ @retval EFI_ALREADY_STARTED The command was returned successfully, but NvIndex is already defined.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2NvDefineSpace (
+ IN TPMI_RH_PROVISION AuthHandle,
+ IN TPMS_AUTH_COMMAND *AuthSession, OPTIONAL
+ IN TPM2B_AUTH *Auth,
+ IN TPM2B_NV_PUBLIC *NvPublic
+ )
+{
+ EFI_STATUS Status;
+ TPM2_NV_DEFINESPACE_COMMAND SendBuffer;
+ TPM2_NV_DEFINESPACE_RESPONSE RecvBuffer;
+ UINT32 SendBufferSize;
+ UINT32 RecvBufferSize;
+ UINT16 NvPublicSize;
+ UINT8 *Buffer;
+ UINT32 SessionInfoSize;
+ TPM_RC ResponseCode;
+
+ //
+ // Construct command
+ //
+ SendBuffer.Header.tag = SwapBytes16(TPM_ST_SESSIONS);
+ SendBuffer.Header.commandCode = SwapBytes32(TPM_CC_NV_DefineSpace);
+ SendBuffer.AuthHandle = SwapBytes32 (AuthHandle);
+
+ //
+ // Add in Auth session
+ //
+ Buffer = (UINT8 *)&SendBuffer.AuthSession;
+
+ // sessionInfoSize
+ SessionInfoSize = CopyAuthSessionCommand (AuthSession, Buffer);
+ Buffer += SessionInfoSize;
+ SendBuffer.AuthSessionSize = SwapBytes32(SessionInfoSize);
+
+ //
+ // IndexAuth
+ //
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16(Auth->size));
+ Buffer += sizeof(UINT16);
+ CopyMem(Buffer, Auth->buffer, Auth->size);
+ Buffer += Auth->size;
+
+ //
+ // NvPublic
+ //
+ NvPublicSize = NvPublic->size;
+
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (NvPublicSize));
+ Buffer += sizeof(UINT16);
+ WriteUnaligned32 ((UINT32 *)Buffer, SwapBytes32 (NvPublic->nvPublic.nvIndex));
+ Buffer += sizeof(UINT32);
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (NvPublic->nvPublic.nameAlg));
+ Buffer += sizeof(UINT16);
+ WriteUnaligned32 ((UINT32 *)Buffer, SwapBytes32 (ReadUnaligned32 ((UINT32 *)&NvPublic->nvPublic.attributes)));
+ Buffer += sizeof(UINT32);
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (NvPublic->nvPublic.authPolicy.size));
+ Buffer += sizeof(UINT16);
+ CopyMem (Buffer, NvPublic->nvPublic.authPolicy.buffer, NvPublic->nvPublic.authPolicy.size);
+ Buffer += NvPublic->nvPublic.authPolicy.size;
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (NvPublic->nvPublic.dataSize));
+ Buffer += sizeof(UINT16);
+
+ SendBufferSize = (UINT32)(Buffer - (UINT8 *)&SendBuffer);
+ SendBuffer.Header.paramSize = SwapBytes32 (SendBufferSize);
+
+ //
+ // send Tpm command
+ //
+ RecvBufferSize = sizeof (RecvBuffer);
+ Status = Tpm2SubmitCommand (SendBufferSize, (UINT8 *)&SendBuffer, &RecvBufferSize, (UINT8 *)&RecvBuffer);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER)) {
+ DEBUG ((EFI_D_ERROR, "Tpm2NvDefineSpace - RecvBufferSize Error - %x\n", RecvBufferSize));
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+ ResponseCode = SwapBytes32(RecvBuffer.Header.responseCode);
+ if (ResponseCode != TPM_RC_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "Tpm2NvDefineSpace - responseCode - %x\n", SwapBytes32(RecvBuffer.Header.responseCode)));
+ }
+ switch (ResponseCode) {
+ case TPM_RC_SUCCESS:
+ // return data
+ break;
+ case TPM_RC_SIZE + RC_NV_DefineSpace_publicInfo:
+ case TPM_RC_SIZE + RC_NV_DefineSpace_auth:
+ Status = EFI_BAD_BUFFER_SIZE;
+ break;
+ case TPM_RC_ATTRIBUTES:
+ case TPM_RC_ATTRIBUTES + RC_NV_DefineSpace_publicInfo:
+ Status = EFI_UNSUPPORTED;
+ break;
+ case TPM_RC_ATTRIBUTES + RC_NV_DefineSpace_authHandle:
+ Status = EFI_INVALID_PARAMETER;
+ break;
+ case TPM_RC_NV_DEFINED:
+ Status = EFI_ALREADY_STARTED;
+ break;
+ case TPM_RC_VALUE + RC_NV_DefineSpace_publicInfo:
+ case TPM_RC_VALUE + RC_NV_DefineSpace_authHandle:
+ Status = EFI_INVALID_PARAMETER;
+ break;
+ case TPM_RC_NV_SPACE:
+ Status = EFI_OUT_OF_RESOURCES;
+ break;
+ default:
+ Status = EFI_DEVICE_ERROR;
+ break;
+ }
+
+Done:
+ //
+ // Clear AuthSession Content
+ //
+ ZeroMem (&SendBuffer, sizeof(SendBuffer));
+ ZeroMem (&RecvBuffer, sizeof(RecvBuffer));
+ return Status;
+}
+
+/**
+ This command removes an index from the TPM.
+
+ @param[in] AuthHandle TPM_RH_OWNER or TPM_RH_PLATFORM+{PP}.
+ @param[in] NvIndex The NV Index.
+ @param[in] AuthSession Auth Session context
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+ @retval EFI_NOT_FOUND The command was returned successfully, but NvIndex is not found.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2NvUndefineSpace (
+ IN TPMI_RH_PROVISION AuthHandle,
+ IN TPMI_RH_NV_INDEX NvIndex,
+ IN TPMS_AUTH_COMMAND *AuthSession OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ TPM2_NV_UNDEFINESPACE_COMMAND SendBuffer;
+ TPM2_NV_UNDEFINESPACE_RESPONSE RecvBuffer;
+ UINT32 SendBufferSize;
+ UINT32 RecvBufferSize;
+ UINT8 *Buffer;
+ UINT32 SessionInfoSize;
+ TPM_RC ResponseCode;
+
+ //
+ // Construct command
+ //
+ SendBuffer.Header.tag = SwapBytes16(TPM_ST_SESSIONS);
+ SendBuffer.Header.commandCode = SwapBytes32(TPM_CC_NV_UndefineSpace);
+
+ SendBuffer.AuthHandle = SwapBytes32 (AuthHandle);
+ SendBuffer.NvIndex = SwapBytes32 (NvIndex);
+
+ //
+ // Add in Auth session
+ //
+ Buffer = (UINT8 *)&SendBuffer.AuthSession;
+
+ // sessionInfoSize
+ SessionInfoSize = CopyAuthSessionCommand (AuthSession, Buffer);
+ Buffer += SessionInfoSize;
+ SendBuffer.AuthSessionSize = SwapBytes32(SessionInfoSize);
+
+ SendBufferSize = (UINT32)(Buffer - (UINT8 *)&SendBuffer);
+ SendBuffer.Header.paramSize = SwapBytes32 (SendBufferSize);
+
+ //
+ // send Tpm command
+ //
+ RecvBufferSize = sizeof (RecvBuffer);
+ Status = Tpm2SubmitCommand (SendBufferSize, (UINT8 *)&SendBuffer, &RecvBufferSize, (UINT8 *)&RecvBuffer);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER)) {
+ DEBUG ((EFI_D_ERROR, "Tpm2NvUndefineSpace - RecvBufferSize Error - %x\n", RecvBufferSize));
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+ ResponseCode = SwapBytes32(RecvBuffer.Header.responseCode);
+ if (ResponseCode != TPM_RC_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "Tpm2NvUndefineSpace - responseCode - %x\n", SwapBytes32(RecvBuffer.Header.responseCode)));
+ }
+ switch (ResponseCode) {
+ case TPM_RC_SUCCESS:
+ // return data
+ break;
+ case TPM_RC_ATTRIBUTES:
+ case TPM_RC_ATTRIBUTES + RC_NV_UndefineSpace_nvIndex:
+ Status = EFI_UNSUPPORTED;
+ break;
+ case TPM_RC_NV_AUTHORIZATION:
+ Status = EFI_SECURITY_VIOLATION;
+ break;
+ case TPM_RC_HANDLE + RC_NV_UndefineSpace_nvIndex: // TPM_RC_NV_DEFINED:
+ Status = EFI_NOT_FOUND;
+ break;
+ case TPM_RC_HANDLE + RC_NV_UndefineSpace_authHandle: // TPM_RC_NV_DEFINED:
+ Status = EFI_INVALID_PARAMETER;
+ break;
+ case TPM_RC_VALUE + RC_NV_UndefineSpace_authHandle:
+ case TPM_RC_VALUE + RC_NV_UndefineSpace_nvIndex:
+ Status = EFI_INVALID_PARAMETER;
+ break;
+ default:
+ Status = EFI_DEVICE_ERROR;
+ break;
+ }
+
+Done:
+ //
+ // Clear AuthSession Content
+ //
+ ZeroMem (&SendBuffer, sizeof(SendBuffer));
+ ZeroMem (&RecvBuffer, sizeof(RecvBuffer));
+ return Status;
+}
+
+/**
+ This command reads a value from an area in NV memory previously defined by TPM2_NV_DefineSpace().
+
+ @param[in] AuthHandle the handle indicating the source of the authorization value.
+ @param[in] NvIndex The index to be read.
+ @param[in] AuthSession Auth Session context
+ @param[in] Size Number of bytes to read.
+ @param[in] Offset Byte offset into the area.
+ @param[in,out] OutData The data read.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+ @retval EFI_NOT_FOUND The command was returned successfully, but NvIndex is not found.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2NvRead (
+ IN TPMI_RH_NV_AUTH AuthHandle,
+ IN TPMI_RH_NV_INDEX NvIndex,
+ IN TPMS_AUTH_COMMAND *AuthSession, OPTIONAL
+ IN UINT16 Size,
+ IN UINT16 Offset,
+ IN OUT TPM2B_MAX_BUFFER *OutData
+ )
+{
+ EFI_STATUS Status;
+ TPM2_NV_READ_COMMAND SendBuffer;
+ TPM2_NV_READ_RESPONSE RecvBuffer;
+ UINT32 SendBufferSize;
+ UINT32 RecvBufferSize;
+ UINT8 *Buffer;
+ UINT32 SessionInfoSize;
+ TPM_RC ResponseCode;
+
+ //
+ // Construct command
+ //
+ SendBuffer.Header.tag = SwapBytes16(TPM_ST_SESSIONS);
+ SendBuffer.Header.commandCode = SwapBytes32(TPM_CC_NV_Read);
+
+ SendBuffer.AuthHandle = SwapBytes32 (AuthHandle);
+ SendBuffer.NvIndex = SwapBytes32 (NvIndex);
+
+ //
+ // Add in Auth session
+ //
+ Buffer = (UINT8 *)&SendBuffer.AuthSession;
+
+ // sessionInfoSize
+ SessionInfoSize = CopyAuthSessionCommand (AuthSession, Buffer);
+ Buffer += SessionInfoSize;
+ SendBuffer.AuthSessionSize = SwapBytes32(SessionInfoSize);
+
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Size));
+ Buffer += sizeof(UINT16);
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Offset));
+ Buffer += sizeof(UINT16);
+
+ SendBufferSize = (UINT32)(Buffer - (UINT8 *)&SendBuffer);
+ SendBuffer.Header.paramSize = SwapBytes32 (SendBufferSize);
+
+ //
+ // send Tpm command
+ //
+ RecvBufferSize = sizeof (RecvBuffer);
+ Status = Tpm2SubmitCommand (SendBufferSize, (UINT8 *)&SendBuffer, &RecvBufferSize, (UINT8 *)&RecvBuffer);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER)) {
+ DEBUG ((EFI_D_ERROR, "Tpm2NvRead - RecvBufferSize Error - %x\n", RecvBufferSize));
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+ ResponseCode = SwapBytes32(RecvBuffer.Header.responseCode);
+ if (ResponseCode != TPM_RC_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "Tpm2NvRead - responseCode - %x\n", ResponseCode));
+ }
+ switch (ResponseCode) {
+ case TPM_RC_SUCCESS:
+ // return data
+ break;
+ case TPM_RC_NV_AUTHORIZATION:
+ Status = EFI_SECURITY_VIOLATION;
+ break;
+ case TPM_RC_NV_LOCKED:
+ Status = EFI_ACCESS_DENIED;
+ break;
+ case TPM_RC_NV_RANGE:
+ Status = EFI_BAD_BUFFER_SIZE;
+ break;
+ case TPM_RC_NV_UNINITIALIZED:
+ Status = EFI_NOT_READY;
+ break;
+ case TPM_RC_HANDLE + RC_NV_Read_nvIndex: // TPM_RC_NV_DEFINED:
+ Status = EFI_NOT_FOUND;
+ break;
+ case TPM_RC_HANDLE + RC_NV_Read_authHandle: // TPM_RC_NV_DEFINED:
+ Status = EFI_INVALID_PARAMETER;
+ break;
+ case TPM_RC_VALUE + RC_NV_Read_nvIndex:
+ case TPM_RC_VALUE + RC_NV_Read_authHandle:
+ Status = EFI_INVALID_PARAMETER;
+ break;
+ case TPM_RC_BAD_AUTH + RC_NV_Read_authHandle + TPM_RC_S:
+ Status = EFI_INVALID_PARAMETER;
+ break;
+ case TPM_RC_AUTH_UNAVAILABLE:
+ Status = EFI_INVALID_PARAMETER;
+ break;
+ case TPM_RC_AUTH_FAIL + RC_NV_Read_authHandle + TPM_RC_S:
+ Status = EFI_INVALID_PARAMETER;
+ break;
+ case TPM_RC_ATTRIBUTES + RC_NV_Read_authHandle + TPM_RC_S:
+ Status = EFI_UNSUPPORTED;
+ break;
+ default:
+ Status = EFI_DEVICE_ERROR;
+ break;
+ }
+ if (Status != EFI_SUCCESS) {
+ goto Done;
+ }
+
+ //
+ // Return the response
+ //
+ OutData->size = SwapBytes16 (RecvBuffer.Data.size);
+ CopyMem (OutData->buffer, &RecvBuffer.Data.buffer, OutData->size);
+
+Done:
+ //
+ // Clear AuthSession Content
+ //
+ ZeroMem (&SendBuffer, sizeof(SendBuffer));
+ ZeroMem (&RecvBuffer, sizeof(RecvBuffer));
+ return Status;
+}
+
+/**
+ This command writes a value to an area in NV memory that was previously defined by TPM2_NV_DefineSpace().
+
+ @param[in] AuthHandle the handle indicating the source of the authorization value.
+ @param[in] NvIndex The NV Index of the area to write.
+ @param[in] AuthSession Auth Session context
+ @param[in] InData The data to write.
+ @param[in] Offset The offset into the NV Area.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+ @retval EFI_NOT_FOUND The command was returned successfully, but NvIndex is not found.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2NvWrite (
+ IN TPMI_RH_NV_AUTH AuthHandle,
+ IN TPMI_RH_NV_INDEX NvIndex,
+ IN TPMS_AUTH_COMMAND *AuthSession, OPTIONAL
+ IN TPM2B_MAX_BUFFER *InData,
+ IN UINT16 Offset
+ )
+{
+ EFI_STATUS Status;
+ TPM2_NV_WRITE_COMMAND SendBuffer;
+ TPM2_NV_WRITE_RESPONSE RecvBuffer;
+ UINT32 SendBufferSize;
+ UINT32 RecvBufferSize;
+ UINT8 *Buffer;
+ UINT32 SessionInfoSize;
+ TPM_RC ResponseCode;
+
+ //
+ // Construct command
+ //
+ SendBuffer.Header.tag = SwapBytes16(TPM_ST_SESSIONS);
+ SendBuffer.Header.commandCode = SwapBytes32(TPM_CC_NV_Write);
+
+ SendBuffer.AuthHandle = SwapBytes32 (AuthHandle);
+ SendBuffer.NvIndex = SwapBytes32 (NvIndex);
+
+ //
+ // Add in Auth session
+ //
+ Buffer = (UINT8 *)&SendBuffer.AuthSession;
+
+ // sessionInfoSize
+ SessionInfoSize = CopyAuthSessionCommand (AuthSession, Buffer);
+ Buffer += SessionInfoSize;
+ SendBuffer.AuthSessionSize = SwapBytes32(SessionInfoSize);
+
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (InData->size));
+ Buffer += sizeof(UINT16);
+ CopyMem (Buffer, InData->buffer, InData->size);
+ Buffer += InData->size;
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Offset));
+ Buffer += sizeof(UINT16);
+
+ SendBufferSize = (UINT32) (Buffer - (UINT8 *)&SendBuffer);
+ SendBuffer.Header.paramSize = SwapBytes32 (SendBufferSize);
+
+ //
+ // send Tpm command
+ //
+ RecvBufferSize = sizeof (RecvBuffer);
+ Status = Tpm2SubmitCommand (SendBufferSize, (UINT8 *)&SendBuffer, &RecvBufferSize, (UINT8 *)&RecvBuffer);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER)) {
+ DEBUG ((EFI_D_ERROR, "Tpm2NvWrite - RecvBufferSize Error - %x\n", RecvBufferSize));
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+ ResponseCode = SwapBytes32(RecvBuffer.Header.responseCode);
+ if (ResponseCode != TPM_RC_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "Tpm2NvWrite - responseCode - %x\n", ResponseCode));
+ }
+ switch (ResponseCode) {
+ case TPM_RC_SUCCESS:
+ // return data
+ break;
+ case TPM_RC_ATTRIBUTES:
+ Status = EFI_UNSUPPORTED;
+ break;
+ case TPM_RC_NV_AUTHORIZATION:
+ Status = EFI_SECURITY_VIOLATION;
+ break;
+ case TPM_RC_NV_LOCKED:
+ Status = EFI_ACCESS_DENIED;
+ break;
+ case TPM_RC_NV_RANGE:
+ Status = EFI_BAD_BUFFER_SIZE;
+ break;
+ case TPM_RC_HANDLE + RC_NV_Write_nvIndex: // TPM_RC_NV_DEFINED:
+ Status = EFI_NOT_FOUND;
+ break;
+ case TPM_RC_HANDLE + RC_NV_Write_authHandle: // TPM_RC_NV_DEFINED:
+ Status = EFI_INVALID_PARAMETER;
+ break;
+ case TPM_RC_VALUE + RC_NV_Write_nvIndex:
+ case TPM_RC_VALUE + RC_NV_Write_authHandle:
+ Status = EFI_INVALID_PARAMETER;
+ break;
+ case TPM_RC_BAD_AUTH + RC_NV_Write_authHandle + TPM_RC_S:
+ Status = EFI_INVALID_PARAMETER;
+ break;
+ case TPM_RC_AUTH_UNAVAILABLE:
+ Status = EFI_INVALID_PARAMETER;
+ break;
+ case TPM_RC_AUTH_FAIL + RC_NV_Write_authHandle + TPM_RC_S:
+ Status = EFI_INVALID_PARAMETER;
+ break;
+ case TPM_RC_ATTRIBUTES + RC_NV_Write_authHandle + TPM_RC_S:
+ Status = EFI_UNSUPPORTED;
+ break;
+ default:
+ Status = EFI_DEVICE_ERROR;
+ break;
+ }
+
+Done:
+ //
+ // Clear AuthSession Content
+ //
+ ZeroMem (&SendBuffer, sizeof(SendBuffer));
+ ZeroMem (&RecvBuffer, sizeof(RecvBuffer));
+ return Status;
+}
+
+/**
+ This command may be used to prevent further reads of the Index until the next TPM2_Startup (TPM_SU_CLEAR).
+
+ @param[in] AuthHandle the handle indicating the source of the authorization value.
+ @param[in] NvIndex The NV Index of the area to lock.
+ @param[in] AuthSession Auth Session context
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+ @retval EFI_NOT_FOUND The command was returned successfully, but NvIndex is not found.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2NvReadLock (
+ IN TPMI_RH_NV_AUTH AuthHandle,
+ IN TPMI_RH_NV_INDEX NvIndex,
+ IN TPMS_AUTH_COMMAND *AuthSession OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ TPM2_NV_READLOCK_COMMAND SendBuffer;
+ TPM2_NV_READLOCK_RESPONSE RecvBuffer;
+ UINT32 SendBufferSize;
+ UINT32 RecvBufferSize;
+ UINT8 *Buffer;
+ UINT32 SessionInfoSize;
+ TPM_RC ResponseCode;
+
+ //
+ // Construct command
+ //
+ SendBuffer.Header.tag = SwapBytes16(TPM_ST_SESSIONS);
+ SendBuffer.Header.commandCode = SwapBytes32(TPM_CC_NV_ReadLock);
+
+ SendBuffer.AuthHandle = SwapBytes32 (AuthHandle);
+ SendBuffer.NvIndex = SwapBytes32 (NvIndex);
+
+ //
+ // Add in Auth session
+ //
+ Buffer = (UINT8 *)&SendBuffer.AuthSession;
+
+ // sessionInfoSize
+ SessionInfoSize = CopyAuthSessionCommand (AuthSession, Buffer);
+ Buffer += SessionInfoSize;
+ SendBuffer.AuthSessionSize = SwapBytes32(SessionInfoSize);
+
+ SendBufferSize = (UINT32)(Buffer - (UINT8 *)&SendBuffer);
+ SendBuffer.Header.paramSize = SwapBytes32 (SendBufferSize);
+
+ //
+ // send Tpm command
+ //
+ RecvBufferSize = sizeof (RecvBuffer);
+ Status = Tpm2SubmitCommand (SendBufferSize, (UINT8 *)&SendBuffer, &RecvBufferSize, (UINT8 *)&RecvBuffer);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER)) {
+ DEBUG ((EFI_D_ERROR, "Tpm2NvReadLock - RecvBufferSize Error - %x\n", RecvBufferSize));
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+ ResponseCode = SwapBytes32(RecvBuffer.Header.responseCode);
+ if (ResponseCode != TPM_RC_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "Tpm2NvReadLock - responseCode - %x\n", SwapBytes32(RecvBuffer.Header.responseCode)));
+ }
+ switch (ResponseCode) {
+ case TPM_RC_SUCCESS:
+ // return data
+ break;
+ default:
+ Status = EFI_DEVICE_ERROR;
+ break;
+ }
+
+Done:
+ //
+ // Clear AuthSession Content
+ //
+ ZeroMem (&SendBuffer, sizeof(SendBuffer));
+ ZeroMem (&RecvBuffer, sizeof(RecvBuffer));
+ return Status;
+}
+
+/**
+ This command may be used to inhibit further writes of the Index.
+
+ @param[in] AuthHandle the handle indicating the source of the authorization value.
+ @param[in] NvIndex The NV Index of the area to lock.
+ @param[in] AuthSession Auth Session context
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+ @retval EFI_NOT_FOUND The command was returned successfully, but NvIndex is not found.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2NvWriteLock (
+ IN TPMI_RH_NV_AUTH AuthHandle,
+ IN TPMI_RH_NV_INDEX NvIndex,
+ IN TPMS_AUTH_COMMAND *AuthSession OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ TPM2_NV_WRITELOCK_COMMAND SendBuffer;
+ TPM2_NV_WRITELOCK_RESPONSE RecvBuffer;
+ UINT32 SendBufferSize;
+ UINT32 RecvBufferSize;
+ UINT8 *Buffer;
+ UINT32 SessionInfoSize;
+ TPM_RC ResponseCode;
+
+ //
+ // Construct command
+ //
+ SendBuffer.Header.tag = SwapBytes16(TPM_ST_SESSIONS);
+ SendBuffer.Header.commandCode = SwapBytes32(TPM_CC_NV_WriteLock);
+
+ SendBuffer.AuthHandle = SwapBytes32 (AuthHandle);
+ SendBuffer.NvIndex = SwapBytes32 (NvIndex);
+
+ //
+ // Add in Auth session
+ //
+ Buffer = (UINT8 *)&SendBuffer.AuthSession;
+
+ // sessionInfoSize
+ SessionInfoSize = CopyAuthSessionCommand (AuthSession, Buffer);
+ Buffer += SessionInfoSize;
+ SendBuffer.AuthSessionSize = SwapBytes32(SessionInfoSize);
+
+ SendBufferSize = (UINT32)(Buffer - (UINT8 *)&SendBuffer);
+ SendBuffer.Header.paramSize = SwapBytes32 (SendBufferSize);
+
+ //
+ // send Tpm command
+ //
+ RecvBufferSize = sizeof (RecvBuffer);
+ Status = Tpm2SubmitCommand (SendBufferSize, (UINT8 *)&SendBuffer, &RecvBufferSize, (UINT8 *)&RecvBuffer);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER)) {
+ DEBUG ((EFI_D_ERROR, "Tpm2NvWriteLock - RecvBufferSize Error - %x\n", RecvBufferSize));
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+ ResponseCode = SwapBytes32(RecvBuffer.Header.responseCode);
+ if (ResponseCode != TPM_RC_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "Tpm2NvWriteLock - responseCode - %x\n", SwapBytes32(RecvBuffer.Header.responseCode)));
+ }
+ switch (ResponseCode) {
+ case TPM_RC_SUCCESS:
+ // return data
+ break;
+ default:
+ Status = EFI_DEVICE_ERROR;
+ break;
+ }
+
+Done:
+ //
+ // Clear AuthSession Content
+ //
+ ZeroMem (&SendBuffer, sizeof(SendBuffer));
+ ZeroMem (&RecvBuffer, sizeof(RecvBuffer));
+ return Status;
+}
+
+/**
+ The command will SET TPMA_NV_WRITELOCKED for all indexes that have their TPMA_NV_GLOBALLOCK attribute SET.
+
+ @param[in] AuthHandle TPM_RH_OWNER or TPM_RH_PLATFORM+{PP}.
+ @param[in] AuthSession Auth Session context
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+ @retval EFI_NOT_FOUND The command was returned successfully, but NvIndex is not found.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2NvGlobalWriteLock (
+ IN TPMI_RH_PROVISION AuthHandle,
+ IN TPMS_AUTH_COMMAND *AuthSession OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ TPM2_NV_GLOBALWRITELOCK_COMMAND SendBuffer;
+ TPM2_NV_GLOBALWRITELOCK_RESPONSE RecvBuffer;
+ UINT32 SendBufferSize;
+ UINT32 RecvBufferSize;
+ UINT8 *Buffer;
+ UINT32 SessionInfoSize;
+ TPM_RC ResponseCode;
+
+ //
+ // Construct command
+ //
+ SendBuffer.Header.tag = SwapBytes16(TPM_ST_SESSIONS);
+ SendBuffer.Header.commandCode = SwapBytes32(TPM_CC_NV_GlobalWriteLock);
+
+ SendBuffer.AuthHandle = SwapBytes32 (AuthHandle);
+
+ //
+ // Add in Auth session
+ //
+ Buffer = (UINT8 *)&SendBuffer.AuthSession;
+
+ // sessionInfoSize
+ SessionInfoSize = CopyAuthSessionCommand (AuthSession, Buffer);
+ Buffer += SessionInfoSize;
+ SendBuffer.AuthSessionSize = SwapBytes32(SessionInfoSize);
+
+ SendBufferSize = (UINT32)(Buffer - (UINT8 *)&SendBuffer);
+ SendBuffer.Header.paramSize = SwapBytes32 (SendBufferSize);
+
+ //
+ // send Tpm command
+ //
+ RecvBufferSize = sizeof (RecvBuffer);
+ Status = Tpm2SubmitCommand (SendBufferSize, (UINT8 *)&SendBuffer, &RecvBufferSize, (UINT8 *)&RecvBuffer);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER)) {
+ DEBUG ((EFI_D_ERROR, "Tpm2NvGlobalWriteLock - RecvBufferSize Error - %x\n", RecvBufferSize));
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+ ResponseCode = SwapBytes32(RecvBuffer.Header.responseCode);
+ if (ResponseCode != TPM_RC_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "Tpm2NvGlobalWriteLock - responseCode - %x\n", SwapBytes32(RecvBuffer.Header.responseCode)));
+ }
+ switch (ResponseCode) {
+ case TPM_RC_SUCCESS:
+ // return data
+ break;
+ default:
+ Status = EFI_DEVICE_ERROR;
+ break;
+ }
+
+Done:
+ //
+ // Clear AuthSession Content
+ //
+ ZeroMem (&SendBuffer, sizeof(SendBuffer));
+ ZeroMem (&RecvBuffer, sizeof(RecvBuffer));
+ return Status;
+}
diff --git a/Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2Object.c b/Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2Object.c
new file mode 100644
index 0000000000..e070ff2f74
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2Object.c
@@ -0,0 +1,346 @@
+/** @file
+ Implement TPM2 Object related command.
+
+Copyright (c) 2017, Intel Corporation. All rights reserved. <BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <IndustryStandard/UefiTcgPlatform.h>
+#include <Library/Tpm2CommandLib.h>
+#include <Library/Tpm2DeviceLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+
+#pragma pack(1)
+
+typedef struct {
+ TPM2_COMMAND_HEADER Header;
+ TPMI_DH_OBJECT ObjectHandle;
+} TPM2_READ_PUBLIC_COMMAND;
+
+typedef struct {
+ TPM2_RESPONSE_HEADER Header;
+ TPM2B_PUBLIC OutPublic;
+ TPM2B_NAME Name;
+ TPM2B_NAME QualifiedName;
+} TPM2_READ_PUBLIC_RESPONSE;
+
+#pragma pack()
+
+/**
+ This command allows access to the public area of a loaded object.
+
+ @param[in] ObjectHandle TPM handle of an object
+ @param[out] OutPublic Structure containing the public area of an object
+ @param[out] Name Name of the object
+ @param[out] QualifiedName The Qualified Name of the object
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2ReadPublic (
+ IN TPMI_DH_OBJECT ObjectHandle,
+ OUT TPM2B_PUBLIC *OutPublic,
+ OUT TPM2B_NAME *Name,
+ OUT TPM2B_NAME *QualifiedName
+ )
+{
+ EFI_STATUS Status;
+ TPM2_READ_PUBLIC_COMMAND SendBuffer;
+ TPM2_READ_PUBLIC_RESPONSE RecvBuffer;
+ UINT32 SendBufferSize;
+ UINT32 RecvBufferSize;
+ TPM_RC ResponseCode;
+ UINT8 *Buffer;
+ UINT16 OutPublicSize;
+ UINT16 NameSize;
+ UINT16 QualifiedNameSize;
+
+ //
+ // Construct command
+ //
+ SendBuffer.Header.tag = SwapBytes16(TPM_ST_NO_SESSIONS);
+ SendBuffer.Header.commandCode = SwapBytes32(TPM_CC_ReadPublic);
+
+ SendBuffer.ObjectHandle = SwapBytes32 (ObjectHandle);
+
+ SendBufferSize = (UINT32) sizeof (SendBuffer);
+ SendBuffer.Header.paramSize = SwapBytes32 (SendBufferSize);
+
+ //
+ // send Tpm command
+ //
+ RecvBufferSize = sizeof (RecvBuffer);
+ Status = Tpm2SubmitCommand (SendBufferSize, (UINT8 *)&SendBuffer, &RecvBufferSize, (UINT8 *)&RecvBuffer);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER)) {
+ DEBUG ((DEBUG_ERROR, "Tpm2ReadPublic - RecvBufferSize Error - %x\n", RecvBufferSize));
+ return EFI_DEVICE_ERROR;
+ }
+ ResponseCode = SwapBytes32(RecvBuffer.Header.responseCode);
+ if (ResponseCode != TPM_RC_SUCCESS) {
+ DEBUG ((DEBUG_ERROR, "Tpm2ReadPublic - responseCode - %x\n", SwapBytes32(RecvBuffer.Header.responseCode)));
+ }
+ switch (ResponseCode) {
+ case TPM_RC_SUCCESS:
+ // return data
+ break;
+ case TPM_RC_SEQUENCE:
+ // objectHandle references a sequence object
+ return EFI_INVALID_PARAMETER;
+ default:
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Basic check
+ //
+ OutPublicSize = SwapBytes16 (RecvBuffer.OutPublic.size);
+ NameSize = SwapBytes16 (ReadUnaligned16 ((UINT16 *)((UINT8 *)&RecvBuffer + sizeof(TPM2_RESPONSE_HEADER) +
+ sizeof(UINT16) + OutPublicSize)));
+ QualifiedNameSize = SwapBytes16 (ReadUnaligned16 ((UINT16 *)((UINT8 *)&RecvBuffer + sizeof(TPM2_RESPONSE_HEADER) +
+ sizeof(UINT16) + OutPublicSize +
+ sizeof(UINT16) + NameSize)));
+
+ if (RecvBufferSize != sizeof(TPM2_RESPONSE_HEADER) + sizeof(UINT16) + OutPublicSize + sizeof(UINT16) + NameSize + sizeof(UINT16) + QualifiedNameSize) {
+ DEBUG ((DEBUG_ERROR, "Tpm2ReadPublic - RecvBufferSize %x Error - OutPublicSize %x, NameSize %x, QualifiedNameSize %x\n", RecvBufferSize, OutPublicSize, NameSize, QualifiedNameSize));
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Return the response
+ //
+ Buffer = (UINT8 *)&RecvBuffer.OutPublic;
+ CopyMem (OutPublic, &RecvBuffer.OutPublic, sizeof(UINT16) + OutPublicSize);
+ OutPublic->size = OutPublicSize;
+ OutPublic->publicArea.type = SwapBytes16 (OutPublic->publicArea.type);
+ OutPublic->publicArea.nameAlg = SwapBytes16 (OutPublic->publicArea.nameAlg);
+ WriteUnaligned32 ((UINT32 *)&OutPublic->publicArea.objectAttributes, SwapBytes32 (ReadUnaligned32 ((UINT32 *)&OutPublic->publicArea.objectAttributes)));
+ Buffer = (UINT8 *)&RecvBuffer.OutPublic.publicArea.authPolicy;
+ OutPublic->publicArea.authPolicy.size = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer));
+ Buffer += sizeof(UINT16);
+ CopyMem (OutPublic->publicArea.authPolicy.buffer, Buffer, OutPublic->publicArea.authPolicy.size);
+ Buffer += OutPublic->publicArea.authPolicy.size;
+
+ // TPMU_PUBLIC_PARMS
+ switch (OutPublic->publicArea.type) {
+ case TPM_ALG_KEYEDHASH:
+ OutPublic->publicArea.parameters.keyedHashDetail.scheme.scheme = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer));
+ Buffer += sizeof(UINT16);
+ switch (OutPublic->publicArea.parameters.keyedHashDetail.scheme.scheme) {
+ case TPM_ALG_HMAC:
+ OutPublic->publicArea.parameters.keyedHashDetail.scheme.details.hmac.hashAlg = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer));
+ Buffer += sizeof(UINT16);
+ break;
+ case TPM_ALG_XOR:
+ OutPublic->publicArea.parameters.keyedHashDetail.scheme.details.xor.hashAlg = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer));
+ Buffer += sizeof(UINT16);
+ OutPublic->publicArea.parameters.keyedHashDetail.scheme.details.xor.kdf = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer));
+ Buffer += sizeof(UINT16);
+ break;
+ default:
+ return EFI_UNSUPPORTED;
+ }
+ case TPM_ALG_SYMCIPHER:
+ OutPublic->publicArea.parameters.symDetail.algorithm = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer));
+ Buffer += sizeof(UINT16);
+ switch (OutPublic->publicArea.parameters.symDetail.algorithm) {
+ case TPM_ALG_AES:
+ OutPublic->publicArea.parameters.symDetail.keyBits.aes = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer));
+ Buffer += sizeof(UINT16);
+ OutPublic->publicArea.parameters.symDetail.mode.aes = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer));
+ Buffer += sizeof(UINT16);
+ break;
+ case TPM_ALG_SM4:
+ OutPublic->publicArea.parameters.symDetail.keyBits.SM4 = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer));
+ Buffer += sizeof(UINT16);
+ OutPublic->publicArea.parameters.symDetail.mode.SM4 = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer));
+ Buffer += sizeof(UINT16);
+ break;
+ case TPM_ALG_XOR:
+ OutPublic->publicArea.parameters.symDetail.keyBits.xor = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer));
+ Buffer += sizeof(UINT16);
+ break;
+ case TPM_ALG_NULL:
+ break;
+ default:
+ return EFI_UNSUPPORTED;
+ }
+ break;
+ case TPM_ALG_RSA:
+ OutPublic->publicArea.parameters.rsaDetail.symmetric.algorithm = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer));
+ Buffer += sizeof(UINT16);
+ switch (OutPublic->publicArea.parameters.rsaDetail.symmetric.algorithm) {
+ case TPM_ALG_AES:
+ OutPublic->publicArea.parameters.rsaDetail.symmetric.keyBits.aes = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer));
+ Buffer += sizeof(UINT16);
+ OutPublic->publicArea.parameters.rsaDetail.symmetric.mode.aes = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer));
+ Buffer += sizeof(UINT16);
+ break;
+ case TPM_ALG_SM4:
+ OutPublic->publicArea.parameters.rsaDetail.symmetric.keyBits.SM4 = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer));
+ Buffer += sizeof(UINT16);
+ OutPublic->publicArea.parameters.rsaDetail.symmetric.mode.SM4 = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer));
+ Buffer += sizeof(UINT16);
+ break;
+ case TPM_ALG_NULL:
+ break;
+ default:
+ return EFI_UNSUPPORTED;
+ }
+ OutPublic->publicArea.parameters.rsaDetail.scheme.scheme = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer));
+ Buffer += sizeof(UINT16);
+ switch (OutPublic->publicArea.parameters.rsaDetail.scheme.scheme) {
+ case TPM_ALG_RSASSA:
+ OutPublic->publicArea.parameters.rsaDetail.scheme.details.rsassa.hashAlg = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer));
+ Buffer += sizeof(UINT16);
+ break;
+ case TPM_ALG_RSAPSS:
+ OutPublic->publicArea.parameters.rsaDetail.scheme.details.rsapss.hashAlg = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer));
+ Buffer += sizeof(UINT16);
+ break;
+ case TPM_ALG_RSAES:
+ break;
+ case TPM_ALG_OAEP:
+ OutPublic->publicArea.parameters.rsaDetail.scheme.details.oaep.hashAlg = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer));
+ Buffer += sizeof(UINT16);
+ break;
+ case TPM_ALG_NULL:
+ break;
+ default:
+ return EFI_UNSUPPORTED;
+ }
+ OutPublic->publicArea.parameters.rsaDetail.keyBits = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer));
+ Buffer += sizeof(UINT16);
+ OutPublic->publicArea.parameters.rsaDetail.exponent = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer));
+ Buffer += sizeof(UINT32);
+ break;
+ case TPM_ALG_ECC:
+ OutPublic->publicArea.parameters.eccDetail.symmetric.algorithm = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer));
+ Buffer += sizeof(UINT16);
+ switch (OutPublic->publicArea.parameters.eccDetail.symmetric.algorithm) {
+ case TPM_ALG_AES:
+ OutPublic->publicArea.parameters.eccDetail.symmetric.keyBits.aes = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer));
+ Buffer += sizeof(UINT16);
+ OutPublic->publicArea.parameters.eccDetail.symmetric.mode.aes = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer));
+ Buffer += sizeof(UINT16);
+ break;
+ case TPM_ALG_SM4:
+ OutPublic->publicArea.parameters.eccDetail.symmetric.keyBits.SM4 = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer));
+ Buffer += sizeof(UINT16);
+ OutPublic->publicArea.parameters.eccDetail.symmetric.mode.SM4 = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer));
+ Buffer += sizeof(UINT16);
+ break;
+ case TPM_ALG_NULL:
+ break;
+ default:
+ return EFI_UNSUPPORTED;
+ }
+ OutPublic->publicArea.parameters.eccDetail.scheme.scheme = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer));
+ Buffer += sizeof(UINT16);
+ switch (OutPublic->publicArea.parameters.eccDetail.scheme.scheme) {
+ case TPM_ALG_ECDSA:
+ OutPublic->publicArea.parameters.eccDetail.scheme.details.ecdsa.hashAlg = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer));
+ Buffer += sizeof(UINT16);
+ break;
+ case TPM_ALG_ECDAA:
+ OutPublic->publicArea.parameters.eccDetail.scheme.details.ecdaa.hashAlg = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer));
+ Buffer += sizeof(UINT16);
+ break;
+ case TPM_ALG_ECSCHNORR:
+ OutPublic->publicArea.parameters.eccDetail.scheme.details.ecSchnorr.hashAlg = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer));
+ Buffer += sizeof(UINT16);
+ break;
+ case TPM_ALG_ECDH:
+ break;
+ case TPM_ALG_NULL:
+ break;
+ default:
+ return EFI_UNSUPPORTED;
+ }
+ OutPublic->publicArea.parameters.eccDetail.curveID = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer));
+ Buffer += sizeof(UINT16);
+ OutPublic->publicArea.parameters.eccDetail.kdf.scheme = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer));
+ Buffer += sizeof(UINT16);
+ switch (OutPublic->publicArea.parameters.eccDetail.kdf.scheme) {
+ case TPM_ALG_MGF1:
+ OutPublic->publicArea.parameters.eccDetail.kdf.details.mgf1.hashAlg = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer));
+ Buffer += sizeof(UINT16);
+ break;
+ case TPM_ALG_KDF1_SP800_108:
+ OutPublic->publicArea.parameters.eccDetail.kdf.details.kdf1_sp800_108.hashAlg = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer));
+ Buffer += sizeof(UINT16);
+ break;
+ case TPM_ALG_KDF1_SP800_56a:
+ OutPublic->publicArea.parameters.eccDetail.kdf.details.kdf1_SP800_56a.hashAlg = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer));
+ Buffer += sizeof(UINT16);
+ break;
+ case TPM_ALG_KDF2:
+ OutPublic->publicArea.parameters.eccDetail.kdf.details.kdf2.hashAlg = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer));
+ Buffer += sizeof(UINT16);
+ break;
+ case TPM_ALG_NULL:
+ break;
+ default:
+ return EFI_UNSUPPORTED;
+ }
+ break;
+ default:
+ return EFI_UNSUPPORTED;
+ }
+
+ // TPMU_PUBLIC_ID
+ switch (OutPublic->publicArea.type) {
+ case TPM_ALG_KEYEDHASH:
+ OutPublic->publicArea.unique.keyedHash.size = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer));
+ Buffer += sizeof(UINT16);
+ CopyMem (OutPublic->publicArea.unique.keyedHash.buffer, Buffer, OutPublic->publicArea.unique.keyedHash.size);
+ Buffer += OutPublic->publicArea.unique.keyedHash.size;
+ break;
+ case TPM_ALG_SYMCIPHER:
+ OutPublic->publicArea.unique.sym.size = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer));
+ Buffer += sizeof(UINT16);
+ CopyMem (OutPublic->publicArea.unique.sym.buffer, Buffer, OutPublic->publicArea.unique.sym.size);
+ Buffer += OutPublic->publicArea.unique.sym.size;
+ break;
+ case TPM_ALG_RSA:
+ OutPublic->publicArea.unique.rsa.size = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer));
+ Buffer += sizeof(UINT16);
+ CopyMem (OutPublic->publicArea.unique.rsa.buffer, Buffer, OutPublic->publicArea.unique.rsa.size);
+ Buffer += OutPublic->publicArea.unique.rsa.size;
+ break;
+ case TPM_ALG_ECC:
+ OutPublic->publicArea.unique.ecc.x.size = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer));
+ Buffer += sizeof(UINT16);
+ CopyMem (OutPublic->publicArea.unique.ecc.x.buffer, Buffer, OutPublic->publicArea.unique.ecc.x.size);
+ Buffer += OutPublic->publicArea.unique.ecc.x.size;
+ OutPublic->publicArea.unique.ecc.y.size = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer));
+ Buffer += sizeof(UINT16);
+ CopyMem (OutPublic->publicArea.unique.ecc.y.buffer, Buffer, OutPublic->publicArea.unique.ecc.y.size);
+ Buffer += OutPublic->publicArea.unique.ecc.y.size;
+ break;
+ default:
+ return EFI_UNSUPPORTED;
+ }
+
+ CopyMem (Name->name, (UINT8 *)&RecvBuffer + sizeof(TPM2_RESPONSE_HEADER) + sizeof(UINT16) + OutPublicSize + sizeof(UINT16), NameSize);
+ Name->size = NameSize;
+
+ CopyMem (QualifiedName->name, (UINT8 *)&RecvBuffer + sizeof(TPM2_RESPONSE_HEADER) + sizeof(UINT16) + OutPublicSize + sizeof(UINT16) + NameSize + sizeof(UINT16), QualifiedNameSize);
+ QualifiedName->size = QualifiedNameSize;
+
+ return EFI_SUCCESS;
+}
diff --git a/Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2Sequences.c b/Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2Sequences.c
new file mode 100644
index 0000000000..305b6f2078
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2Sequences.c
@@ -0,0 +1,508 @@
+/** @file
+ Implement TPM2 Sequences related command.
+
+Copyright (c) 2013, Intel Corporation. All rights reserved. <BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <IndustryStandard/UefiTcgPlatform.h>
+#include <Library/Tpm2CommandLib.h>
+#include <Library/Tpm2DeviceLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+
+#pragma pack(1)
+
+typedef struct {
+ TPM2_COMMAND_HEADER Header;
+ TPM2B_AUTH Auth;
+ TPMI_ALG_HASH HashAlg;
+} TPM2_HASH_SEQUENCE_START_COMMAND;
+
+typedef struct {
+ TPM2_RESPONSE_HEADER Header;
+ TPMI_DH_OBJECT SequenceHandle;
+} TPM2_HASH_SEQUENCE_START_RESPONSE;
+
+typedef struct {
+ TPM2_COMMAND_HEADER Header;
+ TPMI_DH_OBJECT SequenceHandle;
+ UINT32 AuthorizationSize;
+ TPMS_AUTH_COMMAND AuthSessionSeq;
+ TPM2B_MAX_BUFFER Buffer;
+} TPM2_SEQUENCE_UPDATE_COMMAND;
+
+typedef struct {
+ TPM2_RESPONSE_HEADER Header;
+ UINT32 ParameterSize;
+ TPMS_AUTH_RESPONSE AuthSessionSeq;
+} TPM2_SEQUENCE_UPDATE_RESPONSE;
+
+typedef struct {
+ TPM2_COMMAND_HEADER Header;
+ TPMI_DH_PCR PcrHandle;
+ TPMI_DH_OBJECT SequenceHandle;
+ UINT32 AuthorizationSize;
+ TPMS_AUTH_COMMAND AuthSessionPcr;
+ TPMS_AUTH_COMMAND AuthSessionSeq;
+ TPM2B_MAX_BUFFER Buffer;
+} TPM2_EVENT_SEQUENCE_COMPLETE_COMMAND;
+
+typedef struct {
+ TPM2_RESPONSE_HEADER Header;
+ UINT32 ParameterSize;
+ TPML_DIGEST_VALUES Results;
+ TPMS_AUTH_RESPONSE AuthSessionPcr;
+ TPMS_AUTH_RESPONSE AuthSessionSeq;
+} TPM2_EVENT_SEQUENCE_COMPLETE_RESPONSE;
+
+typedef struct {
+ TPM2_COMMAND_HEADER Header;
+ TPMI_DH_OBJECT SequenceHandle;
+ UINT32 AuthorizationSize;
+ TPMS_AUTH_COMMAND AuthSessionSeq;
+ TPM2B_MAX_BUFFER Buffer;
+ TPMI_RH_HIERARCHY Hierarchy;
+} TPM2_SEQUENCE_COMPLETE_COMMAND;
+
+typedef struct {
+ TPM2_RESPONSE_HEADER Header;
+ UINT32 ParameterSize;
+ TPM2B_DIGEST Digest;
+ TPMS_AUTH_RESPONSE AuthSessionSeq;
+} TPM2_SEQUENCE_COMPLETE_RESPONSE;
+
+#pragma pack()
+
+/**
+ This command starts a hash or an Event sequence.
+ If hashAlg is an implemented hash, then a hash sequence is started.
+ If hashAlg is TPM_ALG_NULL, then an Event sequence is started.
+
+ @param[in] HashAlg The hash algorithm to use for the hash sequence
+ An Event sequence starts if this is TPM_ALG_NULL.
+ @param[out] SequenceHandle A handle to reference the sequence
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2HashSequenceStart (
+ IN TPMI_ALG_HASH HashAlg,
+ OUT TPMI_DH_OBJECT *SequenceHandle
+ )
+{
+ EFI_STATUS Status;
+ TPM2_HASH_SEQUENCE_START_COMMAND Cmd;
+ TPM2_HASH_SEQUENCE_START_RESPONSE Res;
+ UINT32 CmdSize;
+ UINT32 RespSize;
+ UINT8 *Buffer;
+ UINT32 ResultBufSize;
+
+ ZeroMem(&Cmd, sizeof(Cmd));
+
+ //
+ // Construct command
+ //
+ Cmd.Header.tag = SwapBytes16(TPM_ST_NO_SESSIONS);
+ Cmd.Header.commandCode = SwapBytes32(TPM_CC_HashSequenceStart);
+
+ Buffer = (UINT8 *)&Cmd.Auth;
+
+ // auth = nullAuth
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16(0));
+ Buffer += sizeof(UINT16);
+
+ // hashAlg
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16(HashAlg));
+ Buffer += sizeof(UINT16);
+
+ CmdSize = (UINT32)(Buffer - (UINT8 *)&Cmd);
+ Cmd.Header.paramSize = SwapBytes32(CmdSize);
+
+ //
+ // Call the TPM
+ //
+ ResultBufSize = sizeof(Res);
+ Status = Tpm2SubmitCommand (CmdSize, (UINT8 *)&Cmd, &ResultBufSize, (UINT8 *)&Res);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ if (ResultBufSize > sizeof(Res)) {
+ DEBUG ((EFI_D_ERROR, "HashSequenceStart: Failed ExecuteCommand: Buffer Too Small\r\n"));
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ //
+ // Validate response headers
+ //
+ RespSize = SwapBytes32(Res.Header.paramSize);
+ if (RespSize > sizeof(Res)) {
+ DEBUG ((EFI_D_ERROR, "HashSequenceStart: Response size too large! %d\r\n", RespSize));
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ //
+ // Fail if command failed
+ //
+ if (SwapBytes32(Res.Header.responseCode) != TPM_RC_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "HashSequenceStart: Response Code error! 0x%08x\r\n", SwapBytes32(Res.Header.responseCode)));
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Unmarshal the response
+ //
+
+ // sequenceHandle
+ *SequenceHandle = SwapBytes32(Res.SequenceHandle);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This command is used to add data to a hash or HMAC sequence.
+ The amount of data in buffer may be any size up to the limits of the TPM.
+ NOTE: In all TPM, a buffer size of 1,024 octets is allowed.
+
+ @param[in] SequenceHandle Handle for the sequence object
+ @param[in] Buffer Data to be added to hash
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2SequenceUpdate (
+ IN TPMI_DH_OBJECT SequenceHandle,
+ IN TPM2B_MAX_BUFFER *Buffer
+ )
+{
+ EFI_STATUS Status;
+ TPM2_SEQUENCE_UPDATE_COMMAND Cmd;
+ TPM2_SEQUENCE_UPDATE_RESPONSE Res;
+ UINT32 CmdSize;
+ UINT32 RespSize;
+ UINT8 *BufferPtr;
+ UINT32 SessionInfoSize;
+ UINT32 ResultBufSize;
+
+ ZeroMem(&Cmd, sizeof(Cmd));
+
+ //
+ // Construct command
+ //
+ Cmd.Header.tag = SwapBytes16(TPM_ST_SESSIONS);
+ Cmd.Header.commandCode = SwapBytes32(TPM_CC_SequenceUpdate);
+ Cmd.SequenceHandle = SwapBytes32(SequenceHandle);
+
+ //
+ // Add in Auth session
+ //
+ BufferPtr = (UINT8 *)&Cmd.AuthSessionSeq;
+
+ // sessionInfoSize
+ SessionInfoSize = CopyAuthSessionCommand (NULL, BufferPtr);
+ BufferPtr += SessionInfoSize;
+ Cmd.AuthorizationSize = SwapBytes32(SessionInfoSize);
+
+ // buffer.size
+ WriteUnaligned16 ((UINT16 *)BufferPtr, SwapBytes16(Buffer->size));
+ BufferPtr += sizeof(UINT16);
+
+ CopyMem(BufferPtr, &Buffer->buffer, Buffer->size);
+ BufferPtr += Buffer->size;
+
+ CmdSize = (UINT32)(BufferPtr - (UINT8 *)&Cmd);
+ Cmd.Header.paramSize = SwapBytes32(CmdSize);
+
+ //
+ // Call the TPM
+ //
+ ResultBufSize = sizeof(Res);
+ Status = Tpm2SubmitCommand (CmdSize, (UINT8 *)&Cmd,&ResultBufSize, (UINT8 *)&Res);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ if (ResultBufSize > sizeof(Res)) {
+ DEBUG ((EFI_D_ERROR, "SequenceUpdate: Failed ExecuteCommand: Buffer Too Small\r\n"));
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ //
+ // Validate response headers
+ //
+ RespSize = SwapBytes32(Res.Header.paramSize);
+ if (RespSize > sizeof(Res)) {
+ DEBUG ((EFI_D_ERROR, "SequenceUpdate: Response size too large! %d\r\n", RespSize));
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ //
+ // Fail if command failed
+ //
+ if (SwapBytes32(Res.Header.responseCode) != TPM_RC_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "SequenceUpdate: Response Code error! 0x%08x\r\n", SwapBytes32(Res.Header.responseCode)));
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Unmarshal the response
+ //
+
+ // None
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This command adds the last part of data, if any, to an Event sequence and returns the result in a digest list.
+ If pcrHandle references a PCR and not TPM_RH_NULL, then the returned digest list is processed in
+ the same manner as the digest list input parameter to TPM2_PCR_Extend() with the pcrHandle in each
+ bank extended with the associated digest value.
+
+ @param[in] PcrHandle PCR to be extended with the Event data
+ @param[in] SequenceHandle Authorization for the sequence
+ @param[in] Buffer Data to be added to the Event
+ @param[out] Results List of digests computed for the PCR
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2EventSequenceComplete (
+ IN TPMI_DH_PCR PcrHandle,
+ IN TPMI_DH_OBJECT SequenceHandle,
+ IN TPM2B_MAX_BUFFER *Buffer,
+ OUT TPML_DIGEST_VALUES *Results
+ )
+{
+ EFI_STATUS Status;
+ TPM2_EVENT_SEQUENCE_COMPLETE_COMMAND Cmd;
+ TPM2_EVENT_SEQUENCE_COMPLETE_RESPONSE Res;
+ UINT32 CmdSize;
+ UINT32 RespSize;
+ UINT8 *BufferPtr;
+ UINT32 SessionInfoSize;
+ UINT32 SessionInfoSize2;
+ UINT32 Index;
+ UINT32 ResultBufSize;
+ UINT16 DigestSize;
+
+ ZeroMem(&Cmd, sizeof(Cmd));
+
+ //
+ // Construct command
+ //
+ Cmd.Header.tag = SwapBytes16(TPM_ST_SESSIONS);
+ Cmd.Header.commandCode = SwapBytes32(TPM_CC_EventSequenceComplete);
+ Cmd.PcrHandle = SwapBytes32(PcrHandle);
+ Cmd.SequenceHandle = SwapBytes32(SequenceHandle);
+
+ //
+ // Add in pcrHandle Auth session
+ //
+ BufferPtr = (UINT8 *)&Cmd.AuthSessionPcr;
+
+ // sessionInfoSize
+ SessionInfoSize = CopyAuthSessionCommand (NULL, BufferPtr);
+ BufferPtr += SessionInfoSize;
+
+ // sessionInfoSize
+ SessionInfoSize2 = CopyAuthSessionCommand (NULL, BufferPtr);
+ BufferPtr += SessionInfoSize2;
+ Cmd.AuthorizationSize = SwapBytes32(SessionInfoSize + SessionInfoSize2);
+
+ // buffer.size
+ WriteUnaligned16 ((UINT16 *)BufferPtr, SwapBytes16(Buffer->size));
+ BufferPtr += sizeof(UINT16);
+
+ CopyMem(BufferPtr, &Buffer->buffer[0], Buffer->size);
+ BufferPtr += Buffer->size;
+
+ CmdSize = (UINT32)(BufferPtr - (UINT8 *)&Cmd);
+ Cmd.Header.paramSize = SwapBytes32(CmdSize);
+
+ //
+ // Call the TPM
+ //
+ ResultBufSize = sizeof(Res);
+ Status = Tpm2SubmitCommand (CmdSize, (UINT8 *)&Cmd, &ResultBufSize, (UINT8 *)&Res);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ if (ResultBufSize > sizeof(Res)) {
+ DEBUG ((EFI_D_ERROR, "EventSequenceComplete: Failed ExecuteCommand: Buffer Too Small\r\n"));
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ //
+ // Validate response headers
+ //
+ RespSize = SwapBytes32(Res.Header.paramSize);
+ if (RespSize > sizeof(Res)) {
+ DEBUG ((EFI_D_ERROR, "EventSequenceComplete: Response size too large! %d\r\n", RespSize));
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ //
+ // Fail if command failed
+ //
+ if (SwapBytes32(Res.Header.responseCode) != TPM_RC_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "EventSequenceComplete: Response Code error! 0x%08x\r\n", SwapBytes32(Res.Header.responseCode)));
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Unmarshal the response
+ //
+
+ BufferPtr = (UINT8 *)&Res.Results;
+
+ // count
+ Results->count = SwapBytes32(ReadUnaligned32 ((UINT32 *)BufferPtr));
+ BufferPtr += sizeof(UINT32);
+
+ for (Index = 0; Index < Results->count; Index++) {
+ Results->digests[Index].hashAlg = SwapBytes16(ReadUnaligned16 ((UINT16 *)BufferPtr));
+ BufferPtr += sizeof(UINT16);
+
+ DigestSize = GetHashSizeFromAlgo (Results->digests[Index].hashAlg);
+ if (DigestSize == 0) {
+ DEBUG ((EFI_D_ERROR, "EventSequenceComplete: Unknown hash algorithm %d\r\n", Results->digests[Index].hashAlg));
+ return EFI_DEVICE_ERROR;
+ }
+ CopyMem(
+ &Results->digests[Index].digest,
+ BufferPtr,
+ DigestSize
+ );
+ BufferPtr += DigestSize;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This command adds the last part of data, if any, to a hash/HMAC sequence and returns the result.
+
+ @param[in] SequenceHandle Authorization for the sequence
+ @param[in] Buffer Data to be added to the hash/HMAC
+ @param[out] Result The returned HMAC or digest in a sized buffer
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2SequenceComplete (
+ IN TPMI_DH_OBJECT SequenceHandle,
+ IN TPM2B_MAX_BUFFER *Buffer,
+ OUT TPM2B_DIGEST *Result
+ )
+{
+ EFI_STATUS Status;
+ TPM2_SEQUENCE_COMPLETE_COMMAND Cmd;
+ TPM2_SEQUENCE_COMPLETE_RESPONSE Res;
+ UINT32 CmdSize;
+ UINT32 RespSize;
+ UINT8 *BufferPtr;
+ UINT32 SessionInfoSize;
+ UINT32 ResultBufSize;
+
+ ZeroMem(&Cmd, sizeof(Cmd));
+
+ //
+ // Construct command
+ //
+ Cmd.Header.tag = SwapBytes16(TPM_ST_SESSIONS);
+ Cmd.Header.commandCode = SwapBytes32(TPM_CC_SequenceComplete);
+ Cmd.SequenceHandle = SwapBytes32(SequenceHandle);
+
+ //
+ // Add in Auth session
+ //
+ BufferPtr = (UINT8 *)&Cmd.AuthSessionSeq;
+
+ // sessionInfoSize
+ SessionInfoSize = CopyAuthSessionCommand (NULL, BufferPtr);
+ BufferPtr += SessionInfoSize;
+ Cmd.AuthorizationSize = SwapBytes32(SessionInfoSize);
+
+ // buffer.size
+ WriteUnaligned16 ((UINT16 *)BufferPtr, SwapBytes16(Buffer->size));
+ BufferPtr += sizeof(UINT16);
+
+ CopyMem(BufferPtr, &Buffer->buffer[0], Buffer->size);
+ BufferPtr += Buffer->size;
+
+ // Hierarchy
+ WriteUnaligned32 ((UINT32 *)BufferPtr, SwapBytes32 (TPM_RH_NULL));
+ BufferPtr += sizeof (UINT32);
+
+ CmdSize = (UINT32)(BufferPtr - (UINT8 *)&Cmd);
+ Cmd.Header.paramSize = SwapBytes32(CmdSize);
+
+ //
+ // Call the TPM
+ //
+ ResultBufSize = sizeof(Res);
+ Status = Tpm2SubmitCommand (CmdSize, (UINT8 *)&Cmd, &ResultBufSize, (UINT8 *)&Res);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ if (ResultBufSize > sizeof(Res)) {
+ DEBUG ((EFI_D_ERROR, "SequenceComplete: Failed ExecuteCommand: Buffer Too Small\r\n"));
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ //
+ // Validate response headers
+ //
+ RespSize = SwapBytes32(Res.Header.paramSize);
+ if (RespSize > sizeof(Res)) {
+ DEBUG ((EFI_D_ERROR, "SequenceComplete: Response size too large! %d\r\n", RespSize));
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ //
+ // Fail if command failed
+ //
+ if (SwapBytes32(Res.Header.responseCode) != TPM_RC_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "SequenceComplete: Response Code error! 0x%08x\r\n", SwapBytes32(Res.Header.responseCode)));
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Unmarshal the response
+ //
+
+ BufferPtr = (UINT8 *)&Res.Digest;
+
+ // digestSize
+ Result->size = SwapBytes16(ReadUnaligned16 ((UINT16 *)BufferPtr));
+ BufferPtr += sizeof(UINT16);
+
+ CopyMem(
+ Result->buffer,
+ BufferPtr,
+ Result->size
+ );
+
+ return EFI_SUCCESS;
+}
diff --git a/Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2Session.c b/Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2Session.c
new file mode 100644
index 0000000000..f03b6689ac
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2Session.c
@@ -0,0 +1,169 @@
+/** @file
+ Implement TPM2 Session related command.
+
+Copyright (c) 2014, Intel Corporation. All rights reserved. <BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <IndustryStandard/UefiTcgPlatform.h>
+#include <Library/Tpm2CommandLib.h>
+#include <Library/Tpm2DeviceLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+
+#pragma pack(1)
+
+typedef struct {
+ TPM2_COMMAND_HEADER Header;
+ TPMI_DH_OBJECT TpmKey;
+ TPMI_DH_ENTITY Bind;
+ TPM2B_NONCE NonceCaller;
+ TPM2B_ENCRYPTED_SECRET Salt;
+ TPM_SE SessionType;
+ TPMT_SYM_DEF Symmetric;
+ TPMI_ALG_HASH AuthHash;
+} TPM2_START_AUTH_SESSION_COMMAND;
+
+typedef struct {
+ TPM2_RESPONSE_HEADER Header;
+ TPMI_SH_AUTH_SESSION SessionHandle;
+ TPM2B_NONCE NonceTPM;
+} TPM2_START_AUTH_SESSION_RESPONSE;
+
+#pragma pack()
+
+/**
+ This command is used to start an authorization session using alternative methods of
+ establishing the session key (sessionKey) that is used for authorization and encrypting value.
+
+ @param[in] TpmKey Handle of a loaded decrypt key used to encrypt salt.
+ @param[in] Bind Entity providing the authValue.
+ @param[in] NonceCaller Initial nonceCaller, sets nonce size for the session.
+ @param[in] Salt Value encrypted according to the type of tpmKey.
+ @param[in] SessionType Indicates the type of the session.
+ @param[in] Symmetric The algorithm and key size for parameter encryption.
+ @param[in] AuthHash Hash algorithm to use for the session.
+ @param[out] SessionHandle Handle for the newly created session.
+ @param[out] NonceTPM The initial nonce from the TPM, used in the computation of the sessionKey.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2StartAuthSession (
+ IN TPMI_DH_OBJECT TpmKey,
+ IN TPMI_DH_ENTITY Bind,
+ IN TPM2B_NONCE *NonceCaller,
+ IN TPM2B_ENCRYPTED_SECRET *Salt,
+ IN TPM_SE SessionType,
+ IN TPMT_SYM_DEF *Symmetric,
+ IN TPMI_ALG_HASH AuthHash,
+ OUT TPMI_SH_AUTH_SESSION *SessionHandle,
+ OUT TPM2B_NONCE *NonceTPM
+ )
+{
+ EFI_STATUS Status;
+ TPM2_START_AUTH_SESSION_COMMAND SendBuffer;
+ TPM2_START_AUTH_SESSION_RESPONSE RecvBuffer;
+ UINT32 SendBufferSize;
+ UINT32 RecvBufferSize;
+ UINT8 *Buffer;
+
+ //
+ // Construct command
+ //
+ SendBuffer.Header.tag = SwapBytes16(TPM_ST_NO_SESSIONS);
+ SendBuffer.Header.commandCode = SwapBytes32(TPM_CC_StartAuthSession);
+
+ SendBuffer.TpmKey = SwapBytes32 (TpmKey);
+ SendBuffer.Bind = SwapBytes32 (Bind);
+ Buffer = (UINT8 *)&SendBuffer.NonceCaller;
+
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (NonceCaller->size));
+ Buffer += sizeof(UINT16);
+ CopyMem (Buffer, NonceCaller->buffer, NonceCaller->size);
+ Buffer += NonceCaller->size;
+
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Salt->size));
+ Buffer += sizeof(UINT16);
+ CopyMem (Buffer, Salt->secret, Salt->size);
+ Buffer += Salt->size;
+
+ *(TPM_SE *)Buffer = SessionType;
+ Buffer++;
+
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Symmetric->algorithm));
+ Buffer += sizeof(UINT16);
+ switch (Symmetric->algorithm) {
+ case TPM_ALG_NULL:
+ break;
+ case TPM_ALG_AES:
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Symmetric->keyBits.aes));
+ Buffer += sizeof(UINT16);
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Symmetric->mode.aes));
+ Buffer += sizeof(UINT16);
+ break;
+ case TPM_ALG_SM4:
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Symmetric->keyBits.SM4));
+ Buffer += sizeof(UINT16);
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Symmetric->mode.SM4));
+ Buffer += sizeof(UINT16);
+ break;
+ case TPM_ALG_SYMCIPHER:
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Symmetric->keyBits.sym));
+ Buffer += sizeof(UINT16);
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Symmetric->mode.sym));
+ Buffer += sizeof(UINT16);
+ break;
+ case TPM_ALG_XOR:
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (Symmetric->keyBits.xor));
+ Buffer += sizeof(UINT16);
+ break;
+ default:
+ ASSERT (FALSE);
+ DEBUG ((EFI_D_ERROR, "Tpm2StartAuthSession - Symmetric->algorithm - %x\n", Symmetric->algorithm));
+ return EFI_UNSUPPORTED;
+ }
+
+ WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (AuthHash));
+ Buffer += sizeof(UINT16);
+
+ SendBufferSize = (UINT32) ((UINTN)Buffer - (UINTN)&SendBuffer);
+ SendBuffer.Header.paramSize = SwapBytes32 (SendBufferSize);
+
+ //
+ // send Tpm command
+ //
+ RecvBufferSize = sizeof (RecvBuffer);
+ Status = Tpm2SubmitCommand (SendBufferSize, (UINT8 *)&SendBuffer, &RecvBufferSize, (UINT8 *)&RecvBuffer);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (RecvBufferSize < sizeof (TPM2_RESPONSE_HEADER)) {
+ DEBUG ((EFI_D_ERROR, "Tpm2StartAuthSession - RecvBufferSize Error - %x\n", RecvBufferSize));
+ return EFI_DEVICE_ERROR;
+ }
+ if (SwapBytes32(RecvBuffer.Header.responseCode) != TPM_RC_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "Tpm2StartAuthSession - responseCode - %x\n", SwapBytes32(RecvBuffer.Header.responseCode)));
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Return the response
+ //
+ *SessionHandle = SwapBytes32 (RecvBuffer.SessionHandle);
+ NonceTPM->size = SwapBytes16 (RecvBuffer.NonceTPM.size);
+ CopyMem (NonceTPM->buffer, &RecvBuffer.NonceTPM.buffer, NonceTPM->size);
+
+ return EFI_SUCCESS;
+}
diff --git a/Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2Startup.c b/Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2Startup.c
new file mode 100644
index 0000000000..dc2c5628f9
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2Startup.c
@@ -0,0 +1,127 @@
+/** @file
+ Implement TPM2 Startup related command.
+
+Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved. <BR>
+(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <IndustryStandard/UefiTcgPlatform.h>
+#include <Library/Tpm2CommandLib.h>
+#include <Library/Tpm2DeviceLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+
+#pragma pack(1)
+
+typedef struct {
+ TPM2_COMMAND_HEADER Header;
+ TPM_SU StartupType;
+} TPM2_STARTUP_COMMAND;
+
+typedef struct {
+ TPM2_RESPONSE_HEADER Header;
+} TPM2_STARTUP_RESPONSE;
+
+typedef struct {
+ TPM2_COMMAND_HEADER Header;
+ TPM_SU ShutdownType;
+} TPM2_SHUTDOWN_COMMAND;
+
+typedef struct {
+ TPM2_RESPONSE_HEADER Header;
+} TPM2_SHUTDOWN_RESPONSE;
+
+#pragma pack()
+
+/**
+ Send Startup command to TPM2.
+
+ @param[in] StartupType TPM_SU_CLEAR or TPM_SU_STATE
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2Startup (
+ IN TPM_SU StartupType
+ )
+{
+ EFI_STATUS Status;
+ TPM2_STARTUP_COMMAND Cmd;
+ TPM2_STARTUP_RESPONSE Res;
+ UINT32 ResultBufSize;
+ TPM_RC ResponseCode;
+
+ Cmd.Header.tag = SwapBytes16(TPM_ST_NO_SESSIONS);
+ Cmd.Header.paramSize = SwapBytes32(sizeof(Cmd));
+ Cmd.Header.commandCode = SwapBytes32(TPM_CC_Startup);
+ Cmd.StartupType = SwapBytes16(StartupType);
+
+ ResultBufSize = sizeof(Res);
+ Status = Tpm2SubmitCommand (sizeof(Cmd), (UINT8 *)&Cmd, &ResultBufSize, (UINT8 *)&Res);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ ResponseCode = SwapBytes32(Res.Header.responseCode);
+ switch (ResponseCode) {
+ case TPM_RC_SUCCESS:
+ DEBUG ((DEBUG_INFO, "TPM2Startup: TPM_RC_SUCCESS\n"));
+ return EFI_SUCCESS;
+ case TPM_RC_INITIALIZE:
+ // TPM_RC_INITIALIZE can be returned if Tpm2Startup is not required.
+ DEBUG ((DEBUG_INFO, "TPM2Startup: TPM_RC_INITIALIZE\n"));
+ return EFI_SUCCESS;
+ default:
+ DEBUG ((EFI_D_ERROR, "Tpm2Startup: Response Code error! 0x%08x\r\n", ResponseCode));
+ return EFI_DEVICE_ERROR;
+ }
+}
+
+/**
+ Send Shutdown command to TPM2.
+
+ @param[in] ShutdownType TPM_SU_CLEAR or TPM_SU_STATE.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2Shutdown (
+ IN TPM_SU ShutdownType
+ )
+{
+ EFI_STATUS Status;
+ TPM2_SHUTDOWN_COMMAND Cmd;
+ TPM2_SHUTDOWN_RESPONSE Res;
+ UINT32 ResultBufSize;
+
+ Cmd.Header.tag = SwapBytes16(TPM_ST_NO_SESSIONS);
+ Cmd.Header.paramSize = SwapBytes32(sizeof(Cmd));
+ Cmd.Header.commandCode = SwapBytes32(TPM_CC_Shutdown);
+ Cmd.ShutdownType = SwapBytes16(ShutdownType);
+
+ ResultBufSize = sizeof(Res);
+ Status = Tpm2SubmitCommand (sizeof(Cmd), (UINT8 *)&Cmd, &ResultBufSize, (UINT8 *)&Res);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ if (SwapBytes32(Res.Header.responseCode) != TPM_RC_SUCCESS) {
+ DEBUG ((EFI_D_ERROR, "Tpm2Shutdown: Response Code error! 0x%08x\r\n", SwapBytes32(Res.Header.responseCode)));
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2Test.c b/Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2Test.c
new file mode 100644
index 0000000000..453351bfb3
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2Test.c
@@ -0,0 +1,66 @@
+/** @file
+ Implement TPM2 Test related command.
+
+Copyright (c) 2013, Intel Corporation. All rights reserved. <BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <IndustryStandard/UefiTcgPlatform.h>
+#include <Library/Tpm2CommandLib.h>
+#include <Library/Tpm2DeviceLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+
+#pragma pack(1)
+
+typedef struct {
+ TPM2_COMMAND_HEADER Header;
+ TPMI_YES_NO FullTest;
+} TPM2_SELF_TEST_COMMAND;
+
+typedef struct {
+ TPM2_RESPONSE_HEADER Header;
+} TPM2_SELF_TEST_RESPONSE;
+
+#pragma pack()
+
+/**
+ This command causes the TPM to perform a test of its capabilities.
+ If the fullTest is YES, the TPM will test all functions.
+ If fullTest = NO, the TPM will only test those functions that have not previously been tested.
+
+ @param[in] FullTest YES if full test to be performed
+ NO if only test of untested functions required
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2SelfTest (
+ IN TPMI_YES_NO FullTest
+ )
+{
+ EFI_STATUS Status;
+ TPM2_SELF_TEST_COMMAND Cmd;
+ TPM2_SELF_TEST_RESPONSE Res;
+ UINT32 ResultBufSize;
+
+ Cmd.Header.tag = SwapBytes16(TPM_ST_NO_SESSIONS);
+ Cmd.Header.paramSize = SwapBytes32(sizeof(Cmd));
+ Cmd.Header.commandCode = SwapBytes32(TPM_CC_SelfTest);
+ Cmd.FullTest = FullTest;
+
+ ResultBufSize = sizeof(Res);
+ Status = Tpm2SubmitCommand (sizeof(Cmd), (UINT8 *)&Cmd, &ResultBufSize, (UINT8 *)&Res);
+
+ return Status;
+}
diff --git a/Core/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2DeviceLibDTpm.c b/Core/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2DeviceLibDTpm.c
new file mode 100644
index 0000000000..0b1723e4a1
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2DeviceLibDTpm.c
@@ -0,0 +1,116 @@
+/** @file
+ This library is TPM2 DTPM device lib.
+ Choosing this library means platform uses and only uses DTPM device as TPM2 engine.
+
+Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved. <BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/Tpm2DeviceLib.h>
+
+/**
+ This service enables the sending of commands to the TPM2.
+
+ @param[in] InputParameterBlockSize Size of the TPM2 input parameter block.
+ @param[in] InputParameterBlock Pointer to the TPM2 input parameter block.
+ @param[in,out] OutputParameterBlockSize Size of the TPM2 output parameter block.
+ @param[in] OutputParameterBlock Pointer to the TPM2 output parameter block.
+
+ @retval EFI_SUCCESS The command byte stream was successfully sent to the device and a response was successfully received.
+ @retval EFI_DEVICE_ERROR The command was not successfully sent to the device or a response was not successfully received from the device.
+ @retval EFI_BUFFER_TOO_SMALL The output parameter block is too small.
+**/
+EFI_STATUS
+EFIAPI
+DTpm2SubmitCommand (
+ IN UINT32 InputParameterBlockSize,
+ IN UINT8 *InputParameterBlock,
+ IN OUT UINT32 *OutputParameterBlockSize,
+ IN UINT8 *OutputParameterBlock
+ );
+
+/**
+ This service requests use TPM2.
+
+ @retval EFI_SUCCESS Get the control of TPM2 chip.
+ @retval EFI_NOT_FOUND TPM2 not found.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+DTpm2RequestUseTpm (
+ VOID
+ );
+
+/**
+ This service enables the sending of commands to the TPM2.
+
+ @param[in] InputParameterBlockSize Size of the TPM2 input parameter block.
+ @param[in] InputParameterBlock Pointer to the TPM2 input parameter block.
+ @param[in,out] OutputParameterBlockSize Size of the TPM2 output parameter block.
+ @param[in] OutputParameterBlock Pointer to the TPM2 output parameter block.
+
+ @retval EFI_SUCCESS The command byte stream was successfully sent to the device and a response was successfully received.
+ @retval EFI_DEVICE_ERROR The command was not successfully sent to the device or a response was not successfully received from the device.
+ @retval EFI_BUFFER_TOO_SMALL The output parameter block is too small.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2SubmitCommand (
+ IN UINT32 InputParameterBlockSize,
+ IN UINT8 *InputParameterBlock,
+ IN OUT UINT32 *OutputParameterBlockSize,
+ IN UINT8 *OutputParameterBlock
+ )
+{
+ return DTpm2SubmitCommand (
+ InputParameterBlockSize,
+ InputParameterBlock,
+ OutputParameterBlockSize,
+ OutputParameterBlock
+ );
+}
+
+/**
+ This service requests use TPM2.
+
+ @retval EFI_SUCCESS Get the control of TPM2 chip.
+ @retval EFI_NOT_FOUND TPM2 not found.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2RequestUseTpm (
+ VOID
+ )
+{
+ return DTpm2RequestUseTpm ();
+}
+
+/**
+ This service register TPM2 device.
+
+ @param Tpm2Device TPM2 device
+
+ @retval EFI_SUCCESS This TPM2 device is registered successfully.
+ @retval EFI_UNSUPPORTED System does not support register this TPM2 device.
+ @retval EFI_ALREADY_STARTED System already register this TPM2 device.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2RegisterTpm2DeviceLib (
+ IN TPM2_DEVICE_INTERFACE *Tpm2Device
+ )
+{
+ return EFI_UNSUPPORTED;
+}
diff --git a/Core/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2DeviceLibDTpm.inf b/Core/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2DeviceLibDTpm.inf
new file mode 100644
index 0000000000..976972d98d
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2DeviceLibDTpm.inf
@@ -0,0 +1,51 @@
+## @file
+# Provides TPM 2.0 TIS/PTP functions for DTPM
+#
+# This library implements TIS (TPM Interface Specification) and
+# PTP (Platform TPM Profile) functions which is
+# used for every TPM 2.0 command. Choosing this library means platform uses and
+# only uses TPM 2.0 DTPM device.
+#
+# Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = Tpm2DeviceLibDTpm
+ MODULE_UNI_FILE = Tpm2DeviceLibDTpm.uni
+ FILE_GUID = E54A3327-A345-4068-8842-70AC0D519855
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = Tpm2DeviceLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF
+#
+
+[Sources]
+ Tpm2Tis.c
+ Tpm2Ptp.c
+ Tpm2DeviceLibDTpm.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ IoLib
+ TimerLib
+ DebugLib
+
+[Pcd]
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpmBaseAddress ## CONSUMES
diff --git a/Core/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2DeviceLibDTpm.uni b/Core/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2DeviceLibDTpm.uni
new file mode 100644
index 0000000000..94180ffd27
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2DeviceLibDTpm.uni
@@ -0,0 +1,24 @@
+// /** @file
+// Provides TPM 2.0 TIS/PTP functions for DTPM
+//
+// This library implements TIS (TPM Interface Specification) and
+// PTP (Platform TPM Profile) functions which is
+// used for every TPM 2.0 command. Choosing this library means platform uses and
+// only uses TPM 2.0 DTPM device.
+//
+// Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides TPM 2.0 TIS/PTP functions for DTPM"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library implements TIS (TPM Interface Specification) and PTP (Platform TPM Profile) functions which is used for every TPM 2.0 command. Choosing this library means platform uses and only uses TPM 2.0 DTPM device."
+
diff --git a/Core/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2InstanceLibDTpm.c b/Core/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2InstanceLibDTpm.c
new file mode 100644
index 0000000000..3f28f21faa
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2InstanceLibDTpm.c
@@ -0,0 +1,98 @@
+/** @file
+ This library is TPM2 DTPM instance.
+ It can be registered to Tpm2 Device router, to be active TPM2 engine,
+ based on platform setting.
+
+Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved. <BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/Tpm2DeviceLib.h>
+
+#include <Guid/TpmInstance.h>
+
+/**
+ Dump PTP register information.
+
+ @param[in] Register Pointer to PTP register.
+**/
+VOID
+DumpPtpInfo (
+ IN VOID *Register
+ );
+
+/**
+ This service enables the sending of commands to the TPM2.
+
+ @param[in] InputParameterBlockSize Size of the TPM2 input parameter block.
+ @param[in] InputParameterBlock Pointer to the TPM2 input parameter block.
+ @param[in,out] OutputParameterBlockSize Size of the TPM2 output parameter block.
+ @param[in] OutputParameterBlock Pointer to the TPM2 output parameter block.
+
+ @retval EFI_SUCCESS The command byte stream was successfully sent to the device and a response was successfully received.
+ @retval EFI_DEVICE_ERROR The command was not successfully sent to the device or a response was not successfully received from the device.
+ @retval EFI_BUFFER_TOO_SMALL The output parameter block is too small.
+**/
+EFI_STATUS
+EFIAPI
+DTpm2SubmitCommand (
+ IN UINT32 InputParameterBlockSize,
+ IN UINT8 *InputParameterBlock,
+ IN OUT UINT32 *OutputParameterBlockSize,
+ IN UINT8 *OutputParameterBlock
+ );
+
+/**
+ This service requests use TPM2.
+
+ @retval EFI_SUCCESS Get the control of TPM2 chip.
+ @retval EFI_NOT_FOUND TPM2 not found.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+DTpm2RequestUseTpm (
+ VOID
+ );
+
+TPM2_DEVICE_INTERFACE mDTpm2InternalTpm2Device = {
+ TPM_DEVICE_INTERFACE_TPM20_DTPM,
+ DTpm2SubmitCommand,
+ DTpm2RequestUseTpm,
+};
+
+/**
+ The function register DTPM2.0 instance.
+
+ @retval EFI_SUCCESS DTPM2.0 instance is registered, or system dose not surpport registr DTPM2.0 instance
+**/
+EFI_STATUS
+EFIAPI
+Tpm2InstanceLibDTpmConstructor (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+
+ Status = Tpm2RegisterTpm2DeviceLib (&mDTpm2InternalTpm2Device);
+ if ((Status == EFI_SUCCESS) || (Status == EFI_UNSUPPORTED)) {
+ //
+ // Unsupported means platform policy does not need this instance enabled.
+ //
+ if (Status == EFI_SUCCESS) {
+ DumpPtpInfo ((VOID *) (UINTN) PcdGet64 (PcdTpmBaseAddress));
+ }
+ return EFI_SUCCESS;
+ }
+ return Status;
+}
diff --git a/Core/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2InstanceLibDTpm.inf b/Core/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2InstanceLibDTpm.inf
new file mode 100644
index 0000000000..22efb1ef4c
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2InstanceLibDTpm.inf
@@ -0,0 +1,51 @@
+## @file
+# Provides a DTPM instance for TPM 2.0 TIS/PTP.
+#
+# This library can be registered to Tpm 2.0 device router, to be active TPM 2.0
+# engine, based on platform setting. It supports both TIS (TPM Interface Specification)
+# and PTP (Platform TPM Profile) functions.
+#
+# Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = Tpm2InstanceLibDTpm
+ MODULE_UNI_FILE = Tpm2InstanceLibDTpm.uni
+ FILE_GUID = 286BF25A-C2C3-408c-B3B4-25E6758B7317
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = NULL
+ CONSTRUCTOR = Tpm2InstanceLibDTpmConstructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF
+#
+
+[Sources]
+ Tpm2Tis.c
+ Tpm2Ptp.c
+ Tpm2InstanceLibDTpm.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ IoLib
+ TimerLib
+ DebugLib
+
+[Pcd]
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpmBaseAddress ## CONSUMES
diff --git a/Core/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2InstanceLibDTpm.uni b/Core/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2InstanceLibDTpm.uni
new file mode 100644
index 0000000000..96bb2ad163
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2InstanceLibDTpm.uni
@@ -0,0 +1,23 @@
+// /** @file
+// Provides a DTPM instance for TPM 2.0 TIS/PTP
+//
+// This library can be registered to Tpm 2.0 device router, to be active TPM 2.0
+// engine, based on platform setting. It supports both TIS (TPM Interface Specification)
+// and PTP (Platform TPM Profile) functions.
+//
+// Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides a DTPM instance for TPM 2.0 TIS/PTP"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library can be registered to Tpm 2.0 device router, to be active TPM 2.0 engine, based on platform setting. It supports both TIS (TPM Interface Specification) and PTP (Platform TPM Profile) functions."
+
diff --git a/Core/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2Ptp.c b/Core/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2Ptp.c
new file mode 100644
index 0000000000..ddd4bd00b4
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2Ptp.c
@@ -0,0 +1,537 @@
+/** @file
+ PTP (Platform TPM Profile) CRB (Command Response Buffer) interface used by dTPM2.0 library.
+
+Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <IndustryStandard/Tpm20.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/IoLib.h>
+#include <Library/TimerLib.h>
+#include <Library/DebugLib.h>
+#include <Library/Tpm2DeviceLib.h>
+#include <Library/PcdLib.h>
+
+#include <IndustryStandard/TpmPtp.h>
+#include <IndustryStandard/TpmTis.h>
+
+typedef enum {
+ PtpInterfaceTis,
+ PtpInterfaceFifo,
+ PtpInterfaceCrb,
+ PtpInterfaceMax,
+} PTP_INTERFACE_TYPE;
+
+//
+// Execution of the command may take from several seconds to minutes for certain
+// commands, such as key generation.
+//
+#define PTP_TIMEOUT_MAX (90000 * 1000) // 90s
+
+//
+// Max TPM command/reponse length
+//
+#define TPMCMDBUFLENGTH 0x500
+
+/**
+ Check whether TPM PTP register exist.
+
+ @param[in] Reg Pointer to PTP register.
+
+ @retval TRUE TPM PTP exists.
+ @retval FALSE TPM PTP is not found.
+**/
+BOOLEAN
+Tpm2IsPtpPresence (
+ IN VOID *Reg
+ )
+{
+ UINT8 RegRead;
+
+ RegRead = MmioRead8 ((UINTN)Reg);
+ if (RegRead == 0xFF) {
+ //
+ // No TPM chip
+ //
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/**
+ 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
+PtpCrbWaitRegisterBits (
+ IN UINT32 *Register,
+ IN UINT32 BitSet,
+ IN UINT32 BitClear,
+ IN UINT32 TimeOut
+ )
+{
+ UINT32 RegRead;
+ UINT32 WaitTime;
+
+ for (WaitTime = 0; WaitTime < TimeOut; WaitTime += 30){
+ RegRead = MmioRead32 ((UINTN)Register);
+ if ((RegRead & BitSet) == BitSet && (RegRead & BitClear) == 0) {
+ return EFI_SUCCESS;
+ }
+ MicroSecondDelay (30);
+ }
+ return EFI_TIMEOUT;
+}
+
+/**
+ Get the control of TPM chip.
+
+ @param[in] CrbReg Pointer to CRB register.
+
+ @retval EFI_SUCCESS Get the control of TPM chip.
+ @retval EFI_INVALID_PARAMETER CrbReg is NULL.
+ @retval EFI_NOT_FOUND TPM chip doesn't exit.
+ @retval EFI_TIMEOUT Can't get the TPM control in time.
+**/
+EFI_STATUS
+PtpCrbRequestUseTpm (
+ IN PTP_CRB_REGISTERS_PTR CrbReg
+ )
+{
+ EFI_STATUS Status;
+
+ if (!Tpm2IsPtpPresence (CrbReg)) {
+ return EFI_NOT_FOUND;
+ }
+
+ MmioWrite32((UINTN)&CrbReg->LocalityControl, PTP_CRB_LOCALITY_CONTROL_REQUEST_ACCESS);
+ Status = PtpCrbWaitRegisterBits (
+ &CrbReg->LocalityStatus,
+ PTP_CRB_LOCALITY_STATUS_GRANTED,
+ 0,
+ PTP_TIMEOUT_A
+ );
+ return Status;
+}
+
+/**
+ Send a command to TPM for execution and return response data.
+
+ @param[in] CrbReg 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_BUFFER_TOO_SMALL Response data buffer is too small.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+ @retval EFI_UNSUPPORTED Unsupported TPM version
+
+**/
+EFI_STATUS
+PtpCrbTpmCommand (
+ IN PTP_CRB_REGISTERS_PTR CrbReg,
+ IN UINT8 *BufferIn,
+ IN UINT32 SizeIn,
+ IN OUT UINT8 *BufferOut,
+ IN OUT UINT32 *SizeOut
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Index;
+ UINT32 TpmOutSize;
+ UINT16 Data16;
+ UINT32 Data32;
+
+ DEBUG_CODE (
+ UINTN DebugSize;
+
+ DEBUG ((EFI_D_VERBOSE, "PtpCrbTpmCommand Send - "));
+ if (SizeIn > 0x100) {
+ DebugSize = 0x40;
+ } else {
+ DebugSize = SizeIn;
+ }
+ for (Index = 0; Index < DebugSize; Index++) {
+ DEBUG ((EFI_D_VERBOSE, "%02x ", BufferIn[Index]));
+ }
+ if (DebugSize != SizeIn) {
+ DEBUG ((EFI_D_VERBOSE, "...... "));
+ for (Index = SizeIn - 0x20; Index < SizeIn; Index++) {
+ DEBUG ((EFI_D_VERBOSE, "%02x ", BufferIn[Index]));
+ }
+ }
+ DEBUG ((EFI_D_VERBOSE, "\n"));
+ );
+ TpmOutSize = 0;
+
+ //
+ // STEP 0:
+ // Ready is any time the TPM is ready to receive a command, following a write
+ // of 1 by software to Request.cmdReady, as indicated by the Status field
+ // being cleared to 0.
+ //
+ MmioWrite32((UINTN)&CrbReg->CrbControlRequest, PTP_CRB_CONTROL_AREA_REQUEST_COMMAND_READY);
+ Status = PtpCrbWaitRegisterBits (
+ &CrbReg->CrbControlRequest,
+ 0,
+ PTP_CRB_CONTROL_AREA_REQUEST_COMMAND_READY,
+ PTP_TIMEOUT_C
+ );
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+ Status = PtpCrbWaitRegisterBits (
+ &CrbReg->CrbControlStatus,
+ 0,
+ PTP_CRB_CONTROL_AREA_STATUS_TPM_IDLE,
+ PTP_TIMEOUT_C
+ );
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ //
+ // STEP 1:
+ // Command Reception occurs following a Ready state between the write of the
+ // first byte of a command to the Command Buffer and the receipt of a write
+ // of 1 to Start.
+ //
+ for (Index = 0; Index < SizeIn; Index++) {
+ MmioWrite8 ((UINTN)&CrbReg->CrbDataBuffer[Index], BufferIn[Index]);
+ }
+ MmioWrite32 ((UINTN)&CrbReg->CrbControlCommandAddressHigh, (UINT32)RShiftU64 ((UINTN)CrbReg->CrbDataBuffer, 32));
+ MmioWrite32 ((UINTN)&CrbReg->CrbControlCommandAddressLow, (UINT32)(UINTN)CrbReg->CrbDataBuffer);
+ MmioWrite32 ((UINTN)&CrbReg->CrbControlCommandSize, sizeof(CrbReg->CrbDataBuffer));
+
+ MmioWrite64 ((UINTN)&CrbReg->CrbControlResponseAddrss, (UINT32)(UINTN)CrbReg->CrbDataBuffer);
+ MmioWrite32 ((UINTN)&CrbReg->CrbControlResponseSize, sizeof(CrbReg->CrbDataBuffer));
+
+ //
+ // STEP 2:
+ // Command Execution occurs after receipt of a 1 to Start and the TPM
+ // clearing Start to 0.
+ //
+ MmioWrite32((UINTN)&CrbReg->CrbControlStart, PTP_CRB_CONTROL_START);
+ Status = PtpCrbWaitRegisterBits (
+ &CrbReg->CrbControlStart,
+ 0,
+ PTP_CRB_CONTROL_START,
+ PTP_TIMEOUT_MAX
+ );
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ //
+ // STEP 3:
+ // Command Completion occurs after completion of a command (indicated by the
+ // TPM clearing TPM_CRB_CTRL_Start_x to 0) and before a write of a 1 by the
+ // software to Request.goIdle.
+ //
+
+ //
+ // Get response data header
+ //
+ for (Index = 0; Index < sizeof (TPM2_RESPONSE_HEADER); Index++) {
+ BufferOut[Index] = MmioRead8 ((UINTN)&CrbReg->CrbDataBuffer[Index]);
+ }
+ DEBUG_CODE (
+ DEBUG ((EFI_D_VERBOSE, "PtpCrbTpmCommand ReceiveHeader - "));
+ for (Index = 0; Index < sizeof (TPM2_RESPONSE_HEADER); Index++) {
+ DEBUG ((EFI_D_VERBOSE, "%02x ", BufferOut[Index]));
+ }
+ DEBUG ((EFI_D_VERBOSE, "\n"));
+ );
+ //
+ // Check the reponse data header (tag, parasize and returncode)
+ //
+ CopyMem (&Data16, BufferOut, sizeof (UINT16));
+ // TPM2 should not use this RSP_COMMAND
+ if (SwapBytes16 (Data16) == TPM_ST_RSP_COMMAND) {
+ DEBUG ((EFI_D_ERROR, "TPM2: TPM_ST_RSP error - %x\n", TPM_ST_RSP_COMMAND));
+ Status = EFI_UNSUPPORTED;
+ 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
+ //
+ for (Index = sizeof (TPM2_RESPONSE_HEADER); Index < TpmOutSize; Index++) {
+ BufferOut[Index] = MmioRead8 ((UINTN)&CrbReg->CrbDataBuffer[Index]);
+ }
+Exit:
+ DEBUG_CODE (
+ DEBUG ((EFI_D_VERBOSE, "PtpCrbTpmCommand Receive - "));
+ for (Index = 0; Index < TpmOutSize; Index++) {
+ DEBUG ((EFI_D_VERBOSE, "%02x ", BufferOut[Index]));
+ }
+ DEBUG ((EFI_D_VERBOSE, "\n"));
+ );
+
+ //
+ // STEP 4:
+ // Idle is any time TPM_CRB_CTRL_STS_x.Status.goIdle is 1.
+ //
+ MmioWrite32((UINTN)&CrbReg->CrbControlRequest, PTP_CRB_CONTROL_AREA_REQUEST_GO_IDLE);
+ return Status;
+}
+
+/**
+ Send a command to TPM for execution and return response data.
+
+ @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_BUFFER_TOO_SMALL Response data buffer is too small.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+ @retval EFI_UNSUPPORTED Unsupported TPM version
+
+**/
+EFI_STATUS
+Tpm2TisTpmCommand (
+ IN TIS_PC_REGISTERS_PTR TisReg,
+ IN UINT8 *BufferIn,
+ IN UINT32 SizeIn,
+ IN OUT UINT8 *BufferOut,
+ IN OUT UINT32 *SizeOut
+ );
+
+/**
+ Get the control of TPM chip by sending requestUse command TIS_PC_ACC_RQUUSE
+ to ACCESS Register in the time of default TIS_TIMEOUT_A.
+
+ @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
+TisPcRequestUseTpm (
+ IN TIS_PC_REGISTERS_PTR TisReg
+ );
+
+/**
+ Return PTP interface type.
+
+ @param[in] Register Pointer to PTP register.
+
+ @return PTP interface type.
+**/
+PTP_INTERFACE_TYPE
+Tpm2GetPtpInterface (
+ IN VOID *Register
+ )
+{
+ PTP_CRB_INTERFACE_IDENTIFIER InterfaceId;
+ PTP_FIFO_INTERFACE_CAPABILITY InterfaceCapability;
+
+ if (!Tpm2IsPtpPresence (Register)) {
+ return PtpInterfaceMax;
+ }
+ //
+ // Check interface id
+ //
+ InterfaceId.Uint32 = MmioRead32 ((UINTN)&((PTP_CRB_REGISTERS *)Register)->InterfaceId);
+ InterfaceCapability.Uint32 = MmioRead32 ((UINTN)&((PTP_FIFO_REGISTERS *)Register)->InterfaceCapability);
+
+ if ((InterfaceId.Bits.InterfaceType == PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_CRB) &&
+ (InterfaceId.Bits.InterfaceVersion == PTP_INTERFACE_IDENTIFIER_INTERFACE_VERSION_CRB) &&
+ (InterfaceId.Bits.CapCRB != 0)) {
+ return PtpInterfaceCrb;
+ }
+ if ((InterfaceId.Bits.InterfaceType == PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_FIFO) &&
+ (InterfaceId.Bits.InterfaceVersion == PTP_INTERFACE_IDENTIFIER_INTERFACE_VERSION_FIFO) &&
+ (InterfaceId.Bits.CapFIFO != 0) &&
+ (InterfaceCapability.Bits.InterfaceVersion == INTERFACE_CAPABILITY_INTERFACE_VERSION_PTP)) {
+ return PtpInterfaceFifo;
+ }
+ return PtpInterfaceTis;
+}
+
+/**
+ Dump PTP register information.
+
+ @param[in] Register Pointer to PTP register.
+**/
+VOID
+DumpPtpInfo (
+ IN VOID *Register
+ )
+{
+ PTP_CRB_INTERFACE_IDENTIFIER InterfaceId;
+ PTP_FIFO_INTERFACE_CAPABILITY InterfaceCapability;
+ UINT8 StatusEx;
+ UINT16 Vid;
+ UINT16 Did;
+ UINT8 Rid;
+ PTP_INTERFACE_TYPE PtpInterface;
+
+ if (!Tpm2IsPtpPresence (Register)) {
+ return ;
+ }
+
+ InterfaceId.Uint32 = MmioRead32 ((UINTN)&((PTP_CRB_REGISTERS *)Register)->InterfaceId);
+ InterfaceCapability.Uint32 = MmioRead32 ((UINTN)&((PTP_FIFO_REGISTERS *)Register)->InterfaceCapability);
+ StatusEx = MmioRead8 ((UINTN)&((PTP_FIFO_REGISTERS *)Register)->StatusEx);
+
+ //
+ // Dump InterfaceId Register for PTP
+ //
+ DEBUG ((EFI_D_INFO, "InterfaceId - 0x%08x\n", InterfaceId.Uint32));
+ DEBUG ((EFI_D_INFO, " InterfaceType - 0x%02x\n", InterfaceId.Bits.InterfaceType));
+ if (InterfaceId.Bits.InterfaceType != PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_TIS) {
+ DEBUG ((EFI_D_INFO, " InterfaceVersion - 0x%02x\n", InterfaceId.Bits.InterfaceVersion));
+ DEBUG ((EFI_D_INFO, " CapFIFO - 0x%x\n", InterfaceId.Bits.CapFIFO));
+ DEBUG ((EFI_D_INFO, " CapCRB - 0x%x\n", InterfaceId.Bits.CapCRB));
+ }
+
+ //
+ // Dump Capability Register for TIS and FIFO
+ //
+ DEBUG ((EFI_D_INFO, "InterfaceCapability - 0x%08x\n", InterfaceCapability.Uint32));
+ if ((InterfaceId.Bits.InterfaceType == PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_TIS) ||
+ (InterfaceId.Bits.InterfaceType == PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_FIFO)) {
+ DEBUG ((EFI_D_INFO, " InterfaceVersion - 0x%x\n", InterfaceCapability.Bits.InterfaceVersion));
+ }
+
+ //
+ // Dump StatusEx Register for PTP FIFO
+ //
+ DEBUG ((EFI_D_INFO, "StatusEx - 0x%02x\n", StatusEx));
+ if (InterfaceCapability.Bits.InterfaceVersion == INTERFACE_CAPABILITY_INTERFACE_VERSION_PTP) {
+ DEBUG ((EFI_D_INFO, " TpmFamily - 0x%x\n", (StatusEx & PTP_FIFO_STS_EX_TPM_FAMILY) >> PTP_FIFO_STS_EX_TPM_FAMILY_OFFSET));
+ }
+
+ Vid = 0xFFFF;
+ Did = 0xFFFF;
+ Rid = 0xFF;
+ PtpInterface = Tpm2GetPtpInterface (Register);
+ DEBUG ((EFI_D_INFO, "PtpInterface - %x\n", PtpInterface));
+ switch (PtpInterface) {
+ case PtpInterfaceCrb:
+ Vid = MmioRead16 ((UINTN)&((PTP_CRB_REGISTERS *)Register)->Vid);
+ Did = MmioRead16 ((UINTN)&((PTP_CRB_REGISTERS *)Register)->Did);
+ Rid = (UINT8)InterfaceId.Bits.Rid;
+ break;
+ case PtpInterfaceFifo:
+ case PtpInterfaceTis:
+ Vid = MmioRead16 ((UINTN)&((PTP_FIFO_REGISTERS *)Register)->Vid);
+ Did = MmioRead16 ((UINTN)&((PTP_FIFO_REGISTERS *)Register)->Did);
+ Rid = MmioRead8 ((UINTN)&((PTP_FIFO_REGISTERS *)Register)->Rid);
+ break;
+ default:
+ break;
+ }
+ DEBUG ((EFI_D_INFO, "VID - 0x%04x\n", Vid));
+ DEBUG ((EFI_D_INFO, "DID - 0x%04x\n", Did));
+ DEBUG ((EFI_D_INFO, "RID - 0x%02x\n", Rid));
+}
+
+/**
+ This service enables the sending of commands to the TPM2.
+
+ @param[in] InputParameterBlockSize Size of the TPM2 input parameter block.
+ @param[in] InputParameterBlock Pointer to the TPM2 input parameter block.
+ @param[in,out] OutputParameterBlockSize Size of the TPM2 output parameter block.
+ @param[in] OutputParameterBlock Pointer to the TPM2 output parameter block.
+
+ @retval EFI_SUCCESS The command byte stream was successfully sent to the device and a response was successfully received.
+ @retval EFI_DEVICE_ERROR The command was not successfully sent to the device or a response was not successfully received from the device.
+ @retval EFI_BUFFER_TOO_SMALL The output parameter block is too small.
+**/
+EFI_STATUS
+EFIAPI
+DTpm2SubmitCommand (
+ IN UINT32 InputParameterBlockSize,
+ IN UINT8 *InputParameterBlock,
+ IN OUT UINT32 *OutputParameterBlockSize,
+ IN UINT8 *OutputParameterBlock
+ )
+{
+ PTP_INTERFACE_TYPE PtpInterface;
+
+ PtpInterface = Tpm2GetPtpInterface ((VOID *) (UINTN) PcdGet64 (PcdTpmBaseAddress));
+ switch (PtpInterface) {
+ case PtpInterfaceCrb:
+ return PtpCrbTpmCommand (
+ (PTP_CRB_REGISTERS_PTR) (UINTN) PcdGet64 (PcdTpmBaseAddress),
+ InputParameterBlock,
+ InputParameterBlockSize,
+ OutputParameterBlock,
+ OutputParameterBlockSize
+ );
+ case PtpInterfaceFifo:
+ case PtpInterfaceTis:
+ return Tpm2TisTpmCommand (
+ (TIS_PC_REGISTERS_PTR) (UINTN) PcdGet64 (PcdTpmBaseAddress),
+ InputParameterBlock,
+ InputParameterBlockSize,
+ OutputParameterBlock,
+ OutputParameterBlockSize
+ );
+ default:
+ return EFI_NOT_FOUND;
+ }
+}
+
+/**
+ This service requests use TPM2.
+
+ @retval EFI_SUCCESS Get the control of TPM2 chip.
+ @retval EFI_NOT_FOUND TPM2 not found.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+DTpm2RequestUseTpm (
+ VOID
+ )
+{
+ PTP_INTERFACE_TYPE PtpInterface;
+
+ PtpInterface = Tpm2GetPtpInterface ((VOID *) (UINTN) PcdGet64 (PcdTpmBaseAddress));
+ switch (PtpInterface) {
+ case PtpInterfaceCrb:
+ return PtpCrbRequestUseTpm ((PTP_CRB_REGISTERS_PTR) (UINTN) PcdGet64 (PcdTpmBaseAddress));
+ case PtpInterfaceFifo:
+ case PtpInterfaceTis:
+ return TisPcRequestUseTpm ((TIS_PC_REGISTERS_PTR) (UINTN) PcdGet64 (PcdTpmBaseAddress));
+ default:
+ return EFI_NOT_FOUND;
+ }
+}
diff --git a/Core/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2Tis.c b/Core/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2Tis.c
new file mode 100644
index 0000000000..6cd7030df2
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2Tis.c
@@ -0,0 +1,418 @@
+/** @file
+ TIS (TPM Interface Specification) functions used by dTPM2.0 library.
+
+Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.<BR>
+(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <IndustryStandard/Tpm20.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/IoLib.h>
+#include <Library/TimerLib.h>
+#include <Library/DebugLib.h>
+#include <Library/Tpm2DeviceLib.h>
+#include <Library/PcdLib.h>
+
+#include <IndustryStandard/TpmTis.h>
+
+#define TIS_TIMEOUT_MAX (90000 * 1000) // 90s
+
+//
+// Max TPM command/reponse length
+//
+#define TPMCMDBUFLENGTH 0x500
+
+/**
+ 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
+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
+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
+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_A.
+
+ @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
+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_A
+ );
+ return Status;
+}
+
+/**
+ Send a command to TPM for execution and return response data.
+
+ @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_BUFFER_TOO_SMALL Response data buffer is too small.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+ @retval EFI_UNSUPPORTED Unsupported TPM version
+
+**/
+EFI_STATUS
+Tpm2TisTpmCommand (
+ 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;
+
+ DEBUG_CODE (
+ UINTN DebugSize;
+
+ DEBUG ((EFI_D_VERBOSE, "Tpm2TisTpmCommand Send - "));
+ if (SizeIn > 0x100) {
+ DebugSize = 0x40;
+ } else {
+ DebugSize = SizeIn;
+ }
+ for (Index = 0; Index < DebugSize; Index++) {
+ DEBUG ((EFI_D_VERBOSE, "%02x ", BufferIn[Index]));
+ }
+ if (DebugSize != SizeIn) {
+ DEBUG ((EFI_D_VERBOSE, "...... "));
+ for (Index = SizeIn - 0x20; Index < SizeIn; Index++) {
+ DEBUG ((EFI_D_VERBOSE, "%02x ", BufferIn[Index]));
+ }
+ }
+ DEBUG ((EFI_D_VERBOSE, "\n"));
+ );
+ TpmOutSize = 0;
+
+ Status = TisPcPrepareCommand (TisReg);
+ if (EFI_ERROR (Status)){
+ DEBUG ((DEBUG_ERROR, "Tpm2 is not ready for command!\n"));
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Send the command data to Tpm
+ //
+ Index = 0;
+ while (Index < SizeIn) {
+ Status = TisPcReadBurstCount (TisReg, &BurstCount);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ 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, "Tpm2 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);
+
+ //
+ // NOTE: That may take many seconds to minutes for certain commands, such as key generation.
+ //
+ Status = TisPcWaitRegisterBits (
+ &TisReg->Status,
+ (UINT8) (TIS_PC_VALID | TIS_PC_STS_DATA),
+ 0,
+ TIS_TIMEOUT_MAX
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Wait for Tpm2 response data time out!!\n"));
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+ //
+ // Get response data header
+ //
+ Index = 0;
+ BurstCount = 0;
+ while (Index < sizeof (TPM2_RESPONSE_HEADER)) {
+ Status = TisPcReadBurstCount (TisReg, &BurstCount);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+ for (; BurstCount > 0; BurstCount--) {
+ *(BufferOut + Index) = MmioRead8 ((UINTN)&TisReg->DataFifo);
+ Index++;
+ if (Index == sizeof (TPM2_RESPONSE_HEADER)) break;
+ }
+ }
+ DEBUG_CODE (
+ DEBUG ((EFI_D_VERBOSE, "Tpm2TisTpmCommand ReceiveHeader - "));
+ for (Index = 0; Index < sizeof (TPM2_RESPONSE_HEADER); Index++) {
+ DEBUG ((EFI_D_VERBOSE, "%02x ", BufferOut[Index]));
+ }
+ DEBUG ((EFI_D_VERBOSE, "\n"));
+ );
+ //
+ // Check the reponse data header (tag,parasize and returncode )
+ //
+ CopyMem (&Data16, BufferOut, sizeof (UINT16));
+ // TPM2 should not use this RSP_COMMAND
+ if (SwapBytes16 (Data16) == TPM_ST_RSP_COMMAND) {
+ DEBUG ((EFI_D_ERROR, "TPM2: TPM_ST_RSP error - %x\n", TPM_ST_RSP_COMMAND));
+ Status = EFI_UNSUPPORTED;
+ 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_DEVICE_ERROR;
+ goto Exit;
+ }
+ }
+Exit:
+ DEBUG_CODE (
+ DEBUG ((EFI_D_VERBOSE, "Tpm2TisTpmCommand Receive - "));
+ for (Index = 0; Index < TpmOutSize; Index++) {
+ DEBUG ((EFI_D_VERBOSE, "%02x ", BufferOut[Index]));
+ }
+ DEBUG ((EFI_D_VERBOSE, "\n"));
+ );
+ MmioWrite8((UINTN)&TisReg->Status, TIS_PC_STS_READY);
+ return Status;
+}
+
+/**
+ This service enables the sending of commands to the TPM2.
+
+ @param[in] InputParameterBlockSize Size of the TPM2 input parameter block.
+ @param[in] InputParameterBlock Pointer to the TPM2 input parameter block.
+ @param[in,out] OutputParameterBlockSize Size of the TPM2 output parameter block.
+ @param[in] OutputParameterBlock Pointer to the TPM2 output parameter block.
+
+ @retval EFI_SUCCESS The command byte stream was successfully sent to the device and a response was successfully received.
+ @retval EFI_DEVICE_ERROR The command was not successfully sent to the device or a response was not successfully received from the device.
+ @retval EFI_BUFFER_TOO_SMALL The output parameter block is too small.
+**/
+EFI_STATUS
+EFIAPI
+DTpm2TisSubmitCommand (
+ IN UINT32 InputParameterBlockSize,
+ IN UINT8 *InputParameterBlock,
+ IN OUT UINT32 *OutputParameterBlockSize,
+ IN UINT8 *OutputParameterBlock
+ )
+{
+ return Tpm2TisTpmCommand (
+ (TIS_PC_REGISTERS_PTR) (UINTN) PcdGet64 (PcdTpmBaseAddress),
+ InputParameterBlock,
+ InputParameterBlockSize,
+ OutputParameterBlock,
+ OutputParameterBlockSize
+ );
+}
+
+/**
+ This service requests use TPM2.
+
+ @retval EFI_SUCCESS Get the control of TPM2 chip.
+ @retval EFI_NOT_FOUND TPM2 not found.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+DTpm2TisRequestUseTpm (
+ VOID
+ )
+{
+ return TisPcRequestUseTpm ((TIS_PC_REGISTERS_PTR) (UINTN) PcdGet64 (PcdTpmBaseAddress));
+}
diff --git a/Core/SecurityPkg/Library/Tpm2DeviceLibRouter/Tpm2DeviceLibRouterDxe.c b/Core/SecurityPkg/Library/Tpm2DeviceLibRouter/Tpm2DeviceLibRouterDxe.c
new file mode 100644
index 0000000000..eedc439228
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm2DeviceLibRouter/Tpm2DeviceLibRouterDxe.c
@@ -0,0 +1,98 @@
+/** @file
+ This library is TPM2 device router. Platform can register multi TPM2 instance to it
+ via PcdTpmInstanceGuid. Platform need make choice that which one will be final one.
+ At most one TPM2 instance can be finally registered, and other will return unsupported.
+
+Copyright (c) 2013 - 2017, Intel Corporation. All rights reserved. <BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PcdLib.h>
+#include <Library/Tpm2DeviceLib.h>
+
+TPM2_DEVICE_INTERFACE mInternalTpm2DeviceInterface;
+
+/**
+ This service enables the sending of commands to the TPM2.
+
+ @param[in] InputParameterBlockSize Size of the TPM2 input parameter block.
+ @param[in] InputParameterBlock Pointer to the TPM2 input parameter block.
+ @param[in,out] OutputParameterBlockSize Size of the TPM2 output parameter block.
+ @param[in] OutputParameterBlock Pointer to the TPM2 output parameter block.
+
+ @retval EFI_SUCCESS The command byte stream was successfully sent to the device and a response was successfully received.
+ @retval EFI_DEVICE_ERROR The command was not successfully sent to the device or a response was not successfully received from the device.
+ @retval EFI_BUFFER_TOO_SMALL The output parameter block is too small.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2SubmitCommand (
+ IN UINT32 InputParameterBlockSize,
+ IN UINT8 *InputParameterBlock,
+ IN OUT UINT32 *OutputParameterBlockSize,
+ IN UINT8 *OutputParameterBlock
+ )
+{
+ if (mInternalTpm2DeviceInterface.Tpm2SubmitCommand == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+ return mInternalTpm2DeviceInterface.Tpm2SubmitCommand (
+ InputParameterBlockSize,
+ InputParameterBlock,
+ OutputParameterBlockSize,
+ OutputParameterBlock
+ );
+}
+
+/**
+ This service requests use TPM2.
+
+ @retval EFI_SUCCESS Get the control of TPM2 chip.
+ @retval EFI_NOT_FOUND TPM2 not found.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2RequestUseTpm (
+ VOID
+ )
+{
+ if (mInternalTpm2DeviceInterface.Tpm2RequestUseTpm == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+ return mInternalTpm2DeviceInterface.Tpm2RequestUseTpm ();
+}
+
+/**
+ This service register TPM2 device.
+
+ @param Tpm2Device TPM2 device
+
+ @retval EFI_SUCCESS This TPM2 device is registered successfully.
+ @retval EFI_UNSUPPORTED System does not support register this TPM2 device.
+ @retval EFI_ALREADY_STARTED System already register this TPM2 device.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2RegisterTpm2DeviceLib (
+ IN TPM2_DEVICE_INTERFACE *Tpm2Device
+ )
+{
+ if (!CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &Tpm2Device->ProviderGuid)){
+ DEBUG ((DEBUG_WARN, "WARNING: Tpm2RegisterTpm2DeviceLib - does not support %g registration\n", &Tpm2Device->ProviderGuid));
+ return EFI_UNSUPPORTED;
+ }
+
+ CopyMem (&mInternalTpm2DeviceInterface, Tpm2Device, sizeof(mInternalTpm2DeviceInterface));
+ return EFI_SUCCESS;
+}
diff --git a/Core/SecurityPkg/Library/Tpm2DeviceLibRouter/Tpm2DeviceLibRouterDxe.inf b/Core/SecurityPkg/Library/Tpm2DeviceLibRouter/Tpm2DeviceLibRouterDxe.inf
new file mode 100644
index 0000000000..28f381c7be
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm2DeviceLibRouter/Tpm2DeviceLibRouterDxe.inf
@@ -0,0 +1,47 @@
+## @file
+# Provides TPM 2.0 TIS functions
+#
+# This library is TPM 2.0 device router. Platform can register multi TPM 2.0 instance to
+# it via PcdTpmInstanceGuid. Platform need make choice that which one will be final one.
+# At most one TPM 2.0 instance can be finally registered, and other will return unsupported.
+#
+# Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = Tpm2DeviceLibRouterDxe
+ MODULE_UNI_FILE = Tpm2DeviceLibRouterDxe.uni
+ FILE_GUID = C3D69D87-5200-4aab-A6DB-2569BA1A92FC
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = Tpm2DeviceLib|DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SAL_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF
+#
+
+[Sources]
+ Tpm2DeviceLibRouterDxe.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ PcdLib
+
+[Pcd]
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpmInstanceGuid ## CONSUMES
diff --git a/Core/SecurityPkg/Library/Tpm2DeviceLibRouter/Tpm2DeviceLibRouterDxe.uni b/Core/SecurityPkg/Library/Tpm2DeviceLibRouter/Tpm2DeviceLibRouterDxe.uni
new file mode 100644
index 0000000000..b6d59e4a27
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm2DeviceLibRouter/Tpm2DeviceLibRouterDxe.uni
@@ -0,0 +1,23 @@
+// /** @file
+// Provides TPM 2.0 TIS functions
+//
+// This library is TPM 2.0 device router. Platform can register multi TPM 2.0 instance to
+// it via PcdTpmInstanceGuid. Platform need make choice that which one will be final one.
+// At most one TPM 2.0 instance can be finally registered, and other will return unsupported.
+//
+// Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides TPM 2.0 TIS functions"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library is TPM 2.0 device router. Platform can register multi TPM 2.0 instance to it via PcdTpmInstanceGuid. Platform need make choice that which one will be final one. At most one TPM 2.0 instance can be finally registered, and other will return unsupported."
+
diff --git a/Core/SecurityPkg/Library/Tpm2DeviceLibRouter/Tpm2DeviceLibRouterPei.c b/Core/SecurityPkg/Library/Tpm2DeviceLibRouter/Tpm2DeviceLibRouterPei.c
new file mode 100644
index 0000000000..7470fe347d
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm2DeviceLibRouter/Tpm2DeviceLibRouterPei.c
@@ -0,0 +1,143 @@
+/** @file
+ This library is TPM2 device router. Platform can register multi TPM2 instance to it
+ via PcdTpmInstanceGuid. Platform need make choice that which one will be final one.
+ At most one TPM2 instance can be finally registered, and other will return unsupported.
+
+Copyright (c) 2013 - 2017, Intel Corporation. All rights reserved. <BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/HobLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PcdLib.h>
+#include <Library/Tpm2DeviceLib.h>
+
+EFI_GUID mInternalTpm2DeviceInterfaceGuid = {
+ 0x349cf818, 0xc0ba, 0x4c43, { 0x92, 0x9a, 0xc8, 0xa1, 0xb1, 0xb3, 0xd2, 0x55 }
+};
+
+/**
+ This function get TPM2.0 interface.
+
+ @retval TPM2.0 interface.
+**/
+TPM2_DEVICE_INTERFACE *
+InternalGetTpm2DeviceInterface (
+ VOID
+ )
+{
+ EFI_HOB_GUID_TYPE *Hob;
+
+ Hob = GetFirstGuidHob (&mInternalTpm2DeviceInterfaceGuid);
+ if (Hob == NULL) {
+ return NULL;
+ }
+ return (TPM2_DEVICE_INTERFACE *)(Hob + 1);
+}
+
+/**
+ This service enables the sending of commands to the TPM2.
+
+ @param[in] InputParameterBlockSize Size of the TPM2 input parameter block.
+ @param[in] InputParameterBlock Pointer to the TPM2 input parameter block.
+ @param[in,out] OutputParameterBlockSize Size of the TPM2 output parameter block.
+ @param[in] OutputParameterBlock Pointer to the TPM2 output parameter block.
+
+ @retval EFI_SUCCESS The command byte stream was successfully sent to the device and a response was successfully received.
+ @retval EFI_DEVICE_ERROR The command was not successfully sent to the device or a response was not successfully received from the device.
+ @retval EFI_BUFFER_TOO_SMALL The output parameter block is too small.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2SubmitCommand (
+ IN UINT32 InputParameterBlockSize,
+ IN UINT8 *InputParameterBlock,
+ IN OUT UINT32 *OutputParameterBlockSize,
+ IN UINT8 *OutputParameterBlock
+ )
+{
+ TPM2_DEVICE_INTERFACE *Tpm2DeviceInterface;
+
+ Tpm2DeviceInterface = InternalGetTpm2DeviceInterface ();
+ if (Tpm2DeviceInterface == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ return Tpm2DeviceInterface->Tpm2SubmitCommand (
+ InputParameterBlockSize,
+ InputParameterBlock,
+ OutputParameterBlockSize,
+ OutputParameterBlock
+ );
+}
+
+/**
+ This service requests use TPM2.
+
+ @retval EFI_SUCCESS Get the control of TPM2 chip.
+ @retval EFI_NOT_FOUND TPM2 not found.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2RequestUseTpm (
+ VOID
+ )
+{
+ TPM2_DEVICE_INTERFACE *Tpm2DeviceInterface;
+
+ Tpm2DeviceInterface = InternalGetTpm2DeviceInterface ();
+ if (Tpm2DeviceInterface == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+ return Tpm2DeviceInterface->Tpm2RequestUseTpm ();
+}
+
+/**
+ This service register TPM2 device.
+
+ @param Tpm2Device TPM2 device
+
+ @retval EFI_SUCCESS This TPM2 device is registered successfully.
+ @retval EFI_UNSUPPORTED System does not support register this TPM2 device.
+ @retval EFI_ALREADY_STARTED System already register this TPM2 device.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2RegisterTpm2DeviceLib (
+ IN TPM2_DEVICE_INTERFACE *Tpm2Device
+ )
+{
+ TPM2_DEVICE_INTERFACE *Tpm2DeviceInterface;
+
+ if (!CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &Tpm2Device->ProviderGuid)){
+ DEBUG ((DEBUG_WARN, "WARNING: Tpm2RegisterTpm2DeviceLib - does not support %g registration\n", &Tpm2Device->ProviderGuid));
+ return EFI_UNSUPPORTED;
+ }
+
+ Tpm2DeviceInterface = InternalGetTpm2DeviceInterface ();
+ if (Tpm2DeviceInterface != NULL) {
+ //
+ // In PEI phase, there will be shadow driver dispatched again.
+ //
+ DEBUG ((EFI_D_INFO, "Tpm2RegisterTpm2DeviceLib - Override\n"));
+ CopyMem (Tpm2DeviceInterface, Tpm2Device, sizeof(*Tpm2Device));
+ return EFI_SUCCESS;
+ } else {
+ Tpm2Device = BuildGuidDataHob (&mInternalTpm2DeviceInterfaceGuid, Tpm2Device, sizeof(*Tpm2Device));
+ if (Tpm2Device != NULL) {
+ return EFI_SUCCESS;
+ } else {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+}
diff --git a/Core/SecurityPkg/Library/Tpm2DeviceLibRouter/Tpm2DeviceLibRouterPei.inf b/Core/SecurityPkg/Library/Tpm2DeviceLibRouter/Tpm2DeviceLibRouterPei.inf
new file mode 100644
index 0000000000..2eca146dd2
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm2DeviceLibRouter/Tpm2DeviceLibRouterPei.inf
@@ -0,0 +1,49 @@
+## @file
+# Provides TPM 2.0 TIS functions
+#
+# This library is TPM 2.0 device router. Platform can register multi TPM 2.0 instance to
+# it via PcdTpmInstanceGuid. Platform need make choice that which one will be final one.
+# At most one TPM 2.0 instance can be finally registered, and other will return unsupported.
+#
+# Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = Tpm2DeviceLibRouterPei
+ MODULE_UNI_FILE = Tpm2DeviceLibRouterPei.uni
+ FILE_GUID = 97CDCF04-4C8E-42fe-8015-11CC8A6E9D81
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = Tpm2DeviceLib|PEIM
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF
+#
+
+[Sources]
+ Tpm2DeviceLibRouterPei.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ HobLib
+ PcdLib
+
+[Pcd]
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpmInstanceGuid ## CONSUMES
+ \ No newline at end of file
diff --git a/Core/SecurityPkg/Library/Tpm2DeviceLibRouter/Tpm2DeviceLibRouterPei.uni b/Core/SecurityPkg/Library/Tpm2DeviceLibRouter/Tpm2DeviceLibRouterPei.uni
new file mode 100644
index 0000000000..b6d59e4a27
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm2DeviceLibRouter/Tpm2DeviceLibRouterPei.uni
@@ -0,0 +1,23 @@
+// /** @file
+// Provides TPM 2.0 TIS functions
+//
+// This library is TPM 2.0 device router. Platform can register multi TPM 2.0 instance to
+// it via PcdTpmInstanceGuid. Platform need make choice that which one will be final one.
+// At most one TPM 2.0 instance can be finally registered, and other will return unsupported.
+//
+// Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides TPM 2.0 TIS functions"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library is TPM 2.0 device router. Platform can register multi TPM 2.0 instance to it via PcdTpmInstanceGuid. Platform need make choice that which one will be final one. At most one TPM 2.0 instance can be finally registered, and other will return unsupported."
+
diff --git a/Core/SecurityPkg/Library/Tpm2DeviceLibTcg2/Tpm2DeviceLibTcg2.c b/Core/SecurityPkg/Library/Tpm2DeviceLibTcg2/Tpm2DeviceLibTcg2.c
new file mode 100644
index 0000000000..1d59050a0b
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm2DeviceLibTcg2/Tpm2DeviceLibTcg2.c
@@ -0,0 +1,125 @@
+/** @file
+ This library is TPM2 TCG2 protocol lib.
+
+Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved. <BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/Tpm2DeviceLib.h>
+#include <Protocol/Tcg2Protocol.h>
+#include <IndustryStandard/Tpm20.h>
+
+EFI_TCG2_PROTOCOL *mTcg2Protocol = NULL;
+
+/**
+ This service enables the sending of commands to the TPM2.
+
+ @param[in] InputParameterBlockSize Size of the TPM2 input parameter block.
+ @param[in] InputParameterBlock Pointer to the TPM2 input parameter block.
+ @param[in,out] OutputParameterBlockSize Size of the TPM2 output parameter block.
+ @param[in] OutputParameterBlock Pointer to the TPM2 output parameter block.
+
+ @retval EFI_SUCCESS The command byte stream was successfully sent to the device and a response was successfully received.
+ @retval EFI_DEVICE_ERROR The command was not successfully sent to the device or a response was not successfully received from the device.
+ @retval EFI_BUFFER_TOO_SMALL The output parameter block is too small.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2SubmitCommand (
+ IN UINT32 InputParameterBlockSize,
+ IN UINT8 *InputParameterBlock,
+ IN OUT UINT32 *OutputParameterBlockSize,
+ IN UINT8 *OutputParameterBlock
+ )
+{
+ EFI_STATUS Status;
+ TPM2_RESPONSE_HEADER *Header;
+
+ if (mTcg2Protocol == NULL) {
+ Status = gBS->LocateProtocol (&gEfiTcg2ProtocolGuid, NULL, (VOID **) &mTcg2Protocol);
+ if (EFI_ERROR (Status)) {
+ //
+ // Tcg2 protocol is not installed. So, TPM2 is not present.
+ //
+ DEBUG ((EFI_D_ERROR, "Tpm2SubmitCommand - Tcg2 - %r\n", Status));
+ return EFI_NOT_FOUND;
+ }
+ }
+ //
+ // Assume when Tcg2 Protocol is ready, RequestUseTpm already done.
+ //
+ Status = mTcg2Protocol->SubmitCommand (
+ mTcg2Protocol,
+ InputParameterBlockSize,
+ InputParameterBlock,
+ *OutputParameterBlockSize,
+ OutputParameterBlock
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Header = (TPM2_RESPONSE_HEADER *)OutputParameterBlock;
+ *OutputParameterBlockSize = SwapBytes32 (Header->paramSize);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This service requests use TPM2.
+
+ @retval EFI_SUCCESS Get the control of TPM2 chip.
+ @retval EFI_NOT_FOUND TPM2 not found.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2RequestUseTpm (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+
+ if (mTcg2Protocol == NULL) {
+ Status = gBS->LocateProtocol (&gEfiTcg2ProtocolGuid, NULL, (VOID **) &mTcg2Protocol);
+ if (EFI_ERROR (Status)) {
+ //
+ // Tcg2 protocol is not installed. So, TPM2 is not present.
+ //
+ DEBUG ((EFI_D_ERROR, "Tpm2RequestUseTpm - Tcg2 - %r\n", Status));
+ return EFI_NOT_FOUND;
+ }
+ }
+ //
+ // Assume when Tcg2 Protocol is ready, RequestUseTpm already done.
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+ This service register TPM2 device.
+
+ @param Tpm2Device TPM2 device
+
+ @retval EFI_SUCCESS This TPM2 device is registered successfully.
+ @retval EFI_UNSUPPORTED System does not support register this TPM2 device.
+ @retval EFI_ALREADY_STARTED System already register this TPM2 device.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2RegisterTpm2DeviceLib (
+ IN TPM2_DEVICE_INTERFACE *Tpm2Device
+ )
+{
+ return EFI_UNSUPPORTED;
+}
diff --git a/Core/SecurityPkg/Library/Tpm2DeviceLibTcg2/Tpm2DeviceLibTcg2.inf b/Core/SecurityPkg/Library/Tpm2DeviceLibTcg2/Tpm2DeviceLibTcg2.inf
new file mode 100644
index 0000000000..6d95ebdd50
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm2DeviceLibTcg2/Tpm2DeviceLibTcg2.inf
@@ -0,0 +1,46 @@
+## @file
+# Provides function interfaces to communicate with TPM 2.0 device
+#
+# This library helps to use TPM 2.0 device in library function API
+# based on TPM2 protocol.
+#
+# Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = Tpm2DeviceLibTcg2
+ MODULE_UNI_FILE = Tpm2DeviceLibTcg2.uni
+ FILE_GUID = A1B0B230-67DC-431E-A94A-A96AF1EBE637
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = Tpm2DeviceLib|DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SAL_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF
+#
+
+[Sources]
+ Tpm2DeviceLibTcg2.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ UefiBootServicesTableLib
+
+[Protocols]
+ gEfiTcg2ProtocolGuid ## CONSUMES
diff --git a/Core/SecurityPkg/Library/Tpm2DeviceLibTcg2/Tpm2DeviceLibTcg2.uni b/Core/SecurityPkg/Library/Tpm2DeviceLibTcg2/Tpm2DeviceLibTcg2.uni
new file mode 100644
index 0000000000..83d4e04773
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm2DeviceLibTcg2/Tpm2DeviceLibTcg2.uni
@@ -0,0 +1,22 @@
+// /** @file
+// Provides function interfaces to communicate with TPM 2.0 device
+//
+// This library helps to use TPM 2.0 device in library function API
+// based on TCG2 protocol.
+//
+// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides function interfaces to communicate with TPM 2.0 device"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library helps to use TPM 2.0 device in library function API based on TCG2 protocol."
+
diff --git a/Core/SecurityPkg/Library/Tpm2DeviceLibTrEE/Tpm2DeviceLibTrEE.c b/Core/SecurityPkg/Library/Tpm2DeviceLibTrEE/Tpm2DeviceLibTrEE.c
new file mode 100644
index 0000000000..dc7b270705
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm2DeviceLibTrEE/Tpm2DeviceLibTrEE.c
@@ -0,0 +1,125 @@
+/** @file
+ This library is TPM2 TREE protocol lib.
+
+Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved. <BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/Tpm2DeviceLib.h>
+#include <Protocol/TrEEProtocol.h>
+#include <IndustryStandard/Tpm20.h>
+
+EFI_TREE_PROTOCOL *mTreeProtocol = NULL;
+
+/**
+ This service enables the sending of commands to the TPM2.
+
+ @param[in] InputParameterBlockSize Size of the TPM2 input parameter block.
+ @param[in] InputParameterBlock Pointer to the TPM2 input parameter block.
+ @param[in,out] OutputParameterBlockSize Size of the TPM2 output parameter block.
+ @param[in] OutputParameterBlock Pointer to the TPM2 output parameter block.
+
+ @retval EFI_SUCCESS The command byte stream was successfully sent to the device and a response was successfully received.
+ @retval EFI_DEVICE_ERROR The command was not successfully sent to the device or a response was not successfully received from the device.
+ @retval EFI_BUFFER_TOO_SMALL The output parameter block is too small.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2SubmitCommand (
+ IN UINT32 InputParameterBlockSize,
+ IN UINT8 *InputParameterBlock,
+ IN OUT UINT32 *OutputParameterBlockSize,
+ IN UINT8 *OutputParameterBlock
+ )
+{
+ EFI_STATUS Status;
+ TPM2_RESPONSE_HEADER *Header;
+
+ if (mTreeProtocol == NULL) {
+ Status = gBS->LocateProtocol (&gEfiTrEEProtocolGuid, NULL, (VOID **) &mTreeProtocol);
+ if (EFI_ERROR (Status)) {
+ //
+ // TrEE protocol is not installed. So, TPM2 is not present.
+ //
+ DEBUG ((EFI_D_ERROR, "Tpm2SubmitCommand - TrEE - %r\n", Status));
+ return EFI_NOT_FOUND;
+ }
+ }
+ //
+ // Assume when TrEE Protocol is ready, RequestUseTpm already done.
+ //
+ Status = mTreeProtocol->SubmitCommand (
+ mTreeProtocol,
+ InputParameterBlockSize,
+ InputParameterBlock,
+ *OutputParameterBlockSize,
+ OutputParameterBlock
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Header = (TPM2_RESPONSE_HEADER *)OutputParameterBlock;
+ *OutputParameterBlockSize = SwapBytes32 (Header->paramSize);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This service requests use TPM2.
+
+ @retval EFI_SUCCESS Get the control of TPM2 chip.
+ @retval EFI_NOT_FOUND TPM2 not found.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2RequestUseTpm (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+
+ if (mTreeProtocol == NULL) {
+ Status = gBS->LocateProtocol (&gEfiTrEEProtocolGuid, NULL, (VOID **) &mTreeProtocol);
+ if (EFI_ERROR (Status)) {
+ //
+ // TrEE protocol is not installed. So, TPM2 is not present.
+ //
+ DEBUG ((EFI_D_ERROR, "Tpm2RequestUseTpm - TrEE - %r\n", Status));
+ return EFI_NOT_FOUND;
+ }
+ }
+ //
+ // Assume when TrEE Protocol is ready, RequestUseTpm already done.
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+ This service register TPM2 device.
+
+ @param Tpm2Device TPM2 device
+
+ @retval EFI_SUCCESS This TPM2 device is registered successfully.
+ @retval EFI_UNSUPPORTED System does not support register this TPM2 device.
+ @retval EFI_ALREADY_STARTED System already register this TPM2 device.
+**/
+EFI_STATUS
+EFIAPI
+Tpm2RegisterTpm2DeviceLib (
+ IN TPM2_DEVICE_INTERFACE *Tpm2Device
+ )
+{
+ return EFI_UNSUPPORTED;
+}
diff --git a/Core/SecurityPkg/Library/Tpm2DeviceLibTrEE/Tpm2DeviceLibTrEE.inf b/Core/SecurityPkg/Library/Tpm2DeviceLibTrEE/Tpm2DeviceLibTrEE.inf
new file mode 100644
index 0000000000..81195e6704
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm2DeviceLibTrEE/Tpm2DeviceLibTrEE.inf
@@ -0,0 +1,46 @@
+## @file
+# Provides function interfaces to communicate with TPM 2.0 device
+#
+# This library helps to use TPM 2.0 device in library function API
+# based on TrEE protocol.
+#
+# Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = Tpm2DeviceLibTrEE
+ MODULE_UNI_FILE = Tpm2DeviceLibTrEE.uni
+ FILE_GUID = BBCB6F85-303C-4eb9-8182-AF98D4B3020C
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = Tpm2DeviceLib|DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SAL_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF
+#
+
+[Sources]
+ Tpm2DeviceLibTrEE.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ UefiBootServicesTableLib
+
+[Protocols]
+ gEfiTrEEProtocolGuid ## CONSUMES
diff --git a/Core/SecurityPkg/Library/Tpm2DeviceLibTrEE/Tpm2DeviceLibTrEE.uni b/Core/SecurityPkg/Library/Tpm2DeviceLibTrEE/Tpm2DeviceLibTrEE.uni
new file mode 100644
index 0000000000..d6defd04c8
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm2DeviceLibTrEE/Tpm2DeviceLibTrEE.uni
@@ -0,0 +1,22 @@
+// /** @file
+// Provides function interfaces to communicate with TPM 2.0 device
+//
+// This library helps to use TPM 2.0 device in library function API
+// based on TrEE protocol.
+//
+// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides function interfaces to communicate with TPM 2.0 device"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library helps to use TPM 2.0 device in library function API based on TrEE protocol."
+
diff --git a/Core/SecurityPkg/Library/TpmCommLib/CommonHeader.h b/Core/SecurityPkg/Library/TpmCommLib/CommonHeader.h
new file mode 100644
index 0000000000..b8496c7276
--- /dev/null
+++ b/Core/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.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _TPMCOMMLIB_COMMON_HEADER_H_
+#define _TPMCOMMLIB_COMMON_HEADER_H_
+
+#include <PiPei.h>
+#include <IndustryStandard/Tpm12.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/IoLib.h>
+#include <Library/TimerLib.h>
+#include <Library/TpmCommLib.h>
+#include <Library/BaseCryptLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DebugLib.h>
+
+#endif
diff --git a/Core/SecurityPkg/Library/TpmCommLib/TisPc.c b/Core/SecurityPkg/Library/TpmCommLib/TisPc.c
new file mode 100644
index 0000000000..c157d41b72
--- /dev/null
+++ b/Core/SecurityPkg/Library/TpmCommLib/TisPc.c
@@ -0,0 +1,183 @@
+/** @file
+ Basic TIS (TPM Interface Specification) functions.
+
+Copyright (c) 2005 - 2012, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "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_A.
+
+ @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);
+ //
+ // No locality set before, ACCESS_X.activeLocality MUST be valid within TIMEOUT_A
+ //
+ Status = TisPcWaitRegisterBits (
+ &TisReg->Access,
+ (UINT8)(TIS_PC_ACC_ACTIVE |TIS_PC_VALID),
+ 0,
+ TIS_TIMEOUT_A
+ );
+ return Status;
+}
diff --git a/Core/SecurityPkg/Library/TpmCommLib/TpmComm.c b/Core/SecurityPkg/Library/TpmCommLib/TpmComm.c
new file mode 100644
index 0000000000..3197f96a99
--- /dev/null
+++ b/Core/SecurityPkg/Library/TpmCommLib/TpmComm.c
@@ -0,0 +1,50 @@
+/** @file
+ Basic TPM command functions.
+
+Copyright (c) 2005 - 2010, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "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/Core/SecurityPkg/Library/TpmCommLib/TpmCommLib.inf b/Core/SecurityPkg/Library/TpmCommLib/TpmCommLib.inf
new file mode 100644
index 0000000000..7f05f59711
--- /dev/null
+++ b/Core/SecurityPkg/Library/TpmCommLib/TpmCommLib.inf
@@ -0,0 +1,50 @@
+## @file
+# Provides some common functions for the TCG feature
+#
+# This instance provides basic TPM Interface Specification (TIS) functions
+# and TPM hashall function.
+#
+# Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = TpmCommLib
+ MODULE_UNI_FILE = TpmCommLib.uni
+ 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/Core/SecurityPkg/Library/TpmCommLib/TpmCommLib.uni b/Core/SecurityPkg/Library/TpmCommLib/TpmCommLib.uni
new file mode 100644
index 0000000000..eb111cb4b7
--- /dev/null
+++ b/Core/SecurityPkg/Library/TpmCommLib/TpmCommLib.uni
@@ -0,0 +1,22 @@
+// /** @file
+// Provides some common functions for the TCG feature
+//
+// This instance provides basic TPM Interface Specification (TIS) functions
+// and TPM hashall function.
+//
+// Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides some common functions for the TCG feature"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This instance provides basic TPM Interface Specification (TIS) functions and TPM hashall function."
+
diff --git a/Core/SecurityPkg/Library/TrEEPpVendorLibNull/TrEEPpVendorLibNull.c b/Core/SecurityPkg/Library/TrEEPpVendorLibNull/TrEEPpVendorLibNull.c
new file mode 100644
index 0000000000..efd477ad19
--- /dev/null
+++ b/Core/SecurityPkg/Library/TrEEPpVendorLibNull/TrEEPpVendorLibNull.c
@@ -0,0 +1,131 @@
+/** @file
+ NULL TrEE PP Vendor library instance that does not support any vendor specific PPI.
+
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Library/DebugLib.h>
+#include <Library/TrEEPpVendorLib.h>
+
+/**
+ Check and execute the requested physical presence command.
+
+ This API should be invoked in BIOS boot phase to process pending request.
+
+ Caution: This function may receive untrusted input.
+
+ If OperationRequest < 128, then ASSERT().
+
+ @param[in] PlatformAuth platform auth value. NULL means no platform auth change.
+ @param[in] OperationRequest TPM physical presence operation request.
+ @param[in, out] ManagementFlags BIOS TPM Management Flags.
+ @param[out] ResetRequired If reset is required to vendor settings in effect.
+ True, it indicates the reset is required.
+ False, it indicates the reset is not required.
+
+ @return TPM Operation Response to OS Environment.
+**/
+UINT32
+EFIAPI
+TrEEPpVendorLibExecutePendingRequest (
+ IN TPM2B_AUTH *PlatformAuth, OPTIONAL
+ IN UINT32 OperationRequest,
+ IN OUT UINT32 *ManagementFlags,
+ OUT BOOLEAN *ResetRequired
+ )
+{
+ ASSERT (OperationRequest >= TREE_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION);
+ return TREE_PP_OPERATION_RESPONSE_BIOS_FAILURE;
+}
+
+/**
+ Check if there is a valid physical presence command request.
+
+ This API should be invoked in BIOS boot phase to process pending request.
+
+ Caution: This function may receive untrusted input.
+
+ If OperationRequest < 128, then ASSERT().
+
+ @param[in] OperationRequest TPM physical presence operation request.
+ @param[in] ManagementFlags BIOS TPM Management Flags.
+ @param[out] RequestConfirmed If the physical presence operation command required user confirm from UI.
+ True, it indicates the command doesn't require user confirm.
+ False, it indicates the command need user confirm from UI.
+
+ @retval TRUE Physical Presence operation command is valid.
+ @retval FALSE Physical Presence operation command is invalid.
+**/
+BOOLEAN
+EFIAPI
+TrEEPpVendorLibHasValidRequest (
+ IN UINT32 OperationRequest,
+ IN UINT32 ManagementFlags,
+ OUT BOOLEAN *RequestConfirmed
+ )
+{
+ ASSERT (OperationRequest >= TREE_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION);
+ return FALSE;
+}
+
+/**
+ The callback for TPM vendor specific physical presence which is called for
+ Submit TPM Operation Request to Pre-OS Environment and
+ Submit TPM Operation Request to Pre-OS Environment 2.
+
+ This API should be invoked in OS runtime phase to interface with ACPI method.
+
+ Caution: This function may receive untrusted input.
+
+ If OperationRequest < 128, then ASSERT().
+
+ @param[in] OperationRequest TPM physical presence operation request.
+ @param[in] ManagementFlags BIOS TPM Management Flags.
+
+ @return Return Code for Submit TPM Operation Request to Pre-OS Environment and
+ Submit TPM Operation Request to Pre-OS Environment 2.
+**/
+UINT32
+EFIAPI
+TrEEPpVendorLibSubmitRequestToPreOSFunction (
+ IN UINT32 OperationRequest,
+ IN UINT32 ManagementFlags
+ )
+{
+ ASSERT (OperationRequest >= TREE_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION);
+ return TREE_PP_SUBMIT_REQUEST_TO_PREOS_NOT_IMPLEMENTED;
+}
+
+/**
+ The callback for TPM vendor specific physical presence which is called for
+ Get User Confirmation Status for Operation.
+
+ This API should be invoked in OS runtime phase to interface with ACPI method.
+
+ Caution: This function may receive untrusted input.
+
+ If OperationRequest < 128, then ASSERT().
+
+ @param[in] OperationRequest TPM physical presence operation request.
+ @param[in] ManagementFlags BIOS TPM Management Flags.
+
+ @return Return Code for Get User Confirmation Status for Operation.
+**/
+UINT32
+EFIAPI
+TrEEPpVendorLibGetUserConfirmationStatusFunction (
+ IN UINT32 OperationRequest,
+ IN UINT32 ManagementFlags
+ )
+{
+ ASSERT (OperationRequest >= TREE_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION);
+ return TREE_PP_GET_USER_CONFIRMATION_NOT_IMPLEMENTED;
+}
diff --git a/Core/SecurityPkg/Library/TrEEPpVendorLibNull/TrEEPpVendorLibNull.inf b/Core/SecurityPkg/Library/TrEEPpVendorLibNull/TrEEPpVendorLibNull.inf
new file mode 100644
index 0000000000..81144e9b92
--- /dev/null
+++ b/Core/SecurityPkg/Library/TrEEPpVendorLibNull/TrEEPpVendorLibNull.inf
@@ -0,0 +1,37 @@
+## @file
+# NULL TrEE PP Vendor library instance that does not support any vendor specific PPI
+#
+# Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = TrEEPpVendorLibNull
+ MODULE_UNI_FILE = TrEEPpVendorLibNull.uni
+ FILE_GUID = FB76E42B-EA77-48F3-A61D-208FF0535F92
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = TrEEPpVendorLib|DXE_RUNTIME_DRIVER DXE_SMM_DRIVER DXE_DRIVER
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ TrEEPpVendorLibNull.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+ DebugLib \ No newline at end of file
diff --git a/Core/SecurityPkg/Library/TrEEPpVendorLibNull/TrEEPpVendorLibNull.uni b/Core/SecurityPkg/Library/TrEEPpVendorLibNull/TrEEPpVendorLibNull.uni
new file mode 100644
index 0000000000..7463e8f635
--- /dev/null
+++ b/Core/SecurityPkg/Library/TrEEPpVendorLibNull/TrEEPpVendorLibNull.uni
@@ -0,0 +1,18 @@
+// /** @file
+// NULL TrEE PP Vendor library instance that does not support any vendor specific PPI
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+#string STR_MODULE_ABSTRACT #language en-US "NULL TrEE PP Vendor library instance that does not support any vendor specific PPI"
+
+#string STR_MODULE_DESCRIPTION #language en-US "NULL TrEE PP Vendor library instance that does not support any vendor specific PPI."
+
diff --git a/Core/SecurityPkg/License.txt b/Core/SecurityPkg/License.txt
new file mode 100644
index 0000000000..be68999be6
--- /dev/null
+++ b/Core/SecurityPkg/License.txt
@@ -0,0 +1,25 @@
+Copyright (c) 2012, Intel Corporation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+* Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
diff --git a/Core/SecurityPkg/Pkcs7Verify/Pkcs7VerifyDxe/Pkcs7VerifyDxe.c b/Core/SecurityPkg/Pkcs7Verify/Pkcs7VerifyDxe/Pkcs7VerifyDxe.c
new file mode 100644
index 0000000000..07fdf552be
--- /dev/null
+++ b/Core/SecurityPkg/Pkcs7Verify/Pkcs7VerifyDxe/Pkcs7VerifyDxe.c
@@ -0,0 +1,1048 @@
+/** @file
+ Pkcs7Verify Driver to produce the UEFI PKCS7 Verification Protocol.
+
+ The driver will produce the UEFI PKCS7 Verification Protocol which is used to
+ verify data signed using PKCS7 structure. The PKCS7 data to be verified must
+ be ASN.1 (DER) encoded.
+
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/BaseCryptLib.h>
+#include <Protocol/Pkcs7Verify.h>
+
+#define MAX_DIGEST_SIZE SHA512_DIGEST_SIZE
+
+/**
+ Calculates the hash of the given data based on the specified hash GUID.
+
+ @param[in] Data Pointer to the data buffer to be hashed.
+ @param[in] DataSize The size of data buffer in bytes.
+ @param[in] CertGuid The GUID to identify the hash algorithm to be used.
+ @param[out] HashValue Pointer to a buffer that receives the hash result.
+
+ @retval TRUE Data hash calculation succeeded.
+ @retval FALSE Data hash calculation failed.
+
+**/
+BOOLEAN
+CalculateDataHash (
+ IN VOID *Data,
+ IN UINTN DataSize,
+ IN EFI_GUID *CertGuid,
+ OUT UINT8 *HashValue
+ )
+{
+ BOOLEAN Status;
+ VOID *HashCtx;
+ UINTN CtxSize;
+
+ Status = FALSE;
+ HashCtx = NULL;
+
+ if (CompareGuid (CertGuid, &gEfiCertSha1Guid)) {
+ //
+ // SHA-1 Hash
+ //
+ CtxSize = Sha1GetContextSize ();
+ HashCtx = AllocatePool (CtxSize);
+ if (HashCtx == NULL) {
+ goto _Exit;
+ }
+ Status = Sha1Init (HashCtx);
+ Status = Sha1Update (HashCtx, Data, DataSize);
+ Status = Sha1Final (HashCtx, HashValue);
+
+ } else if (CompareGuid (CertGuid, &gEfiCertSha256Guid)) {
+ //
+ // SHA256 Hash
+ //
+ CtxSize = Sha256GetContextSize ();
+ HashCtx = AllocatePool (CtxSize);
+ if (HashCtx == NULL) {
+ goto _Exit;
+ }
+ Status = Sha256Init (HashCtx);
+ Status = Sha256Update (HashCtx, Data, DataSize);
+ Status = Sha256Final (HashCtx, HashValue);
+
+ } else if (CompareGuid (CertGuid, &gEfiCertSha384Guid)) {
+ //
+ // SHA384 Hash
+ //
+ CtxSize = Sha384GetContextSize ();
+ HashCtx = AllocatePool (CtxSize);
+ if (HashCtx == NULL) {
+ goto _Exit;
+ }
+ Status = Sha384Init (HashCtx);
+ Status = Sha384Update (HashCtx, Data, DataSize);
+ Status = Sha384Final (HashCtx, HashValue);
+
+ } else if (CompareGuid (CertGuid, &gEfiCertSha512Guid)) {
+ //
+ // SHA512 Hash
+ //
+ CtxSize = Sha512GetContextSize ();
+ HashCtx = AllocatePool (CtxSize);
+ if (HashCtx == NULL) {
+ goto _Exit;
+ }
+ Status = Sha512Init (HashCtx);
+ Status = Sha512Update (HashCtx, Data, DataSize);
+ Status = Sha512Final (HashCtx, HashValue);
+ }
+
+_Exit:
+ if (HashCtx != NULL) {
+ FreePool (HashCtx);
+ }
+
+ return Status;
+}
+
+/**
+ Check whether the hash of data content is revoked by the revocation database.
+
+ @param[in] Content Pointer to the content buffer that is searched for.
+ @param[in] ContentSize The size of data content in bytes.
+ @param[in] RevokedDb Pointer to a list of pointers to EFI_SIGNATURE_LIST
+ structure which contains list of X.509 certificates
+ of revoked signers and revoked content hashes.
+
+ @return TRUE The matched content hash is found in the revocation database.
+ @return FALSE The matched content hash is not found in the revocation database.
+
+**/
+BOOLEAN
+IsContentHashRevoked (
+ IN UINT8 *Content,
+ IN UINTN ContentSize,
+ IN EFI_SIGNATURE_LIST **RevokedDb
+ )
+{
+ EFI_SIGNATURE_LIST *SigList;
+ EFI_SIGNATURE_DATA *SigData;
+ UINTN Index;
+ UINT8 HashVal[MAX_DIGEST_SIZE];
+ UINTN EntryIndex;
+ UINTN EntryCount;
+ BOOLEAN Status;
+
+ if (RevokedDb == NULL) {
+ return FALSE;
+ }
+
+ Status = FALSE;
+ //
+ // Check if any hash matching content hash can be found in RevokedDB
+ //
+ for (Index = 0; ; Index++) {
+ SigList = (EFI_SIGNATURE_LIST *)(RevokedDb[Index]);
+
+ //
+ // The list is terminated by a NULL pointer.
+ //
+ if (SigList == NULL) {
+ break;
+ }
+
+ //
+ // Calculate the digest of supplied data based on the signature hash type.
+ //
+ if (!CalculateDataHash (Content, ContentSize, &SigList->SignatureType, HashVal)) {
+ //
+ // Un-matched Hash GUID or other failure.
+ //
+ continue;
+ }
+
+ //
+ // Search the signature database to search the revoked content hash
+ //
+ SigData = (EFI_SIGNATURE_DATA *) ((UINT8 *) SigList + sizeof (EFI_SIGNATURE_LIST) +
+ SigList->SignatureHeaderSize);
+ EntryCount = (SigList->SignatureListSize - SigList->SignatureHeaderSize -
+ sizeof (EFI_SIGNATURE_LIST)) / SigList->SignatureSize;
+ for (EntryIndex = 0; EntryIndex < EntryCount; EntryIndex++) {
+ //
+ // Compare Data Hash with Signature Data
+ //
+ if (CompareMem (SigData->SignatureData, HashVal, (SigList->SignatureSize - sizeof (EFI_GUID))) == 0) {
+ Status = TRUE;
+ goto _Exit;
+ }
+
+ SigData = (EFI_SIGNATURE_DATA *) ((UINT8 *) SigData + SigList->SignatureSize);
+ }
+ }
+
+_Exit:
+ return Status;
+}
+
+/**
+ Check whether the hash of an given certificate is revoked by the revocation database.
+
+ @param[in] Certificate Pointer to the certificate that is searched for.
+ @param[in] CertSize Size of certificate in bytes.
+ @param[in] RevokedDb Pointer to a list of pointers to EFI_SIGNATURE_LIST
+ structures which contains list of X.509 certificate
+ of revoked signers and revoked content hashes.
+ @param[out] RevocationTime Return the time that the certificate was revoked.
+
+ @return TRUE The certificate hash is found in the revocation database.
+ @return FALSE The certificate hash is not found in the revocation database.
+
+**/
+BOOLEAN
+IsCertHashRevoked (
+ IN UINT8 *Certificate,
+ IN UINTN CertSize,
+ IN EFI_SIGNATURE_LIST **RevokedDb,
+ OUT EFI_TIME *RevocationTime
+ )
+{
+ BOOLEAN Status;
+ EFI_SIGNATURE_LIST *SigList;
+ EFI_SIGNATURE_DATA *SigData;
+ UINT8 *TBSCert;
+ UINTN TBSCertSize;
+ UINTN Index;
+ UINTN EntryIndex;
+ UINTN EntryCount;
+ UINT8 CertHashVal[MAX_DIGEST_SIZE];
+
+ if ((RevocationTime == NULL) || (RevokedDb == NULL)) {
+ return FALSE;
+ }
+
+ //
+ // Retrieve the TBSCertificate from the X.509 Certificate for hash calculation
+ //
+ if (!X509GetTBSCert (Certificate, CertSize, &TBSCert, &TBSCertSize)) {
+ return FALSE;
+ }
+
+ Status = FALSE;
+ for (Index = 0; ; Index++) {
+
+ SigList = (EFI_SIGNATURE_LIST *)(RevokedDb[Index]);
+ //
+ // The list is terminated by a NULL pointer.
+ //
+ if (SigList == NULL) {
+ break;
+ }
+
+ //
+ // Determine Hash Algorithm based on the entry type in revocation database, and
+ // calculate the certificate hash.
+ //
+ if (CompareGuid (&SigList->SignatureType, &gEfiCertX509Sha256Guid)) {
+ Status = CalculateDataHash (TBSCert, TBSCertSize, &gEfiCertSha256Guid, CertHashVal);
+
+ } else if (CompareGuid (&SigList->SignatureType, &gEfiCertX509Sha384Guid)) {
+ Status = CalculateDataHash (TBSCert, TBSCertSize, &gEfiCertSha384Guid, CertHashVal);
+
+ } else if (CompareGuid (&SigList->SignatureType, &gEfiCertX509Sha512Guid)) {
+ Status = CalculateDataHash (TBSCert, TBSCertSize, &gEfiCertSha512Guid, CertHashVal);
+
+ } else {
+ //
+ // Un-matched Cert Hash GUID
+ //
+ continue;
+ }
+
+ if (!Status) {
+ continue;
+ }
+
+ SigData = (EFI_SIGNATURE_DATA *) ((UINT8 *) SigList + sizeof (EFI_SIGNATURE_LIST) +
+ SigList->SignatureHeaderSize);
+ EntryCount = (SigList->SignatureListSize - SigList->SignatureHeaderSize -
+ sizeof (EFI_SIGNATURE_LIST)) / SigList->SignatureSize;
+ for (EntryIndex = 0; EntryIndex < EntryCount; Index++) {
+ //
+ // Check if the Certificate Hash is revoked.
+ //
+ if (CompareMem (SigData->SignatureData, CertHashVal,
+ SigList->SignatureSize - sizeof (EFI_GUID) - sizeof (EFI_TIME)) == 0) {
+ Status = TRUE;
+ //
+ // Return the revocation time of this revoked certificate.
+ //
+ CopyMem (
+ RevocationTime,
+ (EFI_TIME *)((UINT8 *)SigData + SigList->SignatureSize - sizeof (EFI_TIME)),
+ sizeof (EFI_TIME)
+ );
+ goto _Exit;
+ }
+
+ SigData = (EFI_SIGNATURE_DATA *) ((UINT8 *) SigData + SigList->SignatureSize);
+ }
+ }
+
+_Exit:
+ return Status;
+}
+
+/**
+ Check if the given time value is zero.
+
+ @param[in] Time Pointer of a time value.
+
+ @retval TRUE The Time is Zero.
+ @retval FALSE The Time is not Zero.
+
+**/
+BOOLEAN
+IsTimeZero (
+ IN EFI_TIME *Time
+ )
+{
+ if ((Time->Year == 0) && (Time->Month == 0) && (Time->Day == 0) &&
+ (Time->Hour == 0) && (Time->Minute == 0) && (Time->Second == 0)) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Check whether the timestamp is valid by comparing the signing time and the revocation time.
+
+ @param SigningTime Pointer to the signing time.
+ @param RevocationTime Pointer to the revocation time.
+
+ @retval TRUE The SigningTime is not later than the RevocationTime.
+ @retval FALSE The SigningTime is later than the RevocationTime.
+
+**/
+BOOLEAN
+CompareTimestamp (
+ IN EFI_TIME *SigningTime,
+ IN EFI_TIME *RevocationTime
+ )
+{
+ if (SigningTime->Year != RevocationTime->Year) {
+ return (BOOLEAN) (SigningTime->Year < RevocationTime->Year);
+ } else if (SigningTime->Month != RevocationTime->Month) {
+ return (BOOLEAN) (SigningTime->Month < RevocationTime->Month);
+ } else if (SigningTime->Day != RevocationTime->Day) {
+ return (BOOLEAN) (SigningTime->Day < RevocationTime->Day);
+ } else if (SigningTime->Hour != RevocationTime->Hour) {
+ return (BOOLEAN) (SigningTime->Hour < RevocationTime->Hour);
+ } else if (SigningTime->Minute != RevocationTime->Minute) {
+ return (BOOLEAN) (SigningTime->Minute < RevocationTime->Minute);
+ }
+
+ return (BOOLEAN) (SigningTime->Second <= RevocationTime->Second);
+}
+
+/**
+ Check whether the timestamp signature embedded in PKCS7 signedData is valid and
+ the signing time is also earlier than the revocation time.
+
+ @param[in] SignedData Pointer to the PKCS#7 signedData.
+ @param[in] SignedDataSize Size of SignedData in bytes.
+ @param[in] TimeStampDb Pointer to a list of pointers to EFI_SIGNATURE_LIST
+ structures which is used to pass a list of X.509
+ certificates of trusted timestamp signers.
+ @param[in] RevocationTime The time that the certificate was revoked.
+
+ @retval TRUE Timestamp signature is valid and the signing time is no later
+ than the revocation time.
+ @retval FALSE Timestamp signature is not valid or the signing time is later
+ than the revocation time.
+
+**/
+BOOLEAN
+IsValidTimestamp (
+ IN UINT8 *SignedData,
+ IN UINTN SignedDataSize,
+ IN EFI_SIGNATURE_LIST **TimeStampDb,
+ IN EFI_TIME *RevocationTime
+ )
+{
+ BOOLEAN Status;
+ EFI_SIGNATURE_LIST *SigList;
+ EFI_SIGNATURE_DATA *SigData;
+ UINT8 *TsaCert;
+ UINTN TsaCertSize;
+ UINTN Index;
+ EFI_TIME SigningTime;
+
+ //
+ // If no supplied database for verification or RevocationTime is zero,
+ // the certificate shall be considered to always be revoked.
+ //
+ if ((TimeStampDb == NULL) || (IsTimeZero (RevocationTime))) {
+ return FALSE;
+ }
+
+ Status = FALSE;
+ //
+ // RevocationTime is non-zero, the certificate should be considered to be revoked
+ // from that time and onwards.
+ //
+ for (Index = 0; ; Index++) {
+ SigList = (EFI_SIGNATURE_LIST *) (TimeStampDb[Index]);
+
+ //
+ // The list is terminated by a NULL pointer.
+ //
+ if (SigList == NULL) {
+ break;
+ }
+
+ //
+ // Ignore any non-X509-format entry in the list
+ //
+ if (!CompareGuid (&SigList->SignatureType, &gEfiCertX509Guid)) {
+ continue;
+ }
+
+
+ SigData = (EFI_SIGNATURE_DATA *) ((UINT8 *) SigList + sizeof (EFI_SIGNATURE_LIST) +
+ SigList->SignatureHeaderSize);
+ TsaCert = SigData->SignatureData;
+ TsaCertSize = SigList->SignatureSize - sizeof (EFI_GUID);
+
+ //
+ // Each TSA Certificate will normally be in a seperate EFI_SIGNATURE_LIST
+ // Leverage ImageTimestampVerify interface for Timestamp counterSignature Verification
+ //
+ if (ImageTimestampVerify (SignedData, SignedDataSize, TsaCert, TsaCertSize, &SigningTime)) {
+ //
+ // The signer signature is valid only when the signing time is earlier than revocation time.
+ //
+ if (CompareTimestamp (&SigningTime, RevocationTime)) {
+ Status = TRUE;
+ break;
+ }
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Check whether the PKCS7 signedData is revoked by verifying with the revoked
+ certificates database, and if the signedData is timestamped, the embedded timestamp
+ couterSignature will be checked with the supplied timestamp database.
+
+ @param[in] SignedData Pointer to buffer containing ASN.1 DER-encoded PKCS7
+ signature.
+ @param[in] SignedDataSize The size of SignedData buffer in bytes.
+ @param[in] InData Pointer to the buffer containing the raw message data
+ previously signed and to be verified.
+ @param[in] InDataSize The size of InData buffer in bytes.
+ @param[in] RevokedDb Pointer to a list of pointers to EFI_SIGNATURE_LIST
+ structure which contains list of X.509 certificates
+ of revoked signers and revoked content hashes.
+ @param[in] TimeStampDb Pointer to a list of pointers to EFI_SIGNATURE_LIST
+ structures which is used to pass a list of X.509
+ certificates of trusted timestamp signers.
+
+ @retval EFI_SUCCESS The PKCS7 signedData is revoked.
+ @retval EFI_SECURITY_VIOLATION Fail to verify the signature in PKCS7 signedData.
+ @retval EFI_INVALID_PARAMETER SignedData is NULL or SignedDataSize is zero.
+ AllowedDb is NULL.
+ Content is not NULL and ContentSize is NULL.
+ @retval EFI_NOT_FOUND Content not found because InData is NULL and no
+ content embedded in PKCS7 signedData.
+ @retval EFI_UNSUPPORTED The PKCS7 signedData was not correctly formatted.
+
+**/
+EFI_STATUS
+P7CheckRevocation (
+ IN UINT8 *SignedData,
+ IN UINTN SignedDataSize,
+ IN UINT8 *InData,
+ IN UINTN InDataSize,
+ IN EFI_SIGNATURE_LIST **RevokedDb,
+ IN EFI_SIGNATURE_LIST **TimeStampDb
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIGNATURE_LIST *SigList;
+ EFI_SIGNATURE_DATA *SigData;
+ UINT8 *RevokedCert;
+ UINTN RevokedCertSize;
+ UINTN Index;
+ UINT8 *CertBuffer;
+ UINTN BufferLength;
+ UINT8 *TrustedCert;
+ UINTN TrustedCertLength;
+ UINT8 CertNumber;
+ UINT8 *CertPtr;
+ UINT8 *Cert;
+ UINTN CertSize;
+ EFI_TIME RevocationTime;
+
+ Status = EFI_UNSUPPORTED;
+ SigData = NULL;
+ RevokedCert = NULL;
+ RevokedCertSize = 0;
+ CertBuffer = NULL;
+ TrustedCert = NULL;
+
+ //
+ // The signedData is revoked if the hash of content existed in RevokedDb
+ //
+ if (IsContentHashRevoked (InData, InDataSize, RevokedDb)) {
+ Status = EFI_SUCCESS;
+ goto _Exit;
+ }
+
+ //
+ // Check if the signer's certificate can be found in Revoked database
+ //
+ for (Index = 0; ; Index++) {
+ SigList = (EFI_SIGNATURE_LIST *)(RevokedDb[Index]);
+
+ //
+ // The list is terminated by a NULL pointer.
+ //
+ if (SigList == NULL) {
+ break;
+ }
+
+ //
+ // Ignore any non-X509-format entry in the list.
+ //
+ if (!CompareGuid (&SigList->SignatureType, &gEfiCertX509Guid)) {
+ continue;
+ }
+
+ SigData = (EFI_SIGNATURE_DATA *) ((UINT8 *) SigList + sizeof (EFI_SIGNATURE_LIST) +
+ SigList->SignatureHeaderSize);
+
+ RevokedCert = SigData->SignatureData;
+ RevokedCertSize = SigList->SignatureSize - sizeof (EFI_GUID);
+
+ //
+ // Verifying the PKCS#7 SignedData with the revoked certificate in RevokedDb
+ //
+ if (Pkcs7Verify (SignedData, SignedDataSize, RevokedCert, RevokedCertSize, InData, InDataSize)) {
+ //
+ // The signedData was verified by one entry in Revoked Database
+ //
+ Status = EFI_SUCCESS;
+ break;
+ }
+ }
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // The signedData was revoked, since it was hit by RevokedDb
+ //
+ goto _Exit;
+ }
+
+ //
+ // Now we will continue to check the X.509 Certificate Hash & Possible Timestamp
+ //
+ if ((TimeStampDb == NULL) || (*TimeStampDb == NULL)) {
+ goto _Exit;
+ }
+
+ Pkcs7GetSigners (SignedData, SignedDataSize, &CertBuffer, &BufferLength, &TrustedCert, &TrustedCertLength);
+ if ((BufferLength == 0) || (CertBuffer == NULL)) {
+ Status = EFI_SUCCESS;
+ goto _Exit;
+ }
+
+ //
+ // Check if any hash of certificates embedded in P7 data is in the revoked database.
+ //
+ CertNumber = (UINT8) (*CertBuffer);
+ CertPtr = CertBuffer + 1;
+ for (Index = 0; Index < CertNumber; Index++) {
+ //
+ // Retrieve the Certificate data
+ //
+ CertSize = (UINTN) ReadUnaligned32 ((UINT32 *) CertPtr);
+ Cert = (UINT8 *)CertPtr + sizeof (UINT32);
+
+ if (IsCertHashRevoked (Cert, CertSize, RevokedDb, &RevocationTime)) {
+ //
+ // Check the timestamp signature and signing time to determine if p7 data can be trusted.
+ //
+ Status = EFI_SUCCESS;
+ if (IsValidTimestamp (SignedData, SignedDataSize, TimeStampDb, &RevocationTime)) {
+ //
+ // Use EFI_NOT_READY to identify the P7Data is not reovked, because the timestamping
+ // occured prior to the time of certificate revocation.
+ //
+ Status = EFI_NOT_READY;
+ }
+
+ goto _Exit;
+ }
+
+ CertPtr = CertPtr + sizeof (UINT32) + CertSize;
+ }
+
+_Exit:
+ Pkcs7FreeSigners (CertBuffer);
+ Pkcs7FreeSigners (TrustedCert);
+
+ return Status;
+}
+
+/**
+ Check whether the PKCS7 signedData can be verified by the trusted certificates
+ database, and return the content of the signedData if requested.
+
+ @param[in] SignedData Pointer to buffer containing ASN.1 DER-encoded PKCS7
+ signature.
+ @param[in] SignedDataSize The size of SignedData buffer in bytes.
+ @param[in] InData Pointer to the buffer containing the raw message data
+ previously signed and to be verified.
+ @param[in] InDataSize The size of InData buffer in bytes.
+ @param[in] AllowedDb Pointer to a list of pointers to EFI_SIGNATURE_LIST
+ structures which contains lists of X.509 certificates
+ of approved signers.
+
+ @retval EFI_SUCCESS The PKCS7 signedData is trusted.
+ @retval EFI_SECURITY_VIOLATION Fail to verify the signature in PKCS7 signedData.
+ @retval EFI_INVALID_PARAMETER SignedData is NULL or SignedDataSize is zero.
+ AllowedDb is NULL.
+ Content is not NULL and ContentSize is NULL.
+ @retval EFI_NOT_FOUND Content not found because InData is NULL and no
+ content embedded in PKCS7 signedData.
+ @retval EFI_UNSUPPORTED The PKCS7 signedData was not correctly formatted.
+ @retval EFI_BUFFER_TOO_SMALL The size of buffer indicated by ContentSize is too
+ small to hold the content. ContentSize updated to
+ the required size.
+
+**/
+EFI_STATUS
+P7CheckTrust (
+ IN UINT8 *SignedData,
+ IN UINTN SignedDataSize,
+ IN UINT8 *InData,
+ IN UINTN InDataSize,
+ IN EFI_SIGNATURE_LIST **AllowedDb
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIGNATURE_LIST *SigList;
+ EFI_SIGNATURE_DATA *SigData;
+ UINT8 *TrustCert;
+ UINTN TrustCertSize;
+ UINTN Index;
+
+ Status = EFI_SECURITY_VIOLATION;
+ SigData = NULL;
+ TrustCert = NULL;
+ TrustCertSize = 0;
+
+ if (AllowedDb == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Build Certificate Stack with all valid X509 certificates in the supplied
+ // Signature List for PKCS7 Verification.
+ //
+ for (Index = 0; ; Index++) {
+ SigList = (EFI_SIGNATURE_LIST *)(AllowedDb[Index]);
+
+ //
+ // The list is terminated by a NULL pointer.
+ //
+ if (SigList == NULL) {
+ break;
+ }
+
+ //
+ // Ignore any non-X509-format entry in the list.
+ //
+ if (!CompareGuid (&SigList->SignatureType, &gEfiCertX509Guid)) {
+ continue;
+ }
+
+ SigData = (EFI_SIGNATURE_DATA *) ((UINT8 *) SigList + sizeof (EFI_SIGNATURE_LIST) +
+ SigList->SignatureHeaderSize);
+
+ TrustCert = SigData->SignatureData;
+ TrustCertSize = SigList->SignatureSize - sizeof (EFI_GUID);
+
+ //
+ // Verifying the PKCS#7 SignedData with the trusted certificate from AllowedDb
+ //
+ if (Pkcs7Verify (SignedData, SignedDataSize, TrustCert, TrustCertSize, InData, InDataSize)) {
+ //
+ // The SignedData was verified successfully by one entry in Trusted Database
+ //
+ Status = EFI_SUCCESS;
+ break;
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Processes a buffer containing binary DER-encoded PKCS7 signature.
+ The signed data content may be embedded within the buffer or separated. Function
+ verifies the signature of the content is valid and signing certificate was not
+ revoked and is contained within a list of trusted signers.
+
+ @param[in] This Pointer to EFI_PKCS7_VERIFY_PROTOCOL instance.
+ @param[in] SignedData Points to buffer containing ASN.1 DER-encoded PKCS7
+ signature.
+ @param[in] SignedDataSize The size of SignedData buffer in bytes.
+ @param[in] InData In case of detached signature, InData points to
+ buffer containing the raw message data previously
+ signed and to be verified by function. In case of
+ SignedData containing embedded data, InData must be
+ NULL.
+ @param[in] InDataSize When InData is used, the size of InData buffer in
+ bytes. When InData is NULL. This parameter must be
+ 0.
+ @param[in] AllowedDb Pointer to a list of pointers to EFI_SIGNATURE_LIST
+ structures. The list is terminated by a null
+ pointer. The EFI_SIGNATURE_LIST structures contain
+ lists of X.509 certificates of approved signers.
+ Function recognizes signer certificates of type
+ EFI_CERT_X509_GUID. Any hash certificate in AllowedDb
+ list is ignored by this function. Function returns
+ success if signer of the buffer is within this list
+ (and not within RevokedDb). This parameter is
+ required.
+ @param[in] RevokedDb Optional pointer to a list of pointers to
+ EFI_SIGNATURE_LIST structures. The list is terminated
+ by a null pointer. List of X.509 certificates of
+ revoked signers and revoked file hashes. Except as
+ noted in description of TimeStampDb signature
+ verification will always fail if the signer of the
+ file or the hash of the data component of the buffer
+ is in RevokedDb list. This list is optional and
+ caller may pass Null or pointer to NULL if not
+ required.
+ @param[in] TimeStampDb Optional pointer to a list of pointers to
+ EFI_SIGNATURE_LIST structures. The list is terminated
+ by a null pointer. This parameter can be used to pass
+ a list of X.509 certificates of trusted time stamp
+ signers. This list is optional and caller must pass
+ Null or pointer to NULL if not required.
+ @param[out] Content On input, points to an optional caller-allocated
+ buffer into which the function will copy the content
+ portion of the file after verification succeeds.
+ This parameter is optional and if NULL, no copy of
+ content from file is performed.
+ @param[in,out] ContentSize On input, points to the size in bytes of the optional
+ buffer Content previously allocated by caller. On
+ output, if the verification succeeds, the value
+ referenced by ContentSize will contain the actual
+ size of the content from signed file. If ContentSize
+ indicates the caller-allocated buffer is too small
+ to contain content, an error is returned, and
+ ContentSize will be updated with the required size.
+ This parameter must be 0 if Content is Null.
+
+ @retval EFI_SUCCESS Content signature was verified against hash of
+ content, the signer's certificate was not found in
+ RevokedDb, and was found in AllowedDb or if in signer
+ is found in both AllowedDb and RevokedDb, the
+ signing was allowed by reference to TimeStampDb as
+ described above, and no hash matching content hash
+ was found in RevokedDb.
+ @retval EFI_SECURITY_VIOLATION The SignedData buffer was correctly formatted but
+ signer was in RevokedDb or not in AllowedDb. Also
+ returned if matching content hash found in RevokedDb.
+ @retval EFI_COMPROMISED_DATA Calculated hash differs from signed hash.
+ @retval EFI_INVALID_PARAMETER SignedData is NULL or SignedDataSize is zero.
+ AllowedDb is NULL.
+ @retval EFI_INVALID_PARAMETER Content is not NULL and ContentSize is NULL.
+ @retval EFI_ABORTED Unsupported or invalid format in TimeStampDb,
+ RevokedDb or AllowedDb list contents was detected.
+ @retval EFI_NOT_FOUND Content not found because InData is NULL and no
+ content embedded in SignedData.
+ @retval EFI_UNSUPPORTED The SignedData buffer was not correctly formatted
+ for processing by the function.
+ @retval EFI_UNSUPPORTED Signed data embedded in SignedData but InData is not
+ NULL.
+ @retval EFI_BUFFER_TOO_SMALL The size of buffer indicated by ContentSize is too
+ small to hold the content. ContentSize updated to
+ required size.
+
+**/
+EFI_STATUS
+EFIAPI
+VerifyBuffer (
+ IN EFI_PKCS7_VERIFY_PROTOCOL *This,
+ IN VOID *SignedData,
+ IN UINTN SignedDataSize,
+ IN VOID *InData OPTIONAL,
+ IN UINTN InDataSize,
+ IN EFI_SIGNATURE_LIST **AllowedDb,
+ IN EFI_SIGNATURE_LIST **RevokedDb OPTIONAL,
+ IN EFI_SIGNATURE_LIST **TimeStampDb OPTIONAL,
+ OUT VOID *Content OPTIONAL,
+ IN OUT UINTN *ContentSize
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *AttachedData;
+ UINTN AttachedDataSize;
+ UINT8 *DataPtr;
+ UINTN DataSize;
+
+ //
+ // Parameters Checking
+ //
+ if ((SignedData == NULL) || (SignedDataSize == 0) || (AllowedDb == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if ((Content != NULL) && (ContentSize == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Try to retrieve the attached content from PKCS7 signedData
+ //
+ AttachedData = NULL;
+ AttachedDataSize = 0;
+ if (!Pkcs7GetAttachedContent (
+ SignedData,
+ SignedDataSize,
+ (VOID **)&AttachedData,
+ &AttachedDataSize)) {
+ //
+ // The SignedData buffer was not correctly formatted for processing
+ //
+ return EFI_UNSUPPORTED;
+ }
+ if (AttachedData != NULL) {
+ if (InData != NULL) {
+ //
+ // The embedded content is found in SignedData but InData is not NULL
+ //
+ Status = EFI_UNSUPPORTED;
+ goto _Exit;
+ }
+ //
+ // PKCS7-formatted signedData with attached content; Use the embedded
+ // content for verification
+ //
+ DataPtr = AttachedData;
+ DataSize = AttachedDataSize;
+
+ } else if (InData != NULL) {
+ //
+ // PKCS7-formatted signedData with detached content; Use the user-supplied
+ // input data for verification
+ //
+ DataPtr = (UINT8 *)InData;
+ DataSize = InDataSize;
+ } else {
+ //
+ // Content not found because InData is NULL and no content attached in SignedData
+ //
+ Status = EFI_NOT_FOUND;
+ goto _Exit;
+ }
+
+ Status = EFI_UNSUPPORTED;
+
+ //
+ // Verify PKCS7 SignedData with Revoked database
+ //
+ if (RevokedDb != NULL) {
+ Status = P7CheckRevocation (
+ SignedData,
+ SignedDataSize,
+ DataPtr,
+ DataSize,
+ RevokedDb,
+ TimeStampDb
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // The PKCS7 SignedData is reovked
+ //
+ Status = EFI_SECURITY_VIOLATION;
+ goto _Exit;
+ }
+ }
+
+ //
+ // Verify PKCS7 SignedData with AllowedDB
+ //
+ Status = P7CheckTrust (
+ SignedData,
+ SignedDataSize,
+ DataPtr,
+ DataSize,
+ AllowedDb
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Verification failed with AllowedDb
+ //
+ goto _Exit;
+ }
+
+ //
+ // Copy the content portion after verification succeeds
+ //
+ if (Content != NULL) {
+ if (*ContentSize < DataSize) {
+ //
+ // Caller-allocated buffer is too small to contain content
+ //
+ *ContentSize = DataSize;
+ Status = EFI_BUFFER_TOO_SMALL;
+ } else {
+ *ContentSize = DataSize;
+ CopyMem (Content, DataPtr, DataSize);
+ }
+ }
+
+_Exit:
+ if (AttachedData != NULL) {
+ FreePool (AttachedData);
+ }
+
+ return Status;
+}
+
+/**
+ Processes a buffer containing binary DER-encoded detached PKCS7 signature.
+ The hash of the signed data content is calculated and passed by the caller. Function
+ verifies the signature of the content is valid and signing certificate was not revoked
+ and is contained within a list of trusted signers.
+
+ @param[in] This Pointer to EFI_PKCS7_VERIFY_PROTOCOL instance.
+ @param[in] Signature Points to buffer containing ASN.1 DER-encoded PKCS
+ detached signature.
+ @param[in] SignatureSize The size of Signature buffer in bytes.
+ @param[in] InHash InHash points to buffer containing the caller
+ calculated hash of the data. The parameter may not
+ be NULL.
+ @param[in] InHashSize The size in bytes of InHash buffer.
+ @param[in] AllowedDb Pointer to a list of pointers to EFI_SIGNATURE_LIST
+ structures. The list is terminated by a null
+ pointer. The EFI_SIGNATURE_LIST structures contain
+ lists of X.509 certificates of approved signers.
+ Function recognizes signer certificates of type
+ EFI_CERT_X509_GUID. Any hash certificate in AllowedDb
+ list is ignored by this function. Function returns
+ success if signer of the buffer is within this list
+ (and not within RevokedDb). This parameter is
+ required.
+ @param[in] RevokedDb Optional pointer to a list of pointers to
+ EFI_SIGNATURE_LIST structures. The list is terminated
+ by a null pointer. List of X.509 certificates of
+ revoked signers and revoked file hashes. Signature
+ verification will always fail if the signer of the
+ file or the hash of the data component of the buffer
+ is in RevokedDb list. This parameter is optional
+ and caller may pass Null if not required.
+ @param[in] TimeStampDb Optional pointer to a list of pointers to
+ EFI_SIGNATURE_LIST structures. The list is terminated
+ by a null pointer. This parameter can be used to pass
+ a list of X.509 certificates of trusted time stamp
+ counter-signers.
+
+ @retval EFI_SUCCESS Signed hash was verified against caller-provided
+ hash of content, the signer's certificate was not
+ found in RevokedDb, and was found in AllowedDb or
+ if in signer is found in both AllowedDb and
+ RevokedDb, the signing was allowed by reference to
+ TimeStampDb as described above, and no hash matching
+ content hash was found in RevokedDb.
+ @retval EFI_SECURITY_VIOLATION The SignedData buffer was correctly formatted but
+ signer was in RevokedDb or not in AllowedDb. Also
+ returned if matching content hash found in RevokedDb.
+ @retval EFI_COMPROMISED_DATA Caller provided hash differs from signed hash. Or,
+ caller and encrypted hash are different sizes.
+ @retval EFI_INVALID_PARAMETER Signature is NULL or SignatureSize is zero. InHash
+ is NULL or InHashSize is zero. AllowedDb is NULL.
+ @retval EFI_ABORTED Unsupported or invalid format in TimeStampDb,
+ RevokedDb or AllowedDb list contents was detected.
+ @retval EFI_UNSUPPORTED The Signature buffer was not correctly formatted
+ for processing by the function.
+
+**/
+EFI_STATUS
+EFIAPI
+VerifySignature (
+ IN EFI_PKCS7_VERIFY_PROTOCOL *This,
+ IN VOID *Signature,
+ IN UINTN SignatureSize,
+ IN VOID *InHash,
+ IN UINTN InHashSize,
+ IN EFI_SIGNATURE_LIST **AllowedDb,
+ IN EFI_SIGNATURE_LIST **RevokedDb OPTIONAL,
+ IN EFI_SIGNATURE_LIST **TimeStampDb OPTIONAL
+ )
+{
+ //
+ // NOTE: Current EDKII-OpenSSL interface cannot support VerifySignature
+ // directly. EFI_UNSUPPORTED is returned in this version.
+ //
+ return EFI_UNSUPPORTED;
+}
+
+//
+// The PKCS7 Verification Protocol
+//
+EFI_PKCS7_VERIFY_PROTOCOL mPkcs7Verify = {
+ VerifyBuffer,
+ VerifySignature
+};
+
+/**
+ The user Entry Point for the PKCS7 Verification driver.
+
+ @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 EFI_NOT_SUPPORTED Platform does not support PKCS7 Verification.
+ @retval Other Some error occurs when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+Pkcs7VerifyDriverEntry (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE Handle;
+
+ //
+ // Install UEFI Pkcs7 Verification Protocol
+ //
+ Handle = NULL;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Handle,
+ &gEfiPkcs7VerifyProtocolGuid,
+ &mPkcs7Verify,
+ NULL
+ );
+
+ return Status;
+}
diff --git a/Core/SecurityPkg/Pkcs7Verify/Pkcs7VerifyDxe/Pkcs7VerifyDxe.inf b/Core/SecurityPkg/Pkcs7Verify/Pkcs7VerifyDxe/Pkcs7VerifyDxe.inf
new file mode 100644
index 0000000000..db4de92a31
--- /dev/null
+++ b/Core/SecurityPkg/Pkcs7Verify/Pkcs7VerifyDxe/Pkcs7VerifyDxe.inf
@@ -0,0 +1,70 @@
+## @file
+# Produces the UEFI PKCS7 Verification protocol.
+#
+# PKCS7 is a general-purpose Cryptographic Message Syntax Standard (defined by
+# RFC2315, http://tools.ietf.org/html/rfc2315). This module will produce the
+# UEFI PKCS7 Verification Protocol which is used to verify data signed using PKCS7
+# structure.
+#
+# Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = Pkcs7VerifyDxe
+ FILE_GUID = DC952D08-C62B-41c6-BAC7-70ED054F91E5
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = Pkcs7VerifyDriverEntry
+ MODULE_UNI_FILE = Pkcs7VerifyDxe.uni
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources.common]
+ Pkcs7VerifyDxe.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ CryptoPkg/CryptoPkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+ UefiLib
+ UefiBootServicesTableLib
+ BaseLib
+ BaseMemoryLib
+ MemoryAllocationLib
+ DebugLib
+ UefiDriverEntryPoint
+ BaseCryptLib
+
+[Protocols]
+ gEfiPkcs7VerifyProtocolGuid ## PRODUCES
+
+[Guids]
+ gEfiCertX509Guid ## SOMETIMES_CONSUMES ## GUID # Unique ID for the type of the signature.
+ gEfiCertSha1Guid ## SOMETIMES_CONSUMES ## GUID # Unique ID for the type of the signature.
+ gEfiCertSha256Guid ## SOMETIMES_CONSUMES ## GUID # Unique ID for the type of the signature.
+ gEfiCertSha384Guid ## SOMETIMES_CONSUMES ## GUID # Unique ID for the type of the signature.
+ gEfiCertSha512Guid ## SOMETIMES_CONSUMES ## GUID # Unique ID for the type of the signature.
+ gEfiCertX509Sha256Guid ## SOMETIMES_CONSUMES ## GUID # Unique ID for the type of the signature.
+ gEfiCertX509Sha384Guid ## SOMETIMES_CONSUMES ## GUID # Unique ID for the type of the signature.
+ gEfiCertX509Sha512Guid ## SOMETIMES_CONSUMES ## GUID # Unique ID for the type of the signature.
+
+[Depex]
+ TRUE
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ Pkcs7VerifyDxeExtra.uni
diff --git a/Core/SecurityPkg/Pkcs7Verify/Pkcs7VerifyDxe/Pkcs7VerifyDxe.uni b/Core/SecurityPkg/Pkcs7Verify/Pkcs7VerifyDxe/Pkcs7VerifyDxe.uni
new file mode 100644
index 0000000000..ba18ed7ec6
--- /dev/null
+++ b/Core/SecurityPkg/Pkcs7Verify/Pkcs7VerifyDxe/Pkcs7VerifyDxe.uni
@@ -0,0 +1,25 @@
+// /** @file
+// Produces the UEFI PKCS7 Verification Protocol.
+//
+// PKCS7 is a general-purpose Cryptographic Message Syntax Standard (RFC2315,
+// http://tools.ietf.org/html/rfc2315). This module will produce the UEFI PKCS7
+// Verification Protocol which is used to verify data signed using PKCS#7
+// structure. The PKCS#7 data to be verified must be ASN.1 (DER) encoded.
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+//
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Produces UEFI PKCS7 Verification Protocol"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This module will produce UEFI PKCS7 Verification Protocol."
+
diff --git a/Core/SecurityPkg/Pkcs7Verify/Pkcs7VerifyDxe/Pkcs7VerifyDxeExtra.uni b/Core/SecurityPkg/Pkcs7Verify/Pkcs7VerifyDxe/Pkcs7VerifyDxeExtra.uni
new file mode 100644
index 0000000000..55ae8d066a
--- /dev/null
+++ b/Core/SecurityPkg/Pkcs7Verify/Pkcs7VerifyDxe/Pkcs7VerifyDxeExtra.uni
@@ -0,0 +1,19 @@
+// /** @file
+// Pkcs7VerifyDxe Localized Strings and Content
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"UEFI PKCS7 Verification DXE"
+
+
diff --git a/Core/SecurityPkg/RandomNumberGenerator/RngDxe/AesCore.c b/Core/SecurityPkg/RandomNumberGenerator/RngDxe/AesCore.c
new file mode 100644
index 0000000000..13b424dc2e
--- /dev/null
+++ b/Core/SecurityPkg/RandomNumberGenerator/RngDxe/AesCore.c
@@ -0,0 +1,304 @@
+/** @file
+ Core Primitive Implementation of the Advanced Encryption Standard (AES) algorithm.
+ Refer to FIPS PUB 197 ("Advanced Encryption Standard (AES)") for detailed algorithm
+ description of AES.
+
+Copyright (c) 2013, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "AesCore.h"
+
+//
+// Number of columns (32-bit words) comprising the State.
+// AES_NB is a constant (value = 4) for NIST FIPS-197.
+//
+#define AES_NB 4
+
+//
+// Pre-computed AES Forward Table: AesForwardTable[t] = AES_SBOX[t].[02, 01, 01, 03]
+// AES_SBOX (AES S-box) is defined in sec 5.1.1 of FIPS PUB 197.
+// This is to speed up execution of the cipher by combining SubBytes and
+// ShiftRows with MixColumns steps and transforming them into table lookups.
+//
+GLOBAL_REMOVE_IF_UNREFERENCED CONST UINT32 AesForwardTable[] = {
+ 0xc66363a5, 0xf87c7c84, 0xee777799, 0xf67b7b8d, 0xfff2f20d, 0xd66b6bbd,
+ 0xde6f6fb1, 0x91c5c554, 0x60303050, 0x02010103, 0xce6767a9, 0x562b2b7d,
+ 0xe7fefe19, 0xb5d7d762, 0x4dababe6, 0xec76769a, 0x8fcaca45, 0x1f82829d,
+ 0x89c9c940, 0xfa7d7d87, 0xeffafa15, 0xb25959eb, 0x8e4747c9, 0xfbf0f00b,
+ 0x41adadec, 0xb3d4d467, 0x5fa2a2fd, 0x45afafea, 0x239c9cbf, 0x53a4a4f7,
+ 0xe4727296, 0x9bc0c05b, 0x75b7b7c2, 0xe1fdfd1c, 0x3d9393ae, 0x4c26266a,
+ 0x6c36365a, 0x7e3f3f41, 0xf5f7f702, 0x83cccc4f, 0x6834345c, 0x51a5a5f4,
+ 0xd1e5e534, 0xf9f1f108, 0xe2717193, 0xabd8d873, 0x62313153, 0x2a15153f,
+ 0x0804040c, 0x95c7c752, 0x46232365, 0x9dc3c35e, 0x30181828, 0x379696a1,
+ 0x0a05050f, 0x2f9a9ab5, 0x0e070709, 0x24121236, 0x1b80809b, 0xdfe2e23d,
+ 0xcdebeb26, 0x4e272769, 0x7fb2b2cd, 0xea75759f, 0x1209091b, 0x1d83839e,
+ 0x582c2c74, 0x341a1a2e, 0x361b1b2d, 0xdc6e6eb2, 0xb45a5aee, 0x5ba0a0fb,
+ 0xa45252f6, 0x763b3b4d, 0xb7d6d661, 0x7db3b3ce, 0x5229297b, 0xdde3e33e,
+ 0x5e2f2f71, 0x13848497, 0xa65353f5, 0xb9d1d168, 0x00000000, 0xc1eded2c,
+ 0x40202060, 0xe3fcfc1f, 0x79b1b1c8, 0xb65b5bed, 0xd46a6abe, 0x8dcbcb46,
+ 0x67bebed9, 0x7239394b, 0x944a4ade, 0x984c4cd4, 0xb05858e8, 0x85cfcf4a,
+ 0xbbd0d06b, 0xc5efef2a, 0x4faaaae5, 0xedfbfb16, 0x864343c5, 0x9a4d4dd7,
+ 0x66333355, 0x11858594, 0x8a4545cf, 0xe9f9f910, 0x04020206, 0xfe7f7f81,
+ 0xa05050f0, 0x783c3c44, 0x259f9fba, 0x4ba8a8e3, 0xa25151f3, 0x5da3a3fe,
+ 0x804040c0, 0x058f8f8a, 0x3f9292ad, 0x219d9dbc, 0x70383848, 0xf1f5f504,
+ 0x63bcbcdf, 0x77b6b6c1, 0xafdada75, 0x42212163, 0x20101030, 0xe5ffff1a,
+ 0xfdf3f30e, 0xbfd2d26d, 0x81cdcd4c, 0x180c0c14, 0x26131335, 0xc3ecec2f,
+ 0xbe5f5fe1, 0x359797a2, 0x884444cc, 0x2e171739, 0x93c4c457, 0x55a7a7f2,
+ 0xfc7e7e82, 0x7a3d3d47, 0xc86464ac, 0xba5d5de7, 0x3219192b, 0xe6737395,
+ 0xc06060a0, 0x19818198, 0x9e4f4fd1, 0xa3dcdc7f, 0x44222266, 0x542a2a7e,
+ 0x3b9090ab, 0x0b888883, 0x8c4646ca, 0xc7eeee29, 0x6bb8b8d3, 0x2814143c,
+ 0xa7dede79, 0xbc5e5ee2, 0x160b0b1d, 0xaddbdb76, 0xdbe0e03b, 0x64323256,
+ 0x743a3a4e, 0x140a0a1e, 0x924949db, 0x0c06060a, 0x4824246c, 0xb85c5ce4,
+ 0x9fc2c25d, 0xbdd3d36e, 0x43acacef, 0xc46262a6, 0x399191a8, 0x319595a4,
+ 0xd3e4e437, 0xf279798b, 0xd5e7e732, 0x8bc8c843, 0x6e373759, 0xda6d6db7,
+ 0x018d8d8c, 0xb1d5d564, 0x9c4e4ed2, 0x49a9a9e0, 0xd86c6cb4, 0xac5656fa,
+ 0xf3f4f407, 0xcfeaea25, 0xca6565af, 0xf47a7a8e, 0x47aeaee9, 0x10080818,
+ 0x6fbabad5, 0xf0787888, 0x4a25256f, 0x5c2e2e72, 0x381c1c24, 0x57a6a6f1,
+ 0x73b4b4c7, 0x97c6c651, 0xcbe8e823, 0xa1dddd7c, 0xe874749c, 0x3e1f1f21,
+ 0x964b4bdd, 0x61bdbddc, 0x0d8b8b86, 0x0f8a8a85, 0xe0707090, 0x7c3e3e42,
+ 0x71b5b5c4, 0xcc6666aa, 0x904848d8, 0x06030305, 0xf7f6f601, 0x1c0e0e12,
+ 0xc26161a3, 0x6a35355f, 0xae5757f9, 0x69b9b9d0, 0x17868691, 0x99c1c158,
+ 0x3a1d1d27, 0x279e9eb9, 0xd9e1e138, 0xebf8f813, 0x2b9898b3, 0x22111133,
+ 0xd26969bb, 0xa9d9d970, 0x078e8e89, 0x339494a7, 0x2d9b9bb6, 0x3c1e1e22,
+ 0x15878792, 0xc9e9e920, 0x87cece49, 0xaa5555ff, 0x50282878, 0xa5dfdf7a,
+ 0x038c8c8f, 0x59a1a1f8, 0x09898980, 0x1a0d0d17, 0x65bfbfda, 0xd7e6e631,
+ 0x844242c6, 0xd06868b8, 0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11,
+ 0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a
+};
+
+//
+// Round constant word array used in AES key expansion.
+//
+GLOBAL_REMOVE_IF_UNREFERENCED CONST UINT32 Rcon[] = {
+ 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000,
+ 0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000
+};
+
+//
+// Rotates x right n bits (circular right shift operation)
+//
+#define ROTATE_RIGHT32(x, n) (((x) >> (n)) | ((x) << (32-(n))))
+
+//
+// Loading & Storing 32-bit words in big-endian format: y[3..0] --> x; x --> y[3..0];
+//
+#define LOAD32H(x, y) { x = ((UINT32)((y)[0] & 0xFF) << 24) | ((UINT32)((y)[1] & 0xFF) << 16) | \
+ ((UINT32)((y)[2] & 0xFF) << 8) | ((UINT32)((y)[3] & 0xFF)); }
+#define STORE32H(x, y) { (y)[0] = (UINT8)(((x) >> 24) & 0xFF); (y)[1] = (UINT8)(((x) >> 16) & 0xFF); \
+ (y)[2] = (UINT8)(((x) >> 8) & 0xFF); (y)[3] = (UINT8)((x) & 0xFF); }
+
+//
+// Wrap macros for AES forward tables lookups
+//
+#define AES_FT0(x) AesForwardTable[x]
+#define AES_FT1(x) ROTATE_RIGHT32(AesForwardTable[x], 8)
+#define AES_FT2(x) ROTATE_RIGHT32(AesForwardTable[x], 16)
+#define AES_FT3(x) ROTATE_RIGHT32(AesForwardTable[x], 24)
+
+///
+/// AES Key Schedule which is expanded from symmetric key [Size 60 = 4 * ((Max AES Round, 14) + 1)].
+///
+typedef struct {
+ UINTN Nk; // Number of Cipher Key (in 32-bit words);
+ UINT32 EncKey[60]; // Expanded AES encryption key
+ UINT32 DecKey[60]; // Expanded AES decryption key (Not used here)
+} AES_KEY;
+
+/**
+ AES Key Expansion.
+ This function expands the cipher key into encryption schedule.
+
+ @param[in] Key AES symmetric key buffer.
+ @param[in] KeyLenInBits Key length in bits (128, 192, or 256).
+ @param[out] AesKey Expanded AES Key schedule for encryption.
+
+ @retval EFI_SUCCESS AES key expansion succeeded.
+ @retval EFI_INVALID_PARAMETER Unsupported key length.
+
+**/
+EFI_STATUS
+EFIAPI
+AesExpandKey (
+ IN UINT8 *Key,
+ IN UINTN KeyLenInBits,
+ OUT AES_KEY *AesKey
+ )
+{
+ UINTN Nk;
+ UINTN Nr;
+ UINTN Nw;
+ UINTN Index1;
+ UINTN Index2;
+ UINTN Index3;
+ UINT32 *Ek;
+ UINT32 Temp;
+
+ //
+ // Nk - Number of 32-bit words comprising the cipher key. (Nk = 4, 6 or 8)
+ // Nr - Number of rounds. (Nr = 10, 12, or 14), which is dependent on the key size.
+ //
+ Nk = KeyLenInBits >> 5;
+ if (Nk != 4 && Nk != 6 && Nk != 8) {
+ return EFI_INVALID_PARAMETER;
+ }
+ Nr = Nk + 6;
+ Nw = AES_NB * (Nr + 1); // Key Expansion generates a total of Nb * (Nr + 1) words
+ AesKey->Nk = Nk;
+
+ //
+ // Load initial symmetric AES key;
+ // Note that AES was designed on big-endian systems.
+ //
+ Ek = AesKey->EncKey;
+ for (Index1 = Index2 = 0; Index1 < Nk; Index1++, Index2 += 4) {
+ LOAD32H (Ek[Index1], Key + Index2);
+ }
+
+ //
+ // Initialize the encryption key scheduler
+ //
+ for (Index2 = Nk, Index3 = 0; Index2 < Nw; Index2 += Nk, Index3++) {
+ Temp = Ek[Index2 - 1];
+ Ek[Index2] = Ek[Index2 - Nk] ^ (AES_FT2((Temp >> 16) & 0xFF) & 0xFF000000) ^
+ (AES_FT3((Temp >> 8) & 0xFF) & 0x00FF0000) ^
+ (AES_FT0((Temp) & 0xFF) & 0x0000FF00) ^
+ (AES_FT1((Temp >> 24) & 0xFF) & 0x000000FF) ^
+ Rcon[Index3];
+ if (Nk <= 6) {
+ //
+ // If AES Cipher Key is 128 or 192 bits
+ //
+ for (Index1 = 1; Index1 < Nk && (Index1 + Index2) < Nw; Index1++) {
+ Ek [Index1 + Index2] = Ek [Index1 + Index2 - Nk] ^ Ek[Index1 + Index2 - 1];
+ }
+ } else {
+ //
+ // Different routine for key expansion If Cipher Key is 256 bits,
+ //
+ for (Index1 = 1; Index1 < 4 && (Index1 + Index2) < Nw; Index1++) {
+ Ek [Index1 + Index2] = Ek[Index1 + Index2 - Nk] ^ Ek[Index1 + Index2 - 1];
+ }
+ if (Index2 + 4 < Nw) {
+ Temp = Ek[Index2 + 3];
+ Ek[Index2 + 4] = Ek[Index2 + 4 - Nk] ^ (AES_FT2((Temp >> 24) & 0xFF) & 0xFF000000) ^
+ (AES_FT3((Temp >> 16) & 0xFF) & 0x00FF0000) ^
+ (AES_FT0((Temp >> 8) & 0xFF) & 0x0000FF00) ^
+ (AES_FT1((Temp) & 0xFF) & 0x000000FF);
+ }
+
+ for (Index1 = 5; Index1 < Nk && (Index1 + Index2) < Nw; Index1++) {
+ Ek[Index1 + Index2] = Ek[Index1 + Index2 - Nk] ^ Ek[Index1 + Index2 - 1];
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Encrypts one single block data (128 bits) with AES algorithm.
+
+ @param[in] Key AES symmetric key buffer.
+ @param[in] InData One block of input plaintext to be encrypted.
+ @param[out] OutData Encrypted output ciphertext.
+
+ @retval EFI_SUCCESS AES Block Encryption succeeded.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+AesEncrypt (
+ IN UINT8 *Key,
+ IN UINT8 *InData,
+ OUT UINT8 *OutData
+ )
+{
+ AES_KEY AesKey;
+ UINTN Nr;
+ UINT32 *Ek;
+ UINT32 State[4];
+ UINT32 TempState[4];
+ UINT32 *StateX;
+ UINT32 *StateY;
+ UINT32 *Temp;
+ UINTN Index;
+ UINTN NbIndex;
+ UINTN Round;
+
+ if ((Key == NULL) || (InData == NULL) || (OutData == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Expands AES Key for encryption.
+ //
+ AesExpandKey (Key, 128, &AesKey);
+
+ Nr = AesKey.Nk + 6;
+ Ek = AesKey.EncKey;
+
+ //
+ // Initialize the cipher State array with the initial round key
+ //
+ for (Index = 0; Index < AES_NB; Index++) {
+ LOAD32H (State[Index], InData + 4 * Index);
+ State[Index] ^= Ek[Index];
+ }
+
+ NbIndex = AES_NB;
+ StateX = State;
+ StateY = TempState;
+
+ //
+ // AES Cipher transformation rounds (Nr - 1 rounds), in which SubBytes(),
+ // ShiftRows() and MixColumns() operations were combined by a sequence of
+ // table lookups to speed up the execution.
+ //
+ for (Round = 1; Round < Nr; Round++) {
+ StateY[0] = AES_FT0 ((StateX[0] >> 24) ) ^ AES_FT1 ((StateX[1] >> 16) & 0xFF) ^
+ AES_FT2 ((StateX[2] >> 8) & 0xFF) ^ AES_FT3 ((StateX[3] ) & 0xFF) ^ Ek[NbIndex];
+ StateY[1] = AES_FT0 ((StateX[1] >> 24) ) ^ AES_FT1 ((StateX[2] >> 16) & 0xFF) ^
+ AES_FT2 ((StateX[3] >> 8) & 0xFF) ^ AES_FT3 ((StateX[0] ) & 0xFF) ^ Ek[NbIndex + 1];
+ StateY[2] = AES_FT0 ((StateX[2] >> 24) ) ^ AES_FT1 ((StateX[3] >> 16) & 0xFF) ^
+ AES_FT2 ((StateX[0] >> 8) & 0xFF) ^ AES_FT3 ((StateX[1] ) & 0xFF) ^ Ek[NbIndex + 2];
+ StateY[3] = AES_FT0 ((StateX[3] >> 24) ) ^ AES_FT1 ((StateX[0] >> 16) & 0xFF) ^
+ AES_FT2 ((StateX[1] >> 8) & 0xFF) ^ AES_FT3 ((StateX[2] ) & 0xFF) ^ Ek[NbIndex + 3];
+
+ NbIndex += 4;
+ Temp = StateX; StateX = StateY; StateY = Temp;
+ }
+
+ //
+ // Apply the final round, which does not include MixColumns() transformation
+ //
+ StateY[0] = (AES_FT2 ((StateX[0] >> 24) ) & 0xFF000000) ^ (AES_FT3 ((StateX[1] >> 16) & 0xFF) & 0x00FF0000) ^
+ (AES_FT0 ((StateX[2] >> 8) & 0xFF) & 0x0000FF00) ^ (AES_FT1 ((StateX[3] ) & 0xFF) & 0x000000FF) ^
+ Ek[NbIndex];
+ StateY[1] = (AES_FT2 ((StateX[1] >> 24) ) & 0xFF000000) ^ (AES_FT3 ((StateX[2] >> 16) & 0xFF) & 0x00FF0000) ^
+ (AES_FT0 ((StateX[3] >> 8) & 0xFF) & 0x0000FF00) ^ (AES_FT1 ((StateX[0] ) & 0xFF) & 0x000000FF) ^
+ Ek[NbIndex + 1];
+ StateY[2] = (AES_FT2 ((StateX[2] >> 24) ) & 0xFF000000) ^ (AES_FT3 ((StateX[3] >> 16) & 0xFF) & 0x00FF0000) ^
+ (AES_FT0 ((StateX[0] >> 8) & 0xFF) & 0x0000FF00) ^ (AES_FT1 ((StateX[1] ) & 0xFF) & 0x000000FF) ^
+ Ek[NbIndex + 2];
+ StateY[3] = (AES_FT2 ((StateX[3] >> 24) ) & 0xFF000000) ^ (AES_FT3 ((StateX[0] >> 16) & 0xFF) & 0x00FF0000) ^
+ (AES_FT0 ((StateX[1] >> 8) & 0xFF) & 0x0000FF00) ^ (AES_FT1 ((StateX[2] ) & 0xFF) & 0x000000FF) ^
+ Ek[NbIndex + 3];
+
+ //
+ // Output the transformed result;
+ //
+ for (Index = 0; Index < AES_NB; Index++) {
+ STORE32H (StateY[Index], OutData + 4 * Index);
+ }
+
+ return EFI_SUCCESS;
+} \ No newline at end of file
diff --git a/Core/SecurityPkg/RandomNumberGenerator/RngDxe/AesCore.h b/Core/SecurityPkg/RandomNumberGenerator/RngDxe/AesCore.h
new file mode 100644
index 0000000000..8279c61160
--- /dev/null
+++ b/Core/SecurityPkg/RandomNumberGenerator/RngDxe/AesCore.h
@@ -0,0 +1,37 @@
+/** @file
+ Function prototype for AES Block Cipher support.
+
+Copyright (c) 2013, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __AES_CORE_H__
+#define __AES_CORE_H__
+
+/**
+ Encrypts one single block data (128 bits) with AES algorithm.
+
+ @param[in] Key AES symmetric key buffer.
+ @param[in] InData One block of input plaintext to be encrypted.
+ @param[out] OutData Encrypted output ciphertext.
+
+ @retval EFI_SUCCESS AES Block Encryption succeeded.
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+AesEncrypt (
+ IN UINT8 *Key,
+ IN UINT8 *InData,
+ OUT UINT8 *OutData
+ );
+
+#endif // __AES_CORE_H__
diff --git a/Core/SecurityPkg/RandomNumberGenerator/RngDxe/RdRand.c b/Core/SecurityPkg/RandomNumberGenerator/RngDxe/RdRand.c
new file mode 100644
index 0000000000..395b8867c8
--- /dev/null
+++ b/Core/SecurityPkg/RandomNumberGenerator/RngDxe/RdRand.c
@@ -0,0 +1,173 @@
+/** @file
+ Support routines for RDRAND instruction access.
+
+Copyright (c) 2013, Intel Corporation. All rights reserved.<BR>
+(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+#include <Library/RngLib.h>
+
+#include "RdRand.h"
+#include "AesCore.h"
+
+/**
+ Calls RDRAND to fill a buffer of arbitrary size with random bytes.
+
+ @param[in] Length Size of the buffer, in bytes, to fill with.
+ @param[out] RandBuffer Pointer to the buffer to store the random result.
+
+ @retval EFI_SUCCESS Random bytes generation succeeded.
+ @retval EFI_NOT_READY Failed to request random bytes.
+
+**/
+EFI_STATUS
+EFIAPI
+RdRandGetBytes (
+ IN UINTN Length,
+ OUT UINT8 *RandBuffer
+ )
+{
+ BOOLEAN IsRandom;
+ UINT64 TempRand[2];
+
+ while (Length > 0) {
+ IsRandom = GetRandomNumber128 (TempRand);
+ if (!IsRandom) {
+ return EFI_NOT_READY;
+ }
+ if (Length >= sizeof (TempRand)) {
+ WriteUnaligned64 ((UINT64*)RandBuffer, TempRand[0]);
+ RandBuffer += sizeof (UINT64);
+ WriteUnaligned64 ((UINT64*)RandBuffer, TempRand[1]);
+ RandBuffer += sizeof (UINT64);
+ Length -= sizeof (TempRand);
+ } else {
+ CopyMem (RandBuffer, TempRand, Length);
+ Length = 0;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Creates a 128bit random value that is fully forward and backward prediction resistant,
+ suitable for seeding a NIST SP800-90 Compliant, FIPS 1402-2 certifiable SW DRBG.
+ This function takes multiple random numbers through RDRAND without intervening
+ delays to ensure reseeding and performs AES-CBC-MAC over the data to compute the
+ seed value.
+
+ @param[out] SeedBuffer Pointer to a 128bit buffer to store the random seed.
+
+ @retval EFI_SUCCESS Random seed generation succeeded.
+ @retval EFI_NOT_READY Failed to request random bytes.
+
+**/
+EFI_STATUS
+EFIAPI
+RdRandGetSeed128 (
+ OUT UINT8 *SeedBuffer
+ )
+{
+ EFI_STATUS Status;
+ UINT8 RandByte[16];
+ UINT8 Key[16];
+ UINT8 Ffv[16];
+ UINT8 Xored[16];
+ UINT32 Index;
+ UINT32 Index2;
+
+ //
+ // Chose an arbitary key and zero the feed_forward_value (FFV)
+ //
+ for (Index = 0; Index < 16; Index++) {
+ Key[Index] = (UINT8) Index;
+ Ffv[Index] = 0;
+ }
+
+ //
+ // Perform CBC_MAC over 32 * 128 bit values, with 10us gaps between 128 bit value
+ // The 10us gaps will ensure multiple reseeds within the HW RNG with a large design margin.
+ //
+ for (Index = 0; Index < 32; Index++) {
+ MicroSecondDelay (10);
+ Status = RdRandGetBytes (16, RandByte);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Perform XOR operations on two 128-bit value.
+ //
+ for (Index2 = 0; Index2 < 16; Index2++) {
+ Xored[Index2] = RandByte[Index2] ^ Ffv[Index2];
+ }
+
+ AesEncrypt (Key, Xored, Ffv);
+ }
+
+ for (Index = 0; Index < 16; Index++) {
+ SeedBuffer[Index] = Ffv[Index];
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Generate high-quality entropy source through RDRAND.
+
+ @param[in] Length Size of the buffer, in bytes, to fill with.
+ @param[out] Entropy Pointer to the buffer to store the entropy data.
+
+ @retval EFI_SUCCESS Entropy generation succeeded.
+ @retval EFI_NOT_READY Failed to request random data.
+
+**/
+EFI_STATUS
+EFIAPI
+RdRandGenerateEntropy (
+ IN UINTN Length,
+ OUT UINT8 *Entropy
+ )
+{
+ EFI_STATUS Status;
+ UINTN BlockCount;
+ UINT8 Seed[16];
+ UINT8 *Ptr;
+
+ Status = EFI_NOT_READY;
+ BlockCount = Length / 16;
+ Ptr = (UINT8 *)Entropy;
+
+ //
+ // Generate high-quality seed for DRBG Entropy
+ //
+ while (BlockCount > 0) {
+ Status = RdRandGetSeed128 (Seed);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ CopyMem (Ptr, Seed, 16);
+
+ BlockCount--;
+ Ptr = Ptr + 16;
+ }
+
+ //
+ // Populate the remained data as request.
+ //
+ Status = RdRandGetSeed128 (Seed);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ CopyMem (Ptr, Seed, (Length % 16));
+
+ return Status;
+}
diff --git a/Core/SecurityPkg/RandomNumberGenerator/RngDxe/RdRand.h b/Core/SecurityPkg/RandomNumberGenerator/RngDxe/RdRand.h
new file mode 100644
index 0000000000..d6378778cf
--- /dev/null
+++ b/Core/SecurityPkg/RandomNumberGenerator/RngDxe/RdRand.h
@@ -0,0 +1,66 @@
+/** @file
+ Header for the RDRAND APIs used by RNG DXE driver.
+
+ Support API definitions for RDRAND instruction access, which will leverage
+ Intel Secure Key technology to provide high-quality random numbers for use
+ in applications, or entropy for seeding other random number generators.
+ Refer to http://software.intel.com/en-us/articles/intel-digital-random-number
+ -generator-drng-software-implementation-guide/ for more information about Intel
+ Secure Key technology.
+
+Copyright (c) 2013, Intel Corporation. All rights reserved.<BR>
+(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __RD_RAND_H__
+#define __RD_RAND_H__
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/TimerLib.h>
+#include <Protocol/Rng.h>
+
+/**
+ Calls RDRAND to fill a buffer of arbitrary size with random bytes.
+
+ @param[in] Length Size of the buffer, in bytes, to fill with.
+ @param[out] RandBuffer Pointer to the buffer to store the random result.
+
+ @retval EFI_SUCCESS Random bytes generation succeeded.
+ @retval EFI_NOT_READY Failed to request random bytes.
+
+**/
+EFI_STATUS
+EFIAPI
+RdRandGetBytes (
+ IN UINTN Length,
+ OUT UINT8 *RandBuffer
+ );
+
+/**
+ Generate high-quality entropy source through RDRAND.
+
+ @param[in] Length Size of the buffer, in bytes, to fill with.
+ @param[out] Entropy Pointer to the buffer to store the entropy data.
+
+ @retval EFI_SUCCESS Entropy generation succeeded.
+ @retval EFI_NOT_READY Failed to request random data.
+
+**/
+EFI_STATUS
+EFIAPI
+RdRandGenerateEntropy (
+ IN UINTN Length,
+ OUT UINT8 *Entropy
+ );
+
+#endif // __RD_RAND_H__
diff --git a/Core/SecurityPkg/RandomNumberGenerator/RngDxe/RngDxe.c b/Core/SecurityPkg/RandomNumberGenerator/RngDxe/RngDxe.c
new file mode 100644
index 0000000000..32c46ab45f
--- /dev/null
+++ b/Core/SecurityPkg/RandomNumberGenerator/RngDxe/RngDxe.c
@@ -0,0 +1,212 @@
+/** @file
+ RNG Driver to produce the UEFI Random Number Generator protocol.
+
+ The driver will use the new RDRAND instruction to produce high-quality, high-performance
+ entropy and random number.
+
+ RNG Algoritnms defined in UEFI 2.4:
+ - EFI_RNG_ALGORITHM_SP800_90_CTR_256_GUID - Supported
+ (RDRAND implements a hardware NIST SP800-90 AES-CTR-256 based DRBG)
+ - EFI_RNG_ALGORITHM_RAW - Supported
+ (Structuring RDRAND invocation can be guaranteed as high-quality entropy source)
+ - EFI_RNG_ALGORITHM_SP800_90_HMAC_256_GUID - Unsupported
+ - EFI_RNG_ALGORITHM_SP800_90_HASH_256_GUID - Unsupported
+ - EFI_RNG_ALGORITHM_X9_31_3DES_GUID - Unsupported
+ - EFI_RNG_ALGORITHM_X9_31_AES_GUID - Unsupported
+
+Copyright (c) 2013, Intel Corporation. All rights reserved.<BR>
+(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "RdRand.h"
+
+//
+// Supported RNG Algorithms list by this driver.
+//
+EFI_RNG_ALGORITHM mSupportedRngAlgorithms[] = {
+ EFI_RNG_ALGORITHM_SP800_90_CTR_256_GUID,
+ EFI_RNG_ALGORITHM_RAW
+};
+
+/**
+ Returns information about the random number generation implementation.
+
+ @param[in] This A pointer to the EFI_RNG_PROTOCOL instance.
+ @param[in,out] RNGAlgorithmListSize On input, the size in bytes of RNGAlgorithmList.
+ On output with a return code of EFI_SUCCESS, the size
+ in bytes of the data returned in RNGAlgorithmList. On output
+ with a return code of EFI_BUFFER_TOO_SMALL,
+ the size of RNGAlgorithmList required to obtain the list.
+ @param[out] RNGAlgorithmList A caller-allocated memory buffer filled by the driver
+ with one EFI_RNG_ALGORITHM element for each supported
+ RNG algorithm. The list must not change across multiple
+ calls to the same driver. The first algorithm in the list
+ is the default algorithm for the driver.
+
+ @retval EFI_SUCCESS The RNG algorithm list was returned successfully.
+ @retval EFI_UNSUPPORTED The services is not supported by this driver.
+ @retval EFI_DEVICE_ERROR The list of algorithms could not be retrieved due to a
+ hardware or firmware error.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters are incorrect.
+ @retval EFI_BUFFER_TOO_SMALL The buffer RNGAlgorithmList is too small to hold the result.
+
+**/
+EFI_STATUS
+EFIAPI
+RngGetInfo (
+ IN EFI_RNG_PROTOCOL *This,
+ IN OUT UINTN *RNGAlgorithmListSize,
+ OUT EFI_RNG_ALGORITHM *RNGAlgorithmList
+ )
+{
+ EFI_STATUS Status;
+ UINTN RequiredSize;
+
+ if ((This == NULL) || (RNGAlgorithmListSize == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ RequiredSize = sizeof (mSupportedRngAlgorithms);
+ if (*RNGAlgorithmListSize < RequiredSize) {
+ Status = EFI_BUFFER_TOO_SMALL;
+ } else {
+ //
+ // Return algorithm list supported by driver.
+ //
+ if (RNGAlgorithmList != NULL) {
+ CopyMem (RNGAlgorithmList, mSupportedRngAlgorithms, RequiredSize);
+ Status = EFI_SUCCESS;
+ } else {
+ Status = EFI_INVALID_PARAMETER;
+ }
+ }
+ *RNGAlgorithmListSize = RequiredSize;
+
+ return Status;
+}
+
+/**
+ Produces and returns an RNG value using either the default or specified RNG algorithm.
+
+ @param[in] This A pointer to the EFI_RNG_PROTOCOL instance.
+ @param[in] RNGAlgorithm A pointer to the EFI_RNG_ALGORITHM that identifies the RNG
+ algorithm to use. May be NULL in which case the function will
+ use its default RNG algorithm.
+ @param[in] RNGValueLength The length in bytes of the memory buffer pointed to by
+ RNGValue. The driver shall return exactly this numbers of bytes.
+ @param[out] RNGValue A caller-allocated memory buffer filled by the driver with the
+ resulting RNG value.
+
+ @retval EFI_SUCCESS The RNG value was returned successfully.
+ @retval EFI_UNSUPPORTED The algorithm specified by RNGAlgorithm is not supported by
+ this driver.
+ @retval EFI_DEVICE_ERROR An RNG value could not be retrieved due to a hardware or
+ firmware error.
+ @retval EFI_NOT_READY There is not enough random data available to satisfy the length
+ requested by RNGValueLength.
+ @retval EFI_INVALID_PARAMETER RNGValue is NULL or RNGValueLength is zero.
+
+**/
+EFI_STATUS
+EFIAPI
+RngGetRNG (
+ IN EFI_RNG_PROTOCOL *This,
+ IN EFI_RNG_ALGORITHM *RNGAlgorithm, OPTIONAL
+ IN UINTN RNGValueLength,
+ OUT UINT8 *RNGValue
+ )
+{
+ EFI_STATUS Status;
+
+ if ((RNGValueLength == 0) || (RNGValue == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_UNSUPPORTED;
+ if (RNGAlgorithm == NULL) {
+ //
+ // Use the default RNG algorithm if RNGAlgorithm is NULL.
+ //
+ RNGAlgorithm = &gEfiRngAlgorithmSp80090Ctr256Guid;
+ }
+
+ //
+ // NIST SP800-90-AES-CTR-256 supported by RDRAND
+ //
+ if (CompareGuid (RNGAlgorithm, &gEfiRngAlgorithmSp80090Ctr256Guid)) {
+ Status = RdRandGetBytes (RNGValueLength, RNGValue);
+ return Status;
+ }
+
+ //
+ // The "raw" algorithm is intended to provide entropy directly
+ //
+ if (CompareGuid (RNGAlgorithm, &gEfiRngAlgorithmRaw)) {
+ //
+ // When a DRBG is used on the output of a entropy source,
+ // its security level must be at least 256 bits according to UEFI Spec.
+ //
+ if (RNGValueLength < 32) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = RdRandGenerateEntropy (RNGValueLength, RNGValue);
+ return Status;
+ }
+
+ //
+ // Other algorithms were unsupported by this driver.
+ //
+ return Status;
+}
+
+//
+// The Random Number Generator (RNG) protocol
+//
+EFI_RNG_PROTOCOL mRngRdRand = {
+ RngGetInfo,
+ RngGetRNG
+};
+
+/**
+ The user Entry Point for the Random Number Generator (RNG) driver.
+
+ @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 EFI_NOT_SUPPORTED Platform does not support RNG.
+ @retval Other Some error occurs when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+RngDriverEntry (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE Handle;
+
+ //
+ // Install UEFI RNG (Random Number Generator) Protocol
+ //
+ Handle = NULL;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Handle,
+ &gEfiRngProtocolGuid,
+ &mRngRdRand,
+ NULL
+ );
+
+ return Status;
+}
diff --git a/Core/SecurityPkg/RandomNumberGenerator/RngDxe/RngDxe.inf b/Core/SecurityPkg/RandomNumberGenerator/RngDxe/RngDxe.inf
new file mode 100644
index 0000000000..4d668a170a
--- /dev/null
+++ b/Core/SecurityPkg/RandomNumberGenerator/RngDxe/RngDxe.inf
@@ -0,0 +1,72 @@
+## @file
+# Produces the UEFI Random Number Generator protocol
+#
+# This module will leverage Intel Secure Key technology to produce the Random
+# Number Generator protocol, which is used to provide high-quality random numbers
+# for use in applications, or entropy for seeding other random number generators.
+# Refer to http://software.intel.com/en-us/articles/intel-digital-random-number
+# -generator-drng-software-implementation-guide/ for more information about Intel
+# Secure Key technology.
+#
+# Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+# (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = RngDxe
+ FILE_GUID = B981A835-6EE8-4f4c-AE0B-210AA0BFBF01
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = RngDriverEntry
+ MODULE_UNI_FILE = RngDxe.uni
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources.common]
+ RngDxe.c
+ RdRand.c
+ RdRand.h
+ AesCore.c
+ AesCore.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+ UefiLib
+ UefiBootServicesTableLib
+ BaseLib
+ DebugLib
+ UefiDriverEntryPoint
+ TimerLib
+ RngLib
+
+[Guids]
+ gEfiRngAlgorithmSp80090Ctr256Guid ## SOMETIMES_PRODUCES ## GUID # Unique ID of the algorithm for RNG
+ gEfiRngAlgorithmRaw ## SOMETIMES_PRODUCES ## GUID # Unique ID of the algorithm for RNG
+
+[Protocols]
+ gEfiRngProtocolGuid ## PRODUCES
+
+[Depex]
+ TRUE
+
+[BuildOptions]
+ XCODE:*_*_*_CC_FLAGS = -mmmx -msse
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ RngDxeExtra.uni
diff --git a/Core/SecurityPkg/RandomNumberGenerator/RngDxe/RngDxe.uni b/Core/SecurityPkg/RandomNumberGenerator/RngDxe/RngDxe.uni
new file mode 100644
index 0000000000..38f53c98a1
--- /dev/null
+++ b/Core/SecurityPkg/RandomNumberGenerator/RngDxe/RngDxe.uni
@@ -0,0 +1,27 @@
+// /** @file
+// Produces the UEFI Random Number Generator protocol
+//
+// This module will leverage Intel Secure Key technology to produce the Random
+// Number Generator protocol, which is used to provide high-quality random numbers
+// for use in applications, or entropy for seeding other random number generators.
+// Refer to http://software.intel.com/en-us/articles/intel-digital-random-number
+// -generator-drng-software-implementation-guide/ for more information about Intel
+// Secure Key technology.
+//
+// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+//
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Produces UEFI Random Number Generator protocol"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This module will produce UEFI Random Number Generator protocol. In current implementation, Only SP800_90_CTR_256 and "RAW" RNG algorithms are supported."
+
diff --git a/Core/SecurityPkg/RandomNumberGenerator/RngDxe/RngDxeExtra.uni b/Core/SecurityPkg/RandomNumberGenerator/RngDxe/RngDxeExtra.uni
new file mode 100644
index 0000000000..1fdc7e2253
--- /dev/null
+++ b/Core/SecurityPkg/RandomNumberGenerator/RngDxe/RngDxeExtra.uni
@@ -0,0 +1,19 @@
+// /** @file
+// RngDxe Localized Strings and Content
+//
+// Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"UEFI Random Number Generator DXE"
+
+
diff --git a/Core/SecurityPkg/SecurityPkg.dec b/Core/SecurityPkg/SecurityPkg.dec
new file mode 100644
index 0000000000..db0c9ac7be
--- /dev/null
+++ b/Core/SecurityPkg/SecurityPkg.dec
@@ -0,0 +1,473 @@
+## @file SecurityPkg.dec
+# Provides security features that conform to TCG/UEFI industry standards
+#
+# The security features include secure boot, measured boot and user identification.
+# It also provides the definitions(including PPIs/PROTOCOLs/GUIDs and library classes)
+# and libraries instances, which are used for those features.
+#
+# Copyright (c) 2009 - 2017, Intel Corporation. All rights reserved.<BR>
+# (C) Copyright 2015 Hewlett Packard Enterprise Development LP <BR>
+# This program and the accompanying materials are licensed and made available under
+# the terms and conditions of the BSD License which accompanies this distribution.
+# The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ DEC_SPECIFICATION = 0x00010005
+ PACKAGE_NAME = SecurityPkg
+ PACKAGE_UNI_FILE = SecurityPkg.uni
+ PACKAGE_GUID = 4EFC4F66-6219-4427-B780-FB99F470767F
+ PACKAGE_VERSION = 0.96
+
+[Includes]
+ Include
+
+[LibraryClasses]
+ ## @libraryclass Provides hash interfaces from different implementations.
+ #
+ HashLib|Include/Library/HashLib.h
+
+ ## @libraryclass Provides a platform specific interface to detect physically present user.
+ #
+ PlatformSecureLib|Include/Library/PlatformSecureLib.h
+
+ ## @libraryclass Provides interfaces to handle TPM 1.2 request.
+ #
+ TcgPhysicalPresenceLib|Include/Library/TcgPhysicalPresenceLib.h
+
+ ## @libraryclass Provides support for TCG PP >= 128 Vendor Specific PPI Operation.
+ #
+ TcgPpVendorLib|Include/Library/TcgPpVendorLib.h
+
+ ## @libraryclass Provides interfaces for other modules to send TPM 2.0 command.
+ #
+ Tpm2CommandLib|Include/Library/Tpm2CommandLib.h
+
+ ## @libraryclass Provides interfaces on how to access TPM 2.0 hardware device.
+ #
+ Tpm2DeviceLib|Include/Library/Tpm2DeviceLib.h
+
+ ## @libraryclass Provides interfaces for other modules to send TPM 1.2 command.
+ #
+ Tpm12CommandLib|Include/Library/Tpm12CommandLib.h
+
+ ## @libraryclass Provides interfaces on how to access TPM 1.2 hardware device.
+ #
+ Tpm12DeviceLib|Include/Library/Tpm12DeviceLib.h
+
+ ## @libraryclass Provides TPM Interface Specification (TIS) interfaces for TPM command.
+ #
+ TpmCommLib|Include/Library/TpmCommLib.h
+
+ ## @libraryclass Provides interfaces to handle TPM 2.0 request.
+ #
+ TrEEPhysicalPresenceLib|Include/Library/TrEEPhysicalPresenceLib.h
+
+ ## @libraryclass Provides support for TrEE PP >= 128 Vendor Specific PPI Operation.
+ #
+ TrEEPpVendorLib|Include/Library/TrEEPpVendorLib.h
+
+ ## @libraryclass Provides support for TCG Physical Presence Interface (PPI) specification
+ # >= 128 Vendor Specific PPI Operation.
+ #
+ Tcg2PpVendorLib|Include/Library/TcgPpVendorLib.h
+
+ ## @libraryclass Handle TPM 2.0 physical presence request from OS.
+ #
+ Tcg2PhysicalPresenceLib|Include/Library/Tcg2PhysicalPresenceLib.h
+
+ ## @libraryclass Provides interfaces about TCG storage generic commond.
+ #
+ TcgStorageCoreLib|Include/Library/TcgStorageCoreLib.h
+
+ ## @libraryclass Provides interfaces about TCG storage Opal generic commond.
+ #
+ TcgStorageOpalLib|Include/Library/TcgStorageOpalLib.h
+
+ ## @libraryclass Provides interfaces about Opal commond special for Opal password solution.
+ #
+ OpalPasswordSupportLib|Include/Library/OpalPasswordSupportLib.h
+
+[Guids]
+ ## Security package token space guid.
+ # Include/Guid/SecurityPkgTokenSpace.h
+ gEfiSecurityPkgTokenSpaceGuid = { 0xd3fb176, 0x9569, 0x4d51, { 0xa3, 0xef, 0x7d, 0x61, 0xc6, 0x4f, 0xea, 0xba }}
+
+ ## GUID used to "SecureBootEnable" variable for the Secure Boot feature enable/disable.
+ # This variable is used for allowing a physically present user to disable Secure Boot via firmware setup without the possession of PKpriv.
+ # Include/Guid/AuthenticatedVariableFormat.h
+ gEfiSecureBootEnableDisableGuid = { 0xf0a30bc7, 0xaf08, 0x4556, { 0x99, 0xc4, 0x0, 0x10, 0x9, 0xc9, 0x3a, 0x44 } }
+
+ ## GUID used to "CustomMode" variable for two Secure Boot modes feature: "Custom" and "Standard".
+ # Standard Secure Boot mode is the default mode as UEFI Spec's description.
+ # Custom Secure Boot mode allows for more flexibility as specified in the following:
+ # Can enroll or delete PK without existing PK's private key.
+ # Can enroll or delete KEK without existing PK's private key.
+ # Can enroll or delete signature from DB/DBX without KEK's private key.
+ # Include/Guid/AuthenticatedVariableFormat.h
+ gEfiCustomModeEnableGuid = { 0xc076ec0c, 0x7028, 0x4399, { 0xa0, 0x72, 0x71, 0xee, 0x5c, 0x44, 0x8b, 0x9f } }
+
+ ## GUID used to "VendorKeysNv" variable to record the out of band secure boot keys modification.
+ # This variable is a read-only NV variable that indicates whether someone other than the platform vendor has used a
+ # mechanism not defined by the UEFI Specification to transition the system to setup mode or to update secure boot keys.
+ # Include/Guid/AuthenticatedVariableFormat.h
+ gEfiVendorKeysNvGuid = { 0x9073e4e0, 0x60ec, 0x4b6e, { 0x99, 0x3, 0x4c, 0x22, 0x3c, 0x26, 0xf, 0x3c } }
+
+ ## GUID used to "certdb"/"certdbv" variable to store the signer's certificates for common variables with EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute.
+ # Include/Guid/AuthenticatedVariableFormat.h
+ gEfiCertDbGuid = { 0xd9bee56e, 0x75dc, 0x49d9, { 0xb4, 0xd7, 0xb5, 0x34, 0x21, 0xf, 0x63, 0x7a } }
+
+ ## Hob GUID used to pass a TCG_PCR_EVENT from a TPM PEIM to a TPM DXE Driver.
+ # Include/Guid/TcgEventHob.h
+ gTcgEventEntryHobGuid = { 0x2b9ffb52, 0x1b13, 0x416f, { 0xa8, 0x7b, 0xbc, 0x93, 0xd, 0xef, 0x92, 0xa8 }}
+
+ ## Hob GUID used to pass a TCG_PCR_EVENT_2 from a TPM2 PEIM to a TPM2 DXE Driver.
+ ## Include/Guid/TcgEventHob.h
+ gTcgEvent2EntryHobGuid = { 0xd26c221e, 0x2430, 0x4c8a, { 0x91, 0x70, 0x3f, 0xcb, 0x45, 0x0, 0x41, 0x3f }}
+
+ ## HOB GUID used to record TPM device error.
+ # Include/Guid/TcgEventHob.h
+ gTpmErrorHobGuid = { 0xef598499, 0xb25e, 0x473a, { 0xbf, 0xaf, 0xe7, 0xe5, 0x7d, 0xce, 0x82, 0xc4 }}
+
+ ## HOB GUID used to record TPM2 startup locality
+ ## Include/Guid/TcgEventHob.h
+ gTpm2StartupLocalityHobGuid = { 0x397b0c9, 0x22e8, 0x459e, { 0xa4, 0xff, 0x99, 0xbc, 0x65, 0x27, 0x9, 0x29 }}
+
+ ## HOB GUID used to pass all PEI measured FV info to DXE Driver.
+ # Include/Guid/MeasuredFvHob.h
+ gMeasuredFvHobGuid = { 0xb2360b42, 0x7173, 0x420a, { 0x86, 0x96, 0x46, 0xca, 0x6b, 0xab, 0x10, 0x60 }}
+
+ ## GUID used to "PhysicalPresence" variable and "PhysicalPresenceFlags" variable for TPM request and response.
+ # Include/Guid/PhysicalPresenceData.h
+ gEfiPhysicalPresenceGuid = { 0xf6499b1, 0xe9ad, 0x493d, { 0xb9, 0xc2, 0x2f, 0x90, 0x81, 0x5c, 0x6c, 0xbc }}
+
+ ## GUID used to "Tcg2PhysicalPresence" variable and "Tcg2PhysicalPresenceFlags" variable for TPM2 request and response.
+ # Include/Guid/Tcg2PhysicalPresenceData.h
+ gEfiTcg2PhysicalPresenceGuid = { 0xaeb9c5c1, 0x94f1, 0x4d02, { 0xbf, 0xd9, 0x46, 0x2, 0xdb, 0x2d, 0x3c, 0x54 }}
+
+ ## GUID used for form browser, password credential and provider identifier.
+ # Include/Guid/PwdCredentialProviderHii.h
+ gPwdCredentialProviderGuid = { 0x78b9ec8b, 0xc000, 0x46c5, { 0xac, 0x93, 0x24, 0xa0, 0xc1, 0xbb, 0x0, 0xce }}
+
+ ## GUID used for form browser, USB credential and provider identifier.
+ # Include/Guid/UsbCredentialProviderHii.h
+ gUsbCredentialProviderGuid = { 0xd0849ed1, 0xa88c, 0x4ba6, { 0xb1, 0xd6, 0xab, 0x50, 0xe2, 0x80, 0xb7, 0xa9 }}
+
+ ## GUID used for FormSet guid and user profile variable.
+ # Include/Guid/UserIdentifyManagerHii.h
+ gUserIdentifyManagerGuid = { 0x3ccd3dd8, 0x8d45, 0x4fed, { 0x96, 0x2d, 0x2b, 0x38, 0xcd, 0x82, 0xb3, 0xc4 }}
+
+ ## GUID used for FormSet.
+ # Include/Guid/UserProfileManagerHii.h
+ gUserProfileManagerGuid = { 0xc35f272c, 0x97c2, 0x465a, { 0xa2, 0x16, 0x69, 0x6b, 0x66, 0x8a, 0x8c, 0xfe }}
+
+ ## GUID used for FormSet.
+ # Include/Guid/TcgConfigHii.h
+ gTcgConfigFormSetGuid = { 0xb0f901e4, 0xc424, 0x45de, { 0x90, 0x81, 0x95, 0xe2, 0xb, 0xde, 0x6f, 0xb5 }}
+
+ ## GUID used for FormSet and config variable.
+ # Include/Guid/Tcg2ConfigHii.h
+ gTcg2ConfigFormSetGuid = {0x6339d487, 0x26ba, 0x424b, { 0x9a, 0x5d, 0x68, 0x7e, 0x25, 0xd7, 0x40, 0xbc }}
+
+ ## GUID used for FormSet.
+ # Include/Guid/SecureBootConfigHii.h
+ gSecureBootConfigFormSetGuid = { 0x5daf50a5, 0xea81, 0x4de2, {0x8f, 0x9b, 0xca, 0xbd, 0xa9, 0xcf, 0x5c, 0x14}}
+
+ ## GUID used to "TrEEPhysicalPresence" variable and "TrEEPhysicalPresenceFlags" variable for TPM2 request and response.
+ # Include/Guid/TrEEPhysicalPresenceData.h
+ gEfiTrEEPhysicalPresenceGuid = { 0xf24643c2, 0xc622, 0x494e, { 0x8a, 0xd, 0x46, 0x32, 0x57, 0x9c, 0x2d, 0x5b }}
+
+ ## GUID value used for PcdTpmInstanceGuid to indicate TPM is disabled.
+ # Include/Guid/TpmInstance.h
+ gEfiTpmDeviceInstanceNoneGuid = { 0x00000000, 0x0000, 0x0000, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }
+
+ ## GUID value used for PcdTpmInstanceGuid to indicate TPM 1.2 device is selected to support.
+ # Include/Guid/TpmInstance.h
+ gEfiTpmDeviceInstanceTpm12Guid = { 0x8b01e5b6, 0x4f19, 0x46e8, { 0xab, 0x93, 0x1c, 0x53, 0x67, 0x1b, 0x90, 0xcc } }
+
+ ## GUID value used for PcdTpmInstanceGuid to indicate discrete TPM 2.0 device is selected to support.
+ # Include/Guid/TpmInstance.h
+ gEfiTpmDeviceInstanceTpm20DtpmGuid = { 0x286bf25a, 0xc2c3, 0x408c, { 0xb3, 0xb4, 0x25, 0xe6, 0x75, 0x8b, 0x73, 0x17 } }
+
+ ## GUID used to select supported TPM instance from UI.
+ # Include/Guid/TpmInstance.h
+ gEfiTpmDeviceSelectedGuid = { 0x7f4158d3, 0x74d, 0x456d, { 0x8c, 0xb2, 0x1, 0xf9, 0xc8, 0xf7, 0x9d, 0xaa } }
+
+ ## GUID used for FormSet and config variable.
+ # Include/Guid/TrEEConfigHii.h
+ gTrEEConfigFormSetGuid = {0xc54b425f, 0xaa79, 0x48b4, { 0x98, 0x1f, 0x99, 0x8b, 0x3c, 0x4b, 0x64, 0x1c }}
+
+ ## Include/OpalPasswordExtraInfoVariable.h
+ gOpalExtraInfoVariableGuid = {0x44a2ad5d, 0x612c, 0x47b3, {0xb0, 0x6e, 0xc8, 0xf5, 0x0b, 0xfb, 0xf0, 0x7d}}
+
+
+[Ppis]
+ ## The PPI GUID for that TPM physical presence should be locked.
+ # Include/Ppi/LockPhysicalPresence.h
+ gPeiLockPhysicalPresencePpiGuid = { 0xef9aefe5, 0x2bd3, 0x4031, { 0xaf, 0x7d, 0x5e, 0xfe, 0x5a, 0xbb, 0x9a, 0xd } }
+
+ ## The PPI GUID for that TPM is initialized.
+ # Include/Ppi/TpmInitialized.h
+ gPeiTpmInitializedPpiGuid = { 0xe9db0d58, 0xd48d, 0x47f6, { 0x9c, 0x6e, 0x6f, 0x40, 0xe8, 0x6c, 0x7b, 0x41 }}
+
+ ## The PPI GUID for that TPM initialization is done. TPM initialization may be success or fail.
+ # Include/Ppi/TpmInitialized.h
+ gPeiTpmInitializationDonePpiGuid = { 0xa030d115, 0x54dd, 0x447b, { 0x90, 0x64, 0xf2, 0x6, 0x88, 0x3d, 0x7c, 0xcc }}
+
+ ## Include/Ppi/FirmwareVolumeInfoMeasurementExcluded.h
+ gEfiPeiFirmwareVolumeInfoMeasurementExcludedPpiGuid = { 0x6e056ff9, 0xc695, 0x4364, { 0x9e, 0x2c, 0x61, 0x26, 0xf5, 0xce, 0xea, 0xae } }
+
+#
+# [Error.gEfiSecurityPkgTokenSpaceGuid]
+# 0x80000001 | Invalid value provided.
+# 0x80000002 | Reserved bits must be set to zero.
+# 0x80000003 | Incorrect progress or error code provided.
+#
+
+[PcdsFixedAtBuild, PcdsPatchableInModule]
+ ## Image verification policy for OptionRom. Only following values are valid:<BR><BR>
+ # NOTE: Do NOT use 0x5 and 0x2 since it violates the UEFI specification and has been removed.<BR>
+ # 0x00000000 Always trust the image.<BR>
+ # 0x00000001 Never trust the image.<BR>
+ # 0x00000002 Allow execution when there is security violation.<BR>
+ # 0x00000003 Defer execution when there is security violation.<BR>
+ # 0x00000004 Deny execution when there is security violation.<BR>
+ # 0x00000005 Query user when there is security violation.<BR>
+ # @Prompt Set policy for the image from OptionRom.
+ # @ValidRange 0x80000001 | 0x00000000 - 0x00000005
+ gEfiSecurityPkgTokenSpaceGuid.PcdOptionRomImageVerificationPolicy|0x04|UINT32|0x00000001
+
+ ## Image verification policy for removable media which includes CD-ROM, Floppy, USB and network.
+ # Only following values are valid:<BR><BR>
+ # NOTE: Do NOT use 0x5 and 0x2 since it violates the UEFI specification and has been removed.<BR>
+ # 0x00000000 Always trust the image.<BR>
+ # 0x00000001 Never trust the image.<BR>
+ # 0x00000002 Allow execution when there is security violation.<BR>
+ # 0x00000003 Defer execution when there is security violation.<BR>
+ # 0x00000004 Deny execution when there is security violation.<BR>
+ # 0x00000005 Query user when there is security violation.<BR>
+ # @Prompt Set policy for the image from removable media.
+ # @ValidRange 0x80000001 | 0x00000000 - 0x00000005
+ gEfiSecurityPkgTokenSpaceGuid.PcdRemovableMediaImageVerificationPolicy|0x04|UINT32|0x00000002
+
+ ## Image verification policy for fixed media which includes hard disk.
+ # Only following values are valid:<BR><BR>
+ # NOTE: Do NOT use 0x5 and 0x2 since it violates the UEFI specification and has been removed.<BR>
+ # 0x00000000 Always trust the image.<BR>
+ # 0x00000001 Never trust the image.<BR>
+ # 0x00000002 Allow execution when there is security violation.<BR>
+ # 0x00000003 Defer execution when there is security violation.<BR>
+ # 0x00000004 Deny execution when there is security violation.<BR>
+ # 0x00000005 Query user when there is security violation.<BR>
+ # @Prompt Set policy for the image from fixed media.
+ # @ValidRange 0x80000001 | 0x00000000 - 0x00000005
+ gEfiSecurityPkgTokenSpaceGuid.PcdFixedMediaImageVerificationPolicy|0x04|UINT32|0x00000003
+
+ ## Defer Image Load policy settings. The policy is bitwise.
+ # If a bit is set, the image from corresponding device will be trusted when loading. Or
+ # the image will be deferred. The deferred image will be checked after user is identified.<BR><BR>
+ # BIT0 - Image from unknown device. <BR>
+ # BIT1 - Image from firmware volume.<BR>
+ # BIT2 - Image from OptionRom.<BR>
+ # BIT3 - Image from removable media which includes CD-ROM, Floppy, USB and network.<BR>
+ # BIT4 - Image from fixed media device which includes hard disk.<BR>
+ # @Prompt Set policy whether trust image before user identification.
+ # @ValidRange 0x80000002 | 0x00000000 - 0x0000001F
+ gEfiSecurityPkgTokenSpaceGuid.PcdDeferImageLoadPolicy|0x0000001F|UINT32|0x0000004
+
+ ## Null-terminated Unicode string of the file name that is the default name to save USB credential.
+ # The specified file should be saved at the root directory of USB storage disk.
+ # @Prompt File name to save credential.
+ 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.
+ # Note: This PCD is not been used.
+ # @Prompt Max variable size for append operation.
+ gEfiSecurityPkgTokenSpaceGuid.PcdMaxAppendVariableSize|0x2000|UINT32|0x30000005
+
+ ## Specifies the type of TCG platform that contains TPM chip.<BR><BR>
+ # If 0, TCG platform type is PC client.<BR>
+ # If 1, TCG platform type is PC server.<BR>
+ # @Prompt Select platform type.
+ # @ValidRange 0x80000001 | 0x00 - 0x1
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpmPlatformClass|0|UINT8|0x00000006
+
+ ## Progress Code for TPM device subclass definitions.<BR><BR>
+ # EFI_PERIPHERAL_TPM = (EFI_PERIPHERAL | 0x000D0000) = 0x010D0000<BR>
+ # @Prompt Status Code for TPM device definitions
+ # @ValidList 0x80000003 | 0x010D0000
+ gEfiSecurityPkgTokenSpaceGuid.PcdStatusCodeSubClassTpmDevice|0x010D0000|UINT32|0x00000007
+
+[PcdsFixedAtBuild, PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx]
+ ## Indicates the presence or absence of the platform operator during firmware booting.
+ # If platform operator is not physical presence during boot. TPM will be locked and the TPM commands
+ # that required operator physical presence can not run.<BR><BR>
+ # TRUE - The platform operator is physically present.<BR>
+ # FALSE - The platform operator is not physically present.<BR>
+ # @Prompt Physical presence of the platform operator.
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpmPhysicalPresence|TRUE|BOOLEAN|0x00010001
+
+[PcdsFixedAtBuild, PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx]
+ ## Indicates whether TPM physical presence is locked during platform initialization.
+ # Once it is locked, it can not be unlocked for TPM life time.<BR><BR>
+ # TRUE - Lock TPM physical presence asserting method.<BR>
+ # FALSE - Not lock TPM physical presence asserting method.<BR>
+ # @Prompt Lock TPM physical presence asserting method.
+ gEfiSecurityPkgTokenSpaceGuid.PcdPhysicalPresenceLifetimeLock|FALSE|BOOLEAN|0x00010003
+
+[PcdsFixedAtBuild, PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx]
+ ## Indicates whether the platform supports the software method of asserting physical presence.<BR><BR>
+ # TRUE - Supports the software method of asserting physical presence.<BR>
+ # FALSE - Does not support the software method of asserting physical presence.<BR>
+ # @Prompt Enable software method of asserting physical presence.
+ gEfiSecurityPkgTokenSpaceGuid.PcdPhysicalPresenceCmdEnable|TRUE|BOOLEAN|0x00010004
+
+[PcdsFixedAtBuild, PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx]
+ ## Indicates whether the platform supports the hardware method of asserting physical presence.<BR><BR>
+ # TRUE - Supports the hardware method of asserting physical presence.<BR>
+ # FALSE - Does not support the hardware method of asserting physical presence.<BR>
+ # @Prompt Enable hardware method of asserting physical presence.
+ gEfiSecurityPkgTokenSpaceGuid.PcdPhysicalPresenceHwEnable|TRUE|BOOLEAN|0x00010005
+
+[PcdsFixedAtBuild, PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx]
+ ## This PCD indicates if debugger exists. <BR><BR>
+ # TRUE - Firmware debugger exists.<BR>
+ # FALSE - Firmware debugger doesn't exist.<BR>
+ # @Prompt Firmware debugger status.
+ gEfiSecurityPkgTokenSpaceGuid.PcdFirmwareDebuggerInitialized|FALSE|BOOLEAN|0x00010009
+
+ ## This PCD indicates the initialization policy for TPM 2.0.<BR><BR>
+ # If 0, no initialization needed - most likely used for chipset SRTM solution, in which TPM is already initialized.<BR>
+ # If 1, initialization needed.<BR>
+ # @Prompt TPM 2.0 device initialization policy.<BR>
+ # @ValidRange 0x80000001 | 0x00 - 0x1
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpm2InitializationPolicy|1|UINT8|0x0001000A
+
+ ## This PCD indicates the initialization policy for TPM 1.2.<BR><BR>
+ # If 0, no initialization needed - most likely used for chipset SRTM solution, in which TPM is already initialized.<BR>
+ # If 1, initialization needed.<BR>
+ # @Prompt TPM 1.2 device initialization policy.
+ # @ValidRange 0x80000001 | 0x00 - 0x1
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpmInitializationPolicy|1|UINT8|0x0001000B
+
+ ## This PCD indicates the TPM 2.0 SelfTest policy.<BR><BR>
+ # if 0, no SelfTest needed - most likely used for fTPM, because it might already be tested.<BR>
+ # if 1, SelfTest needed.<BR>
+ # @Prompt TPM 2.0 device selftest.
+ # @ValidRange 0x80000001 | 0x00 - 0x1
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpm2SelfTestPolicy|1|UINT8|0x0001000C
+
+ ## This PCD indicates Static Core Root of Trust for Measurement (SCRTM) policy using TPM 2.0.<BR><BR>
+ # if 0, no SCRTM measurement needed - In this case, it is already done.<BR>
+ # if 1, SCRTM measurement done by BIOS.<BR>
+ # @Prompt SCRTM policy setting for TPM 2.0 device.
+ # @ValidRange 0x80000001 | 0x00 - 0x1
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpm2ScrtmPolicy|1|UINT8|0x0001000D
+
+ ## This PCD indicates Static Core Root of Trust for Measurement (SCRTM) policy using TPM 1.2.<BR><BR>
+ # if 0, no SCRTM measurement needed - In this case, it is already done.<BR>
+ # if 1, SCRTM measurement done by BIOS.<BR>
+ # @Prompt SCRTM policy setting for TPM 1.2 device
+ # @ValidRange 0x80000001 | 0x00 - 0x1
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpmScrtmPolicy|1|UINT8|0x0001000E
+
+ ## Guid name to identify TPM instance.<BR><BR>
+ # TPM_DEVICE_INTERFACE_NONE means disable.<BR>
+ # TPM_DEVICE_INTERFACE_TPM12 means TPM 1.2 DTPM.<BR>
+ # TPM_DEVICE_INTERFACE_DTPM2 means TPM 2.0 DTPM.<BR>
+ # Other GUID value means other TPM 2.0 device.<BR>
+ # @Prompt TPM device type identifier
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpmInstanceGuid |{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }|VOID*|0x0001000F
+
+ ## This PCD indicates if BIOS auto detect TPM1.2 or dTPM2.0.<BR><BR>
+ # FALSE - No auto detection.<BR>
+ # TRUE - Auto detection.<BR>
+ # @Prompt TPM type detection.
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpmAutoDetection|TRUE|BOOLEAN|0x00010011
+
+ ## This PCD indicates TPM base address.<BR><BR>
+ # @Prompt TPM device address.
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpmBaseAddress|0xFED40000|UINT64|0x00010012
+
+ ## This PCR means the OEM configurated number of PCR banks.
+ # 0 means dynamic get from supported HASH algorithm
+ # @Prompt OEM configurated number of PCR banks.
+ gEfiSecurityPkgTokenSpaceGuid.PcdTcg2NumberOfPCRBanks|0x0|UINT32|0x00010015
+
+ ## Provides one or more SHA 256 Hashes of the RSA 2048 public keys used to verify Recovery and Capsule Update images
+ # WARNING: The default value is treated as test key. Please do not use default value in the production.
+ # @Prompt One or more SHA 256 Hashes of RSA 2048 bit public keys used to verify Recovery and Capsule Update images
+ #
+ gEfiSecurityPkgTokenSpaceGuid.PcdRsa2048Sha256PublicKeyBuffer|{0x91, 0x29, 0xc4, 0xbd, 0xea, 0x6d, 0xda, 0xb3, 0xaa, 0x6f, 0x50, 0x16, 0xfc, 0xdb, 0x4b, 0x7e, 0x3c, 0xd6, 0xdc, 0xa4, 0x7a, 0x0e, 0xdd, 0xe6, 0x15, 0x8c, 0x73, 0x96, 0xa2, 0xd4, 0xa6, 0x4d}|VOID*|0x00010013
+
+ ## Provides one PKCS7 cert used to verify Recovery and Capsule Update images
+ # WARNING: The default value is treated as test key. Please do not use default value in the production.
+ # @Prompt One PKCS7 cert used to verify Recovery and Capsule Update images
+ #
+ gEfiSecurityPkgTokenSpaceGuid.PcdPkcs7CertBuffer|{0x30, 0x82, 0x03, 0xec, 0x30, 0x82, 0x02, 0xd4, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x09, 0x00, 0xc0, 0x91, 0xc5, 0xe2, 0xb7, 0x66, 0xc0, 0xf8, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x81, 0x82, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x43, 0x4e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x02, 0x53, 0x48, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x02, 0x53, 0x48, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x09, 0x54, 0x69, 0x61, 0x6e, 0x6f, 0x43, 0x6f, 0x72, 0x65, 0x31, 0x0e, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x05, 0x45, 0x44, 0x4b, 0x49, 0x49, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x08, 0x54, 0x65, 0x73, 0x74, 0x52, 0x6f, 0x6f, 0x74, 0x31, 0x22, 0x30, 0x20, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x13, 0x65, 0x64, 0x6b, 0x69, 0x69, 0x40, 0x74, 0x69, 0x61, 0x6e, 0x6f, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x37, 0x30, 0x34, 0x31, 0x30, 0x30, 0x38, 0x32, 0x37, 0x34, 0x30, 0x5a, 0x17, 0x0d, 0x31, 0x37, 0x30, 0x35, 0x31, 0x30, 0x30, 0x38, 0x32, 0x37, 0x34, 0x30, 0x5a, 0x30, 0x81, 0x82, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x43, 0x4e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x02, 0x53, 0x48, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x02, 0x53, 0x48, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x09, 0x54, 0x69, 0x61, 0x6e, 0x6f, 0x43, 0x6f, 0x72, 0x65, 0x31, 0x0e, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x05, 0x45, 0x44, 0x4b, 0x49, 0x49, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x08, 0x54, 0x65, 0x73, 0x74, 0x52, 0x6f, 0x6f, 0x74, 0x31, 0x22, 0x30, 0x20, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x13, 0x65, 0x64, 0x6b, 0x69, 0x69, 0x40, 0x74, 0x69, 0x61, 0x6e, 0x6f, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xb9, 0x29, 0x29, 0x6c, 0x60, 0x0c, 0xd7, 0x23, 0xf6, 0x7d, 0xee, 0xf0, 0x62, 0xff, 0xd9, 0xc9, 0xaa, 0x55, 0x8c, 0x81, 0x95, 0x56, 0x3f, 0xb7, 0x56, 0x53, 0xb0, 0xc2, 0x82, 0x12, 0xc5, 0x3b, 0x75, 0x23, 0xb9, 0x4d, 0xd6, 0xc4, 0x55, 0x73, 0xf3, 0xaa, 0x95, 0xa8, 0x1b, 0xf3, 0x93, 0x7e, 0x9e, 0x40, 0xe4, 0x1d, 0x22, 0x9c, 0x93, 0x07, 0x0b, 0xd7, 0xaa, 0x5b, 0xd7, 0xe4, 0x1a, 0x21, 0x84, 0xd7, 0x63, 0x59, 0x03, 0x50, 0x1f, 0xf5, 0x14, 0x55, 0x93, 0x91, 0x9b, 0xf5, 0x52, 0xb0, 0xbf, 0x0e, 0x5c, 0x68, 0x3b, 0x59, 0x52, 0x98, 0x96, 0x56, 0xe1, 0xab, 0xc4, 0x43, 0xbb, 0x05, 0x57, 0x78, 0x45, 0x01, 0x9f, 0x58, 0x15, 0x53, 0x0e, 0x11, 0x94, 0x2f, 0x0e, 0xf1, 0xa6, 0x19, 0xa2, 0x6e, 0x86, 0x39, 0x2b, 0x33, 0x8d, 0xc7, 0xc5, 0xeb, 0xee, 0x1e, 0x33, 0xd3, 0x32, 0x94, 0xc1, 0x59, 0xc4, 0x0c, 0x97, 0x0b, 0x12, 0x48, 0x5f, 0x33, 0xf6, 0x60, 0x74, 0x7d, 0x57, 0xc2, 0x13, 0x2d, 0x7d, 0xa9, 0x87, 0xa3, 0x35, 0xea, 0x91, 0x83, 0x3f, 0x67, 0x7a, 0x92, 0x1f, 0x01, 0x53, 0x9f, 0x62, 0x5f, 0x99, 0x12, 0xfd, 0x73, 0x1b, 0x2d, 0x9e, 0x2b, 0x6c, 0x34, 0x49, 0xaf, 0x4f, 0x07, 0x8f, 0xc0, 0xe9, 0x6b, 0x9e, 0x5f, 0x79, 0x35, 0xda, 0x2a, 0x5c, 0x88, 0xee, 0xf6, 0x48, 0x61, 0xda, 0x96, 0xe3, 0x48, 0x46, 0xa0, 0x94, 0x1c, 0x9d, 0xf6, 0x5c, 0x87, 0x0e, 0xef, 0x74, 0x09, 0x91, 0x0d, 0x3d, 0x5a, 0xe7, 0xc5, 0x4c, 0x8a, 0x7a, 0xac, 0xa1, 0x85, 0xb6, 0x67, 0x44, 0x17, 0x55, 0x52, 0x3a, 0xe8, 0x11, 0x4d, 0x58, 0xa2, 0x93, 0x00, 0x62, 0xea, 0x7b, 0x80, 0xed, 0xcf, 0xbd, 0xdf, 0x75, 0x80, 0x4b, 0xb9, 0x65, 0x63, 0xad, 0x0b, 0x4d, 0x74, 0xfa, 0x59, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x63, 0x30, 0x61, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x16, 0xaa, 0xd6, 0x8e, 0x1b, 0x2d, 0x43, 0xf3, 0x2d, 0xb0, 0x24, 0xad, 0x36, 0x65, 0x3f, 0xb2, 0xfa, 0xb1, 0x2c, 0xed, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x16, 0xaa, 0xd6, 0x8e, 0x1b, 0x2d, 0x43, 0xf3, 0x2d, 0xb0, 0x24, 0xad, 0x36, 0x65, 0x3f, 0xb2, 0xfa, 0xb1, 0x2c, 0xed, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x86, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x95, 0xde, 0xdf, 0xa4, 0x14, 0xdb, 0x92, 0x22, 0x78, 0x1a, 0xbd, 0x31, 0x9d, 0x1e, 0xd7, 0x2f, 0x0a, 0x10, 0x11, 0x5d, 0x74, 0x61, 0xe8, 0x30, 0xc4, 0xf3, 0x15, 0xe9, 0x30, 0x54, 0xf4, 0xbb, 0x0c, 0x04, 0x78, 0x13, 0x5d, 0x2c, 0xdd, 0x8c, 0x92, 0x90, 0xd1, 0x9c, 0xd0, 0xd0, 0x18, 0xa3, 0xa3, 0xfc, 0x8c, 0x28, 0x5a, 0xd4, 0x91, 0x4d, 0x08, 0xc3, 0xf6, 0x1a, 0xc8, 0xdd, 0xa6, 0x08, 0x58, 0xe2, 0x15, 0x95, 0xfb, 0x2d, 0x2d, 0x8a, 0xb1, 0x30, 0x80, 0xbd, 0x9a, 0xb6, 0xe1, 0x2c, 0x20, 0x3e, 0xdd, 0xc4, 0xc7, 0x55, 0x65, 0xcf, 0x28, 0x17, 0xf4, 0xee, 0xda, 0xbe, 0x77, 0x70, 0xd5, 0x52, 0xd6, 0x15, 0x7a, 0xfb, 0xad, 0xaf, 0xfd, 0xd5, 0x45, 0x90, 0x5a, 0xe6, 0x31, 0x42, 0xd7, 0x84, 0xb3, 0x49, 0x56, 0x6a, 0xd3, 0x47, 0xf3, 0xbf, 0x68, 0x60, 0x8b, 0x0f, 0xe2, 0xaf, 0xf4, 0xe3, 0xec, 0x12, 0xb9, 0xe2, 0x3a, 0x16, 0x11, 0x4e, 0x4d, 0x73, 0x79, 0xaf, 0x47, 0x85, 0x4c, 0x76, 0x26, 0x9e, 0x8b, 0x32, 0xc0, 0x8e, 0xc2, 0xdc, 0x27, 0xa6, 0xef, 0xac, 0x93, 0x9e, 0xa1, 0x5e, 0xcf, 0x34, 0x45, 0xe0, 0x2a, 0xc7, 0x9d, 0x4d, 0xd7, 0xd7, 0x37, 0x72, 0x97, 0xf8, 0x58, 0xf9, 0xb6, 0x35, 0x48, 0xf1, 0xd1, 0x0a, 0x72, 0x7f, 0xfd, 0x4d, 0x7c, 0xe9, 0xcc, 0xd8, 0x48, 0x1b, 0x49, 0x52, 0x53, 0xde, 0x51, 0x01, 0x53, 0x35, 0xbc, 0x90, 0xcd, 0x8c, 0x8a, 0xcc, 0x43, 0x20, 0xa7, 0x45, 0xff, 0x2b, 0x55, 0xb0, 0x8b, 0x2d, 0xff, 0x55, 0x15, 0x4b, 0x84, 0xd0, 0xc3, 0xd3, 0x90, 0x9c, 0x94, 0x4b, 0x55, 0xd5, 0x62, 0xea, 0x22, 0xab, 0x62, 0x68, 0xdd, 0x53, 0xc6, 0xdc, 0xa5, 0xdd, 0x9a, 0x2d, 0x8e, 0x79, 0x7c, 0x2e, 0x9c, 0xe4, 0x66, 0x80, 0x8c, 0x1d}|VOID*|0x00010014
+
+ ## This PCD defines minimum length(in bytes) of the system preboot TCG event log area(LAML).
+ # For PC Client Implementation spec up to and including 1.2 the minimum log size is 64KB.
+ # @Prompt Minimum length(in bytes) of the system preboot TCG event log area(LAML).
+ gEfiSecurityPkgTokenSpaceGuid.PcdTcgLogAreaMinLen|0x10000|UINT32|0x00010017
+
+ ## This PCD defines length(in bytes) of the TCG2 Final event log area.
+ # @Prompt Length(in bytes) of the TCG2 Final event log area.
+ gEfiSecurityPkgTokenSpaceGuid.PcdTcg2FinalLogAreaLen|0x8000|UINT32|0x00010018
+
+ ## Null-terminated string of the Version of Physical Presence interface supported by platform.<BR><BR>
+ # To support configuring from setup page, this PCD can be DynamicHii type and map to a setup option.<BR>
+ # For example, map to TCG2_VERSION.PpiVersion to be configured by Tcg2ConfigDxe driver.<BR>
+ # gEfiSecurityPkgTokenSpaceGuid.PcdTcgPhysicalPresenceInterfaceVer|L"TCG2_VERSION"|gTcg2ConfigFormSetGuid|0x0|"1.3"|NV,BS<BR>
+ # @Prompt Version of Physical Presence interface supported by platform.
+ gEfiSecurityPkgTokenSpaceGuid.PcdTcgPhysicalPresenceInterfaceVer|"1.3"|VOID*|0x00000008
+
+ ## Indicate whether a physical presence user exist.
+ # When it is configured to Dynamic or DynamicEx, it can be set through detection using
+ # a platform-specific method (e.g. Button pressed) in a actual platform in early boot phase.<BR><BR>
+ # @Prompt A physical presence user status
+ gEfiSecurityPkgTokenSpaceGuid.PcdUserPhysicalPresence|FALSE|BOOLEAN|0x00010019
+
+ ## Indicate the TPM2 ACPI table revision. Rev 4 is defined in TCG ACPI Specification Rev 00.37.<BR><BR>
+ # To support configuring from setup page, this PCD can be DynamicHii type and map to a setup option.<BR>
+ # For example, map to TCG2_VERSION.Tpm2AcpiTableRev to be configured by Tcg2ConfigDxe driver.<BR>
+ # gEfiSecurityPkgTokenSpaceGuid.PcdTpm2AcpiTableRev|L"TCG2_VERSION"|gTcg2ConfigFormSetGuid|0x8|3|NV,BS<BR>
+ # @Prompt Revision of TPM2 ACPI table.
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpm2AcpiTableRev|3|UINT8|0x0001001A
+
+ ## This PCD defines initial setting of TCG2 Persistent Firmware Management Flags
+ # PCD can be configured for different settings in different scenarios
+ # Default setting is TCG2_BIOS_TPM_MANAGEMENT_FLAG_DEFAULT | TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_DEFAULT
+ # @Prompt Initial setting of TCG2 Persistent Firmware Management Flags
+ gEfiSecurityPkgTokenSpaceGuid.PcdTcg2PhysicalPresenceFlags|0x300E2|UINT32|0x0001001B
+
+[PcdsDynamic, PcdsDynamicEx]
+
+ ## This PCD indicates Hash mask for TPM 2.0.<BR><BR>
+ # If this bit is set, that means this algorithm is needed to extend to PCR.<BR>
+ # If this bit is clear, that means this algorithm is NOT needed to extend to PCR.<BR>
+ # BIT0 - SHA1.<BR>
+ # BIT1 - SHA256.<BR>
+ # BIT2 - SHA384.<BR>
+ # BIT3 - SHA512.<BR>
+ # @Prompt Hash mask for TPM 2.0
+ # @ValidRange 0x80000001 | 0x00000000 - 0x0000000F
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpm2HashMask|0x0000000F|UINT32|0x00010010
+
+ ## This PCD indicated final BIOS supported Hash mask.
+ # Bios may choose to register a subset of PcdTpm2HashMask.
+ # So this PCD is final value of how many hash algo is extended to PCR.
+ # If software HashLib(HashLibBaseCryptoRouter) solution is chosen, this PCD
+ # has no need to be configured in platform dsc and will be set to correct
+ # value by the HashLib instance according to the HashInstanceLib instances
+ # linked, and the value of this PCD should be got in module entrypoint.
+ # @Prompt Hash Algorithm bitmap.
+ gEfiSecurityPkgTokenSpaceGuid.PcdTcg2HashAlgorithmBitmap|0xFFFFFFFF|UINT32|0x00010016
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ SecurityPkgExtra.uni
diff --git a/Core/SecurityPkg/SecurityPkg.dsc b/Core/SecurityPkg/SecurityPkg.dsc
new file mode 100644
index 0000000000..dee92411d6
--- /dev/null
+++ b/Core/SecurityPkg/SecurityPkg.dsc
@@ -0,0 +1,338 @@
+## @file
+# Security Module Package for All Architectures.
+#
+# Copyright (c) 2009 - 2017, Intel Corporation. All rights reserved.<BR>
+# (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ PLATFORM_NAME = SecurityPkg
+ PLATFORM_GUID = B2C4614D-AE76-47ba-B876-5988BFED064F
+ PLATFORM_VERSION = 0.96
+ DSC_SPECIFICATION = 0x00010005
+ OUTPUT_DIRECTORY = Build/SecurityPkg
+ SUPPORTED_ARCHITECTURES = IA32|IPF|X64|EBC
+ BUILD_TARGETS = DEBUG|RELEASE|NOOPT
+ 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
+ PerformanceLib|MdePkg/Library/BasePerformanceLibNull/BasePerformanceLibNull.inf
+ PeCoffLib|MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf
+ PeCoffExtraActionLib|MdePkg/Library/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull.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
+ ReportStatusCodeLib|MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf
+ OemHookStatusCodeLib|MdeModulePkg/Library/OemHookStatusCodeLibNull/OemHookStatusCodeLibNull.inf
+ HiiLib|MdeModulePkg/Library/UefiHiiLib/UefiHiiLib.inf
+ UefiHiiServicesLib|MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.inf
+ PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.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
+ TcgPhysicalPresenceLib|SecurityPkg/Library/DxeTcgPhysicalPresenceLib/DxeTcgPhysicalPresenceLib.inf
+ TpmMeasurementLib|SecurityPkg/Library/DxeTpmMeasurementLib/DxeTpmMeasurementLib.inf
+ Tpm12CommandLib|SecurityPkg/Library/Tpm12CommandLib/Tpm12CommandLib.inf
+ Tpm2CommandLib|SecurityPkg/Library/Tpm2CommandLib/Tpm2CommandLib.inf
+ Tcg2PhysicalPresenceLib|SecurityPkg/Library/DxeTcg2PhysicalPresenceLib/DxeTcg2PhysicalPresenceLib.inf
+ TrEEPhysicalPresenceLib|SecurityPkg/Library/DxeTrEEPhysicalPresenceLib/DxeTrEEPhysicalPresenceLib.inf
+ TcgPpVendorLib|SecurityPkg/Library/TcgPpVendorLibNull/TcgPpVendorLibNull.inf
+ Tcg2PpVendorLib|SecurityPkg/Library/Tcg2PpVendorLibNull/Tcg2PpVendorLibNull.inf
+ TrEEPpVendorLib|SecurityPkg/Library/TrEEPpVendorLibNull/TrEEPpVendorLibNull.inf
+ RngLib|MdePkg/Library/BaseRngLib/BaseRngLib.inf
+ PciLib|MdePkg/Library/BasePciLibPciExpress/BasePciLibPciExpress.inf
+ PciSegmentLib|MdePkg/Library/BasePciSegmentLibPci/BasePciSegmentLibPci.inf
+ S3BootScriptLib|MdeModulePkg/Library/PiDxeS3BootScriptLib/DxeS3BootScriptLib.inf
+ SmbusLib|MdePkg/Library/BaseSmbusLibNull/BaseSmbusLibNull.inf
+ LockBoxLib|MdeModulePkg/Library/LockBoxNullLib/LockBoxNullLib.inf
+ PciExpressLib|MdePkg/Library/BasePciExpressLib/BasePciExpressLib.inf
+ TcgStorageCoreLib|SecurityPkg/Library/TcgStorageCoreLib/TcgStorageCoreLib.inf
+ TcgStorageOpalLib|SecurityPkg/Library/TcgStorageOpalLib/TcgStorageOpalLib.inf
+ OpalPasswordSupportLib|SecurityPkg/Library/OpalPasswordSupportLib/OpalPasswordSupportLib.inf
+ ResetSystemLib|MdeModulePkg/Library/BaseResetSystemLibNull/BaseResetSystemLibNull.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
+ BaseCryptLib|CryptoPkg/Library/BaseCryptLib/PeiCryptLib.inf
+ HashLib|SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterPei.inf
+ ReportStatusCodeLib|MdeModulePkg/Library/PeiReportStatusCodeLib/PeiReportStatusCodeLib.inf
+ Tpm12DeviceLib|SecurityPkg/Library/Tpm12DeviceLibDTpm/Tpm12DeviceLibDTpm.inf
+ Tpm2DeviceLib|SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2DeviceLibDTpm.inf
+ Tcg2PhysicalPresenceLib|SecurityPkg/Library/PeiTcg2PhysicalPresenceLib/PeiTcg2PhysicalPresenceLib.inf
+ RngLib|MdePkg/Library/BaseRngLib/BaseRngLib.inf
+
+[LibraryClasses.common.DXE_DRIVER]
+ HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf
+ ReportStatusCodeLib|MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf
+ BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf
+ HashLib|SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterDxe.inf
+ Tpm12DeviceLib|SecurityPkg/Library/Tpm12DeviceLibTcg/Tpm12DeviceLibTcg.inf
+ Tpm2DeviceLib|SecurityPkg/Library/Tpm2DeviceLibTcg2/Tpm2DeviceLibTcg2.inf
+ FileExplorerLib|MdeModulePkg/Library/FileExplorerLib/FileExplorerLib.inf
+
+[LibraryClasses.common.UEFI_DRIVER, LibraryClasses.common.DXE_RUNTIME_DRIVER, LibraryClasses.common.DXE_SAL_DRIVER,]
+ HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf
+ DebugLib|MdePkg/Library/UefiDebugLibConOut/UefiDebugLibConOut.inf
+ HashLib|SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterDxe.inf
+ Tpm12DeviceLib|SecurityPkg/Library/Tpm12DeviceLibTcg/Tpm12DeviceLibTcg.inf
+ Tpm2DeviceLib|SecurityPkg/Library/Tpm2DeviceLibTcg2/Tpm2DeviceLibTcg2.inf
+
+[LibraryClasses.common.DXE_RUNTIME_DRIVER]
+ ReportStatusCodeLib|MdeModulePkg/Library/RuntimeDxeReportStatusCodeLib/RuntimeDxeReportStatusCodeLib.inf
+ BaseCryptLib|CryptoPkg/Library/BaseCryptLib/RuntimeCryptLib.inf
+ HashLib|SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterDxe.inf
+ Tpm12DeviceLib|SecurityPkg/Library/Tpm12DeviceLibTcg/Tpm12DeviceLibTcg.inf
+ Tpm2DeviceLib|SecurityPkg/Library/Tpm2DeviceLibTcg2/Tpm2DeviceLibTcg2.inf
+
+[LibraryClasses.common.UEFI_DRIVER, LibraryClasses.common.UEFI_APPLICATION]
+ BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf
+ HashLib|SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterDxe.inf
+ Tpm12DeviceLib|SecurityPkg/Library/Tpm12DeviceLibTcg/Tpm12DeviceLibTcg.inf
+ Tpm2DeviceLib|SecurityPkg/Library/Tpm2DeviceLibTcg2/Tpm2DeviceLibTcg2.inf
+
+[LibraryClasses.IPF.DXE_SAL_DRIVER]
+ ExtendedSalLib|MdePkg/Library/DxeRuntimeExtendedSalLib/DxeRuntimeExtendedSalLib.inf
+ BaseCryptLib|CryptoPkg/Library/BaseCryptLibRuntimeCryptProtocol/BaseCryptLibRuntimeCryptProtocol.inf
+ HashLib|SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterDxe.inf
+ Tpm12DeviceLib|SecurityPkg/Library/Tpm12DeviceLibTcg/Tpm12DeviceLibTcg.inf
+ Tpm2DeviceLib|SecurityPkg/Library/Tpm2DeviceLibTcg2/Tpm2DeviceLibTcg2.inf
+
+[LibraryClasses.common.DXE_SMM_DRIVER]
+ HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf
+ SmmServicesTableLib|MdePkg/Library/SmmServicesTableLib/SmmServicesTableLib.inf
+ MemoryAllocationLib|MdePkg/Library/SmmMemoryAllocationLib/SmmMemoryAllocationLib.inf
+ ReportStatusCodeLib|MdeModulePkg/Library/SmmReportStatusCodeLib/SmmReportStatusCodeLib.inf
+ SmmMemLib|MdePkg/Library/SmmMemLib/SmmMemLib.inf
+ BaseCryptLib|CryptoPkg/Library/BaseCryptLib/SmmCryptLib.inf
+ Tpm12DeviceLib|SecurityPkg/Library/Tpm12DeviceLibTcg/Tpm12DeviceLibTcg.inf
+ Tpm2DeviceLib|SecurityPkg/Library/Tpm2DeviceLibTcg2/Tpm2DeviceLibTcg2.inf
+ Tcg2PhysicalPresenceLib|SecurityPkg/Library/SmmTcg2PhysicalPresenceLib/SmmTcg2PhysicalPresenceLib.inf
+
+[PcdsDynamicDefault.common.DEFAULT]
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpmInstanceGuid|{0xb6, 0xe5, 0x01, 0x8b, 0x19, 0x4f, 0xe8, 0x46, 0xab, 0x93, 0x1c, 0x53, 0x67, 0x1b, 0x90, 0xcc}
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpm2InitializationPolicy|1
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpm2SelfTestPolicy|1
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpm2ScrtmPolicy|1
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpmInitializationPolicy|1
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpmScrtmPolicy|1
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpm2HashMask|3
+ gEfiSecurityPkgTokenSpaceGuid.PcdTcg2HashAlgorithmBitmap|3
+
+[PcdsDynamicHii.common.DEFAULT]
+ gEfiSecurityPkgTokenSpaceGuid.PcdTcgPhysicalPresenceInterfaceVer|L"TCG2_VERSION"|gTcg2ConfigFormSetGuid|0x0|"1.3"|NV,BS
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpm2AcpiTableRev|L"TCG2_VERSION"|gTcg2ConfigFormSetGuid|0x8|3|NV,BS
+
+[Components]
+ SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.inf
+ #SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.inf
+ SecurityPkg/Library/DxeImageAuthenticationStatusLib/DxeImageAuthenticationStatusLib.inf
+ #SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManagerDxe.inf
+ #SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManagerDxe.inf
+
+ #
+ # Application
+ #
+ SecurityPkg/Application/RngTest/RngTest.inf
+
+ #
+ # TPM
+ #
+ SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.inf
+ SecurityPkg/Library/TpmCommLib/TpmCommLib.inf
+ SecurityPkg/Library/DxeTcgPhysicalPresenceLib/DxeTcgPhysicalPresenceLib.inf
+ SecurityPkg/Library/Tpm12CommandLib/Tpm12CommandLib.inf
+ SecurityPkg/Library/Tpm12DeviceLibDTpm/Tpm12DeviceLibDTpm.inf
+ SecurityPkg/Library/Tpm12DeviceLibTcg/Tpm12DeviceLibTcg.inf
+
+ SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePei.inf
+ SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.inf
+
+ #
+ # TPM2
+ #
+ SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.inf
+ SecurityPkg/Library/DxeTcg2PhysicalPresenceLib/DxeTcg2PhysicalPresenceLib.inf
+ SecurityPkg/Library/PeiTcg2PhysicalPresenceLib/PeiTcg2PhysicalPresenceLib.inf
+ #
+ # TrEE - to be deprecated
+ #
+ SecurityPkg/Library/DxeTrEEPhysicalPresenceLib/DxeTrEEPhysicalPresenceLib.inf
+
+ SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterDxe.inf
+ SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterPei.inf
+
+ SecurityPkg/Library/Tpm2CommandLib/Tpm2CommandLib.inf
+ SecurityPkg/Library/Tpm2DeviceLibTcg2/Tpm2DeviceLibTcg2.inf
+ #
+ # TrEE - to be deprecated
+ #
+ SecurityPkg/Library/Tpm2DeviceLibTrEE/Tpm2DeviceLibTrEE.inf
+ SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2DeviceLibDTpm.inf
+ SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2InstanceLibDTpm.inf
+ SecurityPkg/Library/Tpm2DeviceLibRouter/Tpm2DeviceLibRouterDxe.inf
+ SecurityPkg/Library/Tpm2DeviceLibRouter/Tpm2DeviceLibRouterPei.inf
+
+ SecurityPkg/Library/HashLibTpm2/HashLibTpm2.inf
+
+ #
+ # TCG Storage.
+ #
+ SecurityPkg/Library/TcgStorageCoreLib/TcgStorageCoreLib.inf
+ SecurityPkg/Library/TcgStorageOpalLib/TcgStorageOpalLib.inf
+ SecurityPkg/Library/OpalPasswordSupportLib/OpalPasswordSupportLib.inf
+
+ #
+ # Other
+ #
+ SecurityPkg/Library/DxeRsa2048Sha256GuidedSectionExtractLib/DxeRsa2048Sha256GuidedSectionExtractLib.inf
+ SecurityPkg/Library/PeiRsa2048Sha256GuidedSectionExtractLib/PeiRsa2048Sha256GuidedSectionExtractLib.inf
+
+ SecurityPkg/Library/FmpAuthenticationLibPkcs7/FmpAuthenticationLibPkcs7.inf
+ SecurityPkg/Library/FmpAuthenticationLibRsa2048Sha256/FmpAuthenticationLibRsa2048Sha256.inf
+
+ SecurityPkg/Library/AuthVariableLib/AuthVariableLib.inf
+
+[Components.IA32, Components.X64, Components.IPF]
+# SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderDxe.inf
+# SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProviderDxe.inf
+ SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxe.inf
+
+ #
+ # TPM
+ #
+ SecurityPkg/Tcg/TcgPei/TcgPei.inf
+ SecurityPkg/Tcg/TcgDxe/TcgDxe.inf
+ SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDxe.inf {
+ <LibraryClasses>
+ PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf
+ }
+
+ #
+ # TPM2
+ #
+ SecurityPkg/Library/HashInstanceLibSha1/HashInstanceLibSha1.inf
+ SecurityPkg/Library/HashInstanceLibSha256/HashInstanceLibSha256.inf
+
+ SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPei.inf {
+ <LibraryClasses>
+ Tpm12DeviceLib|SecurityPkg/Library/Tpm12DeviceLibDTpm/Tpm12DeviceLibDTpm.inf
+ Tpm2DeviceLib|SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2DeviceLibDTpm.inf
+ }
+ SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.inf {
+ <LibraryClasses>
+ Tpm2DeviceLib|SecurityPkg/Library/Tpm2DeviceLibRouter/Tpm2DeviceLibRouterPei.inf
+ NULL|SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2InstanceLibDTpm.inf
+ NULL|SecurityPkg/Library/HashInstanceLibSha1/HashInstanceLibSha1.inf
+ NULL|SecurityPkg/Library/HashInstanceLibSha256/HashInstanceLibSha256.inf
+ }
+
+ SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.inf {
+ <LibraryClasses>
+ Tpm2DeviceLib|SecurityPkg/Library/Tpm2DeviceLibRouter/Tpm2DeviceLibRouterDxe.inf
+ NULL|SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2InstanceLibDTpm.inf
+ NULL|SecurityPkg/Library/HashInstanceLibSha1/HashInstanceLibSha1.inf
+ NULL|SecurityPkg/Library/HashInstanceLibSha256/HashInstanceLibSha256.inf
+ PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf
+ }
+ SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDxe.inf {
+ <LibraryClasses>
+ Tpm2DeviceLib|SecurityPkg/Library/Tpm2DeviceLibTcg2/Tpm2DeviceLibTcg2.inf
+ }
+
+ #
+ # TrEE - to be deprecated
+ #
+ SecurityPkg/Tcg/TrEEConfig/TrEEConfigPei.inf {
+ <LibraryClasses>
+ Tpm12DeviceLib|SecurityPkg/Library/Tpm12DeviceLibDTpm/Tpm12DeviceLibDTpm.inf
+ Tpm2DeviceLib|SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2DeviceLibDTpm.inf
+ }
+ SecurityPkg/Tcg/TrEEPei/TrEEPei.inf {
+ <LibraryClasses>
+ Tpm2DeviceLib|SecurityPkg/Library/Tpm2DeviceLibRouter/Tpm2DeviceLibRouterPei.inf
+ NULL|SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2InstanceLibDTpm.inf
+ NULL|SecurityPkg/Library/HashInstanceLibSha1/HashInstanceLibSha1.inf
+ NULL|SecurityPkg/Library/HashInstanceLibSha256/HashInstanceLibSha256.inf
+ }
+
+ SecurityPkg/Tcg/TrEEDxe/TrEEDxe.inf {
+ <LibraryClasses>
+ Tpm2DeviceLib|SecurityPkg/Library/Tpm2DeviceLibRouter/Tpm2DeviceLibRouterDxe.inf
+ NULL|SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2InstanceLibDTpm.inf
+ NULL|SecurityPkg/Library/HashInstanceLibSha1/HashInstanceLibSha1.inf
+ NULL|SecurityPkg/Library/HashInstanceLibSha256/HashInstanceLibSha256.inf
+ PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf
+ }
+ SecurityPkg/Tcg/TrEEConfig/TrEEConfigDxe.inf {
+ <LibraryClasses>
+ Tpm2DeviceLib|SecurityPkg/Library/Tpm2DeviceLibTrEE/Tpm2DeviceLibTrEE.inf
+ }
+
+ #
+ # Hash2
+ #
+ SecurityPkg/Hash2DxeCrypto/Hash2DxeCrypto.inf
+
+ #
+ # PKCS7 Verification
+ #
+ SecurityPkg/Pkcs7Verify/Pkcs7VerifyDxe/Pkcs7VerifyDxe.inf
+
+[Components.IA32, Components.X64]
+
+ SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLockSmm.inf
+ SecurityPkg/Tcg/TcgSmm/TcgSmm.inf
+ SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.inf
+ SecurityPkg/Library/SmmTcg2PhysicalPresenceLib/SmmTcg2PhysicalPresenceLib.inf
+ #
+ # TrEE - to be deprecated
+ #
+ SecurityPkg/Tcg/TrEESmm/TrEESmm.inf
+ #
+ # Random Number Generator
+ #
+ SecurityPkg/RandomNumberGenerator/RngDxe/RngDxe.inf
+
+ #
+ # Opal Password solution
+ #
+ SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalPasswordDxe.inf
+ SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalPasswordSmm.inf
+
+[Components.IPF]
+ SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/EsalVariableDxeSal.inf
+
+[BuildOptions]
+ MSFT:*_*_IA32_DLINK_FLAGS = /ALIGN:256
+ INTEL:*_*_IA32_DLINK_FLAGS = /ALIGN:256
+ *_*_*_CC_FLAGS = -D DISABLE_NEW_DEPRECATED_INTERFACES
+
diff --git a/Core/SecurityPkg/SecurityPkg.uni b/Core/SecurityPkg/SecurityPkg.uni
new file mode 100644
index 0000000000..1263516240
--- /dev/null
+++ b/Core/SecurityPkg/SecurityPkg.uni
@@ -0,0 +1,240 @@
+// /** @file
+// Provides security features that conform to TCG/UEFI industry standards
+//
+// The security features include secure boot, measured boot and user identification.
+// It also provides the definitions(including PPIs/PROTOCOLs/GUIDs and library classes)
+// and libraries instances, which are used for those features.
+//
+// Copyright (c) 2009 - 2017, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials are licensed and made available under
+// the terms and conditions of the BSD License which accompanies this distribution.
+// The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+//
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_PACKAGE_ABSTRACT #language en-US "Provides security features that conform to TCG/UEFI industry standards"
+
+#string STR_PACKAGE_DESCRIPTION #language en-US "The security features include secure boot, measured boot and user identification. It also provides the definitions(including PPIs/PROTOCOLs/GUIDs and library classes) and libraries instances, which are used for those features."
+
+
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdOptionRomImageVerificationPolicy_PROMPT #language en-US "Set policy for the image from OptionRom."
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdOptionRomImageVerificationPolicy_HELP #language en-US "Image verification policy for OptionRom. Only following values are valid:<BR><BR>\n"
+ "NOTE: Do NOT use 0x5 and 0x2 since it violates the UEFI specification and has been removed.<BR>\n"
+ "0x00000000 Always trust the image.<BR>\n"
+ "0x00000001 Never trust the image.<BR>\n"
+ "0x00000002 Allow execution when there is security violation.<BR>\n"
+ "0x00000003 Defer execution when there is security violation.<BR>\n"
+ "0x00000004 Deny execution when there is security violation.<BR>\n"
+ "0x00000005 Query user when there is security violation.<BR>"
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_ERR_80000001 #language en-US "Invalid value provided."
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdRemovableMediaImageVerificationPolicy_PROMPT #language en-US "Set policy for the image from removable media."
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdRemovableMediaImageVerificationPolicy_HELP #language en-US "Image verification policy for removable media which includes CD-ROM, Floppy, USB and network. Only following values are valid:<BR><BR>\n"
+ "NOTE: Do NOT use 0x5 and 0x2 since it violates the UEFI specification and has been removed.<BR>\n"
+ "0x00000000 Always trust the image.<BR>\n"
+ "0x00000001 Never trust the image.<BR>\n"
+ "0x00000002 Allow execution when there is security violation.<BR>\n"
+ "0x00000003 Defer execution when there is security violation.<BR>\n"
+ "0x00000004 Deny execution when there is security violation.<BR>\n"
+ "0x00000005 Query user when there is security violation.<BR>"
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdFixedMediaImageVerificationPolicy_PROMPT #language en-US "Set policy for the image from fixed media."
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdFixedMediaImageVerificationPolicy_HELP #language en-US "Image verification policy for fixed media which includes hard disk. Only following values are valid:<BR><BR>\n"
+ "NOTE: Do NOT use 0x5 and 0x2 since it violates the UEFI specification and has been removed.<BR>\n"
+ "0x00000000 Always trust the image.<BR>\n"
+ "0x00000001 Never trust the image.<BR>\n"
+ "0x00000002 Allow execution when there is security violation.<BR>\n"
+ "0x00000003 Defer execution when there is security violation.<BR>\n"
+ "0x00000004 Deny execution when there is security violation.<BR>\n"
+ "0x00000005 Query user when there is security violation.<BR>"
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdDeferImageLoadPolicy_PROMPT #language en-US "Set policy whether trust image before user identification."
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdDeferImageLoadPolicy_HELP #language en-US "Defer Image Load policy settings. The policy is bitwise. If a bit is set, the image from corresponding device will be trusted when loading. Or the image will be deferred. The deferred image will be checked after user is identified.<BR><BR>\n"
+ "BIT0 - Image from unknown device. <BR>\n"
+ "BIT1 - Image from firmware volume.<BR>\n"
+ "BIT2 - Image from OptionRom.<BR>\n"
+ "BIT3 - Image from removable media which includes CD-ROM, Floppy, USB and network.<BR>\n"
+ "BIT4 - Image from fixed media device which includes hard disk.<BR>"
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_ERR_80000002 #language en-US "Reserved bits must be set to zero."
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdFixedUsbCredentialProviderTokenFileName_PROMPT #language en-US "File name to save credential."
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdFixedUsbCredentialProviderTokenFileName_HELP #language en-US "Null-terminated Unicode string of the file name that is the default name to save USB credential. The specified file should be saved at the root directory of USB storage disk."
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdMaxAppendVariableSize_PROMPT #language en-US "Max variable size for append operation."
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdMaxAppendVariableSize_HELP #language en-US "The size of Append variable buffer. This buffer is reserved for runtime use, OS can append data into one existing variable. Note: This PCD is not been used."
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdTpmPlatformClass_PROMPT #language en-US "Select platform type."
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdTpmPlatformClass_HELP #language en-US "Specifies the type of TCG platform that contains TPM chip.<BR><BR>\n"
+ "If 0, TCG platform type is PC client.<BR>\n"
+ "If 1, TCG platform type is PC server.<BR>"
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdTpmPhysicalPresence_PROMPT #language en-US "Physical presence of the platform operator."
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdTpmPhysicalPresence_HELP #language en-US "Indicates the presence or absence of the platform operator during firmware booting. If platform operator is not physical presnece during boot. TPM will be locked and the TPM commands that required operator physical presence can not run.<BR><BR>\n"
+ "TRUE - The platform operator is physically present.<BR>\n"
+ "FALSE - The platform operator is not physically present.<BR>"
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdPhysicalPresenceLifetimeLock_PROMPT #language en-US "Lock TPM physical presence asserting method."
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdPhysicalPresenceLifetimeLock_HELP #language en-US "Indicates whether TPM physical presence is locked during platform initialization. Once it is locked, it can not be unlocked for TPM life time.<BR><BR>\n"
+ "TRUE - Lock TPM physical presence asserting method.<BR>\n"
+ "FALSE - Not lock TPM physical presence asserting method.<BR>"
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdPhysicalPresenceCmdEnable_PROMPT #language en-US "Enable software method of asserting physical presence."
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdPhysicalPresenceCmdEnable_HELP #language en-US "Indicates whether the platform supports the software method of asserting physical presence.<BR><BR>\n"
+ "TRUE - Supports the software method of asserting physical presence.<BR>\n"
+ "FALSE - Does not support the software method of asserting physical presence.<BR>"
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdPhysicalPresenceHwEnable_PROMPT #language en-US "Enable hardware method of asserting physical presence."
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdPhysicalPresenceHwEnable_HELP #language en-US "Indicates whether the platform supports the hardware method of asserting physical presence.<BR><BR>\n"
+ "TRUE - Supports the hardware method of asserting physical presence.<BR>\n"
+ "FALSE - Does not support the hardware method of asserting physical presence.<BR>"
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdFirmwareDebuggerInitialized_PROMPT #language en-US "Firmware debugger status."
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdFirmwareDebuggerInitialized_HELP #language en-US "This PCD indicates if debugger exists. <BR><BR>\n"
+ "TRUE - Firmware debugger exists.<BR>\n"
+ "FALSE - Firmware debugger doesn't exist.<BR>"
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdTpm2InitializationPolicy_PROMPT #language en-US "TPM 2.0 device initialization policy.<BR>"
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdTpm2InitializationPolicy_HELP #language en-US "This PCD indicates the initialization policy for TPM 2.0.<BR><BR>\n"
+ "If 0, no initialization needed - most likely used for chipset SRTM solution, in which TPM is already initialized.<BR>\n"
+ "If 1, initialization needed.<BR>"
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdTpmInitializationPolicy_PROMPT #language en-US "TPM 1.2 device initialization policy."
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdTpmInitializationPolicy_HELP #language en-US "This PCD indicates the initialization policy for TPM 1.2.<BR><BR>\n"
+ "If 0, no initialization needed - most likely used for chipset SRTM solution, in which TPM is already initialized.<BR>\n"
+ "If 1, initialization needed.<BR>"
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdTpm2SelfTestPolicy_PROMPT #language en-US "TPM 2.0 device selftest."
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdTpm2SelfTestPolicy_HELP #language en-US "This PCD indicates the TPM 2.0 SelfTest policy.<BR><BR>\n"
+ "if 0, no SelfTest needed - most likely used for fTPM, because it might already be tested.<BR>\n"
+ "if 1, SelfTest needed.<BR>"
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdTpm2ScrtmPolicy_PROMPT #language en-US "SCRTM policy setting for TPM 2.0 device."
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdTpm2ScrtmPolicy_HELP #language en-US "This PCD indicates Static Core Root of Trust for Measurement (SCRTM) policy using TPM 2.0.<BR><BR>\n"
+ "if 0, no SCRTM measurement needed - In this case, it is already done.<BR>\n"
+ "if 1, SCRTM measurement done by BIOS.<BR>"
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdTpmScrtmPolicy_PROMPT #language en-US "SCRTM policy setting for TPM 1.2 device"
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdTpmScrtmPolicy_HELP #language en-US "This PCD indicates Static Core Root of Trust for Measurement (SCRTM) policy using TPM 1.2.<BR><BR>\n"
+ "if 0, no SCRTM measurement needed - In this case, it is already done.<BR>\n"
+ "if 1, SCRTM measurement done by BIOS.<BR>"
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdTpmInstanceGuid_PROMPT #language en-US "TPM device type identifier"
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdTpmInstanceGuid_HELP #language en-US "Guid name to identify TPM instance.<BR><BR>\n"
+ "TPM_DEVICE_INTERFACE_NONE means disable.<BR>\n"
+ "TPM_DEVICE_INTERFACE_TPM12 means TPM 1.2 DTPM.<BR>\n"
+ "TPM_DEVICE_INTERFACE_DTPM2 means TPM 2.0 DTPM.<BR>\n"
+ "Other GUID value means other TPM 2.0 device.<BR>"
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdTpm2HashMask_PROMPT #language en-US "Hash mask for TPM 2.0"
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdTpm2HashMask_HELP #language en-US "This PCD indicates Hash mask for TPM 2.0.<BR><BR>\n"
+ "If this bit is set, that means this algorithm is needed to extend to PCR.<BR>\n"
+ "If this bit is clear, that means this algorithm is NOT needed to extend to PCR.<BR>\n"
+ "BIT0 - SHA1.<BR>\n"
+ "BIT1 - SHA256.<BR>\n"
+ "BIT2 - SHA384.<BR>\n"
+ "BIT3 - SHA512.<BR>"
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdTpmAutoDetection_PROMPT #language en-US "TPM type detection."
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdTpmAutoDetection_HELP #language en-US "This PCD indicates if BIOS auto detect TPM1.2 or dTPM2.0.<BR><BR>\n"
+ "FALSE - No auto detection.<BR>\n"
+ "TRUE - Auto detection.<BR>"
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdTpmBaseAddress_PROMPT #language en-US "TPM device address."
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdTpmBaseAddress_HELP #language en-US "This PCD indicates TPM base address.<BR><BR>"
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdStatusCodeSubClassTpmDevice_PROMPT #language en-US "Status Code for TPM device definitions"
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdStatusCodeSubClassTpmDevice_HELP #language en-US "Progress Code for TPM device subclass definitions.<BR><BR>\n"
+ "EFI_PERIPHERAL_TPM = (EFI_PERIPHERAL | 0x000D0000) = 0x010D0000<BR>"
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdRsa2048Sha256PublicKeyBuffer_PROMPT #language en-US "One or more SHA 256 Hashes of RSA 2048 bit public keys used to verify Recovery and Capsule Update images"
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdRsa2048Sha256PublicKeyBuffer_HELP #language en-US "Provides one or more SHA 256 Hashes of the RSA 2048 public keys used to verify Recovery and Capsule Update images\n"
+ "WARNING: The default value is treated as test key. Please do not use default value in the production."
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdTcg2NumberOfPCRBanks_PROMPT #language en-US "OEM configurated number of PCR banks."
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdTcg2NumberOfPCRBanks_HELP #language en-US "This PCR means the OEM configurated number of PCR banks.\n"
+ "0 means dynamic get from supported HASH algorithm"
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdTcg2HashAlgorithmBitmap_PROMPT #language en-US "Hash Algorithm bitmap."
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdTcg2HashAlgorithmBitmap_HELP #language en-US "This PCD indicated final BIOS supported Hash mask.\n"
+ "Bios may choose to register a subset of PcdTpm2HashMask.\n"
+ "So this PCD is final value of how many hash algo is extended to PCR.\n"
+ "If software HashLib(HashLibBaseCryptoRouter) solution is chosen, this PCD\n"
+ "has no need to be configured in platform dsc and will be set to correct\n"
+ "value by the HashLib instance according to the HashInstanceLib instances\n"
+ "linked, and the value of this PCD should be got in module entrypoint."
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdTcgLogAreaMinLen_PROMPT #language en-US "Minimum length(in bytes) of the system preboot TCG event log area(LAML)."
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdTcgLogAreaMinLen_HELP #language en-US "This PCD defines minimum length(in bytes) of the system preboot TCG event log area(LAML).\n"
+ "For PC Client Implementation spec up to and including 1.2 the minimum log size is 64KB."
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdTcg2FinalLogAreaLen_PROMPT #language en-US "Length(in bytes) of the TCG2 Final event log area."
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdTcg2FinalLogAreaLen_HELP #language en-US "This PCD defines length(in bytes) of the TCG2 Final event log area."
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdTcgPhysicalPresenceInterfaceVer_PROMPT #language en-US "Version of Physical Presence interface supported by platform."
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdTcgPhysicalPresenceInterfaceVer_HELP #language en-US "Null-terminated string of the Version of Physical Presence interface supported by platform.<BR><BR>\n"
+ "To support configuring from setup page, this PCD can be DynamicHii type and map to a setup option.<BR>\n"
+ "For example, map to TCG2_VERSION.PpiVersion to be configured by Tcg2ConfigDxe driver.<BR>\n"
+ "gEfiSecurityPkgTokenSpaceGuid.PcdTcgPhysicalPresenceInterfaceVer|L\"TCG2_VERSION\"|gTcg2ConfigFormSetGuid|0x0|\"1.3\"|NV,BS<BR>"
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdUserPhysicalPresence_PROMPT
+#language en-US
+"A physical presence user status"
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdUserPhysicalPresence_HELP
+#language en-US
+"Indicate whether a physical presence user exist. "
+"When it is configured to Dynamic or DynamicEx, it can be set through detection using "
+"a platform-specific method (e.g. Button pressed) in a actual platform in early boot phase.<BR><BR>"
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdPkcs7CertBuffer_PROMPT #language en-US "One PKCS7 cert used to verify Recovery and Capsule Update images"
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdPkcs7CertBuffer_HELP #language en-US "Provides one PKCS7 cert used to verify Recovery and Capsule Update images\n"
+ "WARNING: The default value is treated as test key. Please do not use default value in the production."
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdTcg2PhysicalPresenceFlags_PROMPT #language en-US " Initial setting of TCG2 Persistent Firmware Management Flags"
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdTcg2PhysicalPresenceFlags_HELP #language en-US "This PCD defines initial setting of TCG2 Persistent Firmware Management Flags\n"
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdTpm2AcpiTableRev_PROMPT #language en-US "The revision of TPM2 ACPI table"
+
+#string STR_gEfiSecurityPkgTokenSpaceGuid_PcdTpm2AcpiTableRev_HELP #language en-US "This PCD defines initial revision of TPM2 ACPI table\n"
+ "To support configuring from setup page, this PCD can be DynamicHii type and map to a setup option.<BR>\n"
+ "For example, map to TCG2_VERSION.Tpm2AcpiTableRev to be configured by Tcg2ConfigDxe driver.<BR>\n"
+ "gEfiSecurityPkgTokenSpaceGuid.PcdTpm2AcpiTableRev|L\"TCG2_VERSION\"|gTcg2ConfigFormSetGuid|0x8|3|NV,BS<BR>"
diff --git a/Core/SecurityPkg/SecurityPkgExtra.uni b/Core/SecurityPkg/SecurityPkgExtra.uni
new file mode 100644
index 0000000000..d52875dbc6
--- /dev/null
+++ b/Core/SecurityPkg/SecurityPkgExtra.uni
@@ -0,0 +1,19 @@
+// /** @file
+// Security Package Localized Strings and Content.
+//
+// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials are licensed and made available under
+// the terms and conditions of the BSD License which accompanies this distribution.
+// The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+//
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+#string STR_PROPERTIES_PACKAGE_NAME
+#language en-US
+"Security package"
+
diff --git a/Core/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.c b/Core/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.c
new file mode 100644
index 0000000000..e691a084d0
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.c
@@ -0,0 +1,384 @@
+/** @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. It will also do TPer Reset for
+ those encrypted drives through EFI_STORAGE_SECURITY_COMMAND_PROTOCOL at EndOfDxe.
+
+Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "TcgMor.h"
+
+UINT8 mMorControl;
+
+/**
+ 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;
+ UINTN DataSize;
+
+ if (MOR_CLEAR_MEMORY_VALUE (mMorControl) == 0x0) {
+ //
+ // MorControl is expected, directly return to avoid unnecessary variable operation
+ //
+ return ;
+ }
+ //
+ // Clear MOR_CLEAR_MEMORY_BIT
+ //
+ DEBUG ((EFI_D_INFO, "TcgMor: Clear MorClearMemory bit\n"));
+ mMorControl &= 0xFE;
+
+ DataSize = sizeof (mMorControl);
+ Status = gRT->SetVariable (
+ MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,
+ &gEfiMemoryOverwriteControlDataGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ DataSize,
+ &mMorControl
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "TcgMor: Clear MOR_CLEAR_MEMORY_BIT failure, Status = %r\n"));
+ }
+}
+
+/**
+ Send TPer Reset command to reset eDrive to lock all protected bands.
+ Typically, there are 2 mechanism for resetting eDrive. They are:
+ 1. TPer Reset through IEEE 1667 protocol.
+ 2. TPer Reset through native TCG protocol.
+ This routine will detect what protocol the attached eDrive comform to, TCG or
+ IEEE 1667 protocol. Then send out TPer Reset command separately.
+
+ @param[in] Ssp The pointer to EFI_STORAGE_SECURITY_COMMAND_PROTOCOL instance.
+ @param[in] MediaId ID of the medium to receive data from or send data to.
+
+**/
+VOID
+InitiateTPerReset (
+ IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *Ssp,
+ IN UINT32 MediaId
+ )
+{
+
+ EFI_STATUS Status;
+ UINT8 *Buffer;
+ UINTN XferSize;
+ UINTN Len;
+ UINTN Index;
+ BOOLEAN TcgFlag;
+ BOOLEAN IeeeFlag;
+ SUPPORTED_SECURITY_PROTOCOLS_PARAMETER_DATA *Data;
+
+ Buffer = NULL;
+ TcgFlag = FALSE;
+ IeeeFlag = FALSE;
+
+ //
+ // ATA8-ACS 7.57.6.1 indicates the Transfer Length field requirements a multiple of 512.
+ // If the length of the TRUSTED RECEIVE parameter data is greater than the Transfer Length,
+ // then the device shall return the TRUSTED RECEIVE parameter data truncated to the requested Transfer Length.
+ //
+ Len = ROUNDUP512(sizeof(SUPPORTED_SECURITY_PROTOCOLS_PARAMETER_DATA));
+ Buffer = AllocateZeroPool(Len);
+
+ if (Buffer == NULL) {
+ return;
+ }
+
+ //
+ // When the Security Protocol field is set to 00h, and SP Specific is set to 0000h in a TRUSTED RECEIVE
+ // command, the device basic information data shall be returned.
+ //
+ Status = Ssp->ReceiveData (
+ Ssp,
+ MediaId,
+ 100000000, // Timeout 10-sec
+ 0, // SecurityProtocol
+ 0, // SecurityProtocolSpecifcData
+ Len, // PayloadBufferSize,
+ Buffer, // PayloadBuffer
+ &XferSize
+ );
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ //
+ // In returned data, the ListLength field indicates the total length, in bytes,
+ // of the supported security protocol list.
+ //
+ Data = (SUPPORTED_SECURITY_PROTOCOLS_PARAMETER_DATA*)Buffer;
+ Len = ROUNDUP512(sizeof (SUPPORTED_SECURITY_PROTOCOLS_PARAMETER_DATA) +
+ (Data->SupportedSecurityListLength[0] << 8) +
+ (Data->SupportedSecurityListLength[1])
+ );
+
+ //
+ // Free original buffer and allocate new buffer.
+ //
+ FreePool(Buffer);
+ Buffer = AllocateZeroPool(Len);
+ if (Buffer == NULL) {
+ return;
+ }
+
+ //
+ // Read full supported security protocol list from device.
+ //
+ Status = Ssp->ReceiveData (
+ Ssp,
+ MediaId,
+ 100000000, // Timeout 10-sec
+ 0, // SecurityProtocol
+ 0, // SecurityProtocolSpecifcData
+ Len, // PayloadBufferSize,
+ Buffer, // PayloadBuffer
+ &XferSize
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ Data = (SUPPORTED_SECURITY_PROTOCOLS_PARAMETER_DATA*)Buffer;
+ Len = (Data->SupportedSecurityListLength[0] << 8) + Data->SupportedSecurityListLength[1];
+
+ //
+ // Iterate full supported security protocol list to check if TCG or IEEE 1667 protocol
+ // is supported.
+ //
+ for (Index = 0; Index < Len; Index++) {
+ if (Data->SupportedSecurityProtocol[Index] == SECURITY_PROTOCOL_TCG) {
+ //
+ // Found a TCG device.
+ //
+ TcgFlag = TRUE;
+ DEBUG ((EFI_D_INFO, "This device is a TCG protocol device\n"));
+ break;
+ }
+
+ if (Data->SupportedSecurityProtocol[Index] == SECURITY_PROTOCOL_IEEE1667) {
+ //
+ // Found a IEEE 1667 device.
+ //
+ IeeeFlag = TRUE;
+ DEBUG ((EFI_D_INFO, "This device is a IEEE 1667 protocol device\n"));
+ break;
+ }
+ }
+
+ if (!TcgFlag && !IeeeFlag) {
+ DEBUG ((EFI_D_INFO, "Neither a TCG nor IEEE 1667 protocol device is found\n"));
+ goto Exit;
+ }
+
+ if (TcgFlag) {
+ //
+ // As long as TCG protocol is supported, send out a TPer Reset
+ // TCG command to the device via the TrustedSend command with a non-zero Transfer Length.
+ //
+ Status = Ssp->SendData (
+ Ssp,
+ MediaId,
+ 100000000, // Timeout 10-sec
+ SECURITY_PROTOCOL_TCG, // SecurityProtocol
+ 0x0400, // SecurityProtocolSpecifcData
+ 512, // PayloadBufferSize,
+ Buffer // PayloadBuffer
+ );
+
+ if (!EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_INFO, "Send TPer Reset Command Successfully !\n"));
+ } else {
+ DEBUG ((EFI_D_INFO, "Send TPer Reset Command Fail !\n"));
+ }
+ }
+
+ if (IeeeFlag) {
+ //
+ // TBD : Perform a TPer Reset via IEEE 1667 Protocol
+ //
+ DEBUG ((EFI_D_INFO, "IEEE 1667 Protocol didn't support yet!\n"));
+ }
+
+Exit:
+
+ if (Buffer != NULL) {
+ FreePool(Buffer);
+ }
+}
+
+/**
+ Notification function of END_OF_DXE.
+
+ This is a notification function registered on END_OF_DXE event.
+ It is to get VarCheckPcdBin.
+
+ @param[in] Event Event whose notification function is being invoked.
+ @param[in] Context Pointer to the notification function's context.
+
+**/
+VOID
+EFIAPI
+TPerResetAtEndOfDxe (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *Ssp;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ EFI_STATUS Status;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ UINTN Index;
+
+ //
+ // Locate all SSP protocol instances.
+ //
+ HandleCount = 0;
+ HandleBuffer = NULL;
+
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiStorageSecurityCommandProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+
+ if (EFI_ERROR (Status) || (HandleCount == 0) || (HandleBuffer == NULL)) {
+ return;
+ }
+
+ for (Index = 0; Index < HandleCount; Index ++) {
+ //
+ // Get the SSP interface.
+ //
+ Status = gBS->HandleProtocol(
+ HandleBuffer[Index],
+ &gEfiStorageSecurityCommandProtocolGuid,
+ (VOID **) &Ssp
+ );
+
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ Status = gBS->HandleProtocol(
+ HandleBuffer[Index],
+ &gEfiBlockIoProtocolGuid,
+ (VOID **) &BlockIo
+ );
+
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ InitiateTPerReset (Ssp, BlockIo->Media->MediaId);
+ }
+}
+
+/**
+ 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;
+ UINTN DataSize;
+ EFI_EVENT Event;
+
+ ///
+ /// The firmware is required to create the MemoryOverwriteRequestControl UEFI variable.
+ ///
+
+ DataSize = sizeof (mMorControl);
+ Status = gRT->GetVariable (
+ MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,
+ &gEfiMemoryOverwriteControlDataGuid,
+ NULL,
+ &DataSize,
+ &mMorControl
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Set default value to 0
+ //
+ mMorControl = 0;
+ Status = gRT->SetVariable (
+ MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,
+ &gEfiMemoryOverwriteControlDataGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ DataSize,
+ &mMorControl
+ );
+ DEBUG ((EFI_D_INFO, "TcgMor: Create MOR variable! Status = %r\n", Status));
+ } else {
+ //
+ // Create a Ready To Boot Event and Clear the MorControl bit in the call back function.
+ //
+ DEBUG ((EFI_D_INFO, "TcgMor: Create ReadyToBoot Event for MorControl Bit cleanning!\n"));
+ Status = EfiCreateEventReadyToBootEx (
+ TPL_CALLBACK,
+ OnReadyToBoot,
+ NULL,
+ &Event
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Register EFI_END_OF_DXE_EVENT_GROUP_GUID event.
+ //
+ DEBUG ((EFI_D_INFO, "TcgMor: Create EndofDxe Event for Mor TPer Reset!\n"));
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ TPerResetAtEndOfDxe,
+ NULL,
+ &gEfiEndOfDxeEventGroupGuid,
+ &Event
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ return Status;
+}
+
+
diff --git a/Core/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.h b/Core/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.h
new file mode 100644
index 0000000000..a4aae48a5f
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.h
@@ -0,0 +1,48 @@
+/** @file
+ The header file for TcgMor.
+
+Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __TCG_MOR_H__
+#define __TCG_MOR_H__
+
+#include <PiDxe.h>
+
+#include <Guid/MemoryOverwriteControl.h>
+
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+#include <Protocol/StorageSecurityCommand.h>
+#include <Protocol/BlockIo.h>
+
+//
+// Supported Security Protocols List Description.
+// Refer to ATA8-ACS Spec 7.57.6.2 Table 69 or SPC4 7.7.1.3 Table 511.
+//
+typedef struct {
+ UINT8 Reserved1[6];
+ UINT8 SupportedSecurityListLength[2];
+ UINT8 SupportedSecurityProtocol[1];
+} SUPPORTED_SECURITY_PROTOCOLS_PARAMETER_DATA;
+
+#define SECURITY_PROTOCOL_TCG 0x02
+#define SECURITY_PROTOCOL_IEEE1667 0xEE
+
+#define ROUNDUP512(x) (((x) % 512 == 0) ? (x) : ((x) / 512 + 1) * 512)
+
+#endif
+
diff --git a/Core/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.inf b/Core/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.inf
new file mode 100644
index 0000000000..a131342bb6
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.inf
@@ -0,0 +1,67 @@
+## @file
+# Initilizes MemoryOverwriteRequestControl variable
+#
+# This module will clear MOR_CLEAR_MEMORY_BIT bit if it is set. It will also do
+# TPer Reset for those encrypted drives through EFI_STORAGE_SECURITY_COMMAND_PROTOCOL
+# at EndOfDxe.
+#
+# Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = TcgMor
+ MODULE_UNI_FILE = TcgMor.uni
+ 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
+ UefiBootServicesTableLib
+ UefiRuntimeServicesTableLib
+ ReportStatusCodeLib
+ DebugLib
+ UefiLib
+ MemoryAllocationLib
+
+[Guids]
+ ## SOMETIMES_CONSUMES ## Variable:L"MemoryOverwriteRequestControl"
+ ## PRODUCES ## Variable:L"MemoryOverwriteRequestControl"
+ gEfiMemoryOverwriteControlDataGuid
+ gEfiEndOfDxeEventGroupGuid ## SOMETIMES_CONSUMES ## Event
+
+[Protocols]
+ gEfiStorageSecurityCommandProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiBlockIoProtocolGuid ## SOMETIMES_CONSUMES
+
+[Depex]
+ gEfiVariableArchProtocolGuid AND
+ gEfiVariableWriteArchProtocolGuid AND
+ ( gEfiTcgProtocolGuid OR gEfiTcg2ProtocolGuid )
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ TcgMorExtra.uni
diff --git a/Core/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.uni b/Core/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.uni
new file mode 100644
index 0000000000..fc6d92ae98
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.uni
@@ -0,0 +1,21 @@
+// /** @file
+// Initilizes MemoryOverwriteRequestControl variable
+//
+// This module will clear MOR_CLEAR_MEMORY_BIT bit if it is set.
+//
+// Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Initializes the MemoryOverwriteRequestControl variable"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This module will clear MOR_CLEAR_MEMORY_BIT bit if it is set."
+
diff --git a/Core/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMorExtra.uni b/Core/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMorExtra.uni
new file mode 100644
index 0000000000..7278fff4eb
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMorExtra.uni
@@ -0,0 +1,19 @@
+// /** @file
+// TcgMor Localized Strings and Content
+//
+// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"TCG (Trusted Computing Group) MOR"
+
+
diff --git a/Core/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLock.c b/Core/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLock.c
new file mode 100644
index 0000000000..c6f3edc756
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLock.c
@@ -0,0 +1,197 @@
+/** @file
+ TCG MOR (Memory Overwrite Request) Lock Control Driver.
+
+ This driver initilize MemoryOverwriteRequestControlLock variable.
+ This module will add Variable Hook and allow MemoryOverwriteRequestControlLock variable set only once.
+
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiDxe.h>
+#include <Guid/MemoryOverwriteControl.h>
+#include <IndustryStandard/MemoryOverwriteRequestControlLock.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include "TcgMorLock.h"
+
+typedef struct {
+ CHAR16 *VariableName;
+ EFI_GUID *VendorGuid;
+} VARIABLE_TYPE;
+
+VARIABLE_TYPE mMorVariableType[] = {
+ {MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME, &gEfiMemoryOverwriteControlDataGuid},
+ {MEMORY_OVERWRITE_REQUEST_CONTROL_LOCK_NAME, &gEfiMemoryOverwriteRequestControlLockGuid},
+};
+
+/**
+ Returns if this is MOR related variable.
+
+ @param VariableName the name of the vendor's variable, it's a Null-Terminated Unicode String
+ @param VendorGuid Unify identifier for vendor.
+
+ @retval TRUE The variable is MOR related.
+ @retval FALSE The variable is NOT MOR related.
+**/
+BOOLEAN
+IsAnyMorVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < sizeof(mMorVariableType)/sizeof(mMorVariableType[0]); Index++) {
+ if ((StrCmp (VariableName, mMorVariableType[Index].VariableName) == 0) &&
+ (CompareGuid (VendorGuid, mMorVariableType[Index].VendorGuid))) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/**
+ Returns if this is MOR lock variable.
+
+ @param VariableName the name of the vendor's variable, it's a Null-Terminated Unicode String
+ @param VendorGuid Unify identifier for vendor.
+
+ @retval TRUE The variable is MOR lock variable.
+ @retval FALSE The variable is NOT MOR lock variable.
+**/
+BOOLEAN
+IsMorLockVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid
+ )
+{
+ if ((StrCmp (VariableName, MEMORY_OVERWRITE_REQUEST_CONTROL_LOCK_NAME) == 0) &&
+ (CompareGuid (VendorGuid, &gEfiMemoryOverwriteRequestControlLockGuid))) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ This service is a checker handler for the UEFI Runtime Service SetVariable()
+
+ @param VariableName the name of the vendor's variable, as a
+ Null-Terminated Unicode String
+ @param VendorGuid Unify identifier for vendor.
+ @param Attributes Point to memory location to return the attributes of variable. If the point
+ is NULL, the parameter would be ignored.
+ @param DataSize The size in bytes of Data-Buffer.
+ @param Data Point to the content of the variable.
+
+ @retval EFI_SUCCESS The firmware has successfully stored the variable and its data as
+ defined by the Attributes.
+ @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied, or the
+ DataSize exceeds the maximum allowed.
+ @retval EFI_INVALID_PARAMETER VariableName is an empty Unicode string.
+ @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 due to a hardware failure.
+ @retval EFI_WRITE_PROTECTED The variable in question is read-only.
+ @retval EFI_WRITE_PROTECTED The variable in question cannot be deleted.
+ @retval EFI_SECURITY_VIOLATION The variable could not be written due to EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
+ set but the AuthInfo does NOT pass the validation check carried
+ out by the firmware.
+ @retval EFI_NOT_FOUND The variable trying to be updated or deleted was not found.
+
+**/
+EFI_STATUS
+EFIAPI
+SetVariableCheckHandlerMor (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT32 Attributes,
+ IN UINTN DataSize,
+ IN VOID *Data
+ )
+{
+ UINTN MorLockDataSize;
+ BOOLEAN MorLock;
+ EFI_STATUS Status;
+
+ //
+ // do not handle non-MOR variable
+ //
+ if (!IsAnyMorVariable (VariableName, VendorGuid)) {
+ return EFI_SUCCESS;
+ }
+
+ MorLockDataSize = sizeof(MorLock);
+ Status = InternalGetVariable (
+ MEMORY_OVERWRITE_REQUEST_CONTROL_LOCK_NAME,
+ &gEfiMemoryOverwriteRequestControlLockGuid,
+ NULL,
+ &MorLockDataSize,
+ &MorLock
+ );
+ if (!EFI_ERROR (Status) && MorLock) {
+ //
+ // If lock, deny access
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Delete not OK
+ //
+ if ((DataSize != sizeof(UINT8)) || (Data == NULL) || (Attributes == 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // check format
+ //
+ if (IsMorLockVariable(VariableName, VendorGuid)) {
+ //
+ // set to any other value not OK
+ //
+ if ((*(UINT8 *)Data != 1) && (*(UINT8 *)Data != 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ //
+ // Or grant access
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+ Entry Point for MOR Lock 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
+MorLockDriverInit (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Data;
+
+ Data = 0;
+ Status = InternalSetVariable (
+ MEMORY_OVERWRITE_REQUEST_CONTROL_LOCK_NAME,
+ &gEfiMemoryOverwriteRequestControlLockGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ 1,
+ &Data
+ );
+ return Status;
+}
diff --git a/Core/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLock.h b/Core/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLock.h
new file mode 100644
index 0000000000..50a656aeb3
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLock.h
@@ -0,0 +1,137 @@
+/** @file
+ TCG MOR (Memory Overwrite Request) Lock Control Driver header file.
+
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _EFI_TCG_MOR_LOCK_H_
+#define _EFI_TCG_MOR_LOCK_H_
+
+/**
+ This service is a wrapper for the UEFI Runtime Service GetVariable().
+
+ @param VariableName the name of the vendor's variable, it's a Null-Terminated Unicode String
+ @param VendorGuid Unify identifier for vendor.
+ @param Attributes Point to memory location to return the attributes of variable. If the point
+ is NULL, the parameter would be ignored.
+ @param DataSize As input, point to the maximum size of return Data-Buffer.
+ As output, point to the actual size of the returned Data-Buffer.
+ @param Data Point to return Data-Buffer.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_NOT_FOUND The variable was not found.
+ @retval EFI_BUFFER_TOO_SMALL The DataSize is too small for the result. DataSize has
+ been updated with the size needed to complete the request.
+ @retval EFI_INVALID_PARAMETER VariableName is NULL.
+ @retval EFI_INVALID_PARAMETER VendorGuid is NULL.
+ @retval EFI_INVALID_PARAMETER DataSize is NULL.
+ @retval EFI_INVALID_PARAMETER The DataSize is not too small and Data is NULL.
+ @retval EFI_DEVICE_ERROR The variable could not be retrieved due to a hardware error.
+ @retval EFI_SECURITY_VIOLATION The variable could not be retrieved due to an authentication failure.
+**/
+EFI_STATUS
+EFIAPI
+InternalGetVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ OUT UINT32 *Attributes OPTIONAL,
+ IN OUT UINTN *DataSize,
+ OUT VOID *Data
+ );
+
+/**
+ This service is a wrapper for the UEFI Runtime Service SetVariable()
+
+ @param VariableName the name of the vendor's variable, as a
+ Null-Terminated Unicode String
+ @param VendorGuid Unify identifier for vendor.
+ @param Attributes Point to memory location to return the attributes of variable. If the point
+ is NULL, the parameter would be ignored.
+ @param DataSize The size in bytes of Data-Buffer.
+ @param Data Point to the content of the variable.
+
+ @retval EFI_SUCCESS The firmware has successfully stored the variable and its data as
+ defined by the Attributes.
+ @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied, or the
+ DataSize exceeds the maximum allowed.
+ @retval EFI_INVALID_PARAMETER VariableName is an empty Unicode string.
+ @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 due to a hardware failure.
+ @retval EFI_WRITE_PROTECTED The variable in question is read-only.
+ @retval EFI_WRITE_PROTECTED The variable in question cannot be deleted.
+ @retval EFI_SECURITY_VIOLATION The variable could not be written due to EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
+ set but the AuthInfo does NOT pass the validation check carried
+ out by the firmware.
+ @retval EFI_NOT_FOUND The variable trying to be updated or deleted was not found.
+
+**/
+EFI_STATUS
+EFIAPI
+InternalSetVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT32 Attributes,
+ IN UINTN DataSize,
+ IN VOID *Data
+ );
+
+/**
+ This service is a checker handler for the UEFI Runtime Service SetVariable()
+
+ @param VariableName the name of the vendor's variable, as a
+ Null-Terminated Unicode String
+ @param VendorGuid Unify identifier for vendor.
+ @param Attributes Point to memory location to return the attributes of variable. If the point
+ is NULL, the parameter would be ignored.
+ @param DataSize The size in bytes of Data-Buffer.
+ @param Data Point to the content of the variable.
+
+ @retval EFI_SUCCESS The firmware has successfully stored the variable and its data as
+ defined by the Attributes.
+ @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied, or the
+ DataSize exceeds the maximum allowed.
+ @retval EFI_INVALID_PARAMETER VariableName is an empty Unicode string.
+ @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 due to a hardware failure.
+ @retval EFI_WRITE_PROTECTED The variable in question is read-only.
+ @retval EFI_WRITE_PROTECTED The variable in question cannot be deleted.
+ @retval EFI_SECURITY_VIOLATION The variable could not be written due to EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
+ set but the AuthInfo does NOT pass the validation check carried
+ out by the firmware.
+ @retval EFI_NOT_FOUND The variable trying to be updated or deleted was not found.
+
+**/
+EFI_STATUS
+EFIAPI
+SetVariableCheckHandlerMor (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT32 Attributes,
+ IN UINTN DataSize,
+ IN VOID *Data
+ );
+
+/**
+ Entry Point for MOR Lock 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
+MorLockDriverInit (
+ VOID
+ );
+
+#endif
diff --git a/Core/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLock.uni b/Core/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLock.uni
new file mode 100644
index 0000000000..2a40f9d006
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLock.uni
@@ -0,0 +1,21 @@
+// /** @file
+// Initilizes MemoryOverwriteRequestControlLock variable
+//
+// This module will add Variable Hook and allow MemoryOverwriteRequestControlLock variable set only once.
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Initilizes MemoryOverwriteRequestControlLock variable"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This module will add Variable Hook and allow MemoryOverwriteRequestControlLock variable set only once."
+
diff --git a/Core/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLockExtra.uni b/Core/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLockExtra.uni
new file mode 100644
index 0000000000..770092dafc
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLockExtra.uni
@@ -0,0 +1,19 @@
+// /** @file
+// TcgMorLock Localized Strings and Content
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"TCG (Trusted Computing Group) MOR Lock"
+
+
diff --git a/Core/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLockSmm.c b/Core/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLockSmm.c
new file mode 100644
index 0000000000..019cb8bb24
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLockSmm.c
@@ -0,0 +1,158 @@
+/** @file
+ TCG MOR (Memory Overwrite Request) Lock Control Driver SMM wrapper.
+
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiSmm.h>
+#include <Library/SmmServicesTableLib.h>
+#include <Library/DebugLib.h>
+#include <Protocol/SmmVarCheck.h>
+#include <Protocol/SmmVariable.h>
+#include "TcgMorLock.h"
+
+EFI_SMM_VARIABLE_PROTOCOL *mSmmVariable;
+
+/**
+ This service is a wrapper for the UEFI Runtime Service GetVariable().
+
+ @param VariableName the name of the vendor's variable, it's a Null-Terminated Unicode String
+ @param VendorGuid Unify identifier for vendor.
+ @param Attributes Point to memory location to return the attributes of variable. If the point
+ is NULL, the parameter would be ignored.
+ @param DataSize As input, point to the maximum size of return Data-Buffer.
+ As output, point to the actual size of the returned Data-Buffer.
+ @param Data Point to return Data-Buffer.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_NOT_FOUND The variable was not found.
+ @retval EFI_BUFFER_TOO_SMALL The DataSize is too small for the result. DataSize has
+ been updated with the size needed to complete the request.
+ @retval EFI_INVALID_PARAMETER VariableName is NULL.
+ @retval EFI_INVALID_PARAMETER VendorGuid is NULL.
+ @retval EFI_INVALID_PARAMETER DataSize is NULL.
+ @retval EFI_INVALID_PARAMETER The DataSize is not too small and Data is NULL.
+ @retval EFI_DEVICE_ERROR The variable could not be retrieved due to a hardware error.
+ @retval EFI_SECURITY_VIOLATION The variable could not be retrieved due to an authentication failure.
+**/
+EFI_STATUS
+EFIAPI
+InternalGetVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ OUT UINT32 *Attributes OPTIONAL,
+ IN OUT UINTN *DataSize,
+ OUT VOID *Data
+ )
+{
+ return mSmmVariable->SmmGetVariable (
+ VariableName,
+ VendorGuid,
+ Attributes,
+ DataSize,
+ Data
+ );
+}
+
+/**
+ This service is a wrapper for the UEFI Runtime Service SetVariable()
+
+ @param VariableName the name of the vendor's variable, as a
+ Null-Terminated Unicode String
+ @param VendorGuid Unify identifier for vendor.
+ @param Attributes Point to memory location to return the attributes of variable. If the point
+ is NULL, the parameter would be ignored.
+ @param DataSize The size in bytes of Data-Buffer.
+ @param Data Point to the content of the variable.
+
+ @retval EFI_SUCCESS The firmware has successfully stored the variable and its data as
+ defined by the Attributes.
+ @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied, or the
+ DataSize exceeds the maximum allowed.
+ @retval EFI_INVALID_PARAMETER VariableName is an empty Unicode string.
+ @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 due to a hardware failure.
+ @retval EFI_WRITE_PROTECTED The variable in question is read-only.
+ @retval EFI_WRITE_PROTECTED The variable in question cannot be deleted.
+ @retval EFI_SECURITY_VIOLATION The variable could not be written due to EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
+ set but the AuthInfo does NOT pass the validation check carried
+ out by the firmware.
+ @retval EFI_NOT_FOUND The variable trying to be updated or deleted was not found.
+
+**/
+EFI_STATUS
+EFIAPI
+InternalSetVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT32 Attributes,
+ IN UINTN DataSize,
+ IN VOID *Data
+ )
+{
+ return mSmmVariable->SmmSetVariable (
+ VariableName,
+ VendorGuid,
+ Attributes,
+ DataSize,
+ Data
+ );
+}
+
+/**
+ Entry Point for MOR Lock Control driver.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS EntryPoint runs successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+MorLockDriverEntryPointSmm (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EDKII_SMM_VAR_CHECK_PROTOCOL *SmmVarCheck;
+
+ //
+ // This driver link to Smm Variable driver
+ //
+ DEBUG ((EFI_D_INFO, "MorLockDriverEntryPointSmm\n"));
+
+ Status = gSmst->SmmLocateProtocol (
+ &gEfiSmmVariableProtocolGuid,
+ NULL,
+ (VOID **) &mSmmVariable
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gSmst->SmmLocateProtocol (
+ &gEdkiiSmmVarCheckProtocolGuid,
+ NULL,
+ (VOID **) &SmmVarCheck
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = MorLockDriverInit ();
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = SmmVarCheck->SmmRegisterSetVariableCheckHandler (SetVariableCheckHandlerMor);
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
diff --git a/Core/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLockSmm.inf b/Core/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLockSmm.inf
new file mode 100644
index 0000000000..1623bd03bb
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLockSmm.inf
@@ -0,0 +1,70 @@
+## @file
+# Initilizes MemoryOverwriteRequestControlLock variable
+#
+# This module will add Variable Hook and allow MemoryOverwriteRequestControlLock variable set only once.
+#
+# NOTE: This module only handles secure MOR V1 and is deprecated.
+# The secure MOR V2 is handled inside of variable driver.
+#
+# Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = TcgMorLockSmm
+ MODULE_UNI_FILE = TcgMorLock.uni
+ FILE_GUID = E2EA6F47-E678-47FA-8C1B-02A03E825C6E
+ MODULE_TYPE = DXE_SMM_DRIVER
+ VERSION_STRING = 1.0
+ PI_SPECIFICATION_VERSION = 0x0001000A
+ ENTRY_POINT = MorLockDriverEntryPointSmm
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ TcgMorLock.h
+ TcgMorLock.c
+ TcgMorLockSmm.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ SmmServicesTableLib
+ DebugLib
+ BaseLib
+ BaseMemoryLib
+
+[Guids]
+ ## SOMETIMES_CONSUMES ## Variable:L"MemoryOverwriteRequestControl"
+ gEfiMemoryOverwriteControlDataGuid
+
+ ## SOMETIMES_CONSUMES ## Variable:L"MemoryOverwriteRequestControlLock"
+ ## PRODUCES ## Variable:L"MemoryOverwriteRequestControlLock"
+ gEfiMemoryOverwriteRequestControlLockGuid
+
+[Protocols]
+ gEdkiiSmmVarCheckProtocolGuid ## CONSUMES
+ gEfiSmmVariableProtocolGuid ## CONSUMES
+
+[Depex]
+ gEfiSmmVariableProtocolGuid AND
+ gSmmVariableWriteGuid AND
+ ( gEfiTcgProtocolGuid OR gEfiTcg2ProtocolGuid )
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ TcgMorLockExtra.uni
diff --git a/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/ComponentName.c b/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/ComponentName.c
new file mode 100644
index 0000000000..ef963d0e0b
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/ComponentName.c
@@ -0,0 +1,398 @@
+/** @file
+ UEFI Component Name(2) protocol implementation for Opal driver.
+
+Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "OpalDriver.h"
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gOpalComponentName = {
+ OpalEfiDriverComponentNameGetDriverName,
+ OpalEfiDriverComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gOpalComponentName2 = {
+ OpalEfiDriverComponentName2GetDriverName,
+ OpalEfiDriverComponentName2GetControllerName,
+ "en"
+};
+
+
+/// The name of the driver in all the languages we support.
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mOpalDriverNameTable[] = {
+ { LANGUAGE_RFC_3066_ENGLISH, (CHAR16*)EFI_DRIVER_NAME_UNICODE },
+ { LANGUAGE_ISO_639_2_ENGLISH, (CHAR16*)EFI_DRIVER_NAME_UNICODE },
+ { 0, 0 }
+};
+
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+OpalEfiDriverComponentNameGetDriverName(
+ EFI_COMPONENT_NAME_PROTOCOL* This,
+ CHAR8* Language,
+ CHAR16** DriverName
+ )
+{
+ return LookupUnicodeString2(
+ Language,
+ This->SupportedLanguages,
+ mOpalDriverNameTable,
+ DriverName,
+ TRUE
+ );
+}
+
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+OpalEfiDriverComponentName2GetDriverName(
+ EFI_COMPONENT_NAME2_PROTOCOL* This,
+ CHAR8* Language,
+ CHAR16** DriverName
+ )
+{
+ return LookupUnicodeString2(
+ Language,
+ This->SupportedLanguages,
+ mOpalDriverNameTable,
+ DriverName,
+ FALSE
+ );
+}
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+GetControllerName(
+ EFI_HANDLE ControllerHandle,
+ EFI_HANDLE ChildHandle,
+ CHAR8* Language,
+ CHAR16** ControllerName
+ )
+{
+ if (Language == NULL || ControllerName == NULL || ControllerHandle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // don't support any controller or children names
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+OpalEfiDriverComponentNameGetControllerName(
+ EFI_COMPONENT_NAME_PROTOCOL* This,
+ EFI_HANDLE ControllerHandle,
+ EFI_HANDLE ChildHandle,
+ CHAR8* Language,
+ CHAR16** ControllerName
+ )
+{
+ return (GetControllerName( ControllerHandle, ChildHandle, Language, ControllerName));
+}
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+OpalEfiDriverComponentName2GetControllerName(
+ EFI_COMPONENT_NAME2_PROTOCOL* This,
+ EFI_HANDLE ControllerHandle,
+ EFI_HANDLE ChildHandle,
+ CHAR8* Language,
+ CHAR16** ControllerName
+ )
+{
+ return (GetControllerName(ControllerHandle, ChildHandle, Language, ControllerName));
+}
+
diff --git a/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalDriver.c b/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalDriver.c
new file mode 100644
index 0000000000..cd0c5a4096
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalDriver.c
@@ -0,0 +1,1091 @@
+/** @file
+ Entrypoint of Opal UEFI Driver and contains all the logic to
+ register for new Opal device instances.
+
+Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+// This UEFI driver consumes EFI_STORAGE_SECURITY_PROTOCOL instances and installs an
+// HII GUI to manage Opal features if the device is Opal capable
+// If the Opal device is being managed by the UEFI Driver, it shall provide a popup
+// window during boot requesting a user password
+
+#include "OpalDriver.h"
+#include "OpalDriverPrivate.h"
+#include "OpalHii.h"
+
+OPAL_DRIVER mOpalDriver;
+
+#define MAX_PASSWORD_SIZE 32
+#define MAX_PASSWORD_TRY_COUNT 5
+
+//
+// Globals
+//
+EFI_DRIVER_BINDING_PROTOCOL gOpalDriverBinding = {
+ OpalEfiDriverBindingSupported,
+ OpalEfiDriverBindingStart,
+ OpalEfiDriverBindingStop,
+ 0x1b,
+ NULL,
+ NULL
+};
+
+
+/**
+ Add new device to the global device list.
+
+ @param Dev New create device.
+
+**/
+VOID
+AddDeviceToTail(
+ IN OPAL_DRIVER_DEVICE *Dev
+ )
+{
+ OPAL_DRIVER_DEVICE *TmpDev;
+
+ if (mOpalDriver.DeviceList == NULL) {
+ mOpalDriver.DeviceList = Dev;
+ } else {
+ TmpDev = mOpalDriver.DeviceList;
+ while (TmpDev->Next != NULL) {
+ TmpDev = TmpDev->Next;
+ }
+
+ TmpDev->Next = Dev;
+ }
+}
+
+/**
+ Remove one device in the global device list.
+
+ @param Dev The device need to be removed.
+
+**/
+VOID
+RemoveDevice (
+ IN OPAL_DRIVER_DEVICE *Dev
+ )
+{
+ OPAL_DRIVER_DEVICE *TmpDev;
+
+ if (mOpalDriver.DeviceList == NULL) {
+ return;
+ }
+
+ if (mOpalDriver.DeviceList == Dev) {
+ mOpalDriver.DeviceList = NULL;
+ return;
+ }
+
+ TmpDev = mOpalDriver.DeviceList;
+ while (TmpDev->Next != NULL) {
+ if (TmpDev->Next == Dev) {
+ TmpDev->Next = Dev->Next;
+ break;
+ }
+ }
+}
+
+/**
+ Get current device count.
+
+ @retval return the current created device count.
+
+**/
+UINT8
+GetDeviceCount (
+ VOID
+ )
+{
+ UINT8 Count;
+ OPAL_DRIVER_DEVICE *TmpDev;
+
+ Count = 0;
+ TmpDev = mOpalDriver.DeviceList;
+
+ while (TmpDev != NULL) {
+ Count++;
+ TmpDev = TmpDev->Next;
+ }
+
+ return Count;
+}
+
+/**
+ Get password input from the popup windows, and unlock the device.
+
+ @param[in] Dev The device which need to be unlock.
+ @param[out] PressEsc Whether user escape function through Press ESC.
+
+ @retval Password string if success. NULL if failed.
+
+**/
+CHAR8 *
+OpalDriverPopUpHddPassword (
+ IN OPAL_DRIVER_DEVICE *Dev,
+ OUT BOOLEAN *PressEsc
+ )
+{
+ EFI_INPUT_KEY InputKey;
+ UINTN InputLength;
+ CHAR16 Mask[MAX_PASSWORD_SIZE + 1];
+ CHAR16 Unicode[MAX_PASSWORD_SIZE + 1];
+ CHAR8 *Ascii;
+ CHAR16 *PopUpString;
+ UINTN StrLength;
+
+ ZeroMem(Unicode, sizeof(Unicode));
+ ZeroMem(Mask, sizeof(Mask));
+
+ StrLength = StrLen(Dev->Name16);
+ PopUpString = (CHAR16*) AllocateZeroPool ((8 + StrLength) * 2);
+ *PressEsc = FALSE;
+
+ if (Dev->Name16 == NULL) {
+ UnicodeSPrint(PopUpString, StrLen(L"Unlock Disk") + 1, L"Unlock Disk");
+ } else {
+ UnicodeSPrint(PopUpString, StrLen(L"Unlock ") + StrLength + 1, L"Unlock %s", Dev->Name16);
+ }
+
+ gST->ConOut->ClearScreen(gST->ConOut);
+
+ InputLength = 0;
+ while (TRUE) {
+ Mask[InputLength] = L'_';
+ CreatePopUp(
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
+ &InputKey,
+ PopUpString,
+ L"---------------------",
+ Mask,
+ NULL
+ );
+
+ //
+ // Check key.
+ //
+ if (InputKey.ScanCode == SCAN_NULL) {
+ //
+ // password finished
+ //
+ if (InputKey.UnicodeChar == CHAR_CARRIAGE_RETURN) {
+ //
+ // Add the null terminator.
+ //
+ Unicode[InputLength] = 0;
+ InputLength++;
+ break;
+ } else if ((InputKey.UnicodeChar == CHAR_NULL) ||
+ (InputKey.UnicodeChar == CHAR_TAB) ||
+ (InputKey.UnicodeChar == CHAR_LINEFEED)
+ ) {
+ continue;
+ } else {
+ //
+ // delete last key entered
+ //
+ if (InputKey.UnicodeChar == CHAR_BACKSPACE) {
+ if (InputLength > 0) {
+ Unicode[InputLength] = 0;
+ Mask[InputLength] = 0;
+ InputLength--;
+ }
+ } else {
+ //
+ // add Next key entry
+ //
+ Unicode[InputLength] = InputKey.UnicodeChar;
+ Mask[InputLength] = L'*';
+ InputLength++;
+ if (InputLength == MAX_PASSWORD_SIZE) {
+ //
+ // Add the null terminator.
+ //
+ Unicode[InputLength] = 0;
+ Mask[InputLength] = 0;
+ break;
+ }
+ }
+ }
+ }
+
+ //
+ // exit on ESC
+ //
+ if (InputKey.ScanCode == SCAN_ESC) {
+ *PressEsc = TRUE;
+ break;
+ }
+ }
+
+ gST->ConOut->ClearScreen(gST->ConOut);
+
+ if (InputLength == 0 || InputKey.ScanCode == SCAN_ESC) {
+ return NULL;
+ }
+
+ Ascii = AllocateZeroPool (MAX_PASSWORD_SIZE + 1);
+ if (Ascii == NULL) {
+ return NULL;
+ }
+
+ UnicodeStrToAsciiStrS (Unicode, Ascii, MAX_PASSWORD_SIZE + 1);
+ ZeroMem (Unicode, sizeof (Unicode));
+
+ return Ascii;
+}
+
+/**
+ Check if disk is locked, show popup window and ask for password if it is
+
+ @param[in] Dev The device which need to be unlock.
+
+**/
+VOID
+OpalDriverRequestPassword (
+ OPAL_DRIVER_DEVICE *Dev
+ )
+{
+ UINT8 Count;
+ BOOLEAN IsEnabled;
+ CHAR8 *Password;
+ UINT32 PasswordLen;
+ TCG_RESULT Ret;
+ EFI_INPUT_KEY Key;
+ OPAL_SESSION Session;
+ BOOLEAN PressEsc;
+ BOOLEAN Locked;
+
+ if (Dev == NULL) {
+ return;
+ }
+
+ Count = 0;
+
+ IsEnabled = OpalFeatureEnabled (&Dev->OpalDisk.SupportedAttributes, &Dev->OpalDisk.LockingFeature);
+ if (IsEnabled) {
+ ZeroMem(&Session, sizeof(Session));
+ Session.Sscp = Dev->OpalDisk.Sscp;
+ Session.MediaId = Dev->OpalDisk.MediaId;
+ Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId;
+
+ Locked = OpalDeviceLocked (&Dev->OpalDisk.SupportedAttributes, &Dev->OpalDisk.LockingFeature);
+
+ while (Count < MAX_PASSWORD_TRY_COUNT) {
+ Password = OpalDriverPopUpHddPassword (Dev, &PressEsc);
+ if (PressEsc) {
+ if (Locked) {
+ //
+ // Current device in the lock status and
+ // User not input password and press ESC,
+ // keep device in lock status and continue boot.
+ //
+ do {
+ CreatePopUp (
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
+ &Key,
+ L"Press ENTER to skip password, Press ESC to input password",
+ NULL
+ );
+ } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN));
+
+ if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {
+ gST->ConOut->ClearScreen(gST->ConOut);
+ //
+ // Keep lock and continue boot.
+ //
+ return;
+ } else {
+ //
+ // Let user input password again.
+ //
+ continue;
+ }
+ } else {
+ //
+ // Current device in the unlock status and
+ // User not input password and press ESC,
+ // Shutdown the device.
+ //
+ do {
+ CreatePopUp (
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
+ &Key,
+ L"Press ENTER to shutdown, Press ESC to input password",
+ NULL
+ );
+ } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN));
+
+ if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {
+ gRT->ResetSystem (EfiResetShutdown, EFI_SUCCESS, 0, NULL);
+ } else {
+ //
+ // Let user input password again.
+ //
+ continue;
+ }
+ }
+ }
+
+ if (Password == NULL) {
+ Count ++;
+ continue;
+ }
+ PasswordLen = (UINT32) AsciiStrLen(Password);
+
+ if (Locked) {
+ Ret = OpalSupportUnlock(&Session, Password, PasswordLen, Dev->OpalDevicePath);
+ } else {
+ Ret = OpalSupportLock(&Session, Password, PasswordLen, Dev->OpalDevicePath);
+ if (Ret == TcgResultSuccess) {
+ Ret = OpalSupportUnlock(&Session, Password, PasswordLen, Dev->OpalDevicePath);
+ }
+ }
+
+ if (Password != NULL) {
+ ZeroMem (Password, PasswordLen);
+ FreePool (Password);
+ }
+
+ if (Ret == TcgResultSuccess) {
+ break;
+ }
+
+ Count++;
+
+ do {
+ CreatePopUp (
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
+ &Key,
+ L"Invalid password.",
+ L"Press ENTER to retry",
+ NULL
+ );
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
+ }
+
+ if (Count >= MAX_PASSWORD_TRY_COUNT) {
+ do {
+ CreatePopUp (
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
+ &Key,
+ L"Opal password retry count exceeds the limit. Must shutdown!",
+ L"Press ENTER to shutdown",
+ NULL
+ );
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
+
+ gRT->ResetSystem (EfiResetShutdown, EFI_SUCCESS, 0, NULL);
+ }
+ }
+}
+
+/**
+ Get devcie list info.
+
+ @retval return the device list pointer.
+**/
+OPAL_DRIVER_DEVICE*
+OpalDriverGetDeviceList(
+ VOID
+ )
+{
+ return mOpalDriver.DeviceList;
+}
+
+/**
+ ReadyToBoot callback to send BlockSid command.
+
+ @param Event Pointer to this event
+ @param Context Event handler private Data
+
+**/
+VOID
+EFIAPI
+ReadyToBootCallback (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ OPAL_DRIVER_DEVICE *Itr;
+ TCG_RESULT Result;
+ OPAL_SESSION Session;
+ UINT32 PpStorageFlag;
+
+ gBS->CloseEvent (Event);
+
+ PpStorageFlag = Tcg2PhysicalPresenceLibGetManagementFlags ();
+ if ((PpStorageFlag & TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_ENABLE_BLOCK_SID) != 0) {
+ //
+ // Send BlockSID command to each Opal disk
+ //
+ Itr = mOpalDriver.DeviceList;
+ while (Itr != NULL) {
+ if (Itr->OpalDisk.SupportedAttributes.BlockSid) {
+ ZeroMem(&Session, sizeof(Session));
+ Session.Sscp = Itr->OpalDisk.Sscp;
+ Session.MediaId = Itr->OpalDisk.MediaId;
+ Session.OpalBaseComId = Itr->OpalDisk.OpalBaseComId;
+
+ Result = OpalBlockSid (&Session, TRUE); // HardwareReset must always be TRUE
+ if (Result != TcgResultSuccess) {
+ DEBUG ((DEBUG_ERROR, "OpalBlockSid fail\n"));
+ break;
+ }
+ }
+
+ Itr = Itr->Next;
+ }
+ }
+}
+
+/**
+ Stop this Controller.
+
+ @param Dev The device need to be stopped.
+
+**/
+VOID
+OpalDriverStopDevice (
+ OPAL_DRIVER_DEVICE *Dev
+ )
+{
+ //
+ // free each name
+ //
+ FreePool(Dev->Name16);
+
+ //
+ // remove OPAL_DRIVER_DEVICE from the list
+ // it updates the controllerList pointer
+ //
+ RemoveDevice(Dev);
+
+ //
+ // close protocols that were opened
+ //
+ gBS->CloseProtocol(
+ Dev->Handle,
+ &gEfiStorageSecurityCommandProtocolGuid,
+ gOpalDriverBinding.DriverBindingHandle,
+ Dev->Handle
+ );
+
+ gBS->CloseProtocol(
+ Dev->Handle,
+ &gEfiBlockIoProtocolGuid,
+ gOpalDriverBinding.DriverBindingHandle,
+ Dev->Handle
+ );
+
+ FreePool(Dev);
+}
+
+/**
+ Get devcie name through the component name protocol.
+
+ @param[in] AllHandlesBuffer The handle buffer for current system.
+ @param[in] NumAllHandles The number of handles for the handle buffer.
+ @param[in] Dev The device which need to get name.
+ @param[in] UseComp1 Whether use component name or name2 protocol.
+
+ @retval TRUE Find the name for this device.
+ @retval FALSE Not found the name for this device.
+**/
+BOOLEAN
+OpalDriverGetDeviceNameByProtocol(
+ EFI_HANDLE *AllHandlesBuffer,
+ UINTN NumAllHandles,
+ OPAL_DRIVER_DEVICE *Dev,
+ BOOLEAN UseComp1
+ )
+{
+ EFI_HANDLE* ProtocolHandlesBuffer;
+ UINTN NumProtocolHandles;
+ EFI_STATUS Status;
+ EFI_COMPONENT_NAME2_PROTOCOL* Cnp1_2; // efi component name and componentName2 have same layout
+ EFI_GUID Protocol;
+ UINTN StrLength;
+ EFI_DEVICE_PATH_PROTOCOL* TmpDevPath;
+ UINTN Index1;
+ UINTN Index2;
+ EFI_HANDLE TmpHandle;
+ CHAR16 *DevName;
+
+ if (Dev == NULL || AllHandlesBuffer == NULL || NumAllHandles == 0) {
+ return FALSE;
+ }
+
+ Protocol = UseComp1 ? gEfiComponentNameProtocolGuid : gEfiComponentName2ProtocolGuid;
+
+ //
+ // Find all EFI_HANDLES with protocol
+ //
+ Status = gBS->LocateHandleBuffer(
+ ByProtocol,
+ &Protocol,
+ NULL,
+ &NumProtocolHandles,
+ &ProtocolHandlesBuffer
+ );
+ if (EFI_ERROR(Status)) {
+ return FALSE;
+ }
+
+
+ //
+ // Exit early if no supported devices
+ //
+ if (NumProtocolHandles == 0) {
+ return FALSE;
+ }
+
+ //
+ // Get printable name by iterating through all protocols
+ // using the handle as the child, and iterate through all handles for the controller
+ // exit loop early once found, if not found, then delete device
+ // storage security protocol instances already exist, add them to internal list
+ //
+ Status = EFI_DEVICE_ERROR;
+ for (Index1 = 0; Index1 < NumProtocolHandles; Index1++) {
+ DevName = NULL;
+
+ if (Dev->Name16 != NULL) {
+ return TRUE;
+ }
+
+ TmpHandle = ProtocolHandlesBuffer[Index1];
+
+ Status = gBS->OpenProtocol(
+ TmpHandle,
+ &Protocol,
+ (VOID**)&Cnp1_2,
+ gImageHandle,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR(Status) || Cnp1_2 == NULL) {
+ continue;
+ }
+
+ //
+ // Use all handles array as controller handle
+ //
+ for (Index2 = 0; Index2 < NumAllHandles; Index2++) {
+ Status = Cnp1_2->GetControllerName(
+ Cnp1_2,
+ AllHandlesBuffer[Index2],
+ Dev->Handle,
+ LANGUAGE_ISO_639_2_ENGLISH,
+ &DevName
+ );
+ if (EFI_ERROR(Status)) {
+ Status = Cnp1_2->GetControllerName(
+ Cnp1_2,
+ AllHandlesBuffer[Index2],
+ Dev->Handle,
+ LANGUAGE_RFC_3066_ENGLISH,
+ &DevName
+ );
+ }
+ if (!EFI_ERROR(Status) && DevName != NULL) {
+ StrLength = StrLen(DevName) + 1; // Add one for NULL terminator
+ Dev->Name16 = AllocateZeroPool(StrLength * sizeof (CHAR16));
+ ASSERT (Dev->Name16 != NULL);
+ StrCpyS (Dev->Name16, StrLength, DevName);
+ Dev->NameZ = (CHAR8*)AllocateZeroPool(StrLength);
+ UnicodeStrToAsciiStrS (DevName, Dev->NameZ, StrLength);
+
+ //
+ // Retrieve bridge BDF info and port number or namespace depending on type
+ //
+ TmpDevPath = NULL;
+ Status = gBS->OpenProtocol(
+ Dev->Handle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID**)&TmpDevPath,
+ gImageHandle,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (!EFI_ERROR(Status)) {
+ Dev->OpalDevicePath = DuplicateDevicePath (TmpDevPath);
+ return TRUE;
+ }
+
+ if (Dev->Name16 != NULL) {
+ FreePool(Dev->Name16);
+ Dev->Name16 = NULL;
+ }
+ if (Dev->NameZ != NULL) {
+ FreePool(Dev->NameZ);
+ Dev->NameZ = NULL;
+ }
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Get devcie name through the component name protocol.
+
+ @param[in] Dev The device which need to get name.
+
+ @retval TRUE Find the name for this device.
+ @retval FALSE Not found the name for this device.
+**/
+BOOLEAN
+OpalDriverGetDriverDeviceName(
+ OPAL_DRIVER_DEVICE *Dev
+ )
+{
+ EFI_HANDLE* AllHandlesBuffer;
+ UINTN NumAllHandles;
+ EFI_STATUS Status;
+
+ if (Dev == NULL) {
+ DEBUG((DEBUG_ERROR | DEBUG_INIT, "OpalDriverGetDriverDeviceName Exiting, Dev=NULL\n"));
+ return FALSE;
+ }
+
+ //
+ // Iterate through ComponentName2 handles to get name, if fails, try ComponentName
+ //
+ if (Dev->Name16 == NULL) {
+ DEBUG((DEBUG_ERROR | DEBUG_INIT, "Name is null, update it\n"));
+ //
+ // Find all EFI_HANDLES
+ //
+ Status = gBS->LocateHandleBuffer(
+ AllHandles,
+ NULL,
+ NULL,
+ &NumAllHandles,
+ &AllHandlesBuffer
+ );
+ if (EFI_ERROR(Status)) {
+ DEBUG ((DEBUG_INFO, "LocateHandleBuffer for AllHandles failed %r\n", Status ));
+ return FALSE;
+ }
+
+ //
+ // Try component Name2
+ //
+ if (!OpalDriverGetDeviceNameByProtocol(AllHandlesBuffer, NumAllHandles, Dev, FALSE)) {
+ DEBUG((DEBUG_ERROR | DEBUG_INIT, "ComponentName2 failed to get device name, try ComponentName\n"));
+ if (!OpalDriverGetDeviceNameByProtocol(AllHandlesBuffer, NumAllHandles, Dev, TRUE)) {
+ DEBUG((DEBUG_ERROR | DEBUG_INIT, "ComponentName failed to get device name, skip device\n"));
+ return FALSE;
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+/**
+ 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
+EfiDriverEntryPoint(
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE* SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_EVENT ReadyToBootEvent;
+
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gOpalDriverBinding,
+ ImageHandle,
+ &gOpalComponentName,
+ &gOpalComponentName2
+ );
+
+ if (EFI_ERROR(Status)) {
+ DEBUG((DEBUG_ERROR, "Install protocols to Opal driver Handle failed\n"));
+ return Status ;
+ }
+
+ //
+ // Initialize Driver object
+ //
+ ZeroMem(&mOpalDriver, sizeof(mOpalDriver));
+ mOpalDriver.Handle = ImageHandle;
+
+ //
+ // register a ReadyToBoot event callback for sending BlockSid command
+ //
+ Status = EfiCreateEventReadyToBootEx (
+ TPL_CALLBACK,
+ ReadyToBootCallback,
+ (VOID *) &ImageHandle,
+ &ReadyToBootEvent
+ );
+
+ //
+ // Install Hii packages.
+ //
+ HiiInstall();
+
+ return Status;
+}
+
+/**
+ Tests to see if this driver supports a given controller.
+
+ This function checks to see if the controller contains an instance of the
+ EFI_STORAGE_SECURITY_COMMAND_PROTOCOL and the EFI_BLOCK_IO_PROTOCL
+ and returns EFI_SUCCESS if it does.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle The Handle of the controller to test. This Handle
+ must support a protocol interface that supplies
+ an I/O abstraction to the driver.
+ @param[in] RemainingDevicePath This parameter is ignored.
+
+ @retval EFI_SUCCESS The device contains required protocols
+ @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by the driver
+ specified by This.
+ @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
+ RemainingDevicePath is already being managed by a different
+ driver or an application that requires exclusive access.
+ Currently not implemented.
+ @retval EFI_UNSUPPORTED The device does not contain requires protocols
+
+**/
+EFI_STATUS
+EFIAPI
+OpalEfiDriverBindingSupported(
+ IN EFI_DRIVER_BINDING_PROTOCOL* This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL* RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_STORAGE_SECURITY_COMMAND_PROTOCOL* SecurityCommand;
+ EFI_BLOCK_IO_PROTOCOL* BlkIo;
+
+ //
+ // Test EFI_STORAGE_SECURITY_COMMAND_PROTOCOL on controller Handle.
+ //
+ Status = gBS->OpenProtocol(
+ Controller,
+ &gEfiStorageSecurityCommandProtocolGuid,
+ ( VOID ** )&SecurityCommand,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (Status == EFI_ALREADY_STARTED) {
+ return EFI_SUCCESS;
+ }
+
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ //
+ // Close protocol and reopen in Start call
+ //
+ gBS->CloseProtocol(
+ Controller,
+ &gEfiStorageSecurityCommandProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ //
+ // Test EFI_BLOCK_IO_PROTOCOL on controller Handle, required by EFI_STORAGE_SECURITY_COMMAND_PROTOCOL
+ // function APIs
+ //
+ Status = gBS->OpenProtocol(
+ Controller,
+ &gEfiBlockIoProtocolGuid,
+ (VOID **)&BlkIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR(Status)) {
+ DEBUG((DEBUG_INFO, "No EFI_BLOCK_IO_PROTOCOL on controller\n"));
+ return Status;
+ }
+
+ //
+ // Close protocol and reopen in Start call
+ //
+ gBS->CloseProtocol(
+ Controller,
+ &gEfiBlockIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Enables Opal Management on a supported device if available.
+
+ The start function is designed to be called after the Opal UEFI Driver has confirmed the
+ "controller", which is a child Handle, contains the EF_STORAGE_SECURITY_COMMAND protocols.
+ This function will complete the other necessary checks, such as verifying the device supports
+ the correct version of Opal. Upon verification, it will add the device to the
+ Opal HII list in order to expose Opal managmeent options.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle The Handle of the controller to start. This Handle
+ must support a protocol interface that supplies
+ an I/O abstraction to the driver.
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
+ parameter is ignored by device drivers, and is optional for bus
+ drivers. For a bus driver, if this parameter is NULL, then handles
+ for all the children of Controller are created by this driver.
+ If this parameter is not NULL and the first Device Path Node is
+ not the End of Device Path Node, then only the Handle for the
+ child device specified by the first Device Path Node of
+ RemainingDevicePath is created by this driver.
+ If the first Device Path Node of RemainingDevicePath is
+ the End of Device Path Node, no child Handle is created by this
+ driver.
+
+ @retval EFI_SUCCESS Opal management was enabled.
+ @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval Others The driver failed to start the device.
+
+**/
+EFI_STATUS
+EFIAPI
+OpalEfiDriverBindingStart(
+ IN EFI_DRIVER_BINDING_PROTOCOL* This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL* RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_BLOCK_IO_PROTOCOL *BlkIo;
+ OPAL_DRIVER_DEVICE *Dev;
+ OPAL_DRIVER_DEVICE *Itr;
+ BOOLEAN Result;
+
+ Itr = mOpalDriver.DeviceList;
+ while (Itr != NULL) {
+ if (Controller == Itr->Handle) {
+ return EFI_SUCCESS;
+ }
+ Itr = Itr->Next;
+ }
+
+ //
+ // Create internal device for tracking. This allows all disks to be tracked
+ // by same HII form
+ //
+ Dev = (OPAL_DRIVER_DEVICE*)AllocateZeroPool(sizeof(OPAL_DRIVER_DEVICE));
+ if (Dev == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Dev->Handle = Controller;
+
+ //
+ // Open EFI_STORAGE_SECURITY_COMMAND_PROTOCOL to perform Opal supported checks
+ //
+ Status = gBS->OpenProtocol(
+ Controller,
+ &gEfiStorageSecurityCommandProtocolGuid,
+ (VOID **)&Dev->Sscp,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR(Status)) {
+ FreePool(Dev);
+ return Status;
+ }
+
+ //
+ // Open EFI_BLOCK_IO_PROTOCOL on controller Handle, required by EFI_STORAGE_SECURITY_COMMAND_PROTOCOL
+ // function APIs
+ //
+ Status = gBS->OpenProtocol(
+ Controller,
+ &gEfiBlockIoProtocolGuid,
+ (VOID **)&BlkIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR(Status)) {
+ //
+ // Close storage security that was opened
+ //
+ gBS->CloseProtocol(
+ Controller,
+ &gEfiStorageSecurityCommandProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ FreePool(Dev);
+ return Status;
+ }
+
+ //
+ // Save mediaId
+ //
+ Dev->MediaId = BlkIo->Media->MediaId;
+
+ gBS->CloseProtocol(
+ Controller,
+ &gEfiBlockIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ //
+ // Acquire Ascii printable name of child, if not found, then ignore device
+ //
+ Result = OpalDriverGetDriverDeviceName (Dev);
+ if (!Result) {
+ goto Done;
+ }
+
+ Status = OpalDiskInitialize (Dev);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ AddDeviceToTail(Dev);
+
+ //
+ // check if device is locked and prompt for password
+ //
+ OpalDriverRequestPassword (Dev);
+
+ return EFI_SUCCESS;
+
+Done:
+ //
+ // free device, close protocols and exit
+ //
+ gBS->CloseProtocol(
+ Controller,
+ &gEfiStorageSecurityCommandProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ FreePool(Dev);
+
+ return EFI_DEVICE_ERROR;
+}
+
+/**
+ Stop this driver on Controller.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to stop driver on
+ @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
+ children is zero stop the entire bus driver.
+ @param ChildHandleBuffer List of Child Handles to Stop.
+
+ @retval EFI_SUCCESS This driver is removed Controller.
+ @retval other This driver could not be removed from this device.
+
+**/
+EFI_STATUS
+EFIAPI
+OpalEfiDriverBindingStop(
+ EFI_DRIVER_BINDING_PROTOCOL* This,
+ EFI_HANDLE Controller,
+ UINTN NumberOfChildren,
+ EFI_HANDLE* ChildHandleBuffer
+ )
+{
+ OPAL_DRIVER_DEVICE* Itr;
+
+ Itr = mOpalDriver.DeviceList;
+
+ //
+ // does Controller match any of the devices we are managing for Opal
+ //
+ while (Itr != NULL) {
+ if (Itr->Handle == Controller) {
+ OpalDriverStopDevice (Itr);
+ return EFI_SUCCESS;
+ }
+
+ Itr = Itr->Next;
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ Unloads UEFI Driver. Very useful for debugging and testing.
+
+ @param ImageHandle Image Handle this driver.
+
+ @retval EFI_SUCCESS This function always complete successfully.
+ @retval EFI_INVALID_PARAMETER The input ImageHandle is not valid.
+**/
+EFI_STATUS
+EFIAPI
+OpalEfiDriverUnload (
+ IN EFI_HANDLE ImageHandle
+ )
+{
+ EFI_STATUS Status;
+ OPAL_DRIVER_DEVICE *Itr;
+
+ Status = EFI_SUCCESS;
+
+ if (ImageHandle != gImageHandle) {
+ return (EFI_INVALID_PARAMETER);
+ }
+
+ //
+ // Uninstall any interface added to each device by us
+ //
+ while (mOpalDriver.DeviceList) {
+ Itr = mOpalDriver.DeviceList;
+ //
+ // Remove OPAL_DRIVER_DEVICE from the list
+ // it updates the controllerList pointer
+ //
+ OpalDriverStopDevice(Itr);
+ }
+
+ //
+ // Uninstall the HII capability
+ //
+ Status = HiiUninstall();
+
+ return Status;
+}
+
diff --git a/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalDriver.h b/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalDriver.h
new file mode 100644
index 0000000000..7761d64cbb
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalDriver.h
@@ -0,0 +1,412 @@
+/** @file
+ Values defined and used by the Opal UEFI Driver.
+
+Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _OPAL_DRIVER_H_
+#define _OPAL_DRIVER_H_
+
+#include <PiDxe.h>
+
+#include <Protocol/PciIo.h>
+#include <Protocol/SmmCommunication.h>
+#include <Protocol/BlockIo.h>
+#include <Protocol/LoadedImage.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/DevicePathToText.h>
+#include <Protocol/StorageSecurityCommand.h>
+
+#include <Library/UefiLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseLib.h>
+#include <Library/PrintLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/HiiLib.h>
+#include <Library/UefiHiiServicesLib.h>
+#include <Library/TcgStorageOpalLib.h>
+#include <Library/OpalPasswordSupportLib.h>
+#include <Library/Tcg2PhysicalPresenceLib.h>
+
+#define EFI_DRIVER_NAME_UNICODE L"1.0 UEFI Opal Driver"
+
+// UEFI 2.1
+#define LANGUAGE_RFC_3066_ENGLISH ((CHAR8*)"en")
+
+// UEFI/EFI < 2.1
+#define LANGUAGE_ISO_639_2_ENGLISH ((CHAR8*)"eng")
+
+
+#define UNLOCK_VAR_NAME (const CHAR16*)L"UNLOCK"
+#define OPAL_FILTER_DRIVER_VAR_NAME L"FILTER_DRIVER"
+
+
+#define CONCAT_(x, y) x ## y
+#define CONCAT(x, y) CONCAT_(x, y)
+
+#define UNICODE_STR(x) CONCAT( L, x )
+
+extern EFI_DRIVER_BINDING_PROTOCOL gOpalDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL gOpalComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gOpalComponentName2;
+
+/**
+ Unloads UEFI Driver. Very useful for debugging and testing.
+
+ @param ImageHandle Image handle this driver.
+
+ @retval EFI_SUCCESS This function always complete successfully.
+ @retval EFI_INVALID_PARAMETER The input ImageHandle is not valid.
+**/
+EFI_STATUS
+EFIAPI
+EfiDriverUnload(
+ EFI_HANDLE ImageHandle
+ );
+
+
+/**
+ Test to see if this driver supports Controller.
+
+ @param This Protocol instance pointer.
+ @param ControllerHandle Handle of device to test
+ @param RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCESS This driver supports this device.
+ @retval EFI_ALREADY_STARTED This driver is already running on this device.
+ @retval other This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+OpalEfiDriverBindingSupported(
+ EFI_DRIVER_BINDING_PROTOCOL* This,
+ EFI_HANDLE Controller,
+ EFI_DEVICE_PATH_PROTOCOL* RemainingDevicePath
+ );
+
+/**
+ Enables Opal Management on a supported device if available.
+
+ The start function is designed to be called after the Opal UEFI Driver has confirmed the
+ "controller", which is a child handle, contains the EF_STORAGE_SECURITY_COMMAND protocols.
+ This function will complete the other necessary checks, such as verifying the device supports
+ the correct version of Opal. Upon verification, it will add the device to the
+ Opal HII list in order to expose Opal managmeent options.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle The handle of the controller to start. This handle
+ must support a protocol interface that supplies
+ an I/O abstraction to the driver.
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
+ parameter is ignored by device drivers, and is optional for bus
+ drivers. For a bus driver, if this parameter is NULL, then handles
+ for all the children of Controller are created by this driver.
+ If this parameter is not NULL and the first Device Path Node is
+ not the End of Device Path Node, then only the handle for the
+ child device specified by the first Device Path Node of
+ RemainingDevicePath is created by this driver.
+ If the first Device Path Node of RemainingDevicePath is
+ the End of Device Path Node, no child handle is created by this
+ driver.
+
+ @retval EFI_SUCCESS Opal management was enabled.
+ @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval Others The driver failed to start the device.
+
+**/
+EFI_STATUS
+EFIAPI
+OpalEfiDriverBindingStart(
+ EFI_DRIVER_BINDING_PROTOCOL* This,
+ EFI_HANDLE Controller,
+ EFI_DEVICE_PATH_PROTOCOL* RemainingDevicePath
+ );
+
+/**
+ Stop this driver on Controller.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to stop driver on
+ @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
+ children is zero stop the entire bus driver.
+ @param ChildHandleBuffer List of Child Handles to Stop.
+
+ @retval EFI_SUCCESS This driver is removed Controller.
+ @retval other This driver could not be removed from this device.
+
+**/
+EFI_STATUS
+EFIAPI
+OpalEfiDriverBindingStop(
+ EFI_DRIVER_BINDING_PROTOCOL* This,
+ EFI_HANDLE Controller,
+ UINTN NumberOfChildren,
+ EFI_HANDLE* ChildHandleBuffer
+ );
+
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+OpalEfiDriverComponentNameGetDriverName(
+ EFI_COMPONENT_NAME_PROTOCOL* This,
+ CHAR8* Language,
+ CHAR16** DriverName
+ );
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+OpalEfiDriverComponentNameGetControllerName(
+ EFI_COMPONENT_NAME_PROTOCOL* This,
+ EFI_HANDLE ControllerHandle,
+ EFI_HANDLE ChildHandle,
+ CHAR8* Language,
+ CHAR16** ControllerName
+ );
+
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+OpalEfiDriverComponentName2GetDriverName(
+ EFI_COMPONENT_NAME2_PROTOCOL* This,
+ CHAR8* Language,
+ CHAR16** DriverName
+ );
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+OpalEfiDriverComponentName2GetControllerName(
+ EFI_COMPONENT_NAME2_PROTOCOL* This,
+ EFI_HANDLE ControllerHandle,
+ EFI_HANDLE ChildHandle,
+ CHAR8* Language,
+ CHAR16** ControllerName
+ );
+
+#endif //_OPAL_DRIVER_H_
diff --git a/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalDriverPrivate.h b/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalDriverPrivate.h
new file mode 100644
index 0000000000..19ebc32623
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalDriverPrivate.h
@@ -0,0 +1,102 @@
+/** @file
+ Private structures and functions used within OPAL_DRIVER
+
+Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _OPAL_DRIVER_PRIVATE_H_
+#define _OPAL_DRIVER_PRIVATE_H_
+#include "OpalDriver.h"
+
+#define OPAL_MSID_LENGHT 128
+
+#pragma pack(1)
+//
+// Structure that is used to represent an OPAL_DISK.
+//
+typedef struct {
+ UINT32 MsidLength; // Byte length of MSID Pin for device
+ UINT8 Msid[OPAL_MSID_LENGHT]; // MSID Pin for device
+ EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *Sscp;
+ UINT32 MediaId; // MediaId is used by Ssc Protocol.
+ EFI_DEVICE_PATH_PROTOCOL *OpalDevicePath;
+ UINT16 OpalBaseComId; // Opal SSC 1 base com id.
+ OPAL_OWNER_SHIP Owner;
+ OPAL_DISK_SUPPORT_ATTRIBUTE SupportedAttributes;
+ TCG_LOCKING_FEATURE_DESCRIPTOR LockingFeature; // Locking Feature Descriptor retrieved from performing a Level 0 Discovery
+} OPAL_DISK;
+
+//
+// Device with block IO protocol
+//
+typedef struct _OPAL_DRIVER_DEVICE OPAL_DRIVER_DEVICE;
+
+struct _OPAL_DRIVER_DEVICE {
+ OPAL_DRIVER_DEVICE *Next; ///< Linked list pointer
+ EFI_HANDLE Handle; ///< Device handle
+ OPAL_DISK OpalDisk; ///< User context
+ CHAR16 *Name16; ///< Allocated/freed by UEFI Filter Driver at device creation/removal
+ CHAR8 *NameZ; ///< Allocated/freed by UEFI Filter Driver at device creation/removal
+ UINT32 MediaId; ///< Required parameter for EFI_STORAGE_SECURITY_COMMAND_PROTOCOL, from BLOCK_IO_MEDIA
+
+ EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *Sscp; /// Device protocols consumed
+ EFI_DEVICE_PATH_PROTOCOL *OpalDevicePath;
+};
+
+//
+// Opal Driver UEFI Driver Model
+//
+typedef struct {
+ EFI_HANDLE Handle; ///< Driver image handle
+ OPAL_DRIVER_DEVICE *DeviceList; ///< Linked list of controllers owned by this Driver
+} OPAL_DRIVER;
+#pragma pack()
+
+//
+// Retrieves a OPAL_DRIVER_DEVICE based on the pointer to its StorageSecurity protocol.
+//
+#define DRIVER_DEVICE_FROM_OPALDISK(OpalDiskPointer) (OPAL_DRIVER_DEVICE*)(BASE_CR(OpalDiskPointer, OPAL_DRIVER_DEVICE, OpalDisk))
+
+/**
+ Get devcie list info.
+
+ @retval return the device list pointer.
+**/
+OPAL_DRIVER_DEVICE*
+OpalDriverGetDeviceList(
+ VOID
+ );
+
+/**
+ Get devcie name through the component name protocol.
+
+ @param[in] Dev The device which need to get name.
+
+ @retval TRUE Find the name for this device.
+ @retval FALSE Not found the name for this device.
+**/
+BOOLEAN
+OpalDriverGetDriverDeviceName(
+ OPAL_DRIVER_DEVICE *Dev
+ );
+
+/**
+ Get current device count.
+
+ @retval return the current created device count.
+
+**/
+UINT8
+GetDeviceCount (
+ VOID
+ );
+
+#endif // _OPAL_DRIVER_P_H_
diff --git a/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalHii.c b/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalHii.c
new file mode 100644
index 0000000000..4881e72c55
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalHii.c
@@ -0,0 +1,1483 @@
+/** @file
+ Implementation of the HII for the Opal UEFI Driver.
+
+Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "OpalHii.h"
+#include "OpalDriver.h"
+#include "OpalHiiPrivate.h"
+
+//
+// This is the generated IFR binary Data for each formset defined in VFR.
+// This Data array is ready to be used as input of HiiAddPackages() to
+// create a packagelist (which contains Form packages, String packages, etc).
+//
+extern UINT8 OpalPasswordFormBin[];
+
+//
+// This is the generated String package Data for all .UNI files.
+// This Data array is ready to be used as input of HiiAddPackages() to
+// create a packagelist (which contains Form packages, String packages, etc).
+//
+extern UINT8 OpalPasswordDxeStrings[];
+
+CHAR16 OpalPasswordStorageName[] = L"OpalHiiConfig";
+
+EFI_HII_CONFIG_ACCESS_PROTOCOL gHiiConfigAccessProtocol;
+
+//
+// Handle to the list of HII packages (forms and strings) for this driver
+//
+EFI_HII_HANDLE gHiiPackageListHandle = NULL;
+
+//
+// Package List GUID containing all form and string packages
+//
+const EFI_GUID gHiiPackageListGuid = PACKAGE_LIST_GUID;
+const EFI_GUID gHiiSetupVariableGuid = SETUP_VARIABLE_GUID;
+
+//
+// Structure that contains state of the HII
+// This structure is updated by Hii.cpp and its contents
+// is rendered in the HII.
+//
+OPAL_HII_CONFIGURATION gHiiConfiguration;
+
+CHAR8 gHiiOldPassword[MAX_PASSWORD_CHARACTER_LENGTH] = {0};
+UINT32 gHiiOldPasswordLength = 0;
+
+//
+// The device path containing the VENDOR_DEVICE_PATH and EFI_DEVICE_PATH_PROTOCOL
+//
+HII_VENDOR_DEVICE_PATH gHiiVendorDevicePath = {
+ {
+ {
+ HARDWARE_DEVICE_PATH,
+ HW_VENDOR_DP,
+ {
+ (UINT8)(sizeof(VENDOR_DEVICE_PATH)),
+ (UINT8)((sizeof(VENDOR_DEVICE_PATH)) >> 8)
+ }
+ },
+ OPAL_PASSWORD_CONFIG_GUID
+ },
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ (UINT8)(END_DEVICE_PATH_LENGTH),
+ (UINT8)((END_DEVICE_PATH_LENGTH) >> 8)
+ }
+ }
+};
+
+
+/**
+ Sets the current system state of global config variables.
+
+**/
+VOID
+HiiSetCurrentConfiguration(
+ VOID
+ )
+{
+ UINT32 PpStorageFlag;
+ EFI_STRING NewString;
+
+ gHiiConfiguration.NumDisks = GetDeviceCount();
+
+ //
+ // Update the BlockSID status string.
+ //
+ PpStorageFlag = Tcg2PhysicalPresenceLibGetManagementFlags ();
+
+ if ((PpStorageFlag & TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_ENABLE_BLOCK_SID) != 0) {
+ NewString = HiiGetString (gHiiPackageListHandle, STRING_TOKEN(STR_ENABLED), NULL);
+ if (NewString == NULL) {
+ DEBUG ((DEBUG_INFO, "HiiSetCurrentConfiguration: HiiGetString( ) failed\n"));
+ return;
+ }
+ } else {
+ NewString = HiiGetString (gHiiPackageListHandle, STRING_TOKEN(STR_DISABLED), NULL);
+ if (NewString == NULL) {
+ DEBUG ((DEBUG_INFO, "HiiSetCurrentConfiguration: HiiGetString( ) failed\n"));
+ return;
+ }
+ }
+ HiiSetString(gHiiPackageListHandle, STRING_TOKEN(STR_BLOCKSID_STATUS1), NewString, NULL);
+ FreePool (NewString);
+
+ if ((PpStorageFlag & TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_PP_REQUIRED_FOR_ENABLE_BLOCK_SID) != 0) {
+ NewString = HiiGetString (gHiiPackageListHandle, STRING_TOKEN(STR_DISK_INFO_ENABLE_BLOCKSID_TRUE), NULL);
+ if (NewString == NULL) {
+ DEBUG ((DEBUG_INFO, "HiiSetCurrentConfiguration: HiiGetString( ) failed\n"));
+ return;
+ }
+ } else {
+ NewString = HiiGetString (gHiiPackageListHandle, STRING_TOKEN(STR_DISK_INFO_ENABLE_BLOCKSID_FALSE), NULL);
+ if (NewString == NULL) {
+ DEBUG ((DEBUG_INFO, "HiiSetCurrentConfiguration: HiiGetString( ) failed\n"));
+ return;
+ }
+ }
+ HiiSetString(gHiiPackageListHandle, STRING_TOKEN(STR_BLOCKSID_STATUS2), NewString, NULL);
+ FreePool (NewString);
+
+ if ((PpStorageFlag & TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_PP_REQUIRED_FOR_DISABLE_BLOCK_SID) != 0) {
+ NewString = HiiGetString (gHiiPackageListHandle, STRING_TOKEN(STR_DISK_INFO_DISABLE_BLOCKSID_TRUE), NULL);
+ if (NewString == NULL) {
+ DEBUG ((DEBUG_INFO, "HiiSetCurrentConfiguration: HiiGetString( ) failed\n"));
+ return;
+ }
+ } else {
+ NewString = HiiGetString (gHiiPackageListHandle, STRING_TOKEN(STR_DISK_INFO_DISABLE_BLOCKSID_FALSE), NULL);
+ if (NewString == NULL) {
+ DEBUG ((DEBUG_INFO, "HiiSetCurrentConfiguration: HiiGetString( ) failed\n"));
+ return;
+ }
+ }
+ HiiSetString(gHiiPackageListHandle, STRING_TOKEN(STR_BLOCKSID_STATUS3), NewString, NULL);
+ FreePool (NewString);
+}
+
+/**
+ Install the HII related resources.
+
+ @retval EFI_SUCCESS Install all the resources success.
+ @retval other Error occur when install the resources.
+**/
+EFI_STATUS
+HiiInstall(
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE DriverHandle;
+
+ //
+ // Clear the global configuration.
+ //
+ ZeroMem(&gHiiConfiguration, sizeof(gHiiConfiguration));
+
+ //
+ // Obtain the driver handle that the BIOS assigned us
+ //
+ DriverHandle = HiiGetDriverImageHandleCB();
+
+ //
+ // Populate the config access protocol with the three functions we are publishing
+ //
+ gHiiConfigAccessProtocol.ExtractConfig = ExtractConfig;
+ gHiiConfigAccessProtocol.RouteConfig = RouteConfig;
+ gHiiConfigAccessProtocol.Callback = DriverCallback;
+
+ //
+ // Associate the required protocols with our driver handle
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces(
+ &DriverHandle,
+ &gEfiHiiConfigAccessProtocolGuid,
+ &gHiiConfigAccessProtocol, // HII callback
+ &gEfiDevicePathProtocolGuid,
+ &gHiiVendorDevicePath, // required for HII callback allow all disks to be shown in same hii
+ NULL
+ );
+
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ return OpalHiiAddPackages();
+}
+
+/**
+ Install the HII form and string packages.
+
+ @retval EFI_SUCCESS Install all the resources success.
+ @retval EFI_OUT_OF_RESOURCES Out of resource error.
+**/
+EFI_STATUS
+OpalHiiAddPackages(
+ VOID
+ )
+{
+ EFI_HANDLE DriverHandle;
+ CHAR16 *NewString;
+
+ DriverHandle = HiiGetDriverImageHandleCB();
+
+ //
+ // Publish the HII form and HII string packages
+ //
+ gHiiPackageListHandle = HiiAddPackages(
+ &gHiiPackageListGuid,
+ DriverHandle,
+ OpalPasswordDxeStrings,
+ OpalPasswordFormBin,
+ (VOID*)NULL
+ );
+
+ //
+ // Make sure the packages installed successfully
+ //
+ if (gHiiPackageListHandle == NULL) {
+ DEBUG ((DEBUG_INFO, "OpalHiiAddPackages failed\n"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Update Version String in main window
+ //
+ NewString = HiiGetDriverNameCB ();
+ if (HiiSetString(gHiiPackageListHandle, STRING_TOKEN(STR_MAIN_OPAL_VERSION), NewString, NULL) == 0) {
+ DEBUG ((DEBUG_INFO, "OpalHiiAddPackages: HiiSetString( ) failed\n"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Uninstall the HII capability.
+
+ @retval EFI_SUCCESS Uninstall all the resources success.
+ @retval others Other errors occur when unistall the hii resource.
+**/
+EFI_STATUS
+HiiUninstall(
+ VOID
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Remove the packages we've provided to the BIOS
+ //
+ HiiRemovePackages(gHiiPackageListHandle);
+
+ //
+ // Remove the protocols from our driver handle
+ //
+ Status = gBS->UninstallMultipleProtocolInterfaces(
+ HiiGetDriverImageHandleCB(),
+ &gEfiHiiConfigAccessProtocolGuid,
+ &gHiiConfigAccessProtocol, // HII callback
+ &gEfiDevicePathProtocolGuid,
+ &gHiiVendorDevicePath, // required for HII callback
+ NULL
+ );
+ if (EFI_ERROR(Status)) {
+ DEBUG ((DEBUG_INFO, "Cannot uninstall Hii Protocols: %r\n", Status));
+ }
+
+ return Status;
+}
+
+/**
+ Updates the main menu form.
+
+ @retval EFI_SUCCESS update the main form success.
+**/
+EFI_STATUS
+HiiPopulateMainMenuForm (
+ VOID
+ )
+{
+ UINT8 Index;
+ CHAR8 *DiskName;
+ EFI_STRING_ID DiskNameId;
+ OPAL_DISK *OpalDisk;
+
+ HiiSetCurrentConfiguration();
+
+ gHiiConfiguration.SupportedDisks = 0;
+
+ for (Index = 0; Index < gHiiConfiguration.NumDisks; Index++) {
+ OpalDisk = HiiGetOpalDiskCB (Index);
+ if ((OpalDisk != NULL) && OpalFeatureSupported (&OpalDisk->SupportedAttributes)) {
+ gHiiConfiguration.SupportedDisks |= (1 << Index);
+ DiskNameId = GetDiskNameStringId (Index);
+ DiskName = HiiDiskGetNameCB (Index);
+ if ((DiskName == NULL) || (DiskNameId == 0)) {
+ return EFI_UNSUPPORTED;
+ }
+ HiiSetFormString(DiskNameId, DiskName);
+ }
+ }
+
+ OpalHiiSetBrowserData ();
+ return EFI_SUCCESS;
+}
+
+/**
+ Update the disk action info.
+
+ @param ActionString
+ @param SelectedAction
+
+ @retval EFI_SUCCESS Uninstall all the resources success.
+**/
+EFI_STATUS
+HiiSelectDiskAction (
+ CHAR8 *ActionString,
+ UINT8 SelectedAction
+ )
+{
+ OPAL_DISK *OpalDisk;
+ OPAL_DISK_ACTIONS AvailActions;
+
+ OpalHiiGetBrowserData ();
+
+ HiiSetFormString(STRING_TOKEN(STR_DISK_ACTION_LBL), ActionString);
+ HiiSetFormString(STRING_TOKEN(STR_ACTION_STATUS), " ");
+
+ gHiiConfiguration.SelectedAction = SelectedAction;
+ gHiiConfiguration.AvailableFields = 0;
+
+ OpalDisk = HiiGetOpalDiskCB(gHiiConfiguration.SelectedDiskIndex);
+ if (OpalDisk == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (OpalSupportGetAvailableActions (&OpalDisk->SupportedAttributes, &OpalDisk->LockingFeature, OpalDisk->Owner, &AvailActions) != TcgResultSuccess) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ switch (SelectedAction) {
+ case HII_KEY_ID_GOTO_LOCK:
+ case HII_KEY_ID_GOTO_UNLOCK:
+ case HII_KEY_ID_GOTO_SET_ADMIN_PWD:
+ case HII_KEY_ID_GOTO_SET_USER_PWD:
+ case HII_KEY_ID_GOTO_SECURE_ERASE:
+ case HII_KEY_ID_GOTO_DISABLE_USER:
+ case HII_KEY_ID_GOTO_ENABLE_FEATURE: // User is required to enter Password to enable Feature
+ gHiiConfiguration.AvailableFields |= HII_FIELD_PASSWORD;
+ break;
+
+ case HII_KEY_ID_GOTO_PSID_REVERT:
+ gHiiConfiguration.AvailableFields |= HII_FIELD_PSID;
+ break;
+
+ case HII_KEY_ID_GOTO_REVERT:
+ gHiiConfiguration.AvailableFields |= HII_FIELD_PASSWORD;
+ gHiiConfiguration.AvailableFields |= HII_FIELD_KEEP_USER_DATA;
+ if (AvailActions.RevertKeepDataForced) {
+ gHiiConfiguration.AvailableFields |= HII_FIELD_KEEP_USER_DATA_FORCED;
+ }
+ break;
+ }
+
+ OpalHiiSetBrowserData ();
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get disk name string id.
+
+ @param DiskIndex The input disk index info.
+
+ @retval The disk name string id.
+
+**/
+EFI_STRING_ID
+GetDiskNameStringId(
+ UINT8 DiskIndex
+ )
+{
+ switch (DiskIndex) {
+ case 0: return STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_0);
+ case 1: return STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_1);
+ case 2: return STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_2);
+ case 3: return STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_3);
+ case 4: return STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_4);
+ case 5: return STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_5);
+ }
+ return 0;
+}
+
+/**
+ 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
+DriverCallback(
+ CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ EFI_BROWSER_ACTION Action,
+ EFI_QUESTION_ID QuestionId,
+ UINT8 Type,
+ EFI_IFR_TYPE_VALUE *Value,
+ EFI_BROWSER_ACTION_REQUEST *ActionRequest
+ )
+{
+ HII_KEY HiiKey;
+ UINT8 HiiKeyId;
+ UINT32 PpRequest;
+
+ if (ActionRequest != NULL) {
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // If QuestionId is an auto-generated key (label, empty line, etc.), ignore it.
+ //
+ if ((QuestionId & HII_KEY_FLAG) == 0) {
+ return EFI_SUCCESS;
+ }
+
+ HiiKey.Raw = QuestionId;
+ HiiKeyId = (UINT8) HiiKey.KeyBits.Id;
+
+ if (Action == EFI_BROWSER_ACTION_FORM_OPEN) {
+ switch (HiiKeyId) {
+ case HII_KEY_ID_VAR_SUPPORTED_DISKS:
+ DEBUG ((DEBUG_INFO, "HII_KEY_ID_VAR_SUPPORTED_DISKS\n"));
+ return HiiPopulateMainMenuForm ();
+
+ case HII_KEY_ID_VAR_SELECTED_DISK_AVAILABLE_ACTIONS:
+ return HiiPopulateDiskInfoForm();
+ }
+ } else if (Action == EFI_BROWSER_ACTION_CHANGING) {
+ switch (HiiKeyId) {
+ case HII_KEY_ID_GOTO_DISK_INFO:
+ return HiiSelectDisk((UINT8)HiiKey.KeyBits.Index);
+
+ case HII_KEY_ID_GOTO_LOCK:
+ return HiiSelectDiskAction("Action: Lock", HiiKeyId);
+
+ case HII_KEY_ID_GOTO_UNLOCK:
+ return HiiSelectDiskAction("Action: Unlock", HiiKeyId);
+
+ case HII_KEY_ID_GOTO_SET_ADMIN_PWD:
+ return HiiSelectDiskAction("Action: Set Administrator Password", HiiKeyId);
+
+ case HII_KEY_ID_GOTO_SET_USER_PWD:
+ return HiiSelectDiskAction("Action: Set User Password", HiiKeyId);
+
+ case HII_KEY_ID_GOTO_SECURE_ERASE:
+ return HiiSelectDiskAction("Action: Secure Erase", HiiKeyId);
+
+ case HII_KEY_ID_GOTO_PSID_REVERT:
+ return HiiSelectDiskAction("Action: Revert to Factory Defaults with PSID", HiiKeyId);
+
+ case HII_KEY_ID_GOTO_REVERT:
+ return HiiSelectDiskAction("Action: Revert to Factory Defaults", HiiKeyId);
+
+ case HII_KEY_ID_GOTO_DISABLE_USER:
+ return HiiSelectDiskAction("Action: Disable User", HiiKeyId);
+
+ case HII_KEY_ID_GOTO_ENABLE_FEATURE:
+ return HiiSelectDiskAction("Action: Enable Feature", HiiKeyId);
+
+ case HII_KEY_ID_ENTER_PASSWORD:
+ return HiiPasswordEntered(Value->string);
+
+ case HII_KEY_ID_ENTER_PSID:
+ return HiiPsidRevert(Value->string);
+
+ }
+ } else if (Action == EFI_BROWSER_ACTION_CHANGED) {
+ switch (HiiKeyId) {
+ case HII_KEY_ID_BLOCKSID:
+ switch (Value->u8) {
+ case 0:
+ PpRequest = TCG2_PHYSICAL_PRESENCE_NO_ACTION;
+ break;
+
+ case 1:
+ PpRequest = TCG2_PHYSICAL_PRESENCE_ENABLE_BLOCK_SID;
+ break;
+
+ case 2:
+ PpRequest = TCG2_PHYSICAL_PRESENCE_DISABLE_BLOCK_SID;
+ break;
+
+ case 3:
+ PpRequest = TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_ENABLE_BLOCK_SID_FUNC_TRUE;
+ break;
+
+ case 4:
+ PpRequest = TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_ENABLE_BLOCK_SID_FUNC_FALSE;
+ break;
+
+ case 5:
+ PpRequest = TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_DISABLE_BLOCK_SID_FUNC_TRUE;
+ break;
+
+ case 6:
+ PpRequest = TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_DISABLE_BLOCK_SID_FUNC_FALSE;
+ break;
+
+ default:
+ PpRequest = TCG2_PHYSICAL_PRESENCE_NO_ACTION;
+ DEBUG ((DEBUG_ERROR, "Invalid value input!\n"));
+ break;
+ }
+ HiiSetBlockSidAction(PpRequest);
+
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;
+ return EFI_SUCCESS;
+
+ default:
+ break;
+ }
+ }
+
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Update the global Disk index info.
+
+ @param Index The input disk index info.
+
+ @retval EFI_SUCCESS Update the disk index info success.
+
+**/
+EFI_STATUS
+HiiSelectDisk(
+ UINT8 Index
+ )
+{
+ OpalHiiGetBrowserData();
+ gHiiConfiguration.SelectedDiskIndex = Index;
+ OpalHiiSetBrowserData ();
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Draws the disk info form.
+
+ @retval EFI_SUCCESS Draw the disk info success.
+
+**/
+EFI_STATUS
+HiiPopulateDiskInfoForm(
+ VOID
+ )
+{
+ OPAL_DISK* OpalDisk;
+ OPAL_DISK_ACTIONS AvailActions;
+ TCG_RESULT Ret;
+ CHAR8 *DiskName;
+
+ OpalHiiGetBrowserData();
+
+ DiskName = HiiDiskGetNameCB (gHiiConfiguration.SelectedDiskIndex);
+ if (DiskName == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+ HiiSetFormString(STRING_TOKEN(STR_DISK_INFO_SELECTED_DISK_NAME), DiskName);
+
+ ZeroMem(gHiiConfiguration.Psid, sizeof(gHiiConfiguration.Psid));
+
+ gHiiConfiguration.SelectedDiskAvailableActions = HII_ACTION_NONE;
+
+ OpalDisk = HiiGetOpalDiskCB(gHiiConfiguration.SelectedDiskIndex);
+
+ if (OpalDisk != NULL) {
+ OpalDiskUpdateStatus (OpalDisk);
+ Ret = OpalSupportGetAvailableActions(&OpalDisk->SupportedAttributes, &OpalDisk->LockingFeature, OpalDisk->Owner, &AvailActions);
+ if (Ret == TcgResultSuccess) {
+ //
+ // Update actions, always allow PSID Revert
+ //
+ gHiiConfiguration.SelectedDiskAvailableActions |= (AvailActions.PsidRevert == 1) ? HII_ACTION_PSID_REVERT : HII_ACTION_NONE;
+
+ //
+ // Always allow unlock to handle device migration
+ //
+ gHiiConfiguration.SelectedDiskAvailableActions |= (AvailActions.Unlock == 1) ? HII_ACTION_UNLOCK : HII_ACTION_NONE;
+
+ if (!OpalFeatureEnabled (&OpalDisk->SupportedAttributes, &OpalDisk->LockingFeature)) {
+ if (OpalDisk->Owner == OpalOwnershipNobody) {
+ gHiiConfiguration.SelectedDiskAvailableActions |= HII_ACTION_ENABLE_FEATURE;
+
+ //
+ // Update strings
+ //
+ HiiSetFormString( STRING_TOKEN(STR_DISK_INFO_PSID_REVERT), "PSID Revert to factory default");
+ } else {
+ DEBUG ((DEBUG_INFO, "Feature disabled but ownership != nobody\n"));
+ }
+ } else {
+ gHiiConfiguration.SelectedDiskAvailableActions |= (AvailActions.Revert == 1) ? HII_ACTION_REVERT : HII_ACTION_NONE;
+ gHiiConfiguration.SelectedDiskAvailableActions |= (AvailActions.AdminPass == 1) ? HII_ACTION_SET_ADMIN_PWD : HII_ACTION_NONE;
+ gHiiConfiguration.SelectedDiskAvailableActions |= (AvailActions.UserPass == 1) ? HII_ACTION_SET_USER_PWD : HII_ACTION_NONE;
+ gHiiConfiguration.SelectedDiskAvailableActions |= (AvailActions.SecureErase == 1) ? HII_ACTION_SECURE_ERASE : HII_ACTION_NONE;
+ gHiiConfiguration.SelectedDiskAvailableActions |= (AvailActions.DisableUser == 1) ? HII_ACTION_DISABLE_USER : HII_ACTION_NONE;
+
+ HiiSetFormString (STRING_TOKEN(STR_DISK_INFO_PSID_REVERT), "PSID Revert to factory default and Disable");
+
+ //
+ // Determine revert options for disk
+ // Default initialize keep user Data to be true
+ //
+ gHiiConfiguration.KeepUserData = 1;
+ }
+ }
+ }
+
+ //
+ // Pass the current configuration to the BIOS
+ //
+ OpalHiiSetBrowserData ();
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Reverts the Opal disk to factory default.
+
+ @param PsidStringId The string id for the PSID info.
+
+ @retval EFI_SUCCESS Do the required action success.
+
+**/
+EFI_STATUS
+HiiPsidRevert(
+ EFI_STRING_ID PsidStringId
+ )
+{
+ CHAR8 Response[DEFAULT_RESPONSE_SIZE];
+ TCG_PSID Psid;
+ OPAL_DISK *OpalDisk;
+ TCG_RESULT Ret;
+ OPAL_SESSION Session;
+ CHAR16 *UnicodeStr;
+ UINT8 TmpBuf[PSID_CHARACTER_STRING_END_LENGTH];
+
+ Ret = TcgResultFailure;
+
+ UnicodeStr = HiiGetString (gHiiPackageListHandle, PsidStringId, NULL);
+ ZeroMem (TmpBuf, sizeof (TmpBuf));
+ UnicodeStrToAsciiStrS (UnicodeStr, (CHAR8*)TmpBuf, PSID_CHARACTER_STRING_END_LENGTH);
+ CopyMem (Psid.Psid, TmpBuf, PSID_CHARACTER_LENGTH);
+ HiiSetString (gHiiPackageListHandle, PsidStringId, L"", NULL);
+ ZeroMem (TmpBuf, sizeof (TmpBuf));
+ ZeroMem (UnicodeStr, StrSize (UnicodeStr));
+ FreePool (UnicodeStr);
+
+ OpalDisk = HiiGetOpalDiskCB (gHiiConfiguration.SelectedDiskIndex);
+ if (OpalDisk != NULL) {
+ ZeroMem(&Session, sizeof(Session));
+ Session.Sscp = OpalDisk->Sscp;
+ Session.MediaId = OpalDisk->MediaId;
+ Session.OpalBaseComId = OpalDisk->OpalBaseComId;
+
+ Ret = OpalSupportPsidRevert(&Session, Psid.Psid, (UINT32)sizeof(Psid.Psid), OpalDisk->OpalDevicePath);
+ }
+
+ ZeroMem (Psid.Psid, PSID_CHARACTER_LENGTH);
+
+ if (Ret == TcgResultSuccess) {
+ AsciiSPrint( Response, DEFAULT_RESPONSE_SIZE, "%a", "PSID Revert: Success" );
+ } else {
+ AsciiSPrint( Response, DEFAULT_RESPONSE_SIZE, "%a", "PSID Revert: Failure" );
+ }
+
+ HiiSetFormString(STRING_TOKEN(STR_ACTION_STATUS), Response);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Set password for the disk.
+
+ @param OpalDisk The disk need to set the password.
+ @param Password The input password.
+ @param PassLength The input password length.
+
+ @retval EFI_SUCCESS Do the required action success.
+
+**/
+EFI_STATUS
+HiiSetPassword(
+ OPAL_DISK *OpalDisk,
+ VOID *Password,
+ UINT32 PassLength
+ )
+{
+ CHAR8 Response[DEFAULT_RESPONSE_SIZE];
+ TCG_RESULT Ret;
+ BOOLEAN ExistingPassword;
+ OPAL_SESSION Session;
+
+ ExistingPassword = FALSE;
+
+ //
+ // PassLength = 0 means check whether exist old password.
+ //
+ if (PassLength == 0) {
+ ZeroMem(gHiiOldPassword, sizeof(gHiiOldPassword));
+ gHiiOldPasswordLength = 0;
+
+ if (gHiiConfiguration.SelectedAction == HII_KEY_ID_GOTO_ENABLE_FEATURE) {
+ ExistingPassword = FALSE;
+ } else if (gHiiConfiguration.SelectedAction == HII_KEY_ID_GOTO_SET_ADMIN_PWD) {
+ ExistingPassword = OpalUtilAdminPasswordExists(OpalDisk->Owner, &OpalDisk->LockingFeature);
+ } else if (gHiiConfiguration.SelectedAction == HII_KEY_ID_GOTO_SET_USER_PWD) {
+ //
+ // Set user Password option shall only be shown if an Admin Password exists
+ // so a Password is always required (Admin or Existing User Password)
+ //
+ ExistingPassword = TRUE;
+ }
+
+ //
+ // Return error if there is a previous Password
+ // see UEFI 2.4 errata B, Figure 121. Password Flowchart
+ //
+ return ExistingPassword ? EFI_DEVICE_ERROR : EFI_SUCCESS;
+ }
+
+ ZeroMem(&Session, sizeof(Session));
+ Session.Sscp = OpalDisk->Sscp;
+ Session.MediaId = OpalDisk->MediaId;
+ Session.OpalBaseComId = OpalDisk->OpalBaseComId;
+
+ AsciiSPrint(Response, DEFAULT_RESPONSE_SIZE, "%a", "Set Password: Failure");
+ //
+ // Password entered.
+ // No current Owner, so set new Password, must be admin Password
+ //
+ if (OpalDisk->Owner == OpalOwnershipNobody) {
+ Ret = OpalSupportEnableOpalFeature (&Session, OpalDisk->Msid, OpalDisk->MsidLength,Password, PassLength, OpalDisk->OpalDevicePath);
+ if (Ret == TcgResultSuccess) {
+ AsciiSPrint(Response, DEFAULT_RESPONSE_SIZE, "%a", "Set Password: Success");
+ }
+
+ HiiSetFormString(STRING_TOKEN(STR_ACTION_STATUS), Response);
+ return EFI_SUCCESS;
+ }
+
+ //
+ // 1st Password entered
+ //
+ if (OpalDisk->Owner == OpalOwnershipUnknown && gHiiOldPasswordLength == 0) {
+
+ //
+ // Unknown ownership - prompt for old Password, then new
+ // old Password is not set yet - first time through
+ // assume authority provided is admin1, overwritten if user1 authority works below
+ //
+ if (gHiiConfiguration.SelectedAction == HII_KEY_ID_GOTO_SET_USER_PWD) {
+ //
+ // First try to login as USER1 to Locking SP to see if we're simply updating its Password
+ //
+ Ret = OpalUtilVerifyPassword (&Session, Password, PassLength, OPAL_LOCKING_SP_USER1_AUTHORITY);
+ if (Ret == TcgResultSuccess) {
+ //
+ // User1 worked so authority 1 means user 1
+ //
+ CopyMem(gHiiOldPassword, Password, PassLength);
+ gHiiOldPasswordLength = PassLength;
+
+ return EFI_SUCCESS;
+ }
+ }
+
+ //
+ // Else try admin1 below
+ //
+ Ret = OpalUtilVerifyPassword (&Session, Password, PassLength, OPAL_LOCKING_SP_ADMIN1_AUTHORITY);
+ if (Ret == TcgResultSuccess) {
+ CopyMem(gHiiOldPassword, Password, PassLength);
+ gHiiOldPasswordLength = PassLength;
+
+ return EFI_SUCCESS;
+ } else {
+ DEBUG ((DEBUG_INFO, "start session with old PW failed - return EFI_NOT_READY - mistyped old PW\n"));
+ HiiSetFormString(STRING_TOKEN(STR_ACTION_STATUS), "Authentication Failure");
+
+ ZeroMem(gHiiOldPassword, sizeof(gHiiOldPassword));
+ gHiiOldPasswordLength = 0;
+
+ return EFI_NOT_READY;
+ }
+ }
+
+ //
+ // New Password entered
+ //
+ if (gHiiConfiguration.SelectedAction == HII_KEY_ID_GOTO_SET_USER_PWD) {
+ Ret = OpalSupportSetPassword(
+ &Session,
+ gHiiOldPassword,
+ gHiiOldPasswordLength,
+ Password,
+ PassLength,
+ OpalDisk->OpalDevicePath,
+ FALSE
+ );
+ } else {
+ Ret = OpalSupportSetPassword(
+ &Session,
+ gHiiOldPassword,
+ gHiiOldPasswordLength,
+ Password,
+ PassLength,
+ OpalDisk->OpalDevicePath,
+ TRUE
+ );
+ }
+
+ if (Ret == TcgResultSuccess) {
+ AsciiSPrint(Response, DEFAULT_RESPONSE_SIZE, "%a", "Set Password: Success");
+ }
+
+ //
+ // Reset old Password storage
+ //
+ ZeroMem(gHiiOldPassword, sizeof(gHiiOldPassword));
+ gHiiOldPasswordLength = 0;
+
+ HiiSetFormString(STRING_TOKEN(STR_ACTION_STATUS), Response);
+ return Ret == TcgResultSuccess ? EFI_SUCCESS : EFI_NOT_READY;
+}
+
+/**
+ Secure Erases Opal Disk.
+
+ @param OpalDisk The disk need to erase data.
+ @param Password The input password.
+ @param PassLength The input password length.
+
+ @retval EFI_SUCCESS Do the required action success.
+
+**/
+EFI_STATUS
+HiiSecureErase(
+ OPAL_DISK *OpalDisk,
+ const VOID *Password,
+ UINT32 PassLength
+ )
+{
+ CHAR8 Response[DEFAULT_RESPONSE_SIZE];
+ BOOLEAN PasswordFailed;
+ TCG_RESULT Ret;
+ OPAL_SESSION AdminSpSession;
+
+ if (PassLength == 0) {
+ return EFI_DEVICE_ERROR; // return error to indicate there is an existing Password
+ }
+
+ ZeroMem(&AdminSpSession, sizeof(AdminSpSession));
+ AdminSpSession.Sscp = OpalDisk->Sscp;
+ AdminSpSession.MediaId = OpalDisk->MediaId;
+ AdminSpSession.OpalBaseComId = OpalDisk->OpalBaseComId;
+
+ Ret = OpalUtilSecureErase(&AdminSpSession, Password, PassLength, &PasswordFailed);
+ if (Ret == TcgResultSuccess) {
+ AsciiSPrint( Response, DEFAULT_RESPONSE_SIZE, "%a", "Secure Erase: Success" );
+ } else {
+ AsciiSPrint( Response, DEFAULT_RESPONSE_SIZE, "%a", "Secure Erase: Failure" );
+ }
+ HiiSetFormString(STRING_TOKEN(STR_ACTION_STATUS), Response);
+
+ //
+ // If Password failed, return invalid passowrd
+ //
+ if (PasswordFailed) {
+ DEBUG ((DEBUG_INFO, "returning EFI_NOT_READY to indicate Password was not correct\n"));
+ return EFI_NOT_READY;
+ }
+
+ //
+ // Indicates Password was valid and is not changing to UEFI
+ // Response string will indicate action error
+ //
+ return EFI_DEVICE_ERROR;
+}
+
+
+/**
+ Disables User for Opal Disk.
+
+ @param OpalDisk The disk need to the action.
+ @param Password The input password.
+ @param PassLength The input password length.
+
+ @retval EFI_SUCCESS Do the required action success.
+
+**/
+EFI_STATUS
+HiiDisableUser(
+ OPAL_DISK *OpalDisk,
+ VOID *Password,
+ UINT32 PassLength
+ )
+{
+ CHAR8 Response[ DEFAULT_RESPONSE_SIZE ];
+ BOOLEAN PasswordFailed;
+ TCG_RESULT Ret;
+ OPAL_SESSION Session;
+
+ if (PassLength == 0) {
+ return EFI_DEVICE_ERROR; // return error to indicate there is an existing Password
+ }
+
+ ZeroMem(&Session, sizeof(Session));
+ Session.Sscp = OpalDisk->Sscp;
+ Session.MediaId = OpalDisk->MediaId;
+ Session.OpalBaseComId = OpalDisk->OpalBaseComId;
+
+ Ret = OpalSupportDisableUser(&Session, Password, PassLength, &PasswordFailed, OpalDisk->OpalDevicePath);
+ if (Ret == TcgResultSuccess) {
+ AsciiSPrint( Response, DEFAULT_RESPONSE_SIZE, "%a", "Disable User: Success" );
+ } else {
+ AsciiSPrint( Response, DEFAULT_RESPONSE_SIZE, "%a", "Disable User: Failure" );
+ }
+ HiiSetFormString (STRING_TOKEN(STR_ACTION_STATUS), Response);
+
+ //
+ // If Password failed, return invalid passowrd
+ //
+ if (PasswordFailed) {
+ DEBUG ((DEBUG_INFO, "returning EFI_NOT_READY to indicate Password was not correct\n"));
+ return EFI_NOT_READY;
+ }
+
+ //
+ // Indicates Password was valid and is not changing to UEFI
+ // Response string will indicate action error
+ //
+ return EFI_DEVICE_ERROR;
+}
+
+/**
+ Revert Opal Disk as Admin1.
+
+ @param OpalDisk The disk need to the action.
+ @param Password The input password.
+ @param PassLength The input password length.
+ @param KeepUserData Whether need to keey user data.
+
+ @retval EFI_SUCCESS Do the required action success.
+
+**/
+EFI_STATUS
+HiiRevert(
+ OPAL_DISK *OpalDisk,
+ VOID *Password,
+ UINT32 PassLength,
+ BOOLEAN KeepUserData
+ )
+{
+ CHAR8 Response[ DEFAULT_RESPONSE_SIZE ];
+ BOOLEAN PasswordFailed;
+ TCG_RESULT Ret;
+ OPAL_SESSION Session;
+
+ if (PassLength == 0) {
+ DEBUG ((DEBUG_INFO, "Returning error to indicate there is an existing Password\n"));
+ // return error to indicate there is an existing Password
+ return EFI_DEVICE_ERROR;
+ }
+
+ ZeroMem(&Session, sizeof(Session));
+ Session.Sscp = OpalDisk->Sscp;
+ Session.MediaId = OpalDisk->MediaId;
+ Session.OpalBaseComId = OpalDisk->OpalBaseComId;
+
+ Ret = OpalSupportRevert(
+ &Session,
+ KeepUserData,
+ Password,
+ PassLength,
+ OpalDisk->Msid,
+ OpalDisk->MsidLength,
+ &PasswordFailed,
+ OpalDisk->OpalDevicePath
+ );
+ if (Ret == TcgResultSuccess) {
+ AsciiSPrint( Response, DEFAULT_RESPONSE_SIZE, "%a", "Revert: Success" );
+ } else {
+ AsciiSPrint( Response, DEFAULT_RESPONSE_SIZE, "%a", "Revert: Failure" );
+ }
+ HiiSetFormString(STRING_TOKEN(STR_ACTION_STATUS), Response);
+
+ //
+ // If Password failed, return invalid passowrd
+ //
+ if (PasswordFailed) {
+ DEBUG ((DEBUG_INFO, "returning EFI_NOT_READY to indicate Password was not correct\n"));
+ return EFI_NOT_READY;
+ }
+
+ //
+ // Indicates Password was valid and is not changing to UEFI
+ // Response string will indicate action error
+ //
+ return EFI_DEVICE_ERROR;
+}
+
+/**
+ Unlocks Opal Disk.
+
+ @param OpalDisk The disk need to the action.
+ @param Password The input password.
+ @param PassLength The input password length.
+
+ @retval EFI_SUCCESS Do the required action success.
+
+**/
+EFI_STATUS
+HiiUnlock(
+ OPAL_DISK *OpalDisk,
+ VOID *Password,
+ UINT32 PassLength
+ )
+{
+ CHAR8 Response[DEFAULT_RESPONSE_SIZE];
+ TCG_RESULT Ret;
+ OPAL_SESSION Session;
+
+ if (PassLength == 0) {
+ DEBUG ((DEBUG_INFO, "Returning error to indicate there is an existing Password\n"));
+ return EFI_DEVICE_ERROR; // return error to indicate there is an existing Password
+ }
+
+ ZeroMem(&Session, sizeof(Session));
+ Session.Sscp = OpalDisk->Sscp;
+ Session.MediaId = OpalDisk->MediaId;
+ Session.OpalBaseComId = OpalDisk->OpalBaseComId;
+
+ Ret = OpalSupportUnlock(&Session, Password, PassLength, OpalDisk->OpalDevicePath);
+ if (Ret == TcgResultSuccess) {
+ AsciiSPrint( Response, DEFAULT_RESPONSE_SIZE, "%a", "Unlock: Success" );
+ } else {
+ AsciiSPrint( Response, DEFAULT_RESPONSE_SIZE, "%a", "Unlock: Failure" );
+ }
+
+ HiiSetFormString(STRING_TOKEN(STR_ACTION_STATUS), Response);
+
+ if (Ret == TcgResultSuccess) {
+ DEBUG ((DEBUG_INFO, "returning error to indicate Password was correct but is not changing\n"));
+ return EFI_DEVICE_ERROR;
+ } else {
+ DEBUG ((DEBUG_INFO, "returning EFI_NOT_READY to indicate Password was not correct\n"));
+ return EFI_NOT_READY;
+ }
+}
+
+/**
+ Use the input password to do the specified action.
+
+ @param Str The input password saved in.
+
+ @retval EFI_SUCCESS Do the required action success.
+ @retval Others Other error occur.
+
+**/
+EFI_STATUS
+HiiPasswordEntered(
+ EFI_STRING_ID Str
+ )
+{
+ OPAL_DISK* OpalDisk;
+ CHAR8 Password[MAX_PASSWORD_CHARACTER_LENGTH + 1];
+ CHAR16* UniStr;
+ UINT32 PassLength;
+ EFI_STATUS Status;
+
+ OpalHiiGetBrowserData();
+
+ OpalDisk = HiiGetOpalDiskCB(gHiiConfiguration.SelectedDiskIndex);
+ if (OpalDisk == NULL) {
+ DEBUG ((DEBUG_INFO, "ERROR: disk %u not found\n", gHiiConfiguration.SelectedDiskIndex));
+ return EFI_NOT_FOUND;
+ }
+
+ if (Str == 0) {
+ DEBUG ((DEBUG_INFO, "ERROR: str=NULL\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ZeroMem(Password, sizeof(Password));
+
+ UniStr = HiiGetString(gHiiPackageListHandle, Str, NULL);
+ if (UniStr == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ HiiSetString(gHiiPackageListHandle, Str, L"", NULL);
+
+ PassLength = (UINT32) StrLen (UniStr);
+ if (PassLength >= sizeof(Password)) {
+ HiiSetFormString(STRING_TOKEN(STR_ACTION_STATUS), "Password too long");
+ ZeroMem (UniStr, StrSize (UniStr));
+ FreePool(UniStr);
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ UnicodeStrToAsciiStrS (UniStr, Password, sizeof (Password));
+ ZeroMem (UniStr, StrSize (UniStr));
+ FreePool(UniStr);
+
+ if (gHiiConfiguration.SelectedAction == HII_KEY_ID_GOTO_UNLOCK) {
+ Status = HiiUnlock (OpalDisk, Password, PassLength);
+ } else if (gHiiConfiguration.SelectedAction == HII_KEY_ID_GOTO_SECURE_ERASE) {
+ Status = HiiSecureErase (OpalDisk, Password, PassLength);
+ } else if (gHiiConfiguration.SelectedAction == HII_KEY_ID_GOTO_DISABLE_USER) {
+ Status = HiiDisableUser (OpalDisk, Password, PassLength);
+ } else if (gHiiConfiguration.SelectedAction == HII_KEY_ID_GOTO_REVERT) {
+ if (OpalDisk->SupportedAttributes.PyriteSsc == 1 && OpalDisk->LockingFeature.MediaEncryption == 0) {
+ //
+ // For pyrite type device which also not supports media encryption, it not accept "Keep User Data" parameter.
+ // So here hardcode a FALSE for this case.
+ //
+ Status = HiiRevert(OpalDisk, Password, PassLength, FALSE);
+ } else {
+ Status = HiiRevert(OpalDisk, Password, PassLength, gHiiConfiguration.KeepUserData);
+ }
+ } else {
+ Status = HiiSetPassword(OpalDisk, Password, PassLength);
+ }
+
+ ZeroMem (Password, sizeof (Password));
+
+ OpalHiiSetBrowserData ();
+
+ return Status;
+}
+
+/**
+ Send BlockSid request through TPM physical presence module.
+
+ @param PpRequest TPM physical presence operation request.
+
+ @retval EFI_SUCCESS Do the required action success.
+ @retval Others Other error occur.
+
+**/
+EFI_STATUS
+HiiSetBlockSidAction (
+ IN UINT32 PpRequest
+ )
+{
+ UINT32 ReturnCode;
+ EFI_STATUS Status;
+
+ ReturnCode = Tcg2PhysicalPresenceLibSubmitRequestToPreOSFunction (PpRequest, 0);
+ if (ReturnCode == TCG_PP_SUBMIT_REQUEST_TO_PREOS_SUCCESS) {
+ Status = EFI_SUCCESS;
+ } else if (ReturnCode == TCG_PP_SUBMIT_REQUEST_TO_PREOS_GENERAL_FAILURE) {
+ Status = EFI_OUT_OF_RESOURCES;
+ } else if (ReturnCode == TCG_PP_SUBMIT_REQUEST_TO_PREOS_NOT_IMPLEMENTED) {
+ Status = EFI_UNSUPPORTED;
+ } else {
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ return Status;
+}
+
+/**
+ 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 <ConfigResp>
+ 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
+RouteConfig(
+ CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ CONST EFI_STRING Configuration,
+ EFI_STRING *Progress
+ )
+{
+ if (Configuration == NULL || Progress == NULL) {
+ return (EFI_INVALID_PARAMETER);
+ }
+
+ *Progress = Configuration;
+ if (!HiiIsConfigHdrMatch (Configuration, &gHiiSetupVariableGuid, OpalPasswordStorageName)) {
+ return EFI_NOT_FOUND;
+ }
+
+ *Progress = Configuration + StrLen (Configuration);
+
+ 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
+ <ConfigRequest> 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
+ <ConfigAltResp> format which has all values filled
+ in for the names in the Request string. String to
+ be allocated by the called function.
+
+ @retval EFI_SUCCESS The Results is filled with the requested values.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results.
+ @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name.
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in this
+ driver.
+
+**/
+EFI_STATUS
+EFIAPI
+ExtractConfig(
+ CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ CONST EFI_STRING Request,
+ EFI_STRING *Progress,
+ EFI_STRING *Results
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Check for valid parameters
+ //
+ if (Progress == NULL || Results == NULL) {
+ return (EFI_INVALID_PARAMETER);
+ }
+
+ *Progress = Request;
+ if ((Request != NULL) &&
+ !HiiIsConfigHdrMatch (Request, &gHiiSetupVariableGuid, OpalPasswordStorageName)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Convert Buffer Data to <ConfigResp> by helper function BlockToConfig( )
+ //
+ Status = gHiiConfigRouting->BlockToConfig(
+ gHiiConfigRouting,
+ Request,
+ (UINT8*)&gHiiConfiguration,
+ sizeof(OPAL_HII_CONFIGURATION),
+ Results,
+ Progress
+ );
+
+ return (Status);
+}
+
+
+/**
+
+ Pass the current system state to the bios via the hii_G_Configuration.
+
+**/
+VOID
+OpalHiiSetBrowserData (
+ VOID
+ )
+{
+ HiiSetBrowserData(
+ &gHiiSetupVariableGuid,
+ (CHAR16*)L"OpalHiiConfig",
+ sizeof(gHiiConfiguration),
+ (UINT8*)&gHiiConfiguration,
+ NULL
+ );
+}
+
+
+/**
+
+ Populate the hii_g_Configuraton with the browser Data.
+
+**/
+VOID
+OpalHiiGetBrowserData (
+ VOID
+ )
+{
+ HiiGetBrowserData(
+ &gHiiSetupVariableGuid,
+ (CHAR16*)L"OpalHiiConfig",
+ sizeof(gHiiConfiguration),
+ (UINT8*)&gHiiConfiguration
+ );
+}
+
+/**
+ Set a string Value in a form.
+
+ @param DestStringId The stringid which need to update.
+ @param SrcAsciiStr The string nned to update.
+
+ @retval EFI_SUCCESS Do the required action success.
+ @retval Others Other error occur.
+
+**/
+EFI_STATUS
+HiiSetFormString(
+ EFI_STRING_ID DestStringId,
+ CHAR8 *SrcAsciiStr
+ )
+{
+ UINT32 Len;
+ UINT32 UniSize;
+ CHAR16* UniStr;
+
+ //
+ // Determine the Length of the sting
+ //
+ Len = ( UINT32 )AsciiStrLen( SrcAsciiStr );
+
+ //
+ // Allocate space for the unicode string, including terminator
+ //
+ UniSize = (Len + 1) * sizeof(CHAR16);
+ UniStr = (CHAR16*)AllocateZeroPool(UniSize);
+
+ //
+ // Copy into unicode string, then copy into string id
+ //
+ AsciiStrToUnicodeStrS ( SrcAsciiStr, UniStr, Len + 1);
+
+ //
+ // Update the string in the form
+ //
+ if (HiiSetString(gHiiPackageListHandle, DestStringId, UniStr, NULL) == 0) {
+ DEBUG ((DEBUG_INFO, "HiiSetFormString( ) failed\n"));
+ FreePool(UniStr);
+ return (EFI_OUT_OF_RESOURCES);
+ }
+
+ //
+ // Free the memory
+ //
+ FreePool(UniStr);
+
+ return (EFI_SUCCESS);
+}
+
+/**
+ Initialize the Opal disk base on the hardware info get from device.
+
+ @param Dev The Opal device.
+
+ @retval EFI_SUCESS Initialize the device success.
+ @retval EFI_DEVICE_ERROR Get info from device failed.
+
+**/
+EFI_STATUS
+OpalDiskInitialize (
+ IN OPAL_DRIVER_DEVICE *Dev
+ )
+{
+ TCG_RESULT TcgResult;
+ OPAL_SESSION Session;
+
+ ZeroMem(&Dev->OpalDisk, sizeof(OPAL_DISK));
+ Dev->OpalDisk.Sscp = Dev->Sscp;
+ Dev->OpalDisk.MediaId = Dev->MediaId;
+ Dev->OpalDisk.OpalDevicePath = Dev->OpalDevicePath;
+
+ ZeroMem(&Session, sizeof(Session));
+ Session.Sscp = Dev->Sscp;
+ Session.MediaId = Dev->MediaId;
+
+ TcgResult = OpalGetSupportedAttributesInfo (&Session, &Dev->OpalDisk.SupportedAttributes, &Dev->OpalDisk.OpalBaseComId);
+ if (TcgResult != TcgResultSuccess) {
+ return EFI_DEVICE_ERROR;
+ }
+ Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId;
+
+ TcgResult = OpalUtilGetMsid (&Session, Dev->OpalDisk.Msid, OPAL_MSID_LENGHT, &Dev->OpalDisk.MsidLength);
+ if (TcgResult != TcgResultSuccess) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return OpalDiskUpdateStatus (&Dev->OpalDisk);
+}
+
+/**
+ Update the device info.
+
+ @param OpalDisk The Opal device.
+
+ @retval EFI_SUCESS Initialize the device success.
+ @retval EFI_DEVICE_ERROR Get info from device failed.
+ @retval EFI_INVALID_PARAMETER Not get Msid info before get ownership info.
+
+**/
+EFI_STATUS
+OpalDiskUpdateStatus (
+ OPAL_DISK *OpalDisk
+ )
+{
+ TCG_RESULT TcgResult;
+ OPAL_SESSION Session;
+
+ ZeroMem(&Session, sizeof(Session));
+ Session.Sscp = OpalDisk->Sscp;
+ Session.MediaId = OpalDisk->MediaId;
+ Session.OpalBaseComId = OpalDisk->OpalBaseComId;
+
+ TcgResult = OpalGetLockingInfo(&Session, &OpalDisk->LockingFeature);
+ if (TcgResult != TcgResultSuccess) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (OpalDisk->MsidLength == 0) {
+ return EFI_INVALID_PARAMETER;
+ } else {
+ //
+ // Base on the Msid info to get the ownership, so Msid info must get first.
+ //
+ OpalDisk->Owner = OpalUtilDetermineOwnership(&Session, OpalDisk->Msid, OpalDisk->MsidLength);
+ }
+
+ return EFI_SUCCESS;
+}
+
diff --git a/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalHii.h b/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalHii.h
new file mode 100644
index 0000000000..c03f082780
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalHii.h
@@ -0,0 +1,146 @@
+/** @file
+ Public Header file of HII library used by Opal UEFI Driver.
+ Defines required callbacks of Opal HII library.
+
+Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _OPAL_HII_H_
+#define _OPAL_HII_H_
+
+#include <Library/OpalPasswordSupportLib.h>
+#include <OpalDriverPrivate.h>
+
+#define DEFAULT_RESPONSE_SIZE 200
+
+/**
+ Get the driver image handle.
+
+ @retval the driver image handle.
+
+**/
+EFI_HANDLE
+HiiGetDriverImageHandleCB(
+ VOID
+ );
+
+/**
+ Install the HII form and string packages.
+
+ @retval EFI_SUCCESS Install all the resources success.
+ @retval EFI_OUT_OF_RESOURCES Out of resource error.
+**/
+EFI_STATUS
+OpalHiiAddPackages(
+ VOID
+ );
+
+/**
+ Check whether enable feature or not.
+
+ @retval Return the disk number.
+
+**/
+UINT8
+HiiGetNumConfigRequiredOpalDisksCB(
+ VOID
+ );
+
+/**
+ Returns the driver name.
+
+ @retval Returns the driver name.
+
+**/
+CHAR16*
+HiiGetDriverNameCB(
+ VOID
+ );
+
+/**
+ Returns the opaque pointer to a physical disk context.
+
+ @param DiskIndex Input the disk index.
+
+ @retval The device pointer.
+
+**/
+OPAL_DISK*
+HiiGetOpalDiskCB(
+ UINT8 DiskIndex
+ );
+
+/**
+ Returns the disk name.
+
+ @param DiskIndex Input the disk index.
+
+ @retval Returns the disk name.
+
+**/
+CHAR8*
+HiiDiskGetNameCB(
+ UINT8 DiskIndex
+ );
+
+/**
+ Set a string Value in a form.
+
+ @param DestStringId The stringid which need to update.
+ @param SrcAsciiStr The string nned to update.
+
+ @retval EFI_SUCCESS Do the required action success.
+ @retval Others Other error occur.
+
+**/
+EFI_STATUS
+HiiSetFormString(
+ EFI_STRING_ID DestStringId,
+ CHAR8 *SrcAsciiStr
+ );
+
+/**
+ Install the HII related resources.
+
+ @retval EFI_SUCCESS Install all the resources success.
+ @retval other Error occur when install the resources.
+**/
+EFI_STATUS
+HiiInstall(
+ VOID
+ );
+
+/**
+ Uninstall the HII capability.
+
+ @retval EFI_SUCCESS Uninstall all the resources success.
+ @retval others Other errors occur when unistall the hii resource.
+**/
+EFI_STATUS
+HiiUninstall(
+ VOID
+ );
+
+/**
+ Initialize the Opal disk base on the hardware info get from device.
+
+ @param Dev The Opal device.
+
+ @retval EFI_SUCESS Initialize the device success.
+ @retval EFI_DEVICE_ERROR Get info from device failed.
+
+**/
+EFI_STATUS
+OpalDiskInitialize (
+ IN OPAL_DRIVER_DEVICE *Dev
+ );
+
+#endif // _HII_H_
diff --git a/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalHiiCallbacks.c b/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalHiiCallbacks.c
new file mode 100644
index 0000000000..6f2eaeb4c3
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalHiiCallbacks.c
@@ -0,0 +1,221 @@
+/** @file
+ Callbacks required by the HII of the Opal UEFI Driver to help display
+ Opal device information and to send password to SMM handler.
+
+Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "OpalHii.h"
+#include "OpalDriver.h"
+#include "OpalDriverPrivate.h"
+
+/**
+ Get Opal var name.
+ The return Value must be freed by caller if not NULL
+
+ @param OpalDisk The disk.
+ @param Prefix The prefix string.
+
+ @retval The var name string.
+
+**/
+CHAR16*
+OpalDriverGetOpalVarName(
+ OPAL_DISK *OpalDisk,
+ const CHAR16 *Prefix
+ )
+{
+ OPAL_DRIVER_DEVICE* Dev;
+ UINTN PrefixLen;
+ UINTN NameLen;
+ UINTN VarNameLen;
+ CHAR16* VarName;
+
+ Dev = DRIVER_DEVICE_FROM_OPALDISK(OpalDisk);
+ if (Dev == NULL) {
+ return NULL;
+ }
+
+ PrefixLen = StrLen(Prefix);
+
+ NameLen = 0;
+ if (Dev->Name16 != NULL) {
+ NameLen = StrLen(Dev->Name16);
+ }
+
+ VarNameLen = PrefixLen + NameLen;
+
+ VarName = (CHAR16*)AllocateZeroPool((VarNameLen + 1) * sizeof(CHAR16));
+ if (VarName == NULL) {
+ return NULL;
+ }
+
+ CopyMem(VarName, Prefix, PrefixLen * sizeof(CHAR16));
+ if (Dev->Name16 != NULL) {
+ CopyMem(VarName + PrefixLen, Dev->Name16, NameLen * sizeof(CHAR16));
+ }
+ VarName[VarNameLen] = 0;
+
+ return VarName;
+}
+
+/**
+ Get the driver image handle.
+
+ @retval the driver image handle.
+
+**/
+EFI_HANDLE
+HiiGetDriverImageHandleCB(
+ VOID
+ )
+{
+ return gImageHandle;
+}
+
+/**
+ Check whether enable feature or not.
+
+ @retval Return the disk number.
+
+**/
+UINT8
+HiiGetNumConfigRequiredOpalDisksCB(
+ VOID
+ )
+{
+ UINT8 NumDisks;
+ UINT8 NumLockedOpalDisks;
+ OPAL_DISK *OpalDisk;
+ UINT8 Index;
+
+ NumLockedOpalDisks = 0;
+
+ NumDisks = GetDeviceCount();
+
+ for (Index = 0; Index < NumDisks; Index++) {
+ OpalDisk = HiiGetOpalDiskCB(Index);
+
+ if (OpalDisk != NULL) {
+ if (!OpalFeatureEnabled (&OpalDisk->SupportedAttributes, &OpalDisk->LockingFeature)) {
+ DEBUG ((DEBUG_INFO, "Ignoring disk %u because feature is disabled or health has already been inspected\n", Index));
+ } else if (OpalDeviceLocked (&OpalDisk->SupportedAttributes, &OpalDisk->LockingFeature)) {
+ NumLockedOpalDisks++;
+ }
+ }
+ }
+
+ return NumLockedOpalDisks;
+}
+
+
+
+/**
+ Returns the opaque pointer to a physical disk context.
+
+ @param DiskIndex Input the disk index.
+
+ @retval The device pointer.
+
+**/
+VOID *
+HiiGetDiskContextCB(
+ UINT8 DiskIndex
+ )
+{
+ OPAL_DRIVER_DEVICE* Dev;
+ UINT8 CurrentDisk;
+
+ Dev = OpalDriverGetDeviceList();
+ CurrentDisk = 0;
+
+ if (DiskIndex >= GetDeviceCount()) {
+ return NULL;
+ }
+
+ while (Dev != NULL) {
+ if (CurrentDisk == DiskIndex) {
+ return Dev;
+ } else {
+ Dev = Dev->Next;
+ CurrentDisk++;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ Returns the opaque pointer to a physical disk context.
+
+ @param DiskIndex Input the disk index.
+
+ @retval The device pointer.
+
+**/
+OPAL_DISK*
+HiiGetOpalDiskCB(
+ UINT8 DiskIndex
+ )
+{
+ VOID *Ctx;
+ OPAL_DRIVER_DEVICE *Tmp;
+
+ Ctx = HiiGetDiskContextCB (DiskIndex);
+
+ if (Ctx == NULL) {
+ return NULL;
+ }
+
+ Tmp = (OPAL_DRIVER_DEVICE*) Ctx;
+
+ return &Tmp->OpalDisk;
+}
+
+/**
+ Returns the disk name.
+
+ @param DiskIndex Input the disk index.
+
+ @retval Returns the disk name.
+
+**/
+CHAR8*
+HiiDiskGetNameCB(
+ UINT8 DiskIndex
+ )
+{
+ OPAL_DRIVER_DEVICE* Ctx;
+
+ Ctx = (OPAL_DRIVER_DEVICE*) HiiGetDiskContextCB (DiskIndex);
+
+ if (Ctx != NULL) {
+ if (Ctx->NameZ == NULL) {
+ OpalDriverGetDriverDeviceName (Ctx);
+ }
+ return Ctx->NameZ;
+ }
+ return NULL;
+}
+
+/**
+ Returns the driver name.
+
+ @retval Returns the driver name.
+
+**/
+CHAR16*
+HiiGetDriverNameCB(
+ VOID
+ )
+{
+ return (CHAR16*)EFI_DRIVER_NAME_UNICODE;
+}
diff --git a/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalHiiFormStrings.uni b/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalHiiFormStrings.uni
new file mode 100644
index 0000000000..4cfbde3f84
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalHiiFormStrings.uni
@@ -0,0 +1,103 @@
+// /** @file
+//
+// String definitions for Setup formset.
+//
+// Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+//
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+/=#
+///////////////////////////////// GENERIC DEFINITIONS /////////////////////////////////
+#langdef en-US "English"
+#string STR_NULL #language en-US " "
+
+///////////////////////////////// FORM SET /////////////////////////////////
+#string STR_FORM_SET_HELP #language en-US "Manage Opal disks"
+
+///////////////////////////////// MULTIPLE FORMS /////////////////////////////////
+#string STR_OPAL #language en-US "Opal"
+#string STR_MAIN_OPAL_VERSION #language en-US "Version 00.0.0.0000"
+
+///////////////////////////////// MAIN MENU FORM /////////////////////////////////
+#string STR_MAIN_PHY_DISKS_LBL #language en-US "Physical Disks:"
+#string STR_MAIN_LOCKED_DISKS_LBL #language en-US "Locked Disks:"
+
+#string STR_MAIN_GOTO_DISK_INFO_0 #language en-US " "
+#string STR_MAIN_GOTO_DISK_INFO_1 #language en-US " "
+#string STR_MAIN_GOTO_DISK_INFO_2 #language en-US " "
+#string STR_MAIN_GOTO_DISK_INFO_3 #language en-US " "
+#string STR_MAIN_GOTO_DISK_INFO_4 #language en-US " "
+#string STR_MAIN_GOTO_DISK_INFO_5 #language en-US " "
+
+#string STR_MAIN_GOTO_DISK_INFO_HELP #language en-US "Select to see Opal disk actions"
+#string STR_MAIN_GOTO_DISK_HEALTH_HELP #language en-US "Select disk to unlock"
+
+#string STR_MAIN_NO_DISKS_PRESENT_LBL #language en-US "No disks connected to system"
+
+///////////////////////////////// DISK INFO MENU FORM /////////////////////////////////
+#string STR_DISK_INFO_SELECTED_DISK_NAME #language en-US " "
+
+#string STR_DISK_INFO_LOCK #language en-US "Lock"
+#string STR_DISK_INFO_UNLOCK #language en-US "Unlock"
+#string STR_DISK_INFO_SET_ADMIN_PSWD #language en-US "Update Drive Admin Password"
+#string STR_DISK_INFO_SET_USER_PSWD #language en-US "Set Drive User Password"
+#string STR_DISK_INFO_SECURE_ERASE #language en-US "Secure Erase User Data"
+#string STR_DISK_INFO_PSID_REVERT #language en-US "PSID Revert to factory default"
+#string STR_DISK_INFO_REVERT #language en-US "Admin Revert to factory default and Disable"
+#string STR_DISK_INFO_DISABLE_USER #language en-US "Disable User"
+#string STR_DISK_INFO_ENABLE_FEATURE #language en-US "Enable Feature"
+#string STR_DISK_INFO_ENABLE_BLOCKSID #language en-US "TCG Storage Action"
+#string STR_ENABLED #language en-US "Enable BlockSID"
+#string STR_DISABLED #language en-US "Disable BlockSID"
+
+#string STR_NONE #language en-US "None"
+#string STR_DISK_INFO_ENABLE_BLOCKSID_TRUE #language en-US "Require physical presence when remote enable BlockSID"
+#string STR_DISK_INFO_ENABLE_BLOCKSID_FALSE #language en-US "Not require physical presence when remote enable BlockSID"
+#string STR_DISK_INFO_DISABLE_BLOCKSID_TRUE #language en-US "Require physical presence when remote disable BlockSID"
+#string STR_DISK_INFO_DISABLE_BLOCKSID_FALSE #language en-US "Not require physical presence when remote disable BlockSID"
+
+#string STR_BLOCKSID_STATUS_HELP #language en-US "BlockSID action change status"
+#string STR_BLOCKSID_STATUS #language en-US "Current BlockSID Status:"
+#string STR_BLOCKSID_STATUS1 #language en-US ""
+#string STR_BLOCKSID_STATUS2 #language en-US ""
+#string STR_BLOCKSID_STATUS3 #language en-US ""
+
+#string STR_DISK_INFO_GOTO_LOCK_HELP #language en-US "Lock the disk"
+#string STR_DISK_INFO_GOTO_UNLOCK_HELP #language en-US "Unlock the disk"
+#string STR_DISK_INFO_GOTO_SET_ADMIN_PSWD_HELP #language en-US "Set password for the administrator"
+#string STR_DISK_INFO_GOTO_SET_USER_PSWD_HELP #language en-US "Set password for User 1"
+#string STR_DISK_INFO_GOTO_SECURE_ERASE_HELP #language en-US "Securely erase the disk"
+#string STR_DISK_INFO_GOTO_PSID_REVERT_HELP #language en-US "Revert the disk to factory defaults"
+#string STR_DISK_INFO_GOTO_DISABLE_USER_HELP #language en-US "Disable User"
+#string STR_DISK_INFO_GOTO_ENABLE_FEATURE_HELP #language en-US "Enable Feature"
+#string STR_DISK_INFO_GOTO_ENABLE_BLOCKSID_HELP #language en-US "Change BlockSID actions, includes enable or disable BlockSID, Require or not require physical presence when remote enable or disable BlockSID"
+
+///////////////////////////////// DISK ACTION MENU FORM /////////////////////////////////
+#string STR_DISK_ACTION_LBL #language en-US " "
+
+#string STR_PASSWORD_PROMPT #language en-US "Enter Password"
+#string STR_PASSWORD_HELP #language en-US "Password must be between 6 and 20 characters"
+
+#string STR_REVERT_PROMPT #language en-US "Enter PSID"
+#string STR_REVERT_HELP #language en-US "PSID is a 32 character case sensitive value"
+#string STR_ACTION_STATUS #language en-US " "
+
+#string STR_PASSWORD_SUBMIT #language en-US "Submit Password Changes"
+#string STR_PASSWORD_SUBMIT_HELP #language en-US "Submits Password Changes (new and update) after passwords have been entered"
+
+#string STR_GOTO_HOME #language en-US "Main Menu"
+#string STR_GOTO_HOME_HELP #language en-US "Return to the main menu"
+
+#string STR_KEEP_USER_DATA_PROMPT #language en-US "Keep User Data"
+#string STR_KEEP_USER_DATA_HELP #language en-US "Checkmark to keep user data, otherwise data will be lost"
+
+#string STR_OK #language en-US "OK"
+
diff --git a/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalHiiFormValues.h b/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalHiiFormValues.h
new file mode 100644
index 0000000000..88cf9f5b59
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalHiiFormValues.h
@@ -0,0 +1,120 @@
+/** @file
+ Defines Opal HII form ids, structures and values.
+
+Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+
+#ifndef _OPAL_HII_FORM_VALUES_H_
+#define _OPAL_HII_FORM_VALUES_H_
+
+// Maximum Opal password Length
+#define MAX_PASSWORD_CHARACTER_LENGTH 0x14
+
+// PSID Length
+#define PSID_CHARACTER_LENGTH 0x20
+#define PSID_CHARACTER_STRING_END_LENGTH 0x21
+
+// ID's for various forms that will be used by HII
+#define FORMID_VALUE_MAIN_MENU 0x01
+#define FORMID_VALUE_DISK_INFO_FORM_MAIN 0x02
+#define FORMID_VALUE_DISK_ACTION_FORM 0x03
+
+// Structure defining the OPAL_HII_CONFIGURATION
+#pragma pack(1)
+typedef struct {
+ UINT8 NumDisks;
+ UINT8 SelectedDiskIndex;
+ UINT8 SelectedAction;
+ UINT16 SelectedDiskAvailableActions;
+ UINT16 SupportedDisks;
+ UINT8 KeepUserData;
+ UINT16 AvailableFields;
+ UINT16 Password[MAX_PASSWORD_CHARACTER_LENGTH];
+ UINT16 Psid[PSID_CHARACTER_STRING_END_LENGTH];
+ UINT8 EnableBlockSid;
+} OPAL_HII_CONFIGURATION;
+#pragma pack()
+
+/* Action Flags */
+#define HII_ACTION_NONE 0x0000
+#define HII_ACTION_LOCK 0x0001
+#define HII_ACTION_UNLOCK 0x0002
+#define HII_ACTION_SET_ADMIN_PWD 0x0004
+#define HII_ACTION_SET_USER_PWD 0x0008
+#define HII_ACTION_SECURE_ERASE 0x0010
+#define HII_ACTION_PSID_REVERT 0x0020
+#define HII_ACTION_DISABLE_USER 0x0040
+#define HII_ACTION_REVERT 0x0080
+#define HII_ACTION_DISABLE_FEATURE 0x0100
+#define HII_ACTION_ENABLE_FEATURE 0x0200
+
+/* Flags for diskActionAvailableFields */
+#define HII_FIELD_PASSWORD 0x0001
+#define HII_FIELD_PSID 0x0002
+#define HII_FIELD_KEEP_USER_DATA 0x0004
+#define HII_FIELD_KEEP_USER_DATA_FORCED 0x0008
+
+/* Number of bits allocated for each part of a unique key for an HII_ITEM
+ * all bits together must be <= 16 (EFI_QUESTION_ID is UINT16)
+ * 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+ * | |-----------------------| |---------------------------|
+ * FLG INDEX ID
+ */
+#define HII_KEY_ID_BITS 8
+#define HII_KEY_INDEX_BITS 7
+#define HII_KEY_FLAG_BITS 1
+
+#define HII_KEY_FLAG 0x8000 // bit 15 (zero based)
+
+/***********/
+/* Key IDs */
+/***********/
+
+#define HII_KEY_ID_GOTO_MAIN_MENU 0
+#define HII_KEY_ID_GOTO_DISK_INFO 1
+#define HII_KEY_ID_GOTO_LOCK 2
+#define HII_KEY_ID_GOTO_UNLOCK 3
+#define HII_KEY_ID_GOTO_SET_ADMIN_PWD 4
+#define HII_KEY_ID_GOTO_SET_USER_PWD 5
+#define HII_KEY_ID_GOTO_SECURE_ERASE 6
+#define HII_KEY_ID_GOTO_PSID_REVERT 7
+#define HII_KEY_ID_GOTO_REVERT 8
+#define HII_KEY_ID_GOTO_DISABLE_USER 9
+#define HII_KEY_ID_GOTO_ENABLE_FEATURE 0xA //10
+#define HII_KEY_ID_GOTO_CONFIRM_TO_MAIN_MENU 0xB //11
+#define HII_KEY_ID_ENTER_PASSWORD 0xC //12
+#define HII_KEY_ID_ENTER_PSID 0xD //13
+#define HII_KEY_ID_VAR_SUPPORTED_DISKS 0xE //14
+#define HII_KEY_ID_VAR_SELECTED_DISK_AVAILABLE_ACTIONS 0xF //15
+
+#define HII_KEY_ID_BLOCKSID 0x17 //23
+#define HII_KEY_ID_MAX 0x17 //23 // !!Update each time a new ID is added!!
+
+#define HII_KEY_WITH_INDEX(id, index) \
+ ( \
+ HII_KEY_FLAG | \
+ (id) | \
+ ((index) << HII_KEY_ID_BITS) \
+ )
+
+#define HII_KEY(id) HII_KEY_WITH_INDEX(id, 0)
+
+#define PACKAGE_LIST_GUID { 0xf0308176, 0x9058, 0x4153, { 0x93, 0x3d, 0xda, 0x2f, 0xdc, 0xc8, 0x3e, 0x44 } }
+
+/* {410483CF-F4F9-4ece-848A-1958FD31CEB7} */
+#define SETUP_FORMSET_GUID { 0x410483cf, 0xf4f9, 0x4ece, { 0x84, 0x8a, 0x19, 0x58, 0xfd, 0x31, 0xce, 0xb7 } }
+
+// {BBF1ACD2-28D8-44ea-A291-58A237FEDF1A}
+#define SETUP_VARIABLE_GUID { 0xbbf1acd2, 0x28d8, 0x44ea, { 0xa2, 0x91, 0x58, 0xa2, 0x37, 0xfe, 0xdf, 0x1a } }
+
+#endif //_HII_FORM_VALUES_H_
+
diff --git a/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalHiiPrivate.h b/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalHiiPrivate.h
new file mode 100644
index 0000000000..ec5a93cf3f
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalHiiPrivate.h
@@ -0,0 +1,268 @@
+/** @file
+ Private functions and sturctures used by the Opal UEFI Driver.
+
+Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _OPAL_HII_PRIVATE_H_
+#define _OPAL_HII_PRIVATE_H_
+
+
+
+#include <Library/OpalPasswordSupportLib.h>
+#include <Protocol/HiiConfigAccess.h>
+
+#include "OpalHii.h"
+#include "OpalHiiFormValues.h"
+
+
+#define OPAL_PASSWORD_CONFIG_GUID \
+ { \
+ 0x0d510a4f, 0xa81b, 0x473f, { 0x87, 0x07, 0xb7, 0xfd, 0xfb, 0xc0, 0x45, 0xba } \
+ }
+
+#pragma pack(1)
+
+typedef struct {
+ UINT16 Id: HII_KEY_ID_BITS;
+ UINT16 Index: HII_KEY_INDEX_BITS;
+ UINT16 Flag: HII_KEY_FLAG_BITS;
+} KEY_BITS;
+
+typedef union {
+ UINT16 Raw;
+ KEY_BITS KeyBits;
+} HII_KEY;
+
+typedef struct {
+ VENDOR_DEVICE_PATH VendorDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} HII_VENDOR_DEVICE_PATH;
+
+/**
+* Opal PSID Authority utilized for PSID revert
+*
+* The type indicates the structure of the PSID authority
+*/
+typedef struct {
+ UINT8 Psid[PSID_CHARACTER_LENGTH];
+} TCG_PSID;
+
+/**
+ 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 <ConfigResp>
+ 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
+RouteConfig(
+ CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ CONST EFI_STRING Configuration,
+ EFI_STRING *Progress
+ );
+
+/**
+ 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
+ <ConfigRequest> 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
+ <ConfigAltResp> format which has all values filled
+ in for the names in the Request string. String to
+ be allocated by the called function.
+
+ @retval EFI_SUCCESS The Results is filled with the requested values.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results.
+ @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name.
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in this
+ driver.
+
+**/
+EFI_STATUS
+EFIAPI
+ExtractConfig(
+ CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ CONST EFI_STRING Request,
+ EFI_STRING *Progress,
+ EFI_STRING *Results
+ );
+
+/**
+ 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
+DriverCallback(
+ CONST EFI_HII_CONFIG_ACCESS_PROTOCOL* This,
+ EFI_BROWSER_ACTION Action,
+ EFI_QUESTION_ID QuestionId,
+ UINT8 Type,
+ EFI_IFR_TYPE_VALUE* Value,
+ EFI_BROWSER_ACTION_REQUEST* ActionRequest
+ );
+
+/**
+
+ Pass the current system state to the bios via the hii_G_Configuration.
+
+**/
+VOID
+OpalHiiSetBrowserData (
+ VOID
+ );
+
+/**
+
+ Populate the hii_g_Configuraton with the browser Data.
+
+**/
+VOID
+OpalHiiGetBrowserData (
+ VOID
+ );
+
+/**
+ Draws the disk info form.
+
+ @retval EFI_SUCCESS Draw the disk info success.
+
+**/
+EFI_STATUS
+HiiPopulateDiskInfoForm(
+ VOID
+ );
+
+/**
+ Update the global Disk index info.
+
+ @param Index The input disk index info.
+
+ @retval EFI_SUCCESS Update the disk index info success.
+
+**/
+EFI_STATUS
+HiiSelectDisk(
+ UINT8 Index
+ );
+
+/**
+ Use the input password to do the specified action.
+
+ @param Str The input password saved in.
+
+ @retval EFI_SUCCESS Do the required action success.
+ @retval Others Other error occur.
+
+**/
+EFI_STATUS
+HiiPasswordEntered(
+ EFI_STRING_ID Str
+ );
+
+/**
+ Update block sid info.
+
+ @param PpRequest Input the Pp Request.
+
+ @retval EFI_SUCCESS Do the required action success.
+ @retval Others Other error occur.
+
+**/
+EFI_STATUS
+HiiSetBlockSidAction (
+ UINT32 PpRequest
+ );
+
+/**
+ Reverts the Opal disk to factory default.
+
+ @param PsidStringId The string id for the PSID info.
+
+ @retval EFI_SUCCESS Do the required action success.
+
+**/
+EFI_STATUS
+HiiPsidRevert(
+ EFI_STRING_ID PsidStringId
+ );
+
+/**
+ Get disk name string id.
+
+ @param DiskIndex The input disk index info.
+
+ @retval The disk name string id.
+
+**/
+EFI_STRING_ID
+GetDiskNameStringId(
+ UINT8 DiskIndex
+ );
+
+/**
+ Update the device info.
+
+ @param OpalDisk The Opal device.
+
+ @retval EFI_SUCESS Initialize the device success.
+ @retval EFI_DEVICE_ERROR Get info from device failed.
+ @retval EFI_INVALID_PARAMETER Not get Msid info before get ownership info.
+
+**/
+EFI_STATUS
+OpalDiskUpdateStatus (
+ OPAL_DISK *OpalDisk
+ );
+
+#pragma pack()
+
+#endif // _HII_P_H_
diff --git a/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalPasswordDxe.inf b/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalPasswordDxe.inf
new file mode 100644
index 0000000000..f2afc37810
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalPasswordDxe.inf
@@ -0,0 +1,82 @@
+## @file
+# This is a OpalPasswordDxe driver.
+#
+# This module is used to Management the Opal feature
+# for Opal supported devices.
+#
+#
+# Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+[Defines]
+ INF_VERSION = 0x00010007
+ BASE_NAME = OpalPasswordDxe
+ FILE_GUID = E3E4048D-6C0C-43E4-AE1C-FFB579D8EF41
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = EfiDriverEntryPoint
+ UNLOAD_IMAGE = OpalEfiDriverUnload
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ OpalDriver.h
+ OpalHii.c
+ OpalHiiCallbacks.c
+ OpalDriver.c
+ OpalDriverPrivate.h
+ OpalHii.h
+ OpalHiiPrivate.h
+ OpalHiiFormValues.h
+ OpalPasswordForm.vfr
+ OpalHiiFormStrings.uni
+ ComponentName.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ MemoryAllocationLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ UefiHiiServicesLib
+ UefiRuntimeServicesTableLib
+ BaseMemoryLib
+ DebugLib
+ HiiLib
+ PrintLib
+ DevicePathLib
+ OpalPasswordSupportLib
+ UefiLib
+ TcgStorageOpalLib
+ Tcg2PhysicalPresenceLib
+
+[Protocols]
+ gEfiHiiConfigAccessProtocolGuid ## PRODUCES
+ gEfiStorageSecurityCommandProtocolGuid ## CONSUMES
+ gEfiComponentNameProtocolGuid ## PRODUCES
+ gEfiComponentName2ProtocolGuid ## PRODUCES
+ gEfiBlockIoProtocolGuid ## CONSUMES
+ gEfiSmmCommunicationProtocolGuid ## PRODUCES
+ gEfiPciIoProtocolGuid ## CONSUMES
+ gEfiDevicePathToTextProtocolGuid ## CONSUMES
+
+[Guids]
+ gEfiEventExitBootServicesGuid ## CONSUMES ## Event
+ gOpalExtraInfoVariableGuid ## PRODUCES ## GUID
+
+[Depex]
+ gEfiSmmCommunicationProtocolGuid AND gEfiHiiStringProtocolGuid AND gEfiHiiDatabaseProtocolGuid
diff --git a/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalPasswordForm.vfr b/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalPasswordForm.vfr
new file mode 100644
index 0000000000..218e0f442c
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalPasswordForm.vfr
@@ -0,0 +1,350 @@
+/** @file
+
+Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+#include "OpalHiiFormValues.h"
+
+
+#define EFI_HII_PLATFORM_SETUP_FORMSET_GUID \
+ { 0x93039971, 0x8545, 0x4b04, { 0xb4, 0x5e, 0x32, 0xeb, 0x83, 0x26, 0x4, 0xe } }
+
+formset
+ guid = SETUP_FORMSET_GUID,
+ title = STRING_TOKEN(STR_OPAL),
+ help = STRING_TOKEN(STR_FORM_SET_HELP),
+ classguid = EFI_HII_PLATFORM_SETUP_FORMSET_GUID,
+
+ // Define a Buffer Storage (EFI_IFR_VARSTORE) that will be filled
+ // out initially through extractConfig call
+ varstore OPAL_HII_CONFIGURATION, // This is the Data structure type
+ name = OpalHiiConfig, // Define referenced name in vfr
+ guid = SETUP_VARIABLE_GUID; // GUID of this Buffer storage
+
+form formid = FORMID_VALUE_MAIN_MENU,
+ title = STRING_TOKEN(STR_OPAL);
+
+ //CONFIG_VARIABLE(HII_KEY(HII_KEY_ID_VAR_SUPPORTED_DISKS), SupportedDisks, 0x0, 0xFFFF);
+ suppressif TRUE;
+ numeric
+ name = SupportedDisks,
+ varid = OpalHiiConfig.SupportedDisks,
+ prompt = STRING_TOKEN(STR_NULL),
+ help = STRING_TOKEN(STR_NULL),
+ flags = INTERACTIVE,
+ key = 0x800E, //32782,
+ minimum = 0x0,
+ maximum = 0xFFFF,
+ endnumeric;
+ endif;
+
+ subtitle text = STRING_TOKEN(STR_MAIN_OPAL_VERSION);
+
+ subtitle text = STRING_TOKEN(STR_NULL);
+
+ text
+ help = STRING_TOKEN(STR_NULL),
+ text = STRING_TOKEN(STR_MAIN_PHY_DISKS_LBL);
+
+ subtitle text = STRING_TOKEN(STR_NULL);
+
+ //DISK( 0 );
+ suppressif ( questionref(SupportedDisks) & ( 0x1 ) ) == 0;
+ goto FORMID_VALUE_DISK_INFO_FORM_MAIN,
+ prompt = STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_0 ),
+ help = STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_HELP),
+ flags = INTERACTIVE, \
+ key = 0x8001; //32769
+ endif;
+
+ //DISK( 1 );
+ suppressif ( questionref(SupportedDisks) & ( 0x2 ) ) == 0;
+ goto FORMID_VALUE_DISK_INFO_FORM_MAIN,
+ prompt = STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_1 ),
+ help = STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_HELP),
+ flags = INTERACTIVE, \
+ key = 0x8101; //33025
+ endif;
+
+ //DISK( 2 );
+ suppressif ( questionref(SupportedDisks) & ( 0x4 ) ) == 0;
+ goto FORMID_VALUE_DISK_INFO_FORM_MAIN,
+ prompt = STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_2 ),
+ help = STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_HELP),
+ flags = INTERACTIVE, \
+ key = 0x8201; //33281
+ endif;
+
+ //DISK( 3 );
+ suppressif ( questionref(SupportedDisks) & ( 0x8 ) ) == 0;
+ goto FORMID_VALUE_DISK_INFO_FORM_MAIN,
+ prompt = STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_3 ),
+ help = STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_HELP),
+ flags = INTERACTIVE, \
+ key = 0x8301; // 33537
+ endif;
+
+ //DISK( 4 );
+ suppressif ( questionref(SupportedDisks) & ( 0x10 ) ) == 0;
+ goto FORMID_VALUE_DISK_INFO_FORM_MAIN,
+ prompt = STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_4 ),
+ help = STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_HELP),
+ flags = INTERACTIVE, \
+ key = 0x8401; // 33793
+ endif;
+
+ //DISK( 5 );
+ suppressif ( questionref(SupportedDisks) & ( 0x20 ) ) == 0;
+ goto FORMID_VALUE_DISK_INFO_FORM_MAIN,
+ prompt = STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_5 ),
+ help = STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_HELP),
+ flags = INTERACTIVE, \
+ key = 0x8501; // 34049
+ endif;
+
+ //No disks on system
+ suppressif ideqval OpalHiiConfig.NumDisks > 0;
+ text
+ help = STRING_TOKEN(STR_NULL),
+ text = STRING_TOKEN(STR_MAIN_NO_DISKS_PRESENT_LBL);
+ endif;
+
+ subtitle text = STRING_TOKEN(STR_NULL);
+
+ grayoutif TRUE;
+ text
+ help = STRING_TOKEN(STR_BLOCKSID_STATUS_HELP),
+ text = STRING_TOKEN(STR_BLOCKSID_STATUS);
+ text
+ help = STRING_TOKEN(STR_BLOCKSID_STATUS_HELP),
+ text = STRING_TOKEN(STR_BLOCKSID_STATUS1);
+ text
+ help = STRING_TOKEN(STR_BLOCKSID_STATUS_HELP),
+ text = STRING_TOKEN(STR_BLOCKSID_STATUS2);
+ text
+ help = STRING_TOKEN(STR_BLOCKSID_STATUS_HELP),
+ text = STRING_TOKEN(STR_BLOCKSID_STATUS3);
+ subtitle text = STRING_TOKEN(STR_NULL);
+ endif;
+
+ oneof varid = OpalHiiConfig.EnableBlockSid,
+ questionid = 0x8017, // 32791,
+ prompt = STRING_TOKEN(STR_DISK_INFO_ENABLE_BLOCKSID),
+ help = STRING_TOKEN(STR_DISK_INFO_GOTO_ENABLE_BLOCKSID_HELP),
+ flags = INTERACTIVE,
+ option text = STRING_TOKEN(STR_NONE), value = 0, flags = DEFAULT | MANUFACTURING | RESET_REQUIRED;
+ option text = STRING_TOKEN(STR_ENABLED), value = 1, flags = RESET_REQUIRED;
+ option text = STRING_TOKEN(STR_DISABLED), value = 2, flags = RESET_REQUIRED;
+ option text = STRING_TOKEN(STR_DISK_INFO_ENABLE_BLOCKSID_TRUE), value = 3, flags = RESET_REQUIRED;
+ option text = STRING_TOKEN(STR_DISK_INFO_ENABLE_BLOCKSID_FALSE), value = 4, flags = RESET_REQUIRED;
+ option text = STRING_TOKEN(STR_DISK_INFO_DISABLE_BLOCKSID_TRUE), value = 5, flags = RESET_REQUIRED;
+ option text = STRING_TOKEN(STR_DISK_INFO_DISABLE_BLOCKSID_FALSE), value = 6, flags = RESET_REQUIRED;
+ endoneof;
+
+
+
+endform; // MAIN MENU FORM
+
+//
+///////////////// DISK INFO FORM /////////////////
+//
+form formid = FORMID_VALUE_DISK_INFO_FORM_MAIN,
+ title = STRING_TOKEN(STR_OPAL);
+
+ suppressif TRUE;
+ numeric
+ name = SelectedDiskAvailableActions,
+ varid = OpalHiiConfig.SelectedDiskAvailableActions,
+ prompt = STRING_TOKEN(STR_NULL),
+ help = STRING_TOKEN(STR_NULL),
+ flags = INTERACTIVE,
+ key = 0x800F, // 32783
+ minimum = 0x0,
+ maximum = 0xFFFF,
+ endnumeric;
+ endif;
+
+ subtitle text = STRING_TOKEN(STR_MAIN_OPAL_VERSION);
+
+ subtitle text = STRING_TOKEN(STR_NULL);
+
+ text
+ help = STRING_TOKEN(STR_NULL),
+ text = STRING_TOKEN(STR_DISK_INFO_SELECTED_DISK_NAME);
+
+ subtitle text = STRING_TOKEN(STR_NULL);
+
+ suppressif ( questionref(SelectedDiskAvailableActions) & HII_ACTION_LOCK ) == 0;
+ goto FORMID_VALUE_DISK_ACTION_FORM,
+ prompt = STRING_TOKEN(STR_DISK_INFO_LOCK),
+ help = STRING_TOKEN(STR_DISK_INFO_GOTO_LOCK_HELP),
+ flags = INTERACTIVE,
+ key = 0x8002; // 32770
+ endif;
+
+ suppressif ( questionref(SelectedDiskAvailableActions) & HII_ACTION_UNLOCK ) == 0;
+ goto FORMID_VALUE_DISK_ACTION_FORM,
+ prompt = STRING_TOKEN(STR_DISK_INFO_UNLOCK),
+ help = STRING_TOKEN(STR_DISK_INFO_GOTO_UNLOCK_HELP),
+ flags = INTERACTIVE,
+ key = 0x8003; //32771;
+ endif;
+
+ suppressif ( questionref(SelectedDiskAvailableActions) & HII_ACTION_SET_ADMIN_PWD ) == 0;
+ goto FORMID_VALUE_DISK_ACTION_FORM,
+ prompt = STRING_TOKEN(STR_DISK_INFO_SET_ADMIN_PSWD),
+ help = STRING_TOKEN(STR_DISK_INFO_GOTO_SET_ADMIN_PSWD_HELP),
+ flags = INTERACTIVE,
+ key = 0x8004; //32772;
+ endif;
+
+ suppressif ( questionref(SelectedDiskAvailableActions) & HII_ACTION_SET_USER_PWD ) == 0;
+ goto FORMID_VALUE_DISK_ACTION_FORM,
+ prompt = STRING_TOKEN(STR_DISK_INFO_SET_USER_PSWD),
+ help = STRING_TOKEN(STR_DISK_INFO_GOTO_SET_USER_PSWD_HELP),
+ flags = INTERACTIVE,
+ key = 0x8005; //32773;
+ endif;
+
+ suppressif ( questionref(SelectedDiskAvailableActions) & HII_ACTION_SECURE_ERASE ) == 0;
+ goto FORMID_VALUE_DISK_ACTION_FORM,
+ prompt = STRING_TOKEN(STR_DISK_INFO_SECURE_ERASE),
+ help = STRING_TOKEN(STR_DISK_INFO_GOTO_SECURE_ERASE_HELP),
+ flags = INTERACTIVE,
+ key = 0x8006; //32774;
+ endif;
+
+ suppressif ( questionref(SelectedDiskAvailableActions) & HII_ACTION_REVERT ) == 0;
+ goto FORMID_VALUE_DISK_ACTION_FORM,
+ prompt = STRING_TOKEN(STR_DISK_INFO_REVERT),
+ help = STRING_TOKEN(STR_DISK_INFO_GOTO_PSID_REVERT_HELP),
+ flags = INTERACTIVE,
+ key = 0x8008; //32776;
+ endif;
+
+ suppressif ( questionref(SelectedDiskAvailableActions) & HII_ACTION_PSID_REVERT ) == 0;
+ goto FORMID_VALUE_DISK_ACTION_FORM,
+ prompt = STRING_TOKEN(STR_DISK_INFO_PSID_REVERT),
+ help = STRING_TOKEN(STR_DISK_INFO_GOTO_PSID_REVERT_HELP),
+ flags = INTERACTIVE,
+ key = 0x8007; //32775;
+ endif;
+
+ suppressif ( questionref(SelectedDiskAvailableActions) & HII_ACTION_DISABLE_USER ) == 0;
+ goto FORMID_VALUE_DISK_ACTION_FORM,
+ prompt = STRING_TOKEN(STR_DISK_INFO_DISABLE_USER),
+ help = STRING_TOKEN(STR_DISK_INFO_GOTO_DISABLE_USER_HELP),
+ flags = INTERACTIVE,
+ key = 0x8009; //32777;
+ endif;
+
+ suppressif ( questionref(SelectedDiskAvailableActions) & HII_ACTION_ENABLE_FEATURE ) == 0;
+ goto FORMID_VALUE_DISK_ACTION_FORM,
+ prompt = STRING_TOKEN(STR_DISK_INFO_ENABLE_FEATURE),
+ help = STRING_TOKEN(STR_DISK_INFO_GOTO_ENABLE_FEATURE_HELP),
+ flags = INTERACTIVE,
+ key = 0x800A; //32778;
+ endif;
+
+endform; // DISK INFO FORM
+
+//
+///////////////// DISK ACTION FORM /////////////////
+//
+form formid = FORMID_VALUE_DISK_ACTION_FORM,
+ title = STRING_TOKEN(STR_OPAL);
+
+ suppressif TRUE;
+ numeric
+ name = AvailableFields,
+ varid = OpalHiiConfig.AvailableFields,
+ prompt = STRING_TOKEN(STR_NULL),
+ help = STRING_TOKEN(STR_NULL),
+ flags = INTERACTIVE,
+ key = 0x8012, //32786,
+ minimum = 0x0,
+ maximum = 0xFFFF,
+ endnumeric;
+ endif;
+
+ subtitle text = STRING_TOKEN(STR_MAIN_OPAL_VERSION);
+
+ subtitle text = STRING_TOKEN(STR_NULL);
+
+ text
+ help = STRING_TOKEN(STR_NULL),
+ text = STRING_TOKEN(STR_DISK_INFO_SELECTED_DISK_NAME);
+
+ subtitle text = STRING_TOKEN(STR_NULL);
+
+ text
+ help = STRING_TOKEN(STR_NULL),
+ text = STRING_TOKEN(STR_DISK_ACTION_LBL);
+
+ subtitle text = STRING_TOKEN(STR_NULL);
+
+ suppressif (questionref(AvailableFields) & HII_FIELD_KEEP_USER_DATA) == 0;
+ grayoutif (questionref(AvailableFields) & HII_FIELD_KEEP_USER_DATA_FORCED) != 0;
+ checkbox
+ name = MyCheckbox,
+ varid = OpalHiiConfig.KeepUserData,
+ prompt = STRING_TOKEN(STR_KEEP_USER_DATA_PROMPT),
+ help = STRING_TOKEN(STR_KEEP_USER_DATA_HELP),
+ key = 0x8011, //32785,
+ endcheckbox;
+
+ //EMPTY_LINE;
+ text
+ help = STRING_TOKEN(STR_NULL),
+ text = STRING_TOKEN(STR_NULL);
+ endif;
+ endif;
+
+ suppressif (questionref(AvailableFields) & HII_FIELD_PASSWORD) == 0;
+ password
+ varid = OpalHiiConfig.Password,
+ prompt = STRING_TOKEN(STR_PASSWORD_PROMPT),
+ help = STRING_TOKEN(STR_PASSWORD_HELP),
+ flags = INTERACTIVE,
+ key = 0x800C, //32780,
+ minsize = 6,
+ maxsize = 20,
+ endpassword;
+ endif;
+
+ suppressif (questionref(AvailableFields) & HII_FIELD_PSID) == 0;
+ string
+ varid = OpalHiiConfig.Psid,
+ prompt = STRING_TOKEN(STR_REVERT_PROMPT),
+ help = STRING_TOKEN(STR_REVERT_HELP),
+ flags = INTERACTIVE,
+ key = 0x800D, //32781,
+ minsize = PSID_CHARACTER_LENGTH,
+ maxsize = PSID_CHARACTER_LENGTH,
+ endstring;
+ endif;
+
+ subtitle text = STRING_TOKEN(STR_NULL);
+
+ text
+ help = STRING_TOKEN(STR_NULL),
+ text = STRING_TOKEN(STR_ACTION_STATUS);
+
+ subtitle text = STRING_TOKEN(STR_NULL);
+
+ goto FORMID_VALUE_MAIN_MENU,
+ prompt = STRING_TOKEN(STR_GOTO_HOME),
+ help = STRING_TOKEN(STR_GOTO_HOME_HELP),
+ flags = INTERACTIVE,
+ key = 0x8000; //32768;
+
+endform; // DISK ACTION FORM
+
+endformset;
diff --git a/Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalAhciMode.c b/Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalAhciMode.c
new file mode 100644
index 0000000000..33f77bd8a2
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalAhciMode.c
@@ -0,0 +1,1295 @@
+/** @file
+ This driver is used for Opal Password Feature support at AHCI mode.
+
+Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+
+#include "OpalPasswordSmm.h"
+
+/**
+ Start command for give slot on specific port.
+
+ @param Port The number of port.
+ @param CommandSlot The number of CommandSlot.
+ @param Timeout The timeout Value of start.
+
+ @retval EFI_DEVICE_ERROR The command start unsuccessfully.
+ @retval EFI_TIMEOUT The operation is time out.
+ @retval EFI_SUCCESS The command start successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciStartCommand (
+ IN UINT8 Port,
+ IN UINT8 CommandSlot,
+ IN UINT64 Timeout
+ );
+
+/**
+ Stop command running for giving port
+
+ @param Port The number of port.
+ @param Timeout The timeout Value of stop.
+
+ @retval EFI_DEVICE_ERROR The command stop unsuccessfully.
+ @retval EFI_TIMEOUT The operation is time out.
+ @retval EFI_SUCCESS The command stop successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciStopCommand (
+ IN UINT8 Port,
+ IN UINT64 Timeout
+ );
+
+/**
+ Read AHCI Operation register.
+
+ @param Offset The operation register offset.
+
+ @return The register content read.
+
+**/
+UINT32
+EFIAPI
+AhciReadReg (
+ IN UINT32 Offset
+ )
+{
+ UINT32 Data;
+
+ Data = 0;
+
+ Data = MmioRead32 (mAhciBar + Offset);
+
+ return Data;
+}
+
+/**
+ Write AHCI Operation register.
+
+ @param Offset The operation register offset.
+ @param Data The Data used to write down.
+
+**/
+VOID
+EFIAPI
+AhciWriteReg (
+ IN UINT32 Offset,
+ IN UINT32 Data
+ )
+{
+ MmioWrite32 (mAhciBar + Offset, Data);
+
+ return ;
+}
+
+/**
+ Do AND operation with the Value of AHCI Operation register.
+
+ @param Offset The operation register offset.
+ @param AndData The Data used to do AND operation.
+
+**/
+VOID
+EFIAPI
+AhciAndReg (
+ IN UINT32 Offset,
+ IN UINT32 AndData
+ )
+{
+ UINT32 Data;
+
+ Data = AhciReadReg (Offset);
+
+ Data &= AndData;
+
+ AhciWriteReg (Offset, Data);
+}
+
+/**
+ Do OR operation with the Value of AHCI Operation register.
+
+ @param Offset The operation register offset.
+ @param OrData The Data used to do OR operation.
+
+**/
+VOID
+EFIAPI
+AhciOrReg (
+ IN UINT32 Offset,
+ IN UINT32 OrData
+ )
+{
+ UINT32 Data;
+
+ Data = AhciReadReg (Offset);
+
+ Data |= OrData;
+
+ AhciWriteReg (Offset, Data);
+}
+
+/**
+ Wait for memory set to the test Value.
+
+ @param Offset The memory address to test.
+ @param MaskValue The mask Value of memory.
+ @param TestValue The test Value of memory.
+ @param Timeout The time out Value for wait memory set.
+
+ @retval EFI_DEVICE_ERROR The memory is not set.
+ @retval EFI_TIMEOUT The memory setting is time out.
+ @retval EFI_SUCCESS The memory is correct set.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciWaitMmioSet (
+ IN UINT32 Offset,
+ IN UINT32 MaskValue,
+ IN UINT32 TestValue,
+ IN UINT64 Timeout
+ )
+{
+ UINT32 Value;
+ UINT32 Delay;
+
+ Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);
+
+ do {
+ Value = AhciReadReg (Offset) & MaskValue;
+
+ if (Value == TestValue) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Stall for 100 microseconds.
+ //
+ MicroSecondDelay (100);
+
+ Delay--;
+
+ } while (Delay > 0);
+
+ return EFI_TIMEOUT;
+}
+/**
+ Wait for the Value of the specified system memory set to the test Value.
+
+ @param Address The system memory address to test.
+ @param MaskValue The mask Value of memory.
+ @param TestValue The test Value of memory.
+ @param Timeout The time out Value for wait memory set, uses 100ns as a unit.
+
+ @retval EFI_TIMEOUT The system memory setting is time out.
+ @retval EFI_SUCCESS The system memory is correct set.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciWaitMemSet (
+ IN EFI_PHYSICAL_ADDRESS Address,
+ IN UINT32 MaskValue,
+ IN UINT32 TestValue,
+ IN UINT64 Timeout
+ )
+{
+ UINT32 Value;
+ UINT32 Delay;
+
+ Delay = (UINT32) (DivU64x32 (Timeout, 1000) + 1);
+
+ do {
+ //
+ // Access sytem memory to see if the Value is the tested one.
+ //
+ // The system memory pointed by Address will be updated by the
+ // SATA Host Controller, "volatile" is introduced to prevent
+ // compiler from optimizing the access to the memory address
+ // to only read once.
+ //
+ Value = *(volatile UINT32 *) (UINTN) Address;
+ Value &= MaskValue;
+
+ if (Value == TestValue) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Stall for 100 microseconds.
+ //
+ MicroSecondDelay (100);
+
+ Delay--;
+
+ } while (Delay > 0);
+
+ return EFI_TIMEOUT;
+}
+
+/**
+ Check the memory status to the test Value.
+
+ @param[in] Address The memory address to test.
+ @param[in] MaskValue The mask Value of memory.
+ @param[in] TestValue The test Value of memory.
+ @param[in, out] RetryTimes The retry times Value for waitting memory set. If 0, then just try once.
+
+ @retval EFI_NOTREADY The memory is not set.
+ @retval EFI_TIMEOUT The memory setting retry times out.
+ @retval EFI_SUCCESS The memory is correct set.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciCheckMemSet (
+ IN UINTN Address,
+ IN UINT32 MaskValue,
+ IN UINT32 TestValue,
+ IN OUT UINTN *RetryTimes OPTIONAL
+ )
+{
+ UINT32 Value;
+
+ if (RetryTimes != NULL) {
+ (*RetryTimes)--;
+ }
+
+ Value = *(volatile UINT32 *) Address;
+ Value &= MaskValue;
+
+ if (Value == TestValue) {
+ return EFI_SUCCESS;
+ }
+
+ if ((RetryTimes != NULL) && (*RetryTimes == 0)) {
+ return EFI_TIMEOUT;
+ } else {
+ return EFI_NOT_READY;
+ }
+}
+
+/**
+ Clear the port interrupt and error status. It will also clear
+ HBA interrupt status.
+
+ @param Port The number of port.
+
+**/
+VOID
+EFIAPI
+AhciClearPortStatus (
+ IN UINT8 Port
+ )
+{
+ UINT32 Offset;
+
+ //
+ // Clear any error status
+ //
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SERR;
+ AhciWriteReg (Offset, AhciReadReg (Offset));
+
+ //
+ // Clear any port interrupt status
+ //
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IS;
+ AhciWriteReg (Offset, AhciReadReg (Offset));
+
+ //
+ // Clear any HBA interrupt status
+ //
+ AhciWriteReg (EFI_AHCI_IS_OFFSET, AhciReadReg (EFI_AHCI_IS_OFFSET));
+}
+
+/**
+ Enable the FIS running for giving port.
+
+ @param Port The number of port.
+ @param Timeout The timeout Value of enabling FIS.
+
+ @retval EFI_DEVICE_ERROR The FIS enable setting fails.
+ @retval EFI_TIMEOUT The FIS enable setting is time out.
+ @retval EFI_SUCCESS The FIS enable successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciEnableFisReceive (
+ IN UINT8 Port,
+ IN UINT64 Timeout
+ )
+{
+ UINT32 Offset;
+
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;
+ AhciOrReg (Offset, EFI_AHCI_PORT_CMD_FRE);
+
+ return AhciWaitMmioSet (
+ Offset,
+ EFI_AHCI_PORT_CMD_FR,
+ EFI_AHCI_PORT_CMD_FR,
+ Timeout
+ );
+}
+
+/**
+ Disable the FIS running for giving port.
+
+ @param Port The number of port.
+ @param Timeout The timeout Value of disabling FIS.
+
+ @retval EFI_DEVICE_ERROR The FIS disable setting fails.
+ @retval EFI_TIMEOUT The FIS disable setting is time out.
+ @retval EFI_UNSUPPORTED The port is in running state.
+ @retval EFI_SUCCESS The FIS disable successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciDisableFisReceive (
+ IN UINT8 Port,
+ IN UINT64 Timeout
+ )
+{
+ UINT32 Offset;
+ UINT32 Data;
+
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;
+ Data = AhciReadReg (Offset);
+
+ //
+ // Before disabling Fis receive, the DMA engine of the port should NOT be in running status.
+ //
+ if ((Data & (EFI_AHCI_PORT_CMD_ST | EFI_AHCI_PORT_CMD_CR)) != 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Check if the Fis receive DMA engine for the port is running.
+ //
+ if ((Data & EFI_AHCI_PORT_CMD_FR) != EFI_AHCI_PORT_CMD_FR) {
+ return EFI_SUCCESS;
+ }
+
+ AhciAndReg (Offset, (UINT32)~(EFI_AHCI_PORT_CMD_FRE));
+
+ return AhciWaitMmioSet (
+ Offset,
+ EFI_AHCI_PORT_CMD_FR,
+ 0,
+ Timeout
+ );
+}
+
+/**
+ Build the command list, command table and prepare the fis receiver.
+
+ @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
+ @param Port The number of port.
+ @param PortMultiplier The timeout Value of stop.
+ @param CommandFis The control fis will be used for the transfer.
+ @param CommandList The command list will be used for the transfer.
+ @param AtapiCommand The atapi command will be used for the transfer.
+ @param AtapiCommandLength The Length of the atapi command.
+ @param CommandSlotNumber The command slot will be used for the transfer.
+ @param DataPhysicalAddr The pointer to the Data Buffer pci bus master address.
+ @param DataLength The Data count to be transferred.
+
+**/
+VOID
+EFIAPI
+AhciBuildCommand (
+ IN EFI_AHCI_REGISTERS *AhciRegisters,
+ IN UINT8 Port,
+ IN UINT8 PortMultiplier,
+ IN EFI_AHCI_COMMAND_FIS *CommandFis,
+ IN EFI_AHCI_COMMAND_LIST *CommandList,
+ IN EFI_AHCI_ATAPI_COMMAND *AtapiCommand OPTIONAL,
+ IN UINT8 AtapiCommandLength,
+ IN UINT8 CommandSlotNumber,
+ IN OUT VOID *DataPhysicalAddr,
+ IN UINT64 DataLength
+ )
+{
+ UINT64 BaseAddr;
+ UINT64 PrdtNumber;
+ UINTN RemainedData;
+ UINTN MemAddr;
+ DATA_64 Data64;
+ UINT32 Offset;
+
+ //
+ // Filling the PRDT
+ //
+ PrdtNumber = DivU64x32 (DataLength + EFI_AHCI_MAX_DATA_PER_PRDT - 1, EFI_AHCI_MAX_DATA_PER_PRDT);
+
+ //
+ // According to AHCI 1.3 spec, a PRDT entry can point to a maximum 4MB Data block.
+ // It also limits that the maximum amount of the PRDT entry in the command table
+ // is 65535.
+ //
+ ASSERT (PrdtNumber <= 1);
+
+ Data64.Uint64 = (UINTN) (AhciRegisters->AhciRFis);
+
+ BaseAddr = Data64.Uint64;
+
+ ZeroMem ((VOID *)((UINTN) BaseAddr), sizeof (EFI_AHCI_RECEIVED_FIS));
+
+ ZeroMem (AhciRegisters->AhciCommandTable, sizeof (EFI_AHCI_COMMAND_TABLE));
+
+ CommandFis->AhciCFisPmNum = PortMultiplier;
+
+ CopyMem (&AhciRegisters->AhciCommandTable->CommandFis, CommandFis, sizeof (EFI_AHCI_COMMAND_FIS));
+
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;
+ if (AtapiCommand != NULL) {
+ CopyMem (
+ &AhciRegisters->AhciCommandTable->AtapiCmd,
+ AtapiCommand,
+ AtapiCommandLength
+ );
+
+ CommandList->AhciCmdA = 1;
+ CommandList->AhciCmdP = 1;
+
+ AhciOrReg (Offset, (EFI_AHCI_PORT_CMD_DLAE | EFI_AHCI_PORT_CMD_ATAPI));
+ } else {
+ AhciAndReg (Offset, (UINT32)~(EFI_AHCI_PORT_CMD_DLAE | EFI_AHCI_PORT_CMD_ATAPI));
+ }
+
+ RemainedData = (UINTN) DataLength;
+ MemAddr = (UINTN) DataPhysicalAddr;
+ CommandList->AhciCmdPrdtl = (UINT32)PrdtNumber;
+
+ AhciRegisters->AhciCommandTable->PrdtTable.AhciPrdtDbc = (UINT32)RemainedData - 1;
+
+ Data64.Uint64 = (UINT64)MemAddr;
+ AhciRegisters->AhciCommandTable->PrdtTable.AhciPrdtDba = Data64.Uint32.Lower32;
+ AhciRegisters->AhciCommandTable->PrdtTable.AhciPrdtDbau = Data64.Uint32.Upper32;
+
+ //
+ // Set the last PRDT to Interrupt On Complete
+ //
+ AhciRegisters->AhciCommandTable->PrdtTable.AhciPrdtIoc = 1;
+
+ CopyMem (
+ (VOID *) ((UINTN) AhciRegisters->AhciCmdList + (UINTN) CommandSlotNumber * sizeof (EFI_AHCI_COMMAND_LIST)),
+ CommandList,
+ sizeof (EFI_AHCI_COMMAND_LIST)
+ );
+
+ Data64.Uint64 = (UINT64)(UINTN) AhciRegisters->AhciCommandTable;
+ AhciRegisters->AhciCmdList[CommandSlotNumber].AhciCmdCtba = Data64.Uint32.Lower32;
+ AhciRegisters->AhciCmdList[CommandSlotNumber].AhciCmdCtbau = Data64.Uint32.Upper32;
+ AhciRegisters->AhciCmdList[CommandSlotNumber].AhciCmdPmp = PortMultiplier;
+
+}
+
+/**
+ Buid a command FIS.
+
+ @param CmdFis A pointer to the EFI_AHCI_COMMAND_FIS Data structure.
+ @param AtaCommandBlock A pointer to the AhciBuildCommandFis Data structure.
+
+**/
+VOID
+EFIAPI
+AhciBuildCommandFis (
+ IN OUT EFI_AHCI_COMMAND_FIS *CmdFis,
+ IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock
+ )
+{
+ ZeroMem (CmdFis, sizeof (EFI_AHCI_COMMAND_FIS));
+
+ CmdFis->AhciCFisType = EFI_AHCI_FIS_REGISTER_H2D;
+ //
+ // Indicator it's a command
+ //
+ CmdFis->AhciCFisCmdInd = 0x1;
+ CmdFis->AhciCFisCmd = AtaCommandBlock->AtaCommand;
+
+ CmdFis->AhciCFisFeature = AtaCommandBlock->AtaFeatures;
+ CmdFis->AhciCFisFeatureExp = AtaCommandBlock->AtaFeaturesExp;
+
+ CmdFis->AhciCFisSecNum = AtaCommandBlock->AtaSectorNumber;
+ CmdFis->AhciCFisSecNumExp = AtaCommandBlock->AtaSectorNumberExp;
+
+ CmdFis->AhciCFisClyLow = AtaCommandBlock->AtaCylinderLow;
+ CmdFis->AhciCFisClyLowExp = AtaCommandBlock->AtaCylinderLowExp;
+
+ CmdFis->AhciCFisClyHigh = AtaCommandBlock->AtaCylinderHigh;
+ CmdFis->AhciCFisClyHighExp = AtaCommandBlock->AtaCylinderHighExp;
+
+ CmdFis->AhciCFisSecCount = AtaCommandBlock->AtaSectorCount;
+ CmdFis->AhciCFisSecCountExp = AtaCommandBlock->AtaSectorCountExp;
+
+ CmdFis->AhciCFisDevHead = (UINT8) (AtaCommandBlock->AtaDeviceHead | 0xE0);
+}
+
+/**
+ Start a PIO Data transfer on specific port.
+
+ @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
+ @param Port The number of port.
+ @param PortMultiplier The timeout Value of stop.
+ @param AtapiCommand The atapi command will be used for the transfer.
+ @param AtapiCommandLength The Length of the atapi command.
+ @param Read The transfer direction.
+ @param AtaCommandBlock The EFI_ATA_COMMAND_BLOCK Data.
+ @param AtaStatusBlock The EFI_ATA_STATUS_BLOCK Data.
+ @param MemoryAddr The pointer to the Data Buffer.
+ @param DataCount The Data count to be transferred.
+ @param Timeout The timeout Value of non Data transfer.
+
+ @retval EFI_DEVICE_ERROR The PIO Data transfer abort with error occurs.
+ @retval EFI_TIMEOUT The operation is time out.
+ @retval EFI_UNSUPPORTED The device is not ready for transfer.
+ @retval EFI_SUCCESS The PIO Data transfer executes successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciPioTransfer (
+ IN EFI_AHCI_REGISTERS *AhciRegisters,
+ IN UINT8 Port,
+ IN UINT8 PortMultiplier,
+ IN EFI_AHCI_ATAPI_COMMAND *AtapiCommand OPTIONAL,
+ IN UINT8 AtapiCommandLength,
+ IN BOOLEAN Read,
+ IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock,
+ IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock,
+ IN OUT VOID *MemoryAddr,
+ IN UINT32 DataCount,
+ IN UINT64 Timeout
+ )
+{
+ EFI_STATUS Status;
+ UINT32 FisBaseAddr;
+ UINT32 Offset;
+ UINT32 Delay;
+ EFI_AHCI_COMMAND_FIS CFis;
+ EFI_AHCI_COMMAND_LIST CmdList;
+ UINT32 PortTfd;
+ UINT32 PrdCount;
+ UINT32 OldRfisLo;
+ UINT32 OldRfisHi;
+ UINT32 OldCmdListLo;
+ UINT32 OldCmdListHi;
+
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FB;
+ OldRfisLo = AhciReadReg (Offset);
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FBU;
+ OldRfisHi = AhciReadReg (Offset);
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FB;
+ AhciWriteReg (Offset, (UINT32)(UINTN)AhciRegisters->AhciRFis);
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FBU;
+ AhciWriteReg (Offset, 0);
+
+ //
+ // Single task envrionment, we only use one command table for all port
+ //
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLB;
+ OldCmdListLo = AhciReadReg (Offset);
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLBU;
+ OldCmdListHi = AhciReadReg (Offset);
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLB;
+ AhciWriteReg (Offset, (UINT32)(UINTN)AhciRegisters->AhciCmdList);
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLBU;
+ AhciWriteReg (Offset, 0);
+
+ //
+ // Package read needed
+ //
+ AhciBuildCommandFis (&CFis, AtaCommandBlock);
+
+ ZeroMem (&CmdList, sizeof (EFI_AHCI_COMMAND_LIST));
+
+ CmdList.AhciCmdCfl = EFI_AHCI_FIS_REGISTER_H2D_LENGTH / 4;
+ CmdList.AhciCmdW = Read ? 0 : 1;
+
+ AhciBuildCommand (
+ AhciRegisters,
+ Port,
+ PortMultiplier,
+ &CFis,
+ &CmdList,
+ AtapiCommand,
+ AtapiCommandLength,
+ 0,
+ (VOID *)(UINTN)MemoryAddr,
+ DataCount
+ );
+
+ Status = AhciStartCommand (
+ Port,
+ 0,
+ Timeout
+ );
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ //
+ // Checking the status and wait the driver sending Data
+ //
+ FisBaseAddr = (UINT32)(UINTN)AhciRegisters->AhciRFis;
+ if (Read && (AtapiCommand == 0)) {
+ //
+ // Wait device sends the PIO setup fis before Data transfer
+ //
+ Status = EFI_TIMEOUT;
+ Delay = (UINT32) (DivU64x32 (Timeout, 1000) + 1);
+ do {
+ Offset = FisBaseAddr + EFI_AHCI_PIO_FIS_OFFSET;
+
+ Status = AhciCheckMemSet (Offset, EFI_AHCI_FIS_TYPE_MASK, EFI_AHCI_FIS_PIO_SETUP, 0);
+ if (!EFI_ERROR (Status)) {
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;
+ PortTfd = AhciReadReg ((UINT32) Offset);
+ //
+ // PxTFD will be updated if there is a D2H or SetupFIS received.
+ // For PIO IN transfer, D2H means a device error. Therefore we only need to check the TFD after receiving a SetupFIS.
+ //
+ if ((PortTfd & EFI_AHCI_PORT_TFD_ERR) != 0) {
+ Status = EFI_DEVICE_ERROR;
+ break;
+ }
+
+ PrdCount = *(volatile UINT32 *) (&(AhciRegisters->AhciCmdList[0].AhciCmdPrdbc));
+ if (PrdCount == DataCount) {
+ break;
+ }
+ }
+
+ Offset = FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET;
+ Status = AhciCheckMemSet (Offset, EFI_AHCI_FIS_TYPE_MASK, EFI_AHCI_FIS_REGISTER_D2H, 0);
+ if (!EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ break;
+ }
+
+ //
+ // Stall for 100 microseconds.
+ //
+ MicroSecondDelay(100);
+
+ Delay--;
+ } while (Delay > 0);
+ } else {
+ //
+ // Wait for D2H Fis is received
+ //
+ Offset = FisBaseAddr + EFI_AHCI_D2H_FIS_OFFSET;
+ Status = AhciWaitMemSet (
+ Offset,
+ EFI_AHCI_FIS_TYPE_MASK,
+ EFI_AHCI_FIS_REGISTER_D2H,
+ Timeout
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto Exit;
+ }
+
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;
+ PortTfd = AhciReadReg ((UINT32) Offset);
+ if ((PortTfd & EFI_AHCI_PORT_TFD_ERR) != 0) {
+ Status = EFI_DEVICE_ERROR;
+ }
+ }
+
+Exit:
+ AhciStopCommand (
+ Port,
+ Timeout
+ );
+
+ AhciDisableFisReceive (
+ Port,
+ Timeout
+ );
+
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FB;
+ AhciWriteReg (Offset, OldRfisLo);
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FBU;
+ AhciWriteReg (Offset, OldRfisHi);
+
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLB;
+ AhciWriteReg (Offset, OldCmdListLo);
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLBU;
+ AhciWriteReg (Offset, OldCmdListHi);
+
+ return Status;
+}
+
+/**
+ Stop command running for giving port
+
+ @param Port The number of port.
+ @param Timeout The timeout Value of stop.
+
+ @retval EFI_DEVICE_ERROR The command stop unsuccessfully.
+ @retval EFI_TIMEOUT The operation is time out.
+ @retval EFI_SUCCESS The command stop successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciStopCommand (
+ IN UINT8 Port,
+ IN UINT64 Timeout
+ )
+{
+ UINT32 Offset;
+ UINT32 Data;
+
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;
+ Data = AhciReadReg (Offset);
+
+ if ((Data & (EFI_AHCI_PORT_CMD_ST | EFI_AHCI_PORT_CMD_CR)) == 0) {
+ return EFI_SUCCESS;
+ }
+
+ if ((Data & EFI_AHCI_PORT_CMD_ST) != 0) {
+ AhciAndReg (Offset, (UINT32)~(EFI_AHCI_PORT_CMD_ST));
+ }
+
+ return AhciWaitMmioSet (
+ Offset,
+ EFI_AHCI_PORT_CMD_CR,
+ 0,
+ Timeout
+ );
+}
+
+/**
+ Start command for give slot on specific port.
+
+ @param Port The number of port.
+ @param CommandSlot The number of CommandSlot.
+ @param Timeout The timeout Value of start.
+
+ @retval EFI_DEVICE_ERROR The command start unsuccessfully.
+ @retval EFI_TIMEOUT The operation is time out.
+ @retval EFI_SUCCESS The command start successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciStartCommand (
+ IN UINT8 Port,
+ IN UINT8 CommandSlot,
+ IN UINT64 Timeout
+ )
+{
+ UINT32 CmdSlotBit;
+ EFI_STATUS Status;
+ UINT32 PortStatus;
+ UINT32 StartCmd;
+ UINT32 PortTfd;
+ UINT32 Offset;
+ UINT32 Capability;
+
+ //
+ // Collect AHCI controller information
+ //
+ Capability = AhciReadReg(EFI_AHCI_CAPABILITY_OFFSET);
+
+ CmdSlotBit = (UINT32) (1 << CommandSlot);
+
+ AhciClearPortStatus (
+ Port
+ );
+
+ Status = AhciEnableFisReceive (
+ Port,
+ Timeout
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;
+ PortStatus = AhciReadReg (Offset);
+
+ StartCmd = 0;
+ if ((PortStatus & EFI_AHCI_PORT_CMD_ALPE) != 0) {
+ StartCmd = AhciReadReg (Offset);
+ StartCmd &= ~EFI_AHCI_PORT_CMD_ICC_MASK;
+ StartCmd |= EFI_AHCI_PORT_CMD_ACTIVE;
+ }
+
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;
+ PortTfd = AhciReadReg (Offset);
+
+ if ((PortTfd & (EFI_AHCI_PORT_TFD_BSY | EFI_AHCI_PORT_TFD_DRQ)) != 0) {
+ if ((Capability & BIT24) != 0) {
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;
+ AhciOrReg (Offset, EFI_AHCI_PORT_CMD_COL);
+
+ AhciWaitMmioSet (
+ Offset,
+ EFI_AHCI_PORT_CMD_COL,
+ 0,
+ Timeout
+ );
+ }
+ }
+
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;
+ AhciOrReg (Offset, EFI_AHCI_PORT_CMD_ST | StartCmd);
+
+ //
+ // Setting the command
+ //
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SACT;
+ AhciAndReg (Offset, 0);
+ AhciOrReg (Offset, CmdSlotBit);
+
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CI;
+ AhciAndReg (Offset, 0);
+ AhciOrReg (Offset, CmdSlotBit);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Do AHCI HBA reset.
+
+ @param[in] Timeout The timeout Value of reset.
+
+ @retval EFI_DEVICE_ERROR AHCI controller is failed to complete hardware reset.
+ @retval EFI_TIMEOUT The reset operation is time out.
+ @retval EFI_SUCCESS AHCI controller is reset successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciReset (
+ IN UINT64 Timeout
+ )
+{
+ UINT32 Delay;
+ UINT32 Value;
+ UINT32 Capability;
+
+ //
+ // Collect AHCI controller information
+ //
+ Capability = AhciReadReg (EFI_AHCI_CAPABILITY_OFFSET);
+
+ //
+ // Enable AE before accessing any AHCI registers if Supports AHCI Mode Only is not set
+ //
+ if ((Capability & EFI_AHCI_CAP_SAM) == 0) {
+ AhciOrReg (EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_ENABLE);
+ }
+
+ AhciOrReg (EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_RESET);
+
+ Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);
+
+ do {
+ Value = AhciReadReg(EFI_AHCI_GHC_OFFSET);
+ if ((Value & EFI_AHCI_GHC_RESET) == 0) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Stall for 100 microseconds.
+ //
+ MicroSecondDelay(100);
+
+ Delay--;
+ } while (Delay > 0);
+
+ return EFI_TIMEOUT;
+
+
+}
+
+/**
+ Send Buffer cmd to specific device.
+
+ @param[in] AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
+ @param[in] Port The port number of attached ATA device.
+ @param[in] PortMultiplier The port number of port multiplier of attached ATA device.
+ @param[in, out] Buffer The Data Buffer to store IDENTIFY PACKET Data.
+
+ @retval EFI_DEVICE_ERROR The cmd abort with error occurs.
+ @retval EFI_TIMEOUT The operation is time out.
+ @retval EFI_UNSUPPORTED The device is not ready for executing.
+ @retval EFI_SUCCESS The cmd executes successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciIdentify (
+ IN EFI_AHCI_REGISTERS *AhciRegisters,
+ IN UINT8 Port,
+ IN UINT8 PortMultiplier,
+ IN OUT ATA_IDENTIFY_DATA *Buffer
+ )
+{
+ EFI_STATUS Status;
+ EFI_ATA_COMMAND_BLOCK AtaCommandBlock;
+
+ if (AhciRegisters == NULL || Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));
+
+ AtaCommandBlock.AtaCommand = ATA_CMD_IDENTIFY_DRIVE;
+ AtaCommandBlock.AtaSectorCount = 1;
+
+ Status = AhciPioTransfer (
+ AhciRegisters,
+ Port,
+ PortMultiplier,
+ NULL,
+ 0,
+ TRUE,
+ &AtaCommandBlock,
+ NULL,
+ Buffer,
+ sizeof (ATA_IDENTIFY_DATA),
+ ATA_TIMEOUT
+ );
+
+ return Status;
+}
+
+/**
+ Get AHCI mode MMIO Bar Size.
+
+ @param[in] Bus The bus number of ata host controller.
+ @param[in] Device The device number of ata host controller.
+ @param[in] Function The function number of ata host controller.
+
+ @retval The Size of AHCI MMIO BAR.
+
+**/
+UINT32
+EFIAPI
+GetAhciBarSize (
+ IN UINTN Bus,
+ IN UINTN Device,
+ IN UINTN Function
+ )
+{
+ UINT32 Size;
+ UINT32 OldBar;
+
+ OldBar = PciRead32 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x24));
+ //
+ // Disable PCI CMD.MSE bit before calculating MMIO Bar Size as it needs write all 1 to BAR register.
+ //
+ PciAnd32 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x04), (UINT32)~BIT1);
+
+ //
+ // Get AHCI MMIO Bar Size.
+ //
+ PciWrite32 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x24), 0xFFFFFFFF);
+ Size = PciRead32 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x24));
+ Size = (~(Size & 0xFFFFFFF0)) + 1;
+
+ //
+ // Restore old MMIO Bar.
+ //
+ PciWrite32 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x24), OldBar);
+ //
+ // Enable PCI CMD.MSE bit after restoring MMIO Bar.
+ //
+ PciOr32 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x04), BIT1);
+
+ return Size;
+}
+
+/**
+ This function check if the memory region is in GCD MMIO region.
+
+ @param Addr The memory region start address to be checked.
+ @param Size The memory region length to be checked.
+
+ @retval TRUE This memory region is in GCD MMIO region.
+ @retval FALSE This memory region is not in GCD MMIO region.
+**/
+BOOLEAN
+EFIAPI
+OpalIsValidMmioSpace (
+ IN EFI_PHYSICAL_ADDRESS Addr,
+ IN UINTN Size
+ )
+{
+ UINTN Index;
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Desc;
+
+ for (Index = 0; Index < mNumberOfDescriptors; Index ++) {
+ Desc = &mGcdMemSpace[Index];
+ if ((Desc->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) && (Addr >= Desc->BaseAddress) && ((Addr + Size) <= (Desc->BaseAddress + Desc->Length))) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+/**
+ Get AHCI mode base address registers' Value.
+
+ @param[in] Bus The bus number of ata host controller.
+ @param[in] Device The device number of ata host controller.
+ @param[in] Function The function number of ata host controller.
+
+ @retval EFI_UNSUPPORTED Return this Value when the BARs is not IO type
+ @retval EFI_SUCCESS Get the Base address successfully
+ @retval Other Read the pci configureation Data error
+
+**/
+EFI_STATUS
+EFIAPI
+GetAhciBaseAddress (
+ IN UINTN Bus,
+ IN UINTN Device,
+ IN UINTN Function
+ )
+{
+ UINT32 Size;
+
+ //
+ // Get AHCI MMIO Bar
+ //
+ mAhciBar = PciRead32 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x24));
+ //
+ // Get AHCI MMIO Bar Size
+ //
+ Size = GetAhciBarSize (Bus, Device, Function);
+ //
+ // Check if the AHCI Bar region is in SMRAM to avoid malicious attack by modifying MMIO Bar to point to SMRAM.
+ //
+ if (!OpalIsValidMmioSpace ((EFI_PHYSICAL_ADDRESS)mAhciBar, Size)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Allocate transfer-related Data struct which is used at AHCI mode.
+
+ @retval EFI_OUT_OF_RESOURCE The allocation is failure.
+ @retval EFI_SUCCESS Successful to allocate memory.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciAllocateResource (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS Base;
+
+ //
+ // Allocate resources required by AHCI host controller.
+ //
+ Base = 0xFFFFFFFF;
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiACPIMemoryNVS,
+ EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_RECEIVED_FIS)),
+ &Base
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ ZeroMem ((VOID *)(UINTN)Base, EFI_PAGE_SIZE * EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_RECEIVED_FIS)));
+ mAhciRegisters.AhciRFis = (VOID *)(UINTN)Base;
+
+ Base = 0xFFFFFFFF;
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiACPIMemoryNVS,
+ EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_LIST)),
+ &Base
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->FreePages ((EFI_PHYSICAL_ADDRESS)(UINTN)mAhciRegisters.AhciRFis, EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_RECEIVED_FIS)));
+ return EFI_OUT_OF_RESOURCES;
+ }
+ ZeroMem ((VOID *)(UINTN)Base, EFI_PAGE_SIZE * EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_LIST)));
+ mAhciRegisters.AhciCmdList = (VOID *)(UINTN)Base;
+
+ Base = 0xFFFFFFFF;
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiACPIMemoryNVS,
+ EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_TABLE)),
+ &Base
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->FreePages ((EFI_PHYSICAL_ADDRESS)(UINTN)mAhciRegisters.AhciRFis, EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_RECEIVED_FIS)));
+ gBS->FreePages ((EFI_PHYSICAL_ADDRESS)(UINTN)mAhciRegisters.AhciCmdList, EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_LIST)));
+ return EFI_OUT_OF_RESOURCES;
+ }
+ ZeroMem ((VOID *)(UINTN)Base, EFI_PAGE_SIZE * EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_TABLE)));
+ mAhciRegisters.AhciCommandTable = (VOID *)(UINTN)Base;
+ return EFI_SUCCESS;
+}
+
+/**
+ Free allocated transfer-related Data struct which is used at AHCI mode.
+
+**/
+VOID
+EFIAPI
+AhciFreeResource (
+ VOID
+ )
+{
+ if (mAhciRegisters.AhciRFis != NULL) {
+ gBS->FreePages ((EFI_PHYSICAL_ADDRESS)(UINTN)mAhciRegisters.AhciRFis, EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_RECEIVED_FIS)));
+ }
+
+ if (mAhciRegisters.AhciCmdList != NULL) {
+ gBS->FreePages ((EFI_PHYSICAL_ADDRESS)(UINTN)mAhciRegisters.AhciCmdList, EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_LIST)));
+ }
+
+ if (mAhciRegisters.AhciCommandTable != NULL) {
+ gBS->FreePages ((EFI_PHYSICAL_ADDRESS)(UINTN)mAhciRegisters.AhciCommandTable, EFI_SIZE_TO_PAGES (sizeof (EFI_AHCI_COMMAND_TABLE)));
+ }
+}
+
+/**
+ Initialize ATA host controller at AHCI mode.
+
+ The function is designed to initialize ATA host controller.
+
+ @param[in] Port The port number to do initialization.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciModeInitialize (
+ UINT8 Port
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Capability;
+ UINT32 Offset;
+ UINT32 Data;
+ UINT32 PhyDetectDelay;
+
+ Status = AhciReset (ATA_TIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Collect AHCI controller information
+ //
+ Capability = AhciReadReg (EFI_AHCI_CAPABILITY_OFFSET);
+
+ //
+ // Enable AE before accessing any AHCI registers if Supports AHCI Mode Only is not set
+ //
+ if ((Capability & EFI_AHCI_CAP_SAM) == 0) {
+ AhciOrReg (EFI_AHCI_GHC_OFFSET, EFI_AHCI_GHC_ENABLE);
+ }
+
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_FB;
+ AhciWriteReg (Offset, (UINT32)(UINTN)mAhciRegisters.AhciRFis);
+
+ //
+ // Single task envrionment, we only use one command table for all port
+ //
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CLB;
+ AhciWriteReg (Offset, (UINT32)(UINTN)mAhciRegisters.AhciCmdList);
+
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_CMD;
+ Data = AhciReadReg (Offset);
+ if ((Data & EFI_AHCI_PORT_CMD_CPD) != 0) {
+ AhciOrReg (Offset, EFI_AHCI_PORT_CMD_POD);
+ }
+
+ if ((Capability & BIT27) != 0) {
+ AhciOrReg (Offset, EFI_AHCI_PORT_CMD_SUD);
+ }
+
+ //
+ // Disable aggressive power management.
+ //
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SCTL;
+ AhciOrReg (Offset, EFI_AHCI_PORT_SCTL_IPM_INIT);
+ //
+ // Disable the reporting of the corresponding interrupt to system software.
+ //
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_IE;
+ AhciAndReg (Offset, 0);
+
+ Status = AhciEnableFisReceive (
+ Port,
+ EFI_TIMER_PERIOD_MILLISECONDS(500)
+ );
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // According to SATA1.0a spec section 5.2, we need to wait for PxTFD.BSY and PxTFD.DRQ
+ // and PxTFD.ERR to be zero. The maximum wait time is 16s which is defined at ATA spec.
+ //
+ PhyDetectDelay = 16 * 1000;
+ do {
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SERR;
+ if (AhciReadReg(Offset) != 0) {
+ AhciWriteReg (Offset, AhciReadReg(Offset));
+ }
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_TFD;
+
+ Data = AhciReadReg (Offset) & EFI_AHCI_PORT_TFD_MASK;
+ if (Data == 0) {
+ break;
+ }
+
+ MicroSecondDelay (1000);
+ PhyDetectDelay--;
+ } while (PhyDetectDelay > 0);
+
+ if (PhyDetectDelay == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ Offset = EFI_AHCI_PORT_START + Port * EFI_AHCI_PORT_REG_WIDTH + EFI_AHCI_PORT_SIG;
+ Status = AhciWaitMmioSet (
+ Offset,
+ 0x0000FFFF,
+ 0x00000101,
+ EFI_TIMER_PERIOD_SECONDS(16)
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return Status;
+}
+
diff --git a/Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalAhciMode.h b/Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalAhciMode.h
new file mode 100644
index 0000000000..3a7f6331ca
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalAhciMode.h
@@ -0,0 +1,408 @@
+/** @file
+ Header file for AHCI mode of ATA host controller.
+
+Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+
+#ifndef __OPAL_PASSWORD_AHCI_MODE_H__
+#define __OPAL_PASSWORD_AHCI_MODE_H__
+
+//
+// OPAL LIBRARY CALLBACKS
+//
+#define ATA_COMMAND_TRUSTED_RECEIVE 0x5C
+#define ATA_COMMAND_TRUSTED_SEND 0x5E
+
+//
+// ATA TRUSTED commands express transfer Length in 512 byte multiple
+//
+#define ATA_TRUSTED_TRANSFER_LENGTH_MULTIPLE 512
+#define ATA_DEVICE_LBA 0x40 ///< Set for commands with LBA (rather than CHS) addresses
+
+
+#define EFI_AHCI_BAR_INDEX 0x05
+
+#define EFI_AHCI_CAPABILITY_OFFSET 0x0000
+#define EFI_AHCI_CAP_SAM BIT18
+#define EFI_AHCI_GHC_OFFSET 0x0004
+#define EFI_AHCI_GHC_RESET BIT0
+#define EFI_AHCI_GHC_IE BIT1
+#define EFI_AHCI_GHC_ENABLE BIT31
+#define EFI_AHCI_IS_OFFSET 0x0008
+#define EFI_AHCI_PI_OFFSET 0x000C
+
+typedef struct {
+ UINT32 Lower32;
+ UINT32 Upper32;
+} DATA_32;
+
+typedef union {
+ DATA_32 Uint32;
+ UINT64 Uint64;
+} DATA_64;
+
+//
+// Each PRDT entry can point to a memory block up to 4M byte
+//
+#define EFI_AHCI_MAX_DATA_PER_PRDT 0x400000
+
+#define EFI_AHCI_FIS_REGISTER_H2D 0x27 //Register FIS - Host to Device
+#define EFI_AHCI_FIS_REGISTER_H2D_LENGTH 20
+#define EFI_AHCI_FIS_REGISTER_D2H 0x34 //Register FIS - Device to Host
+#define EFI_AHCI_FIS_REGISTER_D2H_LENGTH 20
+#define EFI_AHCI_FIS_DMA_ACTIVATE 0x39 //DMA Activate FIS - Device to Host
+#define EFI_AHCI_FIS_DMA_ACTIVATE_LENGTH 4
+#define EFI_AHCI_FIS_DMA_SETUP 0x41 //DMA Setup FIS - Bi-directional
+#define EFI_AHCI_FIS_DMA_SETUP_LENGTH 28
+#define EFI_AHCI_FIS_DATA 0x46 //Data FIS - Bi-directional
+#define EFI_AHCI_FIS_BIST 0x58 //BIST Activate FIS - Bi-directional
+#define EFI_AHCI_FIS_BIST_LENGTH 12
+#define EFI_AHCI_FIS_PIO_SETUP 0x5F //PIO Setup FIS - Device to Host
+#define EFI_AHCI_FIS_PIO_SETUP_LENGTH 20
+#define EFI_AHCI_FIS_SET_DEVICE 0xA1 //Set Device Bits FIS - Device to Host
+#define EFI_AHCI_FIS_SET_DEVICE_LENGTH 8
+
+#define EFI_AHCI_D2H_FIS_OFFSET 0x40
+#define EFI_AHCI_DMA_FIS_OFFSET 0x00
+#define EFI_AHCI_PIO_FIS_OFFSET 0x20
+#define EFI_AHCI_SDB_FIS_OFFSET 0x58
+#define EFI_AHCI_FIS_TYPE_MASK 0xFF
+#define EFI_AHCI_U_FIS_OFFSET 0x60
+
+//
+// Port register
+//
+#define EFI_AHCI_PORT_START 0x0100
+#define EFI_AHCI_PORT_REG_WIDTH 0x0080
+#define EFI_AHCI_PORT_CLB 0x0000
+#define EFI_AHCI_PORT_CLBU 0x0004
+#define EFI_AHCI_PORT_FB 0x0008
+#define EFI_AHCI_PORT_FBU 0x000C
+#define EFI_AHCI_PORT_IS 0x0010
+#define EFI_AHCI_PORT_IS_DHRS BIT0
+#define EFI_AHCI_PORT_IS_PSS BIT1
+#define EFI_AHCI_PORT_IS_SSS BIT2
+#define EFI_AHCI_PORT_IS_SDBS BIT3
+#define EFI_AHCI_PORT_IS_UFS BIT4
+#define EFI_AHCI_PORT_IS_DPS BIT5
+#define EFI_AHCI_PORT_IS_PCS BIT6
+#define EFI_AHCI_PORT_IS_DIS BIT7
+#define EFI_AHCI_PORT_IS_PRCS BIT22
+#define EFI_AHCI_PORT_IS_IPMS BIT23
+#define EFI_AHCI_PORT_IS_OFS BIT24
+#define EFI_AHCI_PORT_IS_INFS BIT26
+#define EFI_AHCI_PORT_IS_IFS BIT27
+#define EFI_AHCI_PORT_IS_HBDS BIT28
+#define EFI_AHCI_PORT_IS_HBFS BIT29
+#define EFI_AHCI_PORT_IS_TFES BIT30
+#define EFI_AHCI_PORT_IS_CPDS BIT31
+#define EFI_AHCI_PORT_IS_CLEAR 0xFFFFFFFF
+#define EFI_AHCI_PORT_IS_FIS_CLEAR 0x0000000F
+
+#define EFI_AHCI_PORT_IE 0x0014
+#define EFI_AHCI_PORT_CMD 0x0018
+#define EFI_AHCI_PORT_CMD_ST_MASK 0xFFFFFFFE
+#define EFI_AHCI_PORT_CMD_ST BIT0
+#define EFI_AHCI_PORT_CMD_SUD BIT1
+#define EFI_AHCI_PORT_CMD_POD BIT2
+#define EFI_AHCI_PORT_CMD_COL BIT3
+#define EFI_AHCI_PORT_CMD_CR BIT15
+#define EFI_AHCI_PORT_CMD_FRE BIT4
+#define EFI_AHCI_PORT_CMD_FR BIT14
+#define EFI_AHCI_PORT_CMD_MASK ~(EFI_AHCI_PORT_CMD_ST | EFI_AHCI_PORT_CMD_FRE | EFI_AHCI_PORT_CMD_COL)
+#define EFI_AHCI_PORT_CMD_PMA BIT17
+#define EFI_AHCI_PORT_CMD_HPCP BIT18
+#define EFI_AHCI_PORT_CMD_MPSP BIT19
+#define EFI_AHCI_PORT_CMD_CPD BIT20
+#define EFI_AHCI_PORT_CMD_ESP BIT21
+#define EFI_AHCI_PORT_CMD_ATAPI BIT24
+#define EFI_AHCI_PORT_CMD_DLAE BIT25
+#define EFI_AHCI_PORT_CMD_ALPE BIT26
+#define EFI_AHCI_PORT_CMD_ASP BIT27
+#define EFI_AHCI_PORT_CMD_ICC_MASK (BIT28 | BIT29 | BIT30 | BIT31)
+#define EFI_AHCI_PORT_CMD_ACTIVE (1 << 28 )
+#define EFI_AHCI_PORT_TFD 0x0020
+#define EFI_AHCI_PORT_TFD_MASK (BIT7 | BIT3 | BIT0)
+#define EFI_AHCI_PORT_TFD_BSY BIT7
+#define EFI_AHCI_PORT_TFD_DRQ BIT3
+#define EFI_AHCI_PORT_TFD_ERR BIT0
+#define EFI_AHCI_PORT_TFD_ERR_MASK 0x00FF00
+#define EFI_AHCI_PORT_SIG 0x0024
+#define EFI_AHCI_PORT_SSTS 0x0028
+#define EFI_AHCI_PORT_SSTS_DET_MASK 0x000F
+#define EFI_AHCI_PORT_SSTS_DET 0x0001
+#define EFI_AHCI_PORT_SSTS_DET_PCE 0x0003
+#define EFI_AHCI_PORT_SSTS_SPD_MASK 0x00F0
+#define EFI_AHCI_PORT_SCTL 0x002C
+#define EFI_AHCI_PORT_SCTL_DET_MASK 0x000F
+#define EFI_AHCI_PORT_SCTL_MASK (~EFI_AHCI_PORT_SCTL_DET_MASK)
+#define EFI_AHCI_PORT_SCTL_DET_INIT 0x0001
+#define EFI_AHCI_PORT_SCTL_DET_PHYCOMM 0x0003
+#define EFI_AHCI_PORT_SCTL_SPD_MASK 0x00F0
+#define EFI_AHCI_PORT_SCTL_IPM_MASK 0x0F00
+#define EFI_AHCI_PORT_SCTL_IPM_INIT 0x0300
+#define EFI_AHCI_PORT_SCTL_IPM_PSD 0x0100
+#define EFI_AHCI_PORT_SCTL_IPM_SSD 0x0200
+#define EFI_AHCI_PORT_SERR 0x0030
+#define EFI_AHCI_PORT_SERR_RDIE BIT0
+#define EFI_AHCI_PORT_SERR_RCE BIT1
+#define EFI_AHCI_PORT_SERR_TDIE BIT8
+#define EFI_AHCI_PORT_SERR_PCDIE BIT9
+#define EFI_AHCI_PORT_SERR_PE BIT10
+#define EFI_AHCI_PORT_SERR_IE BIT11
+#define EFI_AHCI_PORT_SERR_PRC BIT16
+#define EFI_AHCI_PORT_SERR_PIE BIT17
+#define EFI_AHCI_PORT_SERR_CW BIT18
+#define EFI_AHCI_PORT_SERR_BDE BIT19
+#define EFI_AHCI_PORT_SERR_DE BIT20
+#define EFI_AHCI_PORT_SERR_CRCE BIT21
+#define EFI_AHCI_PORT_SERR_HE BIT22
+#define EFI_AHCI_PORT_SERR_LSE BIT23
+#define EFI_AHCI_PORT_SERR_TSTE BIT24
+#define EFI_AHCI_PORT_SERR_UFT BIT25
+#define EFI_AHCI_PORT_SERR_EX BIT26
+#define EFI_AHCI_PORT_ERR_CLEAR 0xFFFFFFFF
+#define EFI_AHCI_PORT_SACT 0x0034
+#define EFI_AHCI_PORT_CI 0x0038
+#define EFI_AHCI_PORT_SNTF 0x003C
+
+
+#pragma pack(1)
+//
+// Command List structure includes total 32 entries.
+// The entry Data structure is listed at the following.
+//
+typedef struct {
+ UINT32 AhciCmdCfl:5; //Command FIS Length
+ UINT32 AhciCmdA:1; //ATAPI
+ UINT32 AhciCmdW:1; //Write
+ UINT32 AhciCmdP:1; //Prefetchable
+ UINT32 AhciCmdR:1; //Reset
+ UINT32 AhciCmdB:1; //BIST
+ UINT32 AhciCmdC:1; //Clear Busy upon R_OK
+ UINT32 AhciCmdRsvd:1;
+ UINT32 AhciCmdPmp:4; //Port Multiplier Port
+ UINT32 AhciCmdPrdtl:16; //Physical Region Descriptor Table Length
+ UINT32 AhciCmdPrdbc; //Physical Region Descriptor Byte Count
+ UINT32 AhciCmdCtba; //Command Table Descriptor Base Address
+ UINT32 AhciCmdCtbau; //Command Table Descriptor Base Address Upper 32-BITs
+ UINT32 AhciCmdRsvd1[4];
+} EFI_AHCI_COMMAND_LIST;
+
+//
+// This is a software constructed FIS.
+// For Data transfer operations, this is the H2D Register FIS format as
+// specified in the Serial ATA Revision 2.6 specification.
+//
+typedef struct {
+ UINT8 AhciCFisType;
+ UINT8 AhciCFisPmNum:4;
+ UINT8 AhciCFisRsvd:1;
+ UINT8 AhciCFisRsvd1:1;
+ UINT8 AhciCFisRsvd2:1;
+ UINT8 AhciCFisCmdInd:1;
+ UINT8 AhciCFisCmd;
+ UINT8 AhciCFisFeature;
+ UINT8 AhciCFisSecNum;
+ UINT8 AhciCFisClyLow;
+ UINT8 AhciCFisClyHigh;
+ UINT8 AhciCFisDevHead;
+ UINT8 AhciCFisSecNumExp;
+ UINT8 AhciCFisClyLowExp;
+ UINT8 AhciCFisClyHighExp;
+ UINT8 AhciCFisFeatureExp;
+ UINT8 AhciCFisSecCount;
+ UINT8 AhciCFisSecCountExp;
+ UINT8 AhciCFisRsvd3;
+ UINT8 AhciCFisControl;
+ UINT8 AhciCFisRsvd4[4];
+ UINT8 AhciCFisRsvd5[44];
+} EFI_AHCI_COMMAND_FIS;
+
+//
+// ACMD: ATAPI command (12 or 16 bytes)
+//
+typedef struct {
+ UINT8 AtapiCmd[0x10];
+} EFI_AHCI_ATAPI_COMMAND;
+
+//
+// Physical Region Descriptor Table includes up to 65535 entries
+// The entry Data structure is listed at the following.
+// the actual entry number comes from the PRDTL field in the command
+// list entry for this command slot.
+//
+typedef struct {
+ UINT32 AhciPrdtDba; //Data Base Address
+ UINT32 AhciPrdtDbau; //Data Base Address Upper 32-BITs
+ UINT32 AhciPrdtRsvd;
+ UINT32 AhciPrdtDbc:22; //Data Byte Count
+ UINT32 AhciPrdtRsvd1:9;
+ UINT32 AhciPrdtIoc:1; //Interrupt on Completion
+} EFI_AHCI_COMMAND_PRDT;
+
+//
+// Command table Data strucute which is pointed to by the entry in the command list
+//
+typedef struct {
+ EFI_AHCI_COMMAND_FIS CommandFis; // A software constructed FIS.
+ EFI_AHCI_ATAPI_COMMAND AtapiCmd; // 12 or 16 bytes ATAPI cmd.
+ UINT8 Reserved[0x30];
+ EFI_AHCI_COMMAND_PRDT PrdtTable; // The scatter/gather list for Data transfer
+} EFI_AHCI_COMMAND_TABLE;
+
+//
+// Received FIS structure
+//
+typedef struct {
+ UINT8 AhciDmaSetupFis[0x1C]; // Dma Setup Fis: offset 0x00
+ UINT8 AhciDmaSetupFisRsvd[0x04];
+ UINT8 AhciPioSetupFis[0x14]; // Pio Setup Fis: offset 0x20
+ UINT8 AhciPioSetupFisRsvd[0x0C];
+ UINT8 AhciD2HRegisterFis[0x14]; // D2H Register Fis: offset 0x40
+ UINT8 AhciD2HRegisterFisRsvd[0x04];
+ UINT64 AhciSetDeviceBitsFis; // Set Device Bits Fix: offset 0x58
+ UINT8 AhciUnknownFis[0x40]; // Unkonwn Fis: offset 0x60
+ UINT8 AhciUnknownFisRsvd[0x60];
+} EFI_AHCI_RECEIVED_FIS;
+
+#pragma pack()
+
+typedef struct {
+ EFI_AHCI_RECEIVED_FIS *AhciRFis;
+ EFI_AHCI_COMMAND_LIST *AhciCmdList;
+ EFI_AHCI_COMMAND_TABLE *AhciCommandTable;
+} EFI_AHCI_REGISTERS;
+
+extern EFI_AHCI_REGISTERS mAhciRegisters;
+extern UINT32 mAhciBar;
+
+/**
+ Send Buffer cmd to specific device.
+
+ @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
+ @param Port The number of port.
+ @param PortMultiplier The timeout Value of stop.
+ @param Buffer The Data Buffer to store IDENTIFY PACKET Data.
+
+ @retval EFI_DEVICE_ERROR The cmd abort with error occurs.
+ @retval EFI_TIMEOUT The operation is time out.
+ @retval EFI_UNSUPPORTED The device is not ready for executing.
+ @retval EFI_SUCCESS The cmd executes successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciIdentify (
+ IN EFI_AHCI_REGISTERS *AhciRegisters,
+ IN UINT8 Port,
+ IN UINT8 PortMultiplier,
+ IN OUT ATA_IDENTIFY_DATA *Buffer
+ );
+
+/**
+ Get AHCI mode base address registers' Value.
+
+ @param[in] Bus The bus number of ata host controller.
+ @param[in] Device The device number of ata host controller.
+ @param[in] Function The function number of ata host controller.
+
+ @retval EFI_UNSUPPORTED Return this Value when the BARs is not IO type
+ @retval EFI_SUCCESS Get the Base address successfully
+ @retval Other Read the pci configureation Data error
+
+**/
+EFI_STATUS
+EFIAPI
+GetAhciBaseAddress (
+ IN UINTN Bus,
+ IN UINTN Device,
+ IN UINTN Function
+ );
+
+/**
+ Allocate transfer-related Data struct which is used at AHCI mode.
+
+ @retval EFI_OUT_OF_RESOURCE The allocation is failure.
+ @retval EFI_SUCCESS Successful to allocate memory.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciAllocateResource (
+ VOID
+ );
+
+/**
+ Free allocated transfer-related Data struct which is used at AHCI mode.
+
+**/
+VOID
+EFIAPI
+AhciFreeResource (
+ VOID
+ );
+
+/**
+ Initialize ATA host controller at AHCI mode.
+
+ The function is designed to initialize ATA host controller.
+
+ @param[in] Port The port number to do initialization.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciModeInitialize (
+ UINT8 Port
+ );
+
+/**
+ Start a PIO Data transfer on specific port.
+
+ @param AhciRegisters The pointer to the EFI_AHCI_REGISTERS.
+ @param Port The number of port.
+ @param PortMultiplier The timeout Value of stop.
+ @param AtapiCommand The atapi command will be used for the transfer.
+ @param AtapiCommandLength The Length of the atapi command.
+ @param Read The transfer direction.
+ @param AtaCommandBlock The EFI_ATA_COMMAND_BLOCK Data.
+ @param AtaStatusBlock The EFI_ATA_STATUS_BLOCK Data.
+ @param MemoryAddr The pointer to the Data Buffer.
+ @param DataCount The Data count to be transferred.
+ @param Timeout The timeout Value of non Data transfer.
+
+ @retval EFI_DEVICE_ERROR The PIO Data transfer abort with error occurs.
+ @retval EFI_TIMEOUT The operation is time out.
+ @retval EFI_UNSUPPORTED The device is not ready for transfer.
+ @retval EFI_SUCCESS The PIO Data transfer executes successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciPioTransfer (
+ IN EFI_AHCI_REGISTERS *AhciRegisters,
+ IN UINT8 Port,
+ IN UINT8 PortMultiplier,
+ IN EFI_AHCI_ATAPI_COMMAND *AtapiCommand OPTIONAL,
+ IN UINT8 AtapiCommandLength,
+ IN BOOLEAN Read,
+ IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock,
+ IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock,
+ IN OUT VOID *MemoryAddr,
+ IN UINT32 DataCount,
+ IN UINT64 Timeout
+ );
+
+
+#endif
+
diff --git a/Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalIdeMode.c b/Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalIdeMode.c
new file mode 100644
index 0000000000..76204625dd
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalIdeMode.c
@@ -0,0 +1,767 @@
+/** @file
+ This driver is used for Opal Password Feature support at IDE mode.
+
+Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "OpalPasswordSmm.h"
+
+/**
+ Write multiple words of Data to the IDE Data port.
+ Call the IO abstraction once to do the complete read,
+ not one word at a time
+
+ @param Port IO port to read
+ @param Count No. of UINT16's to read
+ @param Buffer Pointer to the Data Buffer for read
+
+**/
+VOID
+EFIAPI
+IdeWritePortWMultiple (
+ IN UINT16 Port,
+ IN UINTN Count,
+ IN UINT16 *Buffer
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < Count; Index++) {
+ IoWrite16 (Port, Buffer[Index]);
+ }
+}
+
+/**
+ Reads multiple words of Data from the IDE Data port.
+ Call the IO abstraction once to do the complete read,
+ not one word at a time
+
+ @param Port IO port to read
+ @param Count Number of UINT16's to read
+ @param Buffer Pointer to the Data Buffer for read
+
+**/
+VOID
+EFIAPI
+IdeReadPortWMultiple (
+ IN UINT16 Port,
+ IN UINTN Count,
+ IN UINT16 *Buffer
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < Count; Index++) {
+ Buffer[Count] = IoRead16 (Port);
+ }
+}
+
+/**
+ This function is used to analyze the Status Register and print out
+ some debug information and if there is ERR bit set in the Status
+ Register, the Error Register's Value is also be parsed and print out.
+
+ @param IdeRegisters A pointer to EFI_IDE_REGISTERS Data structure.
+
+**/
+VOID
+EFIAPI
+DumpAllIdeRegisters (
+ IN EFI_IDE_REGISTERS *IdeRegisters
+ )
+{
+ ASSERT (IdeRegisters != NULL);
+
+ DEBUG_CODE_BEGIN ();
+ if ((IoRead8 (IdeRegisters->CmdOrStatus) & ATA_STSREG_DWF) != 0) {
+ DEBUG ((EFI_D_ERROR, "CheckRegisterStatus()-- %02x : Error : Write Fault\n", IoRead8 (IdeRegisters->CmdOrStatus)));
+ }
+
+ if ((IoRead8 (IdeRegisters->CmdOrStatus) & ATA_STSREG_CORR) != 0) {
+ DEBUG ((EFI_D_ERROR, "CheckRegisterStatus()-- %02x : Error : Corrected Data\n", IoRead8 (IdeRegisters->CmdOrStatus)));
+ }
+
+ if ((IoRead8 (IdeRegisters->CmdOrStatus) & ATA_STSREG_ERR) != 0) {
+ if ((IoRead8 (IdeRegisters->ErrOrFeature) & ATA_ERRREG_BBK) != 0) {
+ DEBUG ((EFI_D_ERROR, "CheckRegisterStatus()-- %02x : Error : Bad Block Detected\n", IoRead8 (IdeRegisters->ErrOrFeature)));
+ }
+
+ if ((IoRead8 (IdeRegisters->ErrOrFeature) & ATA_ERRREG_UNC) != 0) {
+ DEBUG ((EFI_D_ERROR, "CheckRegisterStatus()-- %02x : Error : Uncorrectable Data\n", IoRead8 (IdeRegisters->ErrOrFeature)));
+ }
+
+ if ((IoRead8 (IdeRegisters->ErrOrFeature) & ATA_ERRREG_MC) != 0) {
+ DEBUG ((EFI_D_ERROR, "CheckRegisterStatus()-- %02x : Error : Media Change\n", IoRead8 (IdeRegisters->ErrOrFeature)));
+ }
+
+ if ((IoRead8 (IdeRegisters->ErrOrFeature) & ATA_ERRREG_ABRT) != 0) {
+ DEBUG ((EFI_D_ERROR, "CheckRegisterStatus()-- %02x : Error : Abort\n", IoRead8 (IdeRegisters->ErrOrFeature)));
+ }
+
+ if ((IoRead8 (IdeRegisters->ErrOrFeature) & ATA_ERRREG_TK0NF) != 0) {
+ DEBUG ((EFI_D_ERROR, "CheckRegisterStatus()-- %02x : Error : Track 0 Not Found\n", IoRead8 (IdeRegisters->ErrOrFeature)));
+ }
+
+ if ((IoRead8 (IdeRegisters->ErrOrFeature) & ATA_ERRREG_AMNF) != 0) {
+ DEBUG ((EFI_D_ERROR, "CheckRegisterStatus()-- %02x : Error : Address Mark Not Found\n", IoRead8 (IdeRegisters->ErrOrFeature)));
+ }
+ }
+ DEBUG_CODE_END ();
+}
+
+/**
+ This function is used to analyze the Status Register and print out
+ some debug information and if there is ERR bit set in the Status
+ Register, the Error Register's Value is also be parsed and print out.
+
+ @param IdeRegisters A pointer to EFI_IDE_REGISTERS Data structure.
+
+ @retval EFI_SUCCESS No err information in the Status Register.
+ @retval EFI_DEVICE_ERROR Any err information in the Status Register.
+
+**/
+EFI_STATUS
+EFIAPI
+CheckStatusRegister (
+ IN EFI_IDE_REGISTERS *IdeRegisters
+ )
+{
+ EFI_STATUS Status;
+ UINT8 StatusRegister;
+
+ ASSERT (IdeRegisters != NULL);
+
+ StatusRegister = IoRead8 (IdeRegisters->CmdOrStatus);
+
+ if ((StatusRegister & (ATA_STSREG_ERR | ATA_STSREG_DWF | ATA_STSREG_CORR)) == 0) {
+ Status = EFI_SUCCESS;
+ } else {
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ return Status;
+}
+
+/**
+ This function is used to poll for the DRQ bit clear in the Status
+ Register. DRQ is cleared when the device is finished transferring Data.
+ So this function is called after Data transfer is finished.
+
+ @param IdeRegisters A pointer to EFI_IDE_REGISTERS Data structure.
+ @param Timeout The time to complete the command.
+
+ @retval EFI_SUCCESS DRQ bit clear within the time out.
+ @retval EFI_TIMEOUT DRQ bit not clear within the time out.
+
+ @note
+ Read Status Register will clear interrupt status.
+
+**/
+EFI_STATUS
+EFIAPI
+DRQClear (
+ IN EFI_IDE_REGISTERS *IdeRegisters,
+ IN UINT64 Timeout
+ )
+{
+ UINT32 Delay;
+ UINT8 StatusRegister;
+
+ ASSERT (IdeRegisters != NULL);
+
+ Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);
+ do {
+ StatusRegister = IoRead8 (IdeRegisters->CmdOrStatus);
+
+ //
+ // wait for BSY == 0 and DRQ == 0
+ //
+ if ((StatusRegister & ATA_STSREG_BSY) == 0) {
+
+ if ((StatusRegister & ATA_STSREG_DRQ) == ATA_STSREG_DRQ) {
+ return EFI_DEVICE_ERROR;
+ } else {
+ return EFI_SUCCESS;
+ }
+ }
+
+ //
+ // Stall for 100 microseconds.
+ //
+ MicroSecondDelay (100);
+
+ Delay--;
+
+ } while (Delay > 0);
+
+ return EFI_TIMEOUT;
+}
+/**
+ This function is used to poll for the DRQ bit clear in the Alternate
+ Status Register. DRQ is cleared when the device is finished
+ transferring Data. So this function is called after Data transfer
+ is finished.
+
+ @param IdeRegisters A pointer to EFI_IDE_REGISTERS Data structure.
+ @param Timeout The time to complete the command.
+
+ @retval EFI_SUCCESS DRQ bit clear within the time out.
+
+ @retval EFI_TIMEOUT DRQ bit not clear within the time out.
+ @note Read Alternate Status Register will not clear interrupt status.
+
+**/
+EFI_STATUS
+EFIAPI
+DRQClear2 (
+ IN EFI_IDE_REGISTERS *IdeRegisters,
+ IN UINT64 Timeout
+ )
+{
+ UINT32 Delay;
+ UINT8 AltRegister;
+
+ ASSERT (IdeRegisters != NULL);
+
+ Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);
+ do {
+ AltRegister = IoRead8 (IdeRegisters->AltOrDev);
+
+ //
+ // wait for BSY == 0 and DRQ == 0
+ //
+ if ((AltRegister & ATA_STSREG_BSY) == 0) {
+ if ((AltRegister & ATA_STSREG_DRQ) == ATA_STSREG_DRQ) {
+ return EFI_DEVICE_ERROR;
+ } else {
+ return EFI_SUCCESS;
+ }
+ }
+
+ //
+ // Stall for 100 microseconds.
+ //
+ MicroSecondDelay (100);
+
+ Delay--;
+
+ } while (Delay > 0);
+
+ return EFI_TIMEOUT;
+}
+
+
+/**
+ This function is used to poll for the DRQ bit set in the Alternate Status Register.
+ DRQ is set when the device is ready to transfer Data. So this function is called after
+ the command is sent to the device and before required Data is transferred.
+
+ @param IdeRegisters A pointer to EFI_IDE_REGISTERS Data structure.
+ @param Timeout The time to complete the command.
+
+ @retval EFI_SUCCESS DRQ bit set within the time out.
+ @retval EFI_TIMEOUT DRQ bit not set within the time out.
+ @retval EFI_ABORTED DRQ bit not set caused by the command abort.
+ @note Read Alternate Status Register will not clear interrupt status.
+
+**/
+EFI_STATUS
+EFIAPI
+DRQReady2 (
+ IN EFI_IDE_REGISTERS *IdeRegisters,
+ IN UINT64 Timeout
+ )
+{
+ UINT32 Delay;
+ UINT8 AltRegister;
+ UINT8 ErrorRegister;
+
+ ASSERT (IdeRegisters != NULL);
+
+ Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);
+
+ do {
+ //
+ // Read Alternate Status Register will not clear interrupt status
+ //
+ AltRegister = IoRead8 (IdeRegisters->AltOrDev);
+ //
+ // BSY == 0 , DRQ == 1
+ //
+ if ((AltRegister & ATA_STSREG_BSY) == 0) {
+ if ((AltRegister & ATA_STSREG_ERR) == ATA_STSREG_ERR) {
+ ErrorRegister = IoRead8 (IdeRegisters->ErrOrFeature);
+
+ if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {
+ return EFI_ABORTED;
+ }
+ return EFI_DEVICE_ERROR;
+ }
+
+ if ((AltRegister & ATA_STSREG_DRQ) == ATA_STSREG_DRQ) {
+ return EFI_SUCCESS;
+ } else {
+ return EFI_NOT_READY;
+ }
+ }
+
+ //
+ // Stall for 100 microseconds.
+ //
+ MicroSecondDelay (100);
+
+ Delay--;
+ } while (Delay > 0);
+
+ return EFI_TIMEOUT;
+}
+
+/**
+ This function is used to poll for the BSY bit clear in the Status Register. BSY
+ is clear when the device is not busy. Every command must be sent after device is not busy.
+
+ @param IdeRegisters A pointer to EFI_IDE_REGISTERS Data structure.
+ @param Timeout The time to complete the command.
+
+ @retval EFI_SUCCESS BSY bit clear within the time out.
+ @retval EFI_TIMEOUT BSY bit not clear within the time out.
+
+ @note Read Status Register will clear interrupt status.
+**/
+EFI_STATUS
+EFIAPI
+WaitForBSYClear (
+ IN EFI_IDE_REGISTERS *IdeRegisters,
+ IN UINT64 Timeout
+ )
+{
+ UINT32 Delay;
+ UINT8 StatusRegister;
+
+ ASSERT (IdeRegisters != NULL);
+
+ Delay = (UINT32) (DivU64x32(Timeout, 1000) + 1);
+ do {
+ StatusRegister = IoRead8 (IdeRegisters->CmdOrStatus);
+
+ if ((StatusRegister & ATA_STSREG_BSY) == 0x00) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Stall for 100 microseconds.
+ //
+ MicroSecondDelay (100);
+
+ Delay--;
+
+ } while (Delay > 0);
+
+ return EFI_TIMEOUT;
+}
+
+/**
+ Get IDE i/o port registers' base addresses by mode.
+
+ In 'Compatibility' mode, use fixed addresses.
+ In Native-PCI mode, get base addresses from BARs in the PCI IDE controller's
+ Configuration Space.
+
+ The steps to get IDE i/o port registers' base addresses for each channel
+ as follows:
+
+ 1. Examine the Programming Interface byte of the Class Code fields in PCI IDE
+ controller's Configuration Space to determine the operating mode.
+
+ 2. a) In 'Compatibility' mode, use fixed addresses shown in the Table 1 below.
+ ___________________________________________
+ | | Command Block | Control Block |
+ | Channel | Registers | Registers |
+ |___________|_______________|_______________|
+ | Primary | 1F0h - 1F7h | 3F6h - 3F7h |
+ |___________|_______________|_______________|
+ | Secondary | 170h - 177h | 376h - 377h |
+ |___________|_______________|_______________|
+
+ Table 1. Compatibility resource mappings
+
+ b) In Native-PCI mode, IDE registers are mapped into IO space using the BARs
+ in IDE controller's PCI Configuration Space, shown in the Table 2 below.
+ ___________________________________________________
+ | | Command Block | Control Block |
+ | Channel | Registers | Registers |
+ |___________|___________________|___________________|
+ | Primary | BAR at offset 0x10| BAR at offset 0x14|
+ |___________|___________________|___________________|
+ | Secondary | BAR at offset 0x18| BAR at offset 0x1C|
+ |___________|___________________|___________________|
+
+ Table 2. BARs for Register Mapping
+
+ @param[in] Bus The bus number of ata host controller.
+ @param[in] Device The device number of ata host controller.
+ @param[in] Function The function number of ata host controller.
+ @param[in, out] IdeRegisters Pointer to EFI_IDE_REGISTERS which is used to
+ store the IDE i/o port registers' base addresses
+
+ @retval EFI_UNSUPPORTED Return this Value when the BARs is not IO type
+ @retval EFI_SUCCESS Get the Base address successfully
+ @retval Other Read the pci configureation Data error
+
+**/
+EFI_STATUS
+EFIAPI
+GetIdeRegisterIoAddr (
+ IN UINTN Bus,
+ IN UINTN Device,
+ IN UINTN Function,
+ IN OUT EFI_IDE_REGISTERS *IdeRegisters
+ )
+{
+ UINT16 CommandBlockBaseAddr;
+ UINT16 ControlBlockBaseAddr;
+ UINT8 ClassCode;
+ UINT32 BaseAddress[4];
+
+ if (IdeRegisters == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ClassCode = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x9));
+ BaseAddress[0] = PciRead32 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x10));
+ BaseAddress[1] = PciRead32 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x14));
+ BaseAddress[2] = PciRead32 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x18));
+ BaseAddress[3] = PciRead32 (PCI_LIB_ADDRESS (Bus, Device, Function, 0x1C));
+
+ if ((ClassCode & IDE_PRIMARY_OPERATING_MODE) == 0) {
+ CommandBlockBaseAddr = 0x1f0;
+ ControlBlockBaseAddr = 0x3f6;
+ } else {
+ //
+ // The BARs should be of IO type
+ //
+ if ((BaseAddress[0] & BIT0) == 0 ||
+ (BaseAddress[1] & BIT0) == 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ CommandBlockBaseAddr = (UINT16) (BaseAddress[0] & 0x0000fff8);
+ ControlBlockBaseAddr = (UINT16) ((BaseAddress[1] & 0x0000fffc) + 2);
+ }
+
+ //
+ // Calculate IDE primary channel I/O register base address.
+ //
+ IdeRegisters[EfiIdePrimary].Data = CommandBlockBaseAddr;
+ IdeRegisters[EfiIdePrimary].ErrOrFeature = (UINT16) (CommandBlockBaseAddr + 0x01);
+ IdeRegisters[EfiIdePrimary].SectorCount = (UINT16) (CommandBlockBaseAddr + 0x02);
+ IdeRegisters[EfiIdePrimary].SectorNumber = (UINT16) (CommandBlockBaseAddr + 0x03);
+ IdeRegisters[EfiIdePrimary].CylinderLsb = (UINT16) (CommandBlockBaseAddr + 0x04);
+ IdeRegisters[EfiIdePrimary].CylinderMsb = (UINT16) (CommandBlockBaseAddr + 0x05);
+ IdeRegisters[EfiIdePrimary].Head = (UINT16) (CommandBlockBaseAddr + 0x06);
+ IdeRegisters[EfiIdePrimary].CmdOrStatus = (UINT16) (CommandBlockBaseAddr + 0x07);
+ IdeRegisters[EfiIdePrimary].AltOrDev = ControlBlockBaseAddr;
+
+ if ((ClassCode & IDE_SECONDARY_OPERATING_MODE) == 0) {
+ CommandBlockBaseAddr = 0x170;
+ ControlBlockBaseAddr = 0x376;
+ } else {
+ //
+ // The BARs should be of IO type
+ //
+ if ((BaseAddress[2] & BIT0) == 0 ||
+ (BaseAddress[3] & BIT0) == 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ CommandBlockBaseAddr = (UINT16) (BaseAddress[2] & 0x0000fff8);
+ ControlBlockBaseAddr = (UINT16) ((BaseAddress[3] & 0x0000fffc) + 2);
+ }
+
+ //
+ // Calculate IDE secondary channel I/O register base address.
+ //
+ IdeRegisters[EfiIdeSecondary].Data = CommandBlockBaseAddr;
+ IdeRegisters[EfiIdeSecondary].ErrOrFeature = (UINT16) (CommandBlockBaseAddr + 0x01);
+ IdeRegisters[EfiIdeSecondary].SectorCount = (UINT16) (CommandBlockBaseAddr + 0x02);
+ IdeRegisters[EfiIdeSecondary].SectorNumber = (UINT16) (CommandBlockBaseAddr + 0x03);
+ IdeRegisters[EfiIdeSecondary].CylinderLsb = (UINT16) (CommandBlockBaseAddr + 0x04);
+ IdeRegisters[EfiIdeSecondary].CylinderMsb = (UINT16) (CommandBlockBaseAddr + 0x05);
+ IdeRegisters[EfiIdeSecondary].Head = (UINT16) (CommandBlockBaseAddr + 0x06);
+ IdeRegisters[EfiIdeSecondary].CmdOrStatus = (UINT16) (CommandBlockBaseAddr + 0x07);
+ IdeRegisters[EfiIdeSecondary].AltOrDev = ControlBlockBaseAddr;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Send ATA Ext command into device with NON_DATA protocol.
+
+ @param IdeRegisters A pointer to EFI_IDE_REGISTERS Data structure.
+ @param AtaCommandBlock A pointer to EFI_ATA_COMMAND_BLOCK Data structure.
+ @param Timeout The time to complete the command.
+
+ @retval EFI_SUCCESS Reading succeed
+ @retval EFI_DEVICE_ERROR Error executing commands on this device.
+
+**/
+EFI_STATUS
+EFIAPI
+AtaIssueCommand (
+ IN EFI_IDE_REGISTERS *IdeRegisters,
+ IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock,
+ IN UINT64 Timeout
+ )
+{
+ EFI_STATUS Status;
+ UINT8 DeviceHead;
+ UINT8 AtaCommand;
+
+ ASSERT (IdeRegisters != NULL);
+ ASSERT (AtaCommandBlock != NULL);
+
+ DeviceHead = AtaCommandBlock->AtaDeviceHead;
+ AtaCommand = AtaCommandBlock->AtaCommand;
+
+ Status = WaitForBSYClear (IdeRegisters, Timeout);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility)
+ //
+ IoWrite8 (IdeRegisters->Head, (UINT8) (0xe0 | DeviceHead));
+
+ //
+ // set all the command parameters
+ // Before write to all the following registers, BSY and DRQ must be 0.
+ //
+ Status = DRQClear2 (IdeRegisters, Timeout);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Fill the feature register, which is a two-byte FIFO. Need write twice.
+ //
+ IoWrite8 (IdeRegisters->ErrOrFeature, AtaCommandBlock->AtaFeaturesExp);
+ IoWrite8 (IdeRegisters->ErrOrFeature, AtaCommandBlock->AtaFeatures);
+
+ //
+ // Fill the sector count register, which is a two-byte FIFO. Need write twice.
+ //
+ IoWrite8 (IdeRegisters->SectorCount, AtaCommandBlock->AtaSectorCountExp);
+ IoWrite8 (IdeRegisters->SectorCount, AtaCommandBlock->AtaSectorCount);
+
+ //
+ // Fill the start LBA registers, which are also two-byte FIFO
+ //
+ IoWrite8 (IdeRegisters->SectorNumber, AtaCommandBlock->AtaSectorNumberExp);
+ IoWrite8 (IdeRegisters->SectorNumber, AtaCommandBlock->AtaSectorNumber);
+
+ IoWrite8 (IdeRegisters->CylinderLsb, AtaCommandBlock->AtaCylinderLowExp);
+ IoWrite8 (IdeRegisters->CylinderLsb, AtaCommandBlock->AtaCylinderLow);
+
+ IoWrite8 (IdeRegisters->CylinderMsb, AtaCommandBlock->AtaCylinderHighExp);
+ IoWrite8 (IdeRegisters->CylinderMsb, AtaCommandBlock->AtaCylinderHigh);
+
+ //
+ // Send command via Command Register
+ //
+ IoWrite8 (IdeRegisters->CmdOrStatus, AtaCommand);
+
+ //
+ // Stall at least 400 microseconds.
+ //
+ MicroSecondDelay (400);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function is used to send out ATA commands conforms to the PIO Data In Protocol.
+
+ @param IdeRegisters A pointer to EFI_IDE_REGISTERS Data structure.
+ @param Buffer A pointer to the source Buffer for the Data.
+ @param ByteCount The Length of the Data.
+ @param Read Flag used to determine the Data transfer direction.
+ Read equals 1, means Data transferred from device to host;
+ Read equals 0, means Data transferred from host to device.
+ @param AtaCommandBlock A pointer to EFI_ATA_COMMAND_BLOCK Data structure.
+ @param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK Data structure.
+ @param Timeout The time to complete the command.
+
+ @retval EFI_SUCCESS send out the ATA command and device send required Data successfully.
+ @retval EFI_DEVICE_ERROR command sent failed.
+
+**/
+EFI_STATUS
+EFIAPI
+AtaPioDataInOut (
+ IN EFI_IDE_REGISTERS *IdeRegisters,
+ IN OUT VOID *Buffer,
+ IN UINT64 ByteCount,
+ IN BOOLEAN Read,
+ IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock,
+ IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock,
+ IN UINT64 Timeout
+ )
+{
+ UINTN WordCount;
+ UINTN Increment;
+ UINT16 *Buffer16;
+ EFI_STATUS Status;
+
+ if ((IdeRegisters == NULL) || (Buffer == NULL) || (AtaCommandBlock == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Issue ATA command
+ //
+ Status = AtaIssueCommand (IdeRegisters, AtaCommandBlock, Timeout);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ Buffer16 = (UINT16 *) Buffer;
+
+ //
+ // According to PIO Data in protocol, host can perform a series of reads to
+ // the Data register after each time device set DRQ ready;
+ // The Data Size of "a series of read" is command specific.
+ // For most ATA command, Data Size received from device will not exceed
+ // 1 sector, hence the Data Size for "a series of read" can be the whole Data
+ // Size of one command request.
+ // For ATA command such as Read Sector command, the Data Size of one ATA
+ // command request is often larger than 1 sector, according to the
+ // Read Sector command, the Data Size of "a series of read" is exactly 1
+ // sector.
+ // Here for simplification reason, we specify the Data Size for
+ // "a series of read" to 1 sector (256 words) if Data Size of one ATA command
+ // request is larger than 256 words.
+ //
+ Increment = 256;
+
+ //
+ // used to record bytes of currently transfered Data
+ //
+ WordCount = 0;
+
+ while (WordCount < RShiftU64(ByteCount, 1)) {
+ //
+ // Poll DRQ bit set, Data transfer can be performed only when DRQ is ready
+ //
+ Status = DRQReady2 (IdeRegisters, Timeout);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ //
+ // Get the byte count for one series of read
+ //
+ if ((WordCount + Increment) > RShiftU64(ByteCount, 1)) {
+ Increment = (UINTN)(RShiftU64(ByteCount, 1) - WordCount);
+ }
+
+ if (Read) {
+ IdeReadPortWMultiple (
+ IdeRegisters->Data,
+ Increment,
+ Buffer16
+ );
+ } else {
+ IdeWritePortWMultiple (
+ IdeRegisters->Data,
+ Increment,
+ Buffer16
+ );
+ }
+
+ Status = CheckStatusRegister (IdeRegisters);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ WordCount += Increment;
+ Buffer16 += Increment;
+ }
+
+ Status = DRQClear (IdeRegisters, Timeout);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+Exit:
+ //
+ // Dump All Ide registers to ATA_STATUS_BLOCK
+ //
+ DumpAllIdeRegisters (IdeRegisters);
+
+ return Status;
+}
+
+/**
+ Sends out an ATA Identify Command to the specified device.
+
+ This function sends out the ATA Identify Command to the
+ specified device. Only ATA device responses to this command. If
+ the command succeeds, it returns the Identify Data structure which
+ contains information about the device. This function extracts the
+ information it needs to fill the IDE_BLK_IO_DEV Data structure,
+ including device type, media block Size, media capacity, and etc.
+
+ @param IdeRegisters A pointer to EFI_IDE_REGISTERS Data structure.
+ @param Channel The channel number of device.
+ @param Device The device number of device.
+ @param Buffer A pointer to Data Buffer which is used to contain IDENTIFY Data.
+
+ @retval EFI_SUCCESS Identify ATA device successfully.
+ @retval EFI_DEVICE_ERROR ATA Identify Device Command failed or device is not ATA device.
+ @retval EFI_OUT_OF_RESOURCES Allocate memory failed.
+**/
+EFI_STATUS
+EFIAPI
+AtaIdentify (
+ IN EFI_IDE_REGISTERS *IdeRegisters,
+ IN UINT8 Channel,
+ IN UINT8 Device,
+ IN OUT ATA_IDENTIFY_DATA *Buffer
+ )
+{
+ EFI_STATUS Status;
+ EFI_ATA_COMMAND_BLOCK AtaCommandBlock;
+
+ ZeroMem (&AtaCommandBlock, sizeof (EFI_ATA_COMMAND_BLOCK));
+
+ AtaCommandBlock.AtaCommand = ATA_CMD_IDENTIFY_DRIVE;
+ AtaCommandBlock.AtaDeviceHead = (UINT8)(Device << 0x4);
+
+ Status = AtaPioDataInOut (
+ IdeRegisters,
+ Buffer,
+ sizeof (ATA_IDENTIFY_DATA),
+ TRUE,
+ &AtaCommandBlock,
+ NULL,
+ ATA_TIMEOUT
+ );
+
+ return Status;
+}
+
+
+
diff --git a/Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalIdeMode.h b/Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalIdeMode.h
new file mode 100644
index 0000000000..ba94a97505
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalIdeMode.h
@@ -0,0 +1,173 @@
+/** @file
+ Header file for IDE mode of ATA host controller.
+
+Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+
+
+#ifndef __OPAL_PASSWORD_IDE_MODE_H__
+#define __OPAL_PASSWORD_IDE_MODE_H__
+
+typedef enum {
+ EfiIdePrimary = 0,
+ EfiIdeSecondary = 1,
+ EfiIdeMaxChannel = 2
+} EFI_IDE_CHANNEL;
+
+typedef enum {
+ EfiIdeMaster = 0,
+ EfiIdeSlave = 1,
+ EfiIdeMaxDevice = 2
+} EFI_IDE_DEVICE;
+
+//
+// IDE registers set
+//
+typedef struct {
+ UINT16 Data;
+ UINT16 ErrOrFeature;
+ UINT16 SectorCount;
+ UINT16 SectorNumber;
+ UINT16 CylinderLsb;
+ UINT16 CylinderMsb;
+ UINT16 Head;
+ UINT16 CmdOrStatus;
+ UINT16 AltOrDev;
+} EFI_IDE_REGISTERS;
+
+//
+// Bit definitions in Programming Interface byte of the Class Code field
+// in PCI IDE controller's Configuration Space
+//
+#define IDE_PRIMARY_OPERATING_MODE BIT0
+#define IDE_PRIMARY_PROGRAMMABLE_INDICATOR BIT1
+#define IDE_SECONDARY_OPERATING_MODE BIT2
+#define IDE_SECONDARY_PROGRAMMABLE_INDICATOR BIT3
+
+/**
+ Get IDE i/o port registers' base addresses by mode.
+
+ In 'Compatibility' mode, use fixed addresses.
+ In Native-PCI mode, get base addresses from BARs in the PCI IDE controller's
+ Configuration Space.
+
+ The steps to get IDE i/o port registers' base addresses for each channel
+ as follows:
+
+ 1. Examine the Programming Interface byte of the Class Code fields in PCI IDE
+ controller's Configuration Space to determine the operating mode.
+
+ 2. a) In 'Compatibility' mode, use fixed addresses shown in the Table 1 below.
+ ___________________________________________
+ | | Command Block | Control Block |
+ | Channel | Registers | Registers |
+ |___________|_______________|_______________|
+ | Primary | 1F0h - 1F7h | 3F6h - 3F7h |
+ |___________|_______________|_______________|
+ | Secondary | 170h - 177h | 376h - 377h |
+ |___________|_______________|_______________|
+
+ Table 1. Compatibility resource mappings
+
+ b) In Native-PCI mode, IDE registers are mapped into IO space using the BARs
+ in IDE controller's PCI Configuration Space, shown in the Table 2 below.
+ ___________________________________________________
+ | | Command Block | Control Block |
+ | Channel | Registers | Registers |
+ |___________|___________________|___________________|
+ | Primary | BAR at offset 0x10| BAR at offset 0x14|
+ |___________|___________________|___________________|
+ | Secondary | BAR at offset 0x18| BAR at offset 0x1C|
+ |___________|___________________|___________________|
+
+ Table 2. BARs for Register Mapping
+
+ @param[in] Bus The bus number of ata host controller.
+ @param[in] Device The device number of ata host controller.
+ @param[in] Function The function number of ata host controller.
+ @param[in, out] IdeRegisters Pointer to EFI_IDE_REGISTERS which is used to
+ store the IDE i/o port registers' base addresses
+
+ @retval EFI_UNSUPPORTED Return this Value when the BARs is not IO type
+ @retval EFI_SUCCESS Get the Base address successfully
+ @retval Other Read the pci configureation Data error
+
+**/
+EFI_STATUS
+EFIAPI
+GetIdeRegisterIoAddr (
+ IN UINTN Bus,
+ IN UINTN Device,
+ IN UINTN Function,
+ IN OUT EFI_IDE_REGISTERS *IdeRegisters
+ );
+
+/**
+ Sends out an ATA Identify Command to the specified device.
+
+ This function sends out the ATA Identify Command to the
+ specified device. Only ATA device responses to this command. If
+ the command succeeds, it returns the Identify Data structure which
+ contains information about the device. This function extracts the
+ information it needs to fill the IDE_BLK_IO_DEV Data structure,
+ including device type, media block Size, media capacity, and etc.
+
+ @param IdeRegisters A pointer to EFI_IDE_REGISTERS Data structure.
+ @param Channel The channel number of device.
+ @param Device The device number of device.
+ @param Buffer A pointer to Data Buffer which is used to contain IDENTIFY Data.
+
+ @retval EFI_SUCCESS Identify ATA device successfully.
+ @retval EFI_DEVICE_ERROR ATA Identify Device Command failed or device is not ATA device.
+ @retval EFI_OUT_OF_RESOURCES Allocate memory failed.
+**/
+EFI_STATUS
+EFIAPI
+AtaIdentify (
+ IN EFI_IDE_REGISTERS *IdeRegisters,
+ IN UINT8 Channel,
+ IN UINT8 Device,
+ IN OUT ATA_IDENTIFY_DATA *Buffer
+ );
+
+/**
+ This function is used to send out ATA commands conforms to the PIO Data In Protocol.
+
+ @param IdeRegisters A pointer to EFI_IDE_REGISTERS Data structure.
+ @param Buffer A pointer to the source Buffer for the Data.
+ @param ByteCount The Length of the Data.
+ @param Read Flag used to determine the Data transfer direction.
+ Read equals 1, means Data transferred from device to host;
+ Read equals 0, means Data transferred from host to device.
+ @param AtaCommandBlock A pointer to EFI_ATA_COMMAND_BLOCK Data structure.
+ @param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK Data structure.
+ @param Timeout The time to complete the command.
+
+ @retval EFI_SUCCESS send out the ATA command and device send required Data successfully.
+ @retval EFI_DEVICE_ERROR command sent failed.
+
+**/
+EFI_STATUS
+EFIAPI
+AtaPioDataInOut (
+ IN EFI_IDE_REGISTERS *IdeRegisters,
+ IN OUT VOID *Buffer,
+ IN UINT64 ByteCount,
+ IN BOOLEAN Read,
+ IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock,
+ IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock,
+ IN UINT64 Timeout
+ );
+
+
+#endif
+
diff --git a/Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalNvmeMode.c b/Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalNvmeMode.c
new file mode 100644
index 0000000000..a47d2764c3
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalNvmeMode.c
@@ -0,0 +1,2165 @@
+/** @file
+ Provide functions to initialize NVME controller and perform NVME commands
+
+Copyright (c) 2016 - 2017, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "OpalPasswordSmm.h"
+
+
+#define ALIGN(v, a) (UINTN)((((v) - 1) | ((a) - 1)) + 1)
+
+///
+/// NVME Host controller registers operation
+///
+#define NVME_GET_CAP(Nvme, Cap) NvmeMmioRead (Cap, Nvme->Nbar + NVME_CAP_OFFSET, sizeof (NVME_CAP))
+#define NVME_GET_CC(Nvme, Cc) NvmeMmioRead (Cc, Nvme->Nbar + NVME_CC_OFFSET, sizeof (NVME_CC))
+#define NVME_SET_CC(Nvme, Cc) NvmeMmioWrite (Nvme->Nbar + NVME_CC_OFFSET, Cc, sizeof (NVME_CC))
+#define NVME_GET_CSTS(Nvme, Csts) NvmeMmioRead (Csts, Nvme->Nbar + NVME_CSTS_OFFSET, sizeof (NVME_CSTS))
+#define NVME_GET_AQA(Nvme, Aqa) NvmeMmioRead (Aqa, Nvme->Nbar + NVME_AQA_OFFSET, sizeof (NVME_AQA))
+#define NVME_SET_AQA(Nvme, Aqa) NvmeMmioWrite (Nvme->Nbar + NVME_AQA_OFFSET, Aqa, sizeof (NVME_AQA))
+#define NVME_GET_ASQ(Nvme, Asq) NvmeMmioRead (Asq, Nvme->Nbar + NVME_ASQ_OFFSET, sizeof (NVME_ASQ))
+#define NVME_SET_ASQ(Nvme, Asq) NvmeMmioWrite (Nvme->Nbar + NVME_ASQ_OFFSET, Asq, sizeof (NVME_ASQ))
+#define NVME_GET_ACQ(Nvme, Acq) NvmeMmioRead (Acq, Nvme->Nbar + NVME_ACQ_OFFSET, sizeof (NVME_ACQ))
+#define NVME_SET_ACQ(Nvme, Acq) NvmeMmioWrite (Nvme->Nbar + NVME_ACQ_OFFSET, Acq, sizeof (NVME_ACQ))
+#define NVME_GET_VER(Nvme, Ver) NvmeMmioRead (Ver, Nvme->Nbar + NVME_VER_OFFSET, sizeof (NVME_VER))
+#define NVME_SET_SQTDBL(Nvme, Qid, Sqtdbl) NvmeMmioWrite (Nvme->Nbar + NVME_SQTDBL_OFFSET(Qid, Nvme->Cap.Dstrd), Sqtdbl, sizeof (NVME_SQTDBL))
+#define NVME_SET_CQHDBL(Nvme, Qid, Cqhdbl) NvmeMmioWrite (Nvme->Nbar + NVME_CQHDBL_OFFSET(Qid, Nvme->Cap.Dstrd), Cqhdbl, sizeof (NVME_CQHDBL))
+
+///
+/// Base memory address
+///
+enum {
+ BASEMEM_CONTROLLER_DATA,
+ BASEMEM_IDENTIFY_DATA,
+ BASEMEM_ASQ,
+ BASEMEM_ACQ,
+ BASEMEM_SQ,
+ BASEMEM_CQ,
+ BASEMEM_PRP,
+ BASEMEM_SECURITY,
+ MAX_BASEMEM_COUNT
+};
+
+///
+/// All of base memories are 4K(0x1000) alignment
+///
+#define NVME_MEM_BASE(Nvme) ((UINTN)(Nvme->BaseMem))
+#define NVME_CONTROL_DATA_BASE(Nvme) (ALIGN (NVME_MEM_BASE(Nvme) + ((NvmeGetBaseMemPages (BASEMEM_CONTROLLER_DATA)) * EFI_PAGE_SIZE), EFI_PAGE_SIZE))
+#define NVME_NAMESPACE_DATA_BASE(Nvme) (ALIGN (NVME_MEM_BASE(Nvme) + ((NvmeGetBaseMemPages (BASEMEM_IDENTIFY_DATA)) * EFI_PAGE_SIZE), EFI_PAGE_SIZE))
+#define NVME_ASQ_BASE(Nvme) (ALIGN (NVME_MEM_BASE(Nvme) + ((NvmeGetBaseMemPages (BASEMEM_ASQ)) * EFI_PAGE_SIZE), EFI_PAGE_SIZE))
+#define NVME_ACQ_BASE(Nvme) (ALIGN (NVME_MEM_BASE(Nvme) + ((NvmeGetBaseMemPages (BASEMEM_ACQ)) * EFI_PAGE_SIZE), EFI_PAGE_SIZE))
+#define NVME_SQ_BASE(Nvme, index) (ALIGN (NVME_MEM_BASE(Nvme) + ((NvmeGetBaseMemPages (BASEMEM_SQ) + ((index)*(NVME_MAX_IO_QUEUES-1))) * EFI_PAGE_SIZE), EFI_PAGE_SIZE))
+#define NVME_CQ_BASE(Nvme, index) (ALIGN (NVME_MEM_BASE(Nvme) + ((NvmeGetBaseMemPages (BASEMEM_CQ) + ((index)*(NVME_MAX_IO_QUEUES-1))) * EFI_PAGE_SIZE), EFI_PAGE_SIZE))
+#define NVME_PRP_BASE(Nvme, index) (ALIGN (NVME_MEM_BASE(Nvme) + ((NvmeGetBaseMemPages (BASEMEM_PRP) + ((index)*NVME_PRP_SIZE)) * EFI_PAGE_SIZE), EFI_PAGE_SIZE))
+#define NVME_SEC_BASE(Nvme) (ALIGN (NVME_MEM_BASE(Nvme) + ((NvmeGetBaseMemPages (BASEMEM_SECURITY)) * EFI_PAGE_SIZE), EFI_PAGE_SIZE))
+
+/**
+ Transfer MMIO Data to memory.
+
+ @param[in,out] MemBuffer - Destination: Memory address
+ @param[in] MmioAddr - Source: MMIO address
+ @param[in] Size - Size for read
+
+ @retval EFI_SUCCESS - MMIO read sucessfully
+**/
+EFI_STATUS
+NvmeMmioRead (
+ IN OUT VOID *MemBuffer,
+ IN UINTN MmioAddr,
+ IN UINTN Size
+ )
+{
+ UINTN Offset;
+ UINT8 Data;
+ UINT8 *Ptr;
+
+ // priority has adjusted
+ switch (Size) {
+ case 4:
+ *((UINT32 *)MemBuffer) = MmioRead32 (MmioAddr);
+ break;
+
+ case 8:
+ *((UINT64 *)MemBuffer) = MmioRead64 (MmioAddr);
+ break;
+
+ case 2:
+ *((UINT16 *)MemBuffer) = MmioRead16 (MmioAddr);
+ break;
+
+ case 1:
+ *((UINT8 *)MemBuffer) = MmioRead8 (MmioAddr);
+ break;
+
+ default:
+ Ptr = (UINT8 *)MemBuffer;
+ for (Offset = 0; Offset < Size; Offset += 1) {
+ Data = MmioRead8 (MmioAddr + Offset);
+ Ptr[Offset] = Data;
+ }
+ break;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Transfer memory data to MMIO.
+
+ @param[in,out] MmioAddr - Destination: MMIO address
+ @param[in] MemBuffer - Source: Memory address
+ @param[in] Size - Size for write
+
+ @retval EFI_SUCCESS - MMIO write sucessfully
+**/
+EFI_STATUS
+NvmeMmioWrite (
+ IN OUT UINTN MmioAddr,
+ IN VOID *MemBuffer,
+ IN UINTN Size
+ )
+{
+ UINTN Offset;
+ UINT8 Data;
+ UINT8 *Ptr;
+
+ // priority has adjusted
+ switch (Size) {
+ case 4:
+ MmioWrite32 (MmioAddr, *((UINT32 *)MemBuffer));
+ break;
+
+ case 8:
+ MmioWrite64 (MmioAddr, *((UINT64 *)MemBuffer));
+ break;
+
+ case 2:
+ MmioWrite16 (MmioAddr, *((UINT16 *)MemBuffer));
+ break;
+
+ case 1:
+ MmioWrite8 (MmioAddr, *((UINT8 *)MemBuffer));
+ break;
+
+ default:
+ Ptr = (UINT8 *)MemBuffer;
+ for (Offset = 0; Offset < Size; Offset += 1) {
+ Data = Ptr[Offset];
+ MmioWrite8 (MmioAddr + Offset, Data);
+ }
+ break;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Transfer MMIO data to memory.
+
+ @param[in,out] MemBuffer - Destination: Memory address
+ @param[in] MmioAddr - Source: MMIO address
+ @param[in] Size - Size for read
+
+ @retval EFI_SUCCESS - MMIO read sucessfully
+**/
+EFI_STATUS
+OpalPciRead (
+ IN OUT VOID *MemBuffer,
+ IN UINTN MmioAddr,
+ IN UINTN Size
+ )
+{
+ UINTN Offset;
+ UINT8 Data;
+ UINT8 *Ptr;
+
+ // priority has adjusted
+ switch (Size) {
+ case 4:
+ *((UINT32 *)MemBuffer) = PciRead32 (MmioAddr);
+ break;
+
+ case 2:
+ *((UINT16 *)MemBuffer) = PciRead16 (MmioAddr);
+ break;
+
+ case 1:
+ *((UINT8 *)MemBuffer) = PciRead8 (MmioAddr);
+ break;
+
+ default:
+ Ptr = (UINT8 *)MemBuffer;
+ for (Offset = 0; Offset < Size; Offset += 1) {
+ Data = PciRead8 (MmioAddr + Offset);
+ Ptr[Offset] = Data;
+ }
+ break;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Transfer memory data to MMIO.
+
+ @param[in,out] MmioAddr - Destination: MMIO address
+ @param[in] MemBuffer - Source: Memory address
+ @param[in] Size - Size for write
+
+ @retval EFI_SUCCESS - MMIO write sucessfully
+**/
+EFI_STATUS
+OpalPciWrite (
+ IN OUT UINTN MmioAddr,
+ IN VOID *MemBuffer,
+ IN UINTN Size
+ )
+{
+ UINTN Offset;
+ UINT8 Data;
+ UINT8 *Ptr;
+
+ // priority has adjusted
+ switch (Size) {
+ case 4:
+ PciWrite32 (MmioAddr, *((UINT32 *)MemBuffer));
+ break;
+
+ case 2:
+ PciWrite16 (MmioAddr, *((UINT16 *)MemBuffer));
+ break;
+
+ case 1:
+ PciWrite8 (MmioAddr, *((UINT8 *)MemBuffer));
+ break;
+
+ default:
+ Ptr = (UINT8 *)MemBuffer;
+ for (Offset = 0; Offset < Size; Offset += 1) {
+ Data = Ptr[Offset];
+ PciWrite8 (MmioAddr + Offset, Data);
+ }
+ break;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get total pages for specific NVME based memory.
+
+ @param[in] BaseMemIndex - The Index of BaseMem (0-based).
+
+ @retval - The page count for specific BaseMem Index
+
+**/
+UINT32
+NvmeGetBaseMemPages (
+ IN UINTN BaseMemIndex
+ )
+{
+ UINT32 Pages;
+ UINTN Index;
+ UINT32 PageSizeList[8];
+
+ PageSizeList[0] = 1; /* Controller Data */
+ PageSizeList[1] = 1; /* Identify Data */
+ PageSizeList[2] = 1; /* ASQ */
+ PageSizeList[3] = 1; /* ACQ */
+ PageSizeList[4] = 1; /* SQs */
+ PageSizeList[5] = 1; /* CQs */
+ PageSizeList[6] = NVME_PRP_SIZE * NVME_CSQ_DEPTH; /* PRPs */
+ PageSizeList[7] = 1; /* Security Commands */
+
+ if (BaseMemIndex > MAX_BASEMEM_COUNT) {
+ ASSERT (FALSE);
+ return 0;
+ }
+
+ Pages = 0;
+ for (Index = 0; Index < BaseMemIndex; Index++) {
+ Pages += PageSizeList[Index];
+ }
+
+ return Pages;
+}
+
+/**
+ Wait for NVME controller status to be ready or not.
+
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
+ @param[in] WaitReady - Flag for waitting status ready or not
+
+ @return EFI_SUCCESS - Successfully to wait specific status.
+ @return others - Fail to wait for specific controller status.
+
+**/
+STATIC
+EFI_STATUS
+NvmeWaitController (
+ IN NVME_CONTEXT *Nvme,
+ IN BOOLEAN WaitReady
+ )
+{
+ NVME_CSTS Csts;
+ EFI_STATUS Status;
+ UINT32 Index;
+ UINT8 Timeout;
+
+ //
+ // Cap.To specifies max delay time in 500ms increments for Csts.Rdy to set after
+ // Cc.Enable. Loop produces a 1 millisecond delay per itteration, up to 500 * Cap.To.
+ //
+ if (Nvme->Cap.To == 0) {
+ Timeout = 1;
+ } else {
+ Timeout = Nvme->Cap.To;
+ }
+
+ Status = EFI_SUCCESS;
+ for(Index = (Timeout * 500); Index != 0; --Index) {
+ MicroSecondDelay (1000);
+
+ //
+ // Check if the controller is initialized
+ //
+ Status = NVME_GET_CSTS (Nvme, &Csts);
+ if (EFI_ERROR(Status)) {
+ DEBUG ((DEBUG_ERROR, "NVME_GET_CSTS fail, Status = %r\n", Status));
+ return Status;
+ }
+
+ if ((BOOLEAN) Csts.Rdy == WaitReady) {
+ break;
+ }
+ }
+
+ if (Index == 0) {
+ Status = EFI_TIMEOUT;
+ }
+
+ return Status;
+}
+
+/**
+ Disable the Nvm Express controller.
+
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
+
+ @return EFI_SUCCESS - Successfully disable the controller.
+ @return others - Fail to disable the controller.
+
+**/
+STATIC
+EFI_STATUS
+NvmeDisableController (
+ IN NVME_CONTEXT *Nvme
+ )
+{
+ NVME_CC Cc;
+ NVME_CSTS Csts;
+ EFI_STATUS Status;
+
+ Status = NVME_GET_CSTS (Nvme, &Csts);
+
+ ///
+ /// Read Controller Configuration Register.
+ ///
+ Status = NVME_GET_CC (Nvme, &Cc);
+ if (EFI_ERROR(Status)) {
+ DEBUG ((DEBUG_ERROR, "NVME_GET_CC fail, Status = %r\n", Status));
+ goto Done;
+ }
+
+ if (Cc.En == 1) {
+ Cc.En = 0;
+ ///
+ /// Disable the controller.
+ ///
+ Status = NVME_SET_CC (Nvme, &Cc);
+ if (EFI_ERROR(Status)) {
+ DEBUG ((DEBUG_ERROR, "NVME_SET_CC fail, Status = %r\n", Status));
+ goto Done;
+ }
+ }
+
+ Status = NvmeWaitController (Nvme, FALSE);
+ if (EFI_ERROR(Status)) {
+ DEBUG ((DEBUG_ERROR, "NvmeWaitController fail, Status = %r\n", Status));
+ goto Done;
+ }
+
+ return EFI_SUCCESS;
+
+Done:
+ DEBUG ((DEBUG_INFO, "NvmeDisableController fail, Status: %r\n", Status));
+ return Status;
+}
+
+/**
+ Enable the Nvm Express controller.
+
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
+
+ @return EFI_SUCCESS - Successfully enable the controller.
+ @return EFI_DEVICE_ERROR - Fail to enable the controller.
+ @return EFI_TIMEOUT - Fail to enable the controller in given time slot.
+
+**/
+STATIC
+EFI_STATUS
+NvmeEnableController (
+ IN NVME_CONTEXT *Nvme
+ )
+{
+ NVME_CC Cc;
+ EFI_STATUS Status;
+
+ //
+ // Enable the controller
+ //
+ ZeroMem (&Cc, sizeof (NVME_CC));
+ Cc.En = 1;
+ Cc.Iosqes = 6;
+ Cc.Iocqes = 4;
+ Status = NVME_SET_CC (Nvme, &Cc);
+ if (EFI_ERROR(Status)) {
+ DEBUG ((DEBUG_ERROR, "NVME_SET_CC fail, Status = %r\n", Status));
+ goto Done;
+ }
+
+ Status = NvmeWaitController (Nvme, TRUE);
+ if (EFI_ERROR(Status)) {
+ DEBUG ((DEBUG_ERROR, "NvmeWaitController fail, Status = %r\n", Status));
+ goto Done;
+ }
+
+ return EFI_SUCCESS;
+
+Done:
+ DEBUG ((DEBUG_INFO, "NvmeEnableController fail, Status: %r\n", Status));
+ return Status;
+}
+
+/**
+ Shutdown the Nvm Express controller.
+
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
+
+ @return EFI_SUCCESS - Successfully shutdown the controller.
+ @return EFI_DEVICE_ERROR - Fail to shutdown the controller.
+ @return EFI_TIMEOUT - Fail to shutdown the controller in given time slot.
+
+**/
+STATIC
+EFI_STATUS
+NvmeShutdownController (
+ IN NVME_CONTEXT *Nvme
+ )
+{
+ NVME_CC Cc;
+ NVME_CSTS Csts;
+ EFI_STATUS Status;
+ UINT32 Index;
+ UINTN Timeout;
+
+ Status = NVME_GET_CC (Nvme, &Cc);
+ if (EFI_ERROR(Status)) {
+ DEBUG ((DEBUG_ERROR, "NVME_GET_CC fail, Status = %r\n", Status));
+ return Status;
+ }
+
+ Cc.Shn = 1; // Normal shutdown
+
+ Status = NVME_SET_CC (Nvme, &Cc);
+ if (EFI_ERROR(Status)) {
+ DEBUG ((DEBUG_ERROR, "NVME_SET_CC fail, Status = %r\n", Status));
+ return Status;
+ }
+
+ Timeout = NVME_GENERIC_TIMEOUT/1000; // ms
+ for(Index = (UINT32)(Timeout); Index != 0; --Index) {
+ MicroSecondDelay (1000);
+
+ Status = NVME_GET_CSTS (Nvme, &Csts);
+ if (EFI_ERROR(Status)) {
+ DEBUG ((DEBUG_ERROR, "NVME_GET_CSTS fail, Status = %r\n", Status));
+ return Status;
+ }
+
+ if (Csts.Shst == 2) { // Shutdown processing complete
+ break;
+ }
+ }
+
+ if (Index == 0) {
+ Status = EFI_TIMEOUT;
+ }
+
+ return Status;
+}
+
+/**
+ Check the execution status from a given completion queue entry.
+
+ @param[in] Cq - A pointer to the NVME_CQ item.
+
+**/
+EFI_STATUS
+NvmeCheckCqStatus (
+ IN NVME_CQ *Cq
+ )
+{
+ if (Cq->Sct == 0x0 && Cq->Sc == 0x0) {
+ return EFI_SUCCESS;
+ }
+
+ DEBUG ((DEBUG_INFO, "Dump NVMe Completion Entry Status from [0x%x]:\n", (UINTN)Cq));
+ DEBUG ((DEBUG_INFO, " SQ Identifier : [0x%x], Phase Tag : [%d], Cmd Identifier : [0x%x]\n", Cq->Sqid, Cq->Pt, Cq->Cid));
+ DEBUG ((DEBUG_INFO, " NVMe Cmd Execution Result - "));
+
+ switch (Cq->Sct) {
+ case 0x0:
+ switch (Cq->Sc) {
+ case 0x0:
+ DEBUG ((DEBUG_INFO, "Successful Completion\n"));
+ return EFI_SUCCESS;
+ case 0x1:
+ DEBUG ((DEBUG_INFO, "Invalid Command Opcode\n"));
+ break;
+ case 0x2:
+ DEBUG ((DEBUG_INFO, "Invalid Field in Command\n"));
+ break;
+ case 0x3:
+ DEBUG ((DEBUG_INFO, "Command ID Conflict\n"));
+ break;
+ case 0x4:
+ DEBUG ((DEBUG_INFO, "Data Transfer Error\n"));
+ break;
+ case 0x5:
+ DEBUG ((DEBUG_INFO, "Commands Aborted due to Power Loss Notification\n"));
+ break;
+ case 0x6:
+ DEBUG ((DEBUG_INFO, "Internal Device Error\n"));
+ break;
+ case 0x7:
+ DEBUG ((DEBUG_INFO, "Command Abort Requested\n"));
+ break;
+ case 0x8:
+ DEBUG ((DEBUG_INFO, "Command Aborted due to SQ Deletion\n"));
+ break;
+ case 0x9:
+ DEBUG ((DEBUG_INFO, "Command Aborted due to Failed Fused Command\n"));
+ break;
+ case 0xA:
+ DEBUG ((DEBUG_INFO, "Command Aborted due to Missing Fused Command\n"));
+ break;
+ case 0xB:
+ DEBUG ((DEBUG_INFO, "Invalid Namespace or Format\n"));
+ break;
+ case 0xC:
+ DEBUG ((DEBUG_INFO, "Command Sequence Error\n"));
+ break;
+ case 0xD:
+ DEBUG ((DEBUG_INFO, "Invalid SGL Last Segment Descriptor\n"));
+ break;
+ case 0xE:
+ DEBUG ((DEBUG_INFO, "Invalid Number of SGL Descriptors\n"));
+ break;
+ case 0xF:
+ DEBUG ((DEBUG_INFO, "Data SGL Length Invalid\n"));
+ break;
+ case 0x10:
+ DEBUG ((DEBUG_INFO, "Metadata SGL Length Invalid\n"));
+ break;
+ case 0x11:
+ DEBUG ((DEBUG_INFO, "SGL Descriptor Type Invalid\n"));
+ break;
+ case 0x80:
+ DEBUG ((DEBUG_INFO, "LBA Out of Range\n"));
+ break;
+ case 0x81:
+ DEBUG ((DEBUG_INFO, "Capacity Exceeded\n"));
+ break;
+ case 0x82:
+ DEBUG ((DEBUG_INFO, "Namespace Not Ready\n"));
+ break;
+ case 0x83:
+ DEBUG ((DEBUG_INFO, "Reservation Conflict\n"));
+ break;
+ }
+ break;
+
+ case 0x1:
+ switch (Cq->Sc) {
+ case 0x0:
+ DEBUG ((DEBUG_INFO, "Completion Queue Invalid\n"));
+ break;
+ case 0x1:
+ DEBUG ((DEBUG_INFO, "Invalid Queue Identifier\n"));
+ break;
+ case 0x2:
+ DEBUG ((DEBUG_INFO, "Maximum Queue Size Exceeded\n"));
+ break;
+ case 0x3:
+ DEBUG ((DEBUG_INFO, "Abort Command Limit Exceeded\n"));
+ break;
+ case 0x5:
+ DEBUG ((DEBUG_INFO, "Asynchronous Event Request Limit Exceeded\n"));
+ break;
+ case 0x6:
+ DEBUG ((DEBUG_INFO, "Invalid Firmware Slot\n"));
+ break;
+ case 0x7:
+ DEBUG ((DEBUG_INFO, "Invalid Firmware Image\n"));
+ break;
+ case 0x8:
+ DEBUG ((DEBUG_INFO, "Invalid Interrupt Vector\n"));
+ break;
+ case 0x9:
+ DEBUG ((DEBUG_INFO, "Invalid Log Page\n"));
+ break;
+ case 0xA:
+ DEBUG ((DEBUG_INFO, "Invalid Format\n"));
+ break;
+ case 0xB:
+ DEBUG ((DEBUG_INFO, "Firmware Application Requires Conventional Reset\n"));
+ break;
+ case 0xC:
+ DEBUG ((DEBUG_INFO, "Invalid Queue Deletion\n"));
+ break;
+ case 0xD:
+ DEBUG ((DEBUG_INFO, "Feature Identifier Not Saveable\n"));
+ break;
+ case 0xE:
+ DEBUG ((DEBUG_INFO, "Feature Not Changeable\n"));
+ break;
+ case 0xF:
+ DEBUG ((DEBUG_INFO, "Feature Not Namespace Specific\n"));
+ break;
+ case 0x10:
+ DEBUG ((DEBUG_INFO, "Firmware Application Requires NVM Subsystem Reset\n"));
+ break;
+ case 0x80:
+ DEBUG ((DEBUG_INFO, "Conflicting Attributes\n"));
+ break;
+ case 0x81:
+ DEBUG ((DEBUG_INFO, "Invalid Protection Information\n"));
+ break;
+ case 0x82:
+ DEBUG ((DEBUG_INFO, "Attempted Write to Read Only Range\n"));
+ break;
+ }
+ break;
+
+ case 0x2:
+ switch (Cq->Sc) {
+ case 0x80:
+ DEBUG ((DEBUG_INFO, "Write Fault\n"));
+ break;
+ case 0x81:
+ DEBUG ((DEBUG_INFO, "Unrecovered Read Error\n"));
+ break;
+ case 0x82:
+ DEBUG ((DEBUG_INFO, "End-to-end Guard Check Error\n"));
+ break;
+ case 0x83:
+ DEBUG ((DEBUG_INFO, "End-to-end Application Tag Check Error\n"));
+ break;
+ case 0x84:
+ DEBUG ((DEBUG_INFO, "End-to-end Reference Tag Check Error\n"));
+ break;
+ case 0x85:
+ DEBUG ((DEBUG_INFO, "Compare Failure\n"));
+ break;
+ case 0x86:
+ DEBUG ((DEBUG_INFO, "Access Denied\n"));
+ break;
+ }
+ break;
+
+ default:
+ DEBUG ((DEBUG_INFO, "Unknown error\n"));
+ break;
+ }
+
+ return EFI_DEVICE_ERROR;
+}
+
+/**
+ Create PRP lists for Data transfer which is larger than 2 memory pages.
+ Note here we calcuate the number of required PRP lists and allocate them at one time.
+
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
+ @param[in] SqId - The SQ index for this PRP
+ @param[in] PhysicalAddr - The physical base address of Data Buffer.
+ @param[in] Pages - The number of pages to be transfered.
+ @param[out] PrpListHost - The host base address of PRP lists.
+ @param[in,out] PrpListNo - The number of PRP List.
+
+ @retval The pointer Value to the first PRP List of the PRP lists.
+
+**/
+STATIC
+UINT64
+NvmeCreatePrpList (
+ IN NVME_CONTEXT *Nvme,
+ IN UINT16 SqId,
+ IN EFI_PHYSICAL_ADDRESS PhysicalAddr,
+ IN UINTN Pages,
+ OUT VOID **PrpListHost,
+ IN OUT UINTN *PrpListNo
+ )
+{
+ UINTN PrpEntryNo;
+ UINT64 PrpListBase;
+ UINTN PrpListIndex;
+ UINTN PrpEntryIndex;
+ UINT64 Remainder;
+ EFI_PHYSICAL_ADDRESS PrpListPhyAddr;
+ UINTN Bytes;
+ UINT8 *PrpEntry;
+ EFI_PHYSICAL_ADDRESS NewPhyAddr;
+
+ ///
+ /// The number of Prp Entry in a memory page.
+ ///
+ PrpEntryNo = EFI_PAGE_SIZE / sizeof (UINT64);
+
+ ///
+ /// Calculate total PrpList number.
+ ///
+ *PrpListNo = (UINTN) DivU64x64Remainder ((UINT64)Pages, (UINT64)PrpEntryNo, &Remainder);
+ if (Remainder != 0) {
+ *PrpListNo += 1;
+ }
+
+ if (*PrpListNo > NVME_PRP_SIZE) {
+ DEBUG ((DEBUG_INFO, "NvmeCreatePrpList (PhysicalAddr: %lx, Pages: %x) PrpEntryNo: %x\n",
+ PhysicalAddr, Pages, PrpEntryNo));
+ DEBUG ((DEBUG_INFO, "*PrpListNo: %x, Remainder: %lx", *PrpListNo, Remainder));
+ ASSERT (FALSE);
+ }
+ *PrpListHost = (VOID *)(UINTN) NVME_PRP_BASE (Nvme, SqId);
+
+ Bytes = EFI_PAGES_TO_SIZE (*PrpListNo);
+ PrpListPhyAddr = (UINT64)(UINTN)(*PrpListHost);
+
+ ///
+ /// Fill all PRP lists except of last one.
+ ///
+ ZeroMem (*PrpListHost, Bytes);
+ for (PrpListIndex = 0; PrpListIndex < *PrpListNo - 1; ++PrpListIndex) {
+ PrpListBase = *(UINT64*)PrpListHost + PrpListIndex * EFI_PAGE_SIZE;
+
+ for (PrpEntryIndex = 0; PrpEntryIndex < PrpEntryNo; ++PrpEntryIndex) {
+ PrpEntry = (UINT8 *)(UINTN) (PrpListBase + PrpEntryIndex * sizeof(UINT64));
+ if (PrpEntryIndex != PrpEntryNo - 1) {
+ ///
+ /// Fill all PRP entries except of last one.
+ ///
+ CopyMem (PrpEntry, (VOID *)(UINTN) (&PhysicalAddr), sizeof (UINT64));
+ PhysicalAddr += EFI_PAGE_SIZE;
+ } else {
+ ///
+ /// Fill last PRP entries with next PRP List pointer.
+ ///
+ NewPhyAddr = (PrpListPhyAddr + (PrpListIndex + 1) * EFI_PAGE_SIZE);
+ CopyMem (PrpEntry, (VOID *)(UINTN) (&NewPhyAddr), sizeof (UINT64));
+ }
+ }
+ }
+
+ ///
+ /// Fill last PRP list.
+ ///
+ PrpListBase = *(UINT64*)PrpListHost + PrpListIndex * EFI_PAGE_SIZE;
+ for (PrpEntryIndex = 0; PrpEntryIndex < ((Remainder != 0) ? Remainder : PrpEntryNo); ++PrpEntryIndex) {
+ PrpEntry = (UINT8 *)(UINTN) (PrpListBase + PrpEntryIndex * sizeof(UINT64));
+ CopyMem (PrpEntry, (VOID *)(UINTN) (&PhysicalAddr), sizeof (UINT64));
+
+ PhysicalAddr += EFI_PAGE_SIZE;
+ }
+
+ return PrpListPhyAddr;
+}
+
+/**
+ Check whether there are available command slots.
+
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
+ @param[in] Qid - Queue index
+
+ @retval EFI_SUCCESS - Available command slot is found
+ @retval EFI_NOT_READY - No available command slot is found
+ @retval EFI_DEVICE_ERROR - Error occurred on device side.
+
+**/
+EFI_STATUS
+NvmeHasFreeCmdSlot (
+ IN NVME_CONTEXT *Nvme,
+ IN UINT8 Qid
+ )
+{
+ return TRUE;
+}
+
+/**
+ Check whether all command slots are clean.
+
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
+ @param[in] Qid - Queue index
+
+ @retval EFI_SUCCESS - All command slots are clean
+ @retval EFI_NOT_READY - Not all command slots are clean
+ @retval EFI_DEVICE_ERROR - Error occurred on device side.
+
+**/
+EFI_STATUS
+NvmeIsAllCmdSlotClean (
+ IN NVME_CONTEXT *Nvme,
+ IN UINT8 Qid
+ )
+{
+ return EFI_SUCCESS;
+}
+
+/**
+ Waits until all NVME commands completed.
+
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
+ @param[in] Qid - Queue index
+
+ @retval EFI_SUCCESS - All NVME commands have completed
+ @retval EFI_TIMEOUT - Timeout occured
+ @retval EFI_NOT_READY - Not all NVME commands have completed
+ @retval others - Error occurred on device side.
+**/
+EFI_STATUS
+NvmeWaitAllComplete (
+ IN NVME_CONTEXT *Nvme,
+ IN UINT8 Qid
+ )
+{
+ return EFI_SUCCESS;
+}
+
+/**
+ Sends an NVM Express Command Packet to an NVM Express controller or namespace. This function supports
+ both blocking I/O and nonblocking I/O. The blocking I/O functionality is required, and the nonblocking
+ I/O functionality is optional.
+
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
+ @param[in] NamespaceId - Is a 32 bit Namespace ID to which the Express HCI command packet will be sent.
+ A Value of 0 denotes the NVM Express controller, a Value of all 0FFh in the namespace
+ ID specifies that the command packet should be sent to all valid namespaces.
+ @param[in] NamespaceUuid - Is a 64 bit Namespace UUID to which the Express HCI command packet will be sent.
+ A Value of 0 denotes the NVM Express controller, a Value of all 0FFh in the namespace
+ UUID specifies that the command packet should be sent to all valid namespaces.
+ @param[in,out] Packet - A pointer to the NVM Express HCI Command Packet to send to the NVMe namespace specified
+ by NamespaceId.
+
+ @retval EFI_SUCCESS - The NVM Express Command Packet was sent by the host. TransferLength bytes were transferred
+ to, or from DataBuffer.
+ @retval EFI_NOT_READY - The NVM Express Command Packet could not be sent because the controller is not ready. The caller
+ may retry again later.
+ @retval EFI_DEVICE_ERROR - A device error occurred while attempting to send the NVM Express Command Packet.
+ @retval EFI_INVALID_PARAMETER - Namespace, or the contents of NVM_EXPRESS_PASS_THRU_COMMAND_PACKET are invalid. The NVM
+ Express Command Packet was not sent, so no additional status information is available.
+ @retval EFI_UNSUPPORTED - The command described by the NVM Express Command Packet is not supported by the host adapter.
+ The NVM Express Command Packet was not sent, so no additional status information is available.
+ @retval EFI_TIMEOUT - A timeout occurred while waiting for the NVM Express Command Packet to execute.
+
+**/
+EFI_STATUS
+NvmePassThru (
+ IN NVME_CONTEXT *Nvme,
+ IN UINT32 NamespaceId,
+ IN UINT64 NamespaceUuid,
+ IN OUT NVM_EXPRESS_PASS_THRU_COMMAND_PACKET *Packet
+ )
+{
+ EFI_STATUS Status;
+ NVME_SQ *Sq;
+ NVME_CQ *Cq;
+ UINT8 Qid;
+ UINT32 Bytes;
+ UINT32 Offset;
+ EFI_PHYSICAL_ADDRESS PhyAddr;
+ VOID *PrpListHost;
+ UINTN PrpListNo;
+ UINT32 Timer;
+ UINTN SqSize;
+ UINTN CqSize;
+
+ ///
+ /// check the Data fields in Packet parameter.
+ ///
+ if ((Nvme == NULL) || (Packet == NULL)) {
+ DEBUG ((DEBUG_ERROR, "NvmePassThru, invalid parameter: Nvme(%x)/Packet(%x)\n",
+ (UINTN)Nvme, (UINTN)Packet));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Packet->NvmeCmd == NULL) || (Packet->NvmeResponse == NULL)) {
+ DEBUG ((DEBUG_ERROR, "NvmePassThru, invalid parameter: NvmeCmd(%x)/NvmeResponse(%x)\n",
+ (UINTN)Packet->NvmeCmd, (UINTN)Packet->NvmeResponse));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Packet->QueueId != NVME_ADMIN_QUEUE && Packet->QueueId != NVME_IO_QUEUE) {
+ DEBUG ((DEBUG_ERROR, "NvmePassThru, invalid parameter: QueueId(%x)\n",
+ Packet->QueueId));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PrpListHost = NULL;
+ PrpListNo = 0;
+ Status = EFI_SUCCESS;
+
+ Qid = Packet->QueueId;
+ Sq = Nvme->SqBuffer[Qid] + Nvme->SqTdbl[Qid].Sqt;
+ Cq = Nvme->CqBuffer[Qid] + Nvme->CqHdbl[Qid].Cqh;
+ if (Qid == NVME_ADMIN_QUEUE) {
+ SqSize = NVME_ASQ_SIZE + 1;
+ CqSize = NVME_ACQ_SIZE + 1;
+ } else {
+ SqSize = NVME_CSQ_DEPTH;
+ CqSize = NVME_CCQ_DEPTH;
+ }
+
+ if (Packet->NvmeCmd->Nsid != NamespaceId) {
+ DEBUG ((DEBUG_ERROR, "NvmePassThru: Nsid mismatch (%x, %x)\n",
+ Packet->NvmeCmd->Nsid, NamespaceId));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ZeroMem (Sq, sizeof (NVME_SQ));
+ Sq->Opc = Packet->NvmeCmd->Cdw0.Opcode;
+ Sq->Fuse = Packet->NvmeCmd->Cdw0.FusedOperation;
+ Sq->Cid = Packet->NvmeCmd->Cdw0.Cid;
+ Sq->Nsid = Packet->NvmeCmd->Nsid;
+
+ ///
+ /// Currently we only support PRP for Data transfer, SGL is NOT supported.
+ ///
+ ASSERT (Sq->Psdt == 0);
+ if (Sq->Psdt != 0) {
+ DEBUG ((DEBUG_ERROR, "NvmePassThru: doesn't support SGL mechanism\n"));
+ return EFI_UNSUPPORTED;
+ }
+
+ Sq->Prp[0] = Packet->TransferBuffer;
+ Sq->Prp[1] = 0;
+
+ if(Packet->MetadataBuffer != (UINT64)(UINTN)NULL) {
+ Sq->Mptr = Packet->MetadataBuffer;
+ }
+
+ ///
+ /// If the Buffer Size spans more than two memory pages (page Size as defined in CC.Mps),
+ /// then build a PRP list in the second PRP submission queue entry.
+ ///
+ Offset = ((UINT32)Sq->Prp[0]) & (EFI_PAGE_SIZE - 1);
+ Bytes = Packet->TransferLength;
+
+ if ((Offset + Bytes) > (EFI_PAGE_SIZE * 2)) {
+ ///
+ /// Create PrpList for remaining Data Buffer.
+ ///
+ PhyAddr = (Sq->Prp[0] + EFI_PAGE_SIZE) & ~(EFI_PAGE_SIZE - 1);
+ Sq->Prp[1] = NvmeCreatePrpList (Nvme, Nvme->SqTdbl[Qid].Sqt, PhyAddr, EFI_SIZE_TO_PAGES(Offset + Bytes) - 1, &PrpListHost, &PrpListNo);
+ if (Sq->Prp[1] == 0) {
+ Status = EFI_OUT_OF_RESOURCES;
+ DEBUG ((DEBUG_ERROR, "NvmeCreatePrpList fail, Status: %r\n", Status));
+ goto EXIT;
+ }
+
+ } else if ((Offset + Bytes) > EFI_PAGE_SIZE) {
+ Sq->Prp[1] = (Sq->Prp[0] + EFI_PAGE_SIZE) & ~(EFI_PAGE_SIZE - 1);
+ }
+
+ if(Packet->NvmeCmd->Flags & CDW10_VALID) {
+ Sq->Payload.Raw.Cdw10 = Packet->NvmeCmd->Cdw10;
+ }
+ if(Packet->NvmeCmd->Flags & CDW11_VALID) {
+ Sq->Payload.Raw.Cdw11 = Packet->NvmeCmd->Cdw11;
+ }
+ if(Packet->NvmeCmd->Flags & CDW12_VALID) {
+ Sq->Payload.Raw.Cdw12 = Packet->NvmeCmd->Cdw12;
+ }
+ if(Packet->NvmeCmd->Flags & CDW13_VALID) {
+ Sq->Payload.Raw.Cdw13 = Packet->NvmeCmd->Cdw13;
+ }
+ if(Packet->NvmeCmd->Flags & CDW14_VALID) {
+ Sq->Payload.Raw.Cdw14 = Packet->NvmeCmd->Cdw14;
+ }
+ if(Packet->NvmeCmd->Flags & CDW15_VALID) {
+ Sq->Payload.Raw.Cdw15 = Packet->NvmeCmd->Cdw15;
+ }
+
+ ///
+ /// Ring the submission queue doorbell.
+ ///
+ Nvme->SqTdbl[Qid].Sqt++;
+ if(Nvme->SqTdbl[Qid].Sqt == SqSize) {
+ Nvme->SqTdbl[Qid].Sqt = 0;
+ }
+ Status = NVME_SET_SQTDBL (Nvme, Qid, &Nvme->SqTdbl[Qid]);
+ if (EFI_ERROR(Status)) {
+ DEBUG ((DEBUG_ERROR, "NVME_SET_SQTDBL fail, Status: %r\n", Status));
+ goto EXIT;
+ }
+
+ ///
+ /// Wait for completion queue to get filled in.
+ ///
+ Status = EFI_TIMEOUT;
+ Timer = 0;
+ while (Timer < NVME_CMD_TIMEOUT) {
+ //DEBUG ((DEBUG_VERBOSE, "Timer: %x, Cq:\n", Timer));
+ //DumpMem (Cq, sizeof (NVME_CQ));
+ if (Cq->Pt != Nvme->Pt[Qid]) {
+ Status = EFI_SUCCESS;
+ break;
+ }
+
+ MicroSecondDelay (NVME_CMD_WAIT);
+ Timer += NVME_CMD_WAIT;
+ }
+
+ Nvme->CqHdbl[Qid].Cqh++;
+ if (Nvme->CqHdbl[Qid].Cqh == CqSize) {
+ Nvme->CqHdbl[Qid].Cqh = 0;
+ Nvme->Pt[Qid] ^= 1;
+ }
+
+ ///
+ /// Copy the Respose Queue entry for this command to the callers response Buffer
+ ///
+ CopyMem (Packet->NvmeResponse, Cq, sizeof(NVM_EXPRESS_RESPONSE));
+
+ if (!EFI_ERROR(Status)) { // We still need to check CQ status if no timeout error occured
+ Status = NvmeCheckCqStatus (Cq);
+ }
+ NVME_SET_CQHDBL (Nvme, Qid, &Nvme->CqHdbl[Qid]);
+
+EXIT:
+ return Status;
+}
+
+/**
+ Get identify controller Data.
+
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
+ @param[in] Buffer - The Buffer used to store the identify controller Data.
+
+ @return EFI_SUCCESS - Successfully get the identify controller Data.
+ @return others - Fail to get the identify controller Data.
+
+**/
+STATIC
+EFI_STATUS
+NvmeIdentifyController (
+ IN NVME_CONTEXT *Nvme,
+ IN VOID *Buffer
+ )
+{
+ NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;
+ NVM_EXPRESS_COMMAND Command;
+ NVM_EXPRESS_RESPONSE Response;
+ EFI_STATUS Status;
+
+ ZeroMem (&CommandPacket, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
+ ZeroMem (&Command, sizeof(NVM_EXPRESS_COMMAND));
+ ZeroMem (&Response, sizeof(NVM_EXPRESS_RESPONSE));
+
+ Command.Cdw0.Opcode = NVME_ADMIN_IDENTIFY_OPC;
+ Command.Cdw0.Cid = Nvme->Cid[NVME_ADMIN_QUEUE]++;
+ //
+ // According to Nvm Express 1.1 spec Figure 38, When not used, the field shall be cleared to 0h.
+ // For the Identify command, the Namespace Identifier is only used for the Namespace Data structure.
+ //
+ Command.Nsid = 0;
+
+ CommandPacket.NvmeCmd = &Command;
+ CommandPacket.NvmeResponse = &Response;
+ CommandPacket.TransferBuffer = (UINT64)(UINTN)Buffer;
+ CommandPacket.TransferLength = sizeof (NVME_ADMIN_CONTROLLER_DATA);
+ CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;
+ CommandPacket.QueueId = NVME_ADMIN_QUEUE;
+ //
+ // Set bit 0 (Cns bit) to 1 to identify a controller
+ //
+ Command.Cdw10 = 1;
+ Command.Flags = CDW10_VALID;
+
+ Status = NvmePassThru (
+ Nvme,
+ NVME_CONTROLLER_ID,
+ 0,
+ &CommandPacket
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = NvmeWaitAllComplete (Nvme, CommandPacket.QueueId);
+ }
+
+ return Status;
+}
+
+/**
+ Get specified identify namespace Data.
+
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
+ @param[in] NamespaceId - The specified namespace identifier.
+ @param[in] Buffer - The Buffer used to store the identify namespace Data.
+
+ @return EFI_SUCCESS - Successfully get the identify namespace Data.
+ @return others - Fail to get the identify namespace Data.
+
+**/
+STATIC
+EFI_STATUS
+NvmeIdentifyNamespace (
+ IN NVME_CONTEXT *Nvme,
+ IN UINT32 NamespaceId,
+ IN VOID *Buffer
+ )
+{
+ NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;
+ NVM_EXPRESS_COMMAND Command;
+ NVM_EXPRESS_RESPONSE Response;
+ EFI_STATUS Status;
+
+ ZeroMem (&CommandPacket, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
+ ZeroMem (&Command, sizeof(NVM_EXPRESS_COMMAND));
+ ZeroMem (&Response, sizeof(NVM_EXPRESS_RESPONSE));
+
+ CommandPacket.NvmeCmd = &Command;
+ CommandPacket.NvmeResponse = &Response;
+
+ Command.Cdw0.Opcode = NVME_ADMIN_IDENTIFY_OPC;
+ Command.Cdw0.Cid = Nvme->Cid[NVME_ADMIN_QUEUE]++;
+ Command.Nsid = NamespaceId;
+ CommandPacket.TransferBuffer = (UINT64)(UINTN)Buffer;
+ CommandPacket.TransferLength = sizeof (NVME_ADMIN_NAMESPACE_DATA);
+ CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;
+ CommandPacket.QueueId = NVME_ADMIN_QUEUE;
+ //
+ // Set bit 0 (Cns bit) to 1 to identify a namespace
+ //
+ CommandPacket.NvmeCmd->Cdw10 = 0;
+ CommandPacket.NvmeCmd->Flags = CDW10_VALID;
+
+ Status = NvmePassThru (
+ Nvme,
+ NamespaceId,
+ 0,
+ &CommandPacket
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = NvmeWaitAllComplete (Nvme, CommandPacket.QueueId);
+ }
+
+ return Status;
+}
+
+/**
+ Get Block Size for specific namespace of NVME.
+
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
+
+ @return - Block Size in bytes
+
+**/
+STATIC
+UINT32
+NvmeGetBlockSize (
+ IN NVME_CONTEXT *Nvme
+ )
+{
+ UINT32 BlockSize;
+ UINT32 Lbads;
+ UINT32 Flbas;
+ UINT32 LbaFmtIdx;
+
+ Flbas = Nvme->NamespaceData->Flbas;
+ LbaFmtIdx = Flbas & 3;
+ Lbads = Nvme->NamespaceData->LbaFormat[LbaFmtIdx].Lbads;
+
+ BlockSize = (UINT32)1 << Lbads;
+ return BlockSize;
+}
+
+/**
+ Get last LBA for specific namespace of NVME.
+
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
+
+ @return - Last LBA address
+
+**/
+STATIC
+EFI_LBA
+NvmeGetLastLba (
+ IN NVME_CONTEXT *Nvme
+ )
+{
+ EFI_LBA LastBlock;
+ LastBlock = Nvme->NamespaceData->Nsze - 1;
+ return LastBlock;
+}
+
+/**
+ Create io completion queue.
+
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
+
+ @return EFI_SUCCESS - Successfully create io completion queue.
+ @return others - Fail to create io completion queue.
+
+**/
+STATIC
+EFI_STATUS
+NvmeCreateIoCompletionQueue (
+ IN NVME_CONTEXT *Nvme
+ )
+{
+ NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;
+ NVM_EXPRESS_COMMAND Command;
+ NVM_EXPRESS_RESPONSE Response;
+ EFI_STATUS Status;
+ NVME_ADMIN_CRIOCQ CrIoCq;
+
+ ZeroMem (&CommandPacket, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
+ ZeroMem (&Command, sizeof(NVM_EXPRESS_COMMAND));
+ ZeroMem (&Response, sizeof(NVM_EXPRESS_RESPONSE));
+ ZeroMem (&CrIoCq, sizeof(NVME_ADMIN_CRIOCQ));
+
+ CommandPacket.NvmeCmd = &Command;
+ CommandPacket.NvmeResponse = &Response;
+
+ Command.Cdw0.Opcode = NVME_ADMIN_CRIOCQ_OPC;
+ Command.Cdw0.Cid = Nvme->Cid[NVME_ADMIN_QUEUE]++;
+ CommandPacket.TransferBuffer = (UINT64)(UINTN)Nvme->CqBuffer[NVME_IO_QUEUE];
+ CommandPacket.TransferLength = EFI_PAGE_SIZE;
+ CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;
+ CommandPacket.QueueId = NVME_ADMIN_QUEUE;
+
+ CrIoCq.Qid = NVME_IO_QUEUE;
+ CrIoCq.Qsize = NVME_CCQ_SIZE;
+ CrIoCq.Pc = 1;
+ CopyMem (&CommandPacket.NvmeCmd->Cdw10, &CrIoCq, sizeof (NVME_ADMIN_CRIOCQ));
+ CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID;
+
+ Status = NvmePassThru (
+ Nvme,
+ NVME_CONTROLLER_ID,
+ 0,
+ &CommandPacket
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = NvmeWaitAllComplete (Nvme, CommandPacket.QueueId);
+ }
+
+ return Status;
+}
+
+/**
+ Create io submission queue.
+
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
+
+ @return EFI_SUCCESS - Successfully create io submission queue.
+ @return others - Fail to create io submission queue.
+
+**/
+STATIC
+EFI_STATUS
+NvmeCreateIoSubmissionQueue (
+ IN NVME_CONTEXT *Nvme
+ )
+{
+ NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;
+ NVM_EXPRESS_COMMAND Command;
+ NVM_EXPRESS_RESPONSE Response;
+ EFI_STATUS Status;
+ NVME_ADMIN_CRIOSQ CrIoSq;
+
+ ZeroMem (&CommandPacket, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
+ ZeroMem (&Command, sizeof(NVM_EXPRESS_COMMAND));
+ ZeroMem (&Response, sizeof(NVM_EXPRESS_RESPONSE));
+ ZeroMem (&CrIoSq, sizeof(NVME_ADMIN_CRIOSQ));
+
+ CommandPacket.NvmeCmd = &Command;
+ CommandPacket.NvmeResponse = &Response;
+
+ Command.Cdw0.Opcode = NVME_ADMIN_CRIOSQ_OPC;
+ Command.Cdw0.Cid = Nvme->Cid[NVME_ADMIN_QUEUE]++;
+ CommandPacket.TransferBuffer = (UINT64)(UINTN)Nvme->SqBuffer[NVME_IO_QUEUE];
+ CommandPacket.TransferLength = EFI_PAGE_SIZE;
+ CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;
+ CommandPacket.QueueId = NVME_ADMIN_QUEUE;
+
+ CrIoSq.Qid = NVME_IO_QUEUE;
+ CrIoSq.Qsize = NVME_CSQ_SIZE;
+ CrIoSq.Pc = 1;
+ CrIoSq.Cqid = NVME_IO_QUEUE;
+ CrIoSq.Qprio = 0;
+ CopyMem (&CommandPacket.NvmeCmd->Cdw10, &CrIoSq, sizeof (NVME_ADMIN_CRIOSQ));
+ CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID;
+
+ Status = NvmePassThru (
+ Nvme,
+ NVME_CONTROLLER_ID,
+ 0,
+ &CommandPacket
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = NvmeWaitAllComplete (Nvme, CommandPacket.QueueId);
+ }
+
+ return Status;
+}
+
+/**
+ Security send and receive commands.
+
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
+ @param[in] SendCommand - The flag to indicate the command type, TRUE for Send command and FALSE for receive command
+ @param[in] SecurityProtocol - Security Protocol
+ @param[in] SpSpecific - Security Protocol Specific
+ @param[in] TransferLength - Transfer Length of Buffer (in bytes) - always a multiple of 512
+ @param[in,out] TransferBuffer - Address of Data to transfer
+
+ @return EFI_SUCCESS - Successfully create io submission queue.
+ @return others - Fail to send/receive commands.
+
+**/
+EFI_STATUS
+NvmeSecuritySendReceive (
+ IN NVME_CONTEXT *Nvme,
+ IN BOOLEAN SendCommand,
+ IN UINT8 SecurityProtocol,
+ IN UINT16 SpSpecific,
+ IN UINTN TransferLength,
+ IN OUT VOID *TransferBuffer
+ )
+{
+ NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;
+ NVM_EXPRESS_COMMAND Command;
+ NVM_EXPRESS_RESPONSE Response;
+ EFI_STATUS Status;
+ NVME_ADMIN_SECSEND SecSend;
+ OACS *Oacs;
+ UINT8 Opcode;
+ VOID* *SecBuff;
+
+ Oacs = (OACS *)&Nvme->ControllerData->Oacs;
+
+ //
+ // Verify security bit for Security Send/Receive commands
+ //
+ if (Oacs->Security == 0) {
+ DEBUG ((DEBUG_ERROR, "Security command doesn't support.\n"));
+ return EFI_NOT_READY;
+ }
+
+ SecBuff = (VOID *)(UINTN) NVME_SEC_BASE (Nvme);
+
+ //
+ // Actions for sending security command
+ //
+ if (SendCommand) {
+ CopyMem (SecBuff, TransferBuffer, TransferLength);
+ }
+
+ ZeroMem (&CommandPacket, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
+ ZeroMem (&Command, sizeof(NVM_EXPRESS_COMMAND));
+ ZeroMem (&Response, sizeof(NVM_EXPRESS_RESPONSE));
+ ZeroMem (&SecSend, sizeof(NVME_ADMIN_SECSEND));
+
+ CommandPacket.NvmeCmd = &Command;
+ CommandPacket.NvmeResponse = &Response;
+
+ Opcode = (UINT8)(SendCommand ? NVME_ADMIN_SECURITY_SEND_OPC : NVME_ADMIN_SECURITY_RECV_OPC);
+ Command.Cdw0.Opcode = Opcode;
+ Command.Cdw0.Cid = Nvme->Cid[NVME_ADMIN_QUEUE]++;
+ CommandPacket.TransferBuffer = (UINT64)(UINTN)SecBuff;
+ CommandPacket.TransferLength = (UINT32)TransferLength;
+ CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;
+ CommandPacket.QueueId = NVME_ADMIN_QUEUE;
+
+ SecSend.Spsp = SpSpecific;
+ SecSend.Secp = SecurityProtocol;
+ SecSend.Tl = (UINT32)TransferLength;
+
+ CopyMem (&CommandPacket.NvmeCmd->Cdw10, &SecSend, sizeof (NVME_ADMIN_SECSEND));
+ CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID;
+
+ Status = NvmePassThru (
+ Nvme,
+ NVME_CONTROLLER_ID,
+ 0,
+ &CommandPacket
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = NvmeWaitAllComplete (Nvme, CommandPacket.QueueId);
+ }
+
+ //
+ // Actions for receiving security command
+ //
+ if (!SendCommand) {
+ CopyMem (TransferBuffer, SecBuff, TransferLength);
+ }
+
+ return Status;
+}
+
+/**
+ Destroy io completion queue.
+
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
+
+ @return EFI_SUCCESS - Successfully destroy io completion queue.
+ @return others - Fail to destroy io completion queue.
+
+**/
+STATIC
+EFI_STATUS
+NvmeDestroyIoCompletionQueue (
+ IN NVME_CONTEXT *Nvme
+ )
+{
+ NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;
+ NVM_EXPRESS_COMMAND Command;
+ NVM_EXPRESS_RESPONSE Response;
+ EFI_STATUS Status;
+ NVME_ADMIN_DEIOCQ DelIoCq;
+
+ ZeroMem (&CommandPacket, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
+ ZeroMem (&Command, sizeof(NVM_EXPRESS_COMMAND));
+ ZeroMem (&Response, sizeof(NVM_EXPRESS_RESPONSE));
+ ZeroMem (&DelIoCq, sizeof(NVME_ADMIN_DEIOCQ));
+
+ CommandPacket.NvmeCmd = &Command;
+ CommandPacket.NvmeResponse = &Response;
+
+ Command.Cdw0.Opcode = NVME_ADMIN_DELIOCQ_OPC;
+ Command.Cdw0.Cid = Nvme->Cid[NVME_ADMIN_QUEUE]++;
+ CommandPacket.TransferBuffer = (UINT64)(UINTN)Nvme->CqBuffer[NVME_IO_QUEUE];
+ CommandPacket.TransferLength = EFI_PAGE_SIZE;
+ CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;
+ CommandPacket.QueueId = NVME_ADMIN_QUEUE;
+
+ DelIoCq.Qid = NVME_IO_QUEUE;
+ CopyMem (&CommandPacket.NvmeCmd->Cdw10, &DelIoCq, sizeof (NVME_ADMIN_DEIOCQ));
+ CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID;
+
+ Status = NvmePassThru (
+ Nvme,
+ NVME_CONTROLLER_ID,
+ 0,
+ &CommandPacket
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = NvmeWaitAllComplete (Nvme, CommandPacket.QueueId);
+ }
+
+ return Status;
+}
+
+/**
+ Destroy io submission queue.
+
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
+
+ @return EFI_SUCCESS - Successfully destroy io submission queue.
+ @return others - Fail to destroy io submission queue.
+
+**/
+STATIC
+EFI_STATUS
+NvmeDestroyIoSubmissionQueue (
+ IN NVME_CONTEXT *Nvme
+ )
+{
+ NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;
+ NVM_EXPRESS_COMMAND Command;
+ NVM_EXPRESS_RESPONSE Response;
+ EFI_STATUS Status;
+ NVME_ADMIN_DEIOSQ DelIoSq;
+
+ ZeroMem (&CommandPacket, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
+ ZeroMem (&Command, sizeof(NVM_EXPRESS_COMMAND));
+ ZeroMem (&Response, sizeof(NVM_EXPRESS_RESPONSE));
+ ZeroMem (&DelIoSq, sizeof(NVME_ADMIN_DEIOSQ));
+
+ CommandPacket.NvmeCmd = &Command;
+ CommandPacket.NvmeResponse = &Response;
+
+ Command.Cdw0.Opcode = NVME_ADMIN_DELIOSQ_OPC;
+ Command.Cdw0.Cid = Nvme->Cid[NVME_ADMIN_QUEUE]++;
+ CommandPacket.TransferBuffer = (UINT64)(UINTN)Nvme->SqBuffer[NVME_IO_QUEUE];
+ CommandPacket.TransferLength = EFI_PAGE_SIZE;
+ CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;
+ CommandPacket.QueueId = NVME_ADMIN_QUEUE;
+
+ DelIoSq.Qid = NVME_IO_QUEUE;
+ CopyMem (&CommandPacket.NvmeCmd->Cdw10, &DelIoSq, sizeof (NVME_ADMIN_DEIOSQ));
+ CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID;
+
+ Status = NvmePassThru (
+ Nvme,
+ NVME_CONTROLLER_ID,
+ 0,
+ &CommandPacket
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = NvmeWaitAllComplete (Nvme, CommandPacket.QueueId);
+ }
+
+ return Status;
+}
+
+/**
+ Allocate transfer-related Data struct which is used at Nvme.
+
+ @param[in] ImageHandle Image handle for this driver image
+ @param[in] Nvme The pointer to the NVME_CONTEXT Data structure.
+
+ @retval EFI_OUT_OF_RESOURCE The allocation is failure.
+ @retval EFI_SUCCESS Successful to allocate memory.
+
+**/
+EFI_STATUS
+EFIAPI
+NvmeAllocateResource (
+ IN EFI_HANDLE ImageHandle,
+ IN NVME_CONTEXT *Nvme
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS Addr;
+ UINT32 Size;
+
+ //
+ // Allocate resources required by NVMe host controller.
+ //
+ // NBAR
+ Size = 0x10000;
+ Addr = 0xFFFFFFFF;
+ Status = gDS->AllocateMemorySpace (
+ EfiGcdAllocateMaxAddressSearchBottomUp,
+ EfiGcdMemoryTypeMemoryMappedIo,
+ 15, // 2^15: 32K Alignment
+ Size,
+ &Addr,
+ ImageHandle,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Nvme->Nbar = (UINT32) Addr;
+
+ // DMA Buffer
+ Size = NVME_MEM_MAX_SIZE;
+ Addr = 0xFFFFFFFF;
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiACPIMemoryNVS,
+ EFI_SIZE_TO_PAGES (Size),
+ (EFI_PHYSICAL_ADDRESS *)&Addr
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Nvme->BaseMem = (UINT32) Addr;
+
+ // Clean up DMA Buffer before using
+ ZeroMem ((VOID *)(UINTN)Addr, NVME_MEM_MAX_SIZE);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Free allocated transfer-related Data struct which is used at NVMe.
+
+ @param[in] Nvme The pointer to the NVME_CONTEXT Data structure.
+
+**/
+VOID
+EFIAPI
+NvmeFreeResource (
+ IN NVME_CONTEXT *Nvme
+ )
+{
+ UINT32 Size;
+
+ // NBAR
+ if (Nvme->BaseMem != 0) {
+ Size = 0x10000;
+ gDS->FreeMemorySpace (Nvme->Nbar, Size);
+ }
+
+ // DMA Buffer
+ if (Nvme->Nbar != 0) {
+ Size = NVME_MEM_MAX_SIZE;
+ gBS->FreePages ((EFI_PHYSICAL_ADDRESS)(UINTN) Nvme->Nbar, EFI_SIZE_TO_PAGES (Size));
+ }
+}
+
+
+/**
+ Initialize the Nvm Express controller.
+
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
+
+ @retval EFI_SUCCESS - The NVM Express Controller is initialized successfully.
+ @retval Others - A device error occurred while initializing the controller.
+
+**/
+EFI_STATUS
+NvmeControllerInit (
+ IN NVME_CONTEXT *Nvme
+ )
+{
+ EFI_STATUS Status;
+ NVME_AQA Aqa;
+ NVME_ASQ Asq;
+ NVME_ACQ Acq;
+ NVME_VER Ver;
+
+ UINT32 MlBAR;
+ UINT32 MuBAR;
+
+ ///
+ /// Update PCIE BAR0/1 for NVME device
+ ///
+ MlBAR = Nvme->Nbar;
+ MuBAR = 0;
+ PciWrite32 (Nvme->PciBase + 0x10, MlBAR); // MLBAR (BAR0)
+ PciWrite32 (Nvme->PciBase + 0x14, MuBAR); // MUBAR (BAR1)
+
+ ///
+ /// Enable PCIE decode
+ ///
+ PciWrite8 (Nvme->PciBase + NVME_PCIE_PCICMD, 0x6);
+
+ // Version
+ NVME_GET_VER (Nvme, &Ver);
+ if (!(Ver.Mjr == 0x0001) && (Ver.Mnr == 0x0000)) {
+ DEBUG ((DEBUG_INFO, "\n!!!\n!!! NVME Version mismatch for the implementation !!!\n!!!\n"));
+ }
+
+ ///
+ /// Read the Controller Capabilities register and verify that the NVM command set is supported
+ ///
+ Status = NVME_GET_CAP (Nvme, &Nvme->Cap);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "NVME_GET_CAP fail, Status: %r\n", Status));
+ goto Done;
+ }
+
+ if (Nvme->Cap.Css != 0x01) {
+ DEBUG ((DEBUG_ERROR, "NvmeControllerInit fail: the controller doesn't support NVMe command set\n"));
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+
+ ///
+ /// Currently the driver only supports 4k page Size.
+ ///
+ if ((Nvme->Cap.Mpsmin + 12) > EFI_PAGE_SHIFT) {
+ DEBUG ((DEBUG_ERROR, "NvmeControllerInit fail: only supports 4k page Size\n"));
+ ASSERT (FALSE);
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+
+ Nvme->Cid[0] = 0;
+ Nvme->Cid[1] = 0;
+
+ Nvme->Pt[0] = 0;
+ Nvme->Pt[1] = 0;
+
+ ZeroMem ((VOID *)(UINTN)(&(Nvme->SqTdbl[0])), sizeof (NVME_SQTDBL) * NVME_MAX_IO_QUEUES);
+ ZeroMem ((VOID *)(UINTN)(&(Nvme->CqHdbl[0])), sizeof (NVME_CQHDBL) * NVME_MAX_IO_QUEUES);
+
+ ZeroMem ((VOID *)(UINTN)Nvme->BaseMem, NVME_MEM_MAX_SIZE);
+
+ Status = NvmeDisableController (Nvme);
+ if (EFI_ERROR(Status)) {
+ DEBUG ((DEBUG_ERROR, "NvmeDisableController fail, Status: %r\n", Status));
+ goto Done;
+ }
+
+ ///
+ /// set number of entries admin submission & completion queues.
+ ///
+ Aqa.Asqs = NVME_ASQ_SIZE;
+ Aqa.Rsvd1 = 0;
+ Aqa.Acqs = NVME_ACQ_SIZE;
+ Aqa.Rsvd2 = 0;
+
+ ///
+ /// Address of admin submission queue.
+ ///
+ Asq = (UINT64)(UINTN)(NVME_ASQ_BASE (Nvme) & ~0xFFF);
+
+ ///
+ /// Address of admin completion queue.
+ ///
+ Acq = (UINT64)(UINTN)(NVME_ACQ_BASE (Nvme) & ~0xFFF);
+
+ ///
+ /// Address of I/O submission & completion queue.
+ ///
+ Nvme->SqBuffer[0] = (NVME_SQ *)(UINTN)NVME_ASQ_BASE (Nvme); // NVME_ADMIN_QUEUE
+ Nvme->CqBuffer[0] = (NVME_CQ *)(UINTN)NVME_ACQ_BASE (Nvme); // NVME_ADMIN_QUEUE
+ Nvme->SqBuffer[1] = (NVME_SQ *)(UINTN)NVME_SQ_BASE (Nvme, 0); // NVME_IO_QUEUE
+ Nvme->CqBuffer[1] = (NVME_CQ *)(UINTN)NVME_CQ_BASE (Nvme, 0); // NVME_IO_QUEUE
+
+ DEBUG ((DEBUG_INFO, "BaseMem = [%08X]\n", Nvme->BaseMem));
+ DEBUG ((DEBUG_INFO, "Admin Submission Queue Size (Aqa.Asqs) = [%08X]\n", Aqa.Asqs));
+ DEBUG ((DEBUG_INFO, "Admin Completion Queue Size (Aqa.Acqs) = [%08X]\n", Aqa.Acqs));
+ DEBUG ((DEBUG_INFO, "Admin Submission Queue (SqBuffer[0]) = [%08X]\n", Nvme->SqBuffer[0]));
+ DEBUG ((DEBUG_INFO, "Admin Completion Queue (CqBuffer[0]) = [%08X]\n", Nvme->CqBuffer[0]));
+ DEBUG ((DEBUG_INFO, "I/O Submission Queue (SqBuffer[1]) = [%08X]\n", Nvme->SqBuffer[1]));
+ DEBUG ((DEBUG_INFO, "I/O Completion Queue (CqBuffer[1]) = [%08X]\n", Nvme->CqBuffer[1]));
+
+ ///
+ /// Program admin queue attributes.
+ ///
+ Status = NVME_SET_AQA (Nvme, &Aqa);
+ if (EFI_ERROR(Status)) {
+ goto Done;
+ }
+
+ ///
+ /// Program admin submission queue address.
+ ///
+ Status = NVME_SET_ASQ (Nvme, &Asq);
+ if (EFI_ERROR(Status)) {
+ goto Done;
+ }
+
+ ///
+ /// Program admin completion queue address.
+ ///
+ Status = NVME_SET_ACQ (Nvme, &Acq);
+ if (EFI_ERROR(Status)) {
+ goto Done;
+ }
+
+ Status = NvmeEnableController (Nvme);
+ if (EFI_ERROR(Status)) {
+ goto Done;
+ }
+
+ ///
+ /// Create one I/O completion queue.
+ ///
+ Status = NvmeCreateIoCompletionQueue (Nvme);
+ if (EFI_ERROR(Status)) {
+ goto Done;
+ }
+
+ ///
+ /// Create one I/O Submission queue.
+ ///
+ Status = NvmeCreateIoSubmissionQueue (Nvme);
+ if (EFI_ERROR(Status)) {
+ goto Done;
+ }
+
+ ///
+ /// Get current Identify Controller Data
+ ///
+ Nvme->ControllerData = (NVME_ADMIN_CONTROLLER_DATA *)(UINTN) NVME_CONTROL_DATA_BASE (Nvme);
+ Status = NvmeIdentifyController (Nvme, Nvme->ControllerData);
+ if (EFI_ERROR(Status)) {
+ goto Done;
+ }
+
+ ///
+ /// Dump NvmExpress Identify Controller Data
+ ///
+ Nvme->ControllerData->Sn[19] = 0;
+ Nvme->ControllerData->Mn[39] = 0;
+ //NvmeDumpIdentifyController (Nvme->ControllerData);
+
+ ///
+ /// Get current Identify Namespace Data
+ ///
+ Nvme->NamespaceData = (NVME_ADMIN_NAMESPACE_DATA *)NVME_NAMESPACE_DATA_BASE (Nvme);
+ Status = NvmeIdentifyNamespace (Nvme, Nvme->Nsid, Nvme->NamespaceData);
+ if (EFI_ERROR(Status)) {
+ DEBUG ((DEBUG_ERROR, "NvmeIdentifyNamespace fail, Status = %r\n", Status));
+ goto Done;
+ }
+
+ ///
+ /// Dump NvmExpress Identify Namespace Data
+ ///
+ if (Nvme->NamespaceData->Ncap == 0) {
+ DEBUG ((DEBUG_ERROR, "Invalid Namespace, Ncap: %lx\n", Nvme->NamespaceData->Ncap));
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+ Nvme->BlockSize = NvmeGetBlockSize (Nvme);
+ Nvme->LastBlock = NvmeGetLastLba (Nvme);
+
+ Nvme->State = NvmeStatusInit;
+
+ return EFI_SUCCESS;
+
+Done:
+ return Status;
+}
+
+/**
+ Un-initialize the Nvm Express controller.
+
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
+
+ @retval EFI_SUCCESS - The NVM Express Controller is un-initialized successfully.
+ @retval Others - A device error occurred while un-initializing the controller.
+
+**/
+EFI_STATUS
+NvmeControllerExit (
+ IN NVME_CONTEXT *Nvme
+ )
+{
+ EFI_STATUS Status;
+
+ Status = EFI_SUCCESS;
+ if (Nvme->State == NvmeStatusInit || Nvme->State == NvmeStatusMax) {
+ ///
+ /// Destroy I/O Submission queue.
+ ///
+ Status = NvmeDestroyIoSubmissionQueue (Nvme);
+ if (EFI_ERROR(Status)) {
+ DEBUG ((DEBUG_ERROR, "NvmeDestroyIoSubmissionQueue fail, Status = %r\n", Status));
+ return Status;
+ }
+
+ ///
+ /// Destroy I/O completion queue.
+ ///
+ Status = NvmeDestroyIoCompletionQueue (Nvme);
+ if (EFI_ERROR(Status)) {
+ DEBUG ((DEBUG_ERROR, "NvmeDestroyIoCompletionQueue fail, Status = %r\n", Status));
+ return Status;
+ }
+
+ Status = NvmeShutdownController (Nvme);
+ if (EFI_ERROR(Status)) {
+ DEBUG ((DEBUG_ERROR, "NvmeShutdownController fail, Status: %r\n", Status));
+ }
+ }
+
+ ///
+ /// Disable PCIE decode
+ ///
+ PciWrite8 (Nvme->PciBase + NVME_PCIE_PCICMD, 0x0);
+ PciWrite32 (Nvme->PciBase + 0x10, 0); // MLBAR (BAR0)
+ PciWrite32 (Nvme->PciBase + 0x14, 0); // MUBAR (BAR1)
+
+ Nvme->State = NvmeStatusUnknown;
+ return Status;
+}
+
+/**
+ Read sector Data from the NVMe device.
+
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
+ @param[in,out] Buffer - The Buffer used to store the Data read from the device.
+ @param[in] Lba - The start block number.
+ @param[in] Blocks - Total block number to be read.
+
+ @retval EFI_SUCCESS - Datum are read from the device.
+ @retval Others - Fail to read all the datum.
+
+**/
+EFI_STATUS
+NvmeReadSectors (
+ IN NVME_CONTEXT *Nvme,
+ IN OUT UINT64 Buffer,
+ IN UINT64 Lba,
+ IN UINT32 Blocks
+ )
+{
+ UINT32 Bytes;
+ NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;
+ NVM_EXPRESS_COMMAND Command;
+ NVM_EXPRESS_RESPONSE Response;
+ EFI_STATUS Status;
+ UINT32 BlockSize;
+
+ BlockSize = Nvme->BlockSize;
+ Bytes = Blocks * BlockSize;
+
+ ZeroMem (&CommandPacket, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
+ ZeroMem (&Command, sizeof(NVM_EXPRESS_COMMAND));
+ ZeroMem (&Response, sizeof(NVM_EXPRESS_RESPONSE));
+
+ CommandPacket.NvmeCmd = &Command;
+ CommandPacket.NvmeResponse = &Response;
+
+ CommandPacket.NvmeCmd->Cdw0.Opcode = NVME_IO_READ_OPC;
+ CommandPacket.NvmeCmd->Cdw0.Cid = Nvme->Cid[NVME_IO_QUEUE]++;
+ CommandPacket.NvmeCmd->Nsid = Nvme->Nsid;
+ CommandPacket.TransferBuffer = Buffer;
+
+ CommandPacket.TransferLength = Bytes;
+ CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;
+ CommandPacket.QueueId = NVME_IO_QUEUE;
+
+ CommandPacket.NvmeCmd->Cdw10 = (UINT32)Lba;
+ CommandPacket.NvmeCmd->Cdw11 = (UINT32)(RShiftU64 (Lba, 32));
+ CommandPacket.NvmeCmd->Cdw12 = (Blocks - 1) & 0xFFFF;
+
+ CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID | CDW12_VALID;
+
+ Status = NvmePassThru (
+ Nvme,
+ Nvme->Nsid,
+ 0,
+ &CommandPacket
+ );
+
+ return Status;
+}
+
+/**
+ Write sector Data to the NVMe device.
+
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
+ @param[in] Buffer - The Buffer to be written into the device.
+ @param[in] Lba - The start block number.
+ @param[in] Blocks - Total block number to be written.
+
+ @retval EFI_SUCCESS - Datum are written into the Buffer.
+ @retval Others - Fail to write all the datum.
+
+**/
+EFI_STATUS
+NvmeWriteSectors (
+ IN NVME_CONTEXT *Nvme,
+ IN UINT64 Buffer,
+ IN UINT64 Lba,
+ IN UINT32 Blocks
+ )
+{
+ NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;
+ NVM_EXPRESS_COMMAND Command;
+ NVM_EXPRESS_RESPONSE Response;
+ EFI_STATUS Status;
+ UINT32 Bytes;
+ UINT32 BlockSize;
+
+ BlockSize = Nvme->BlockSize;
+ Bytes = Blocks * BlockSize;
+
+ ZeroMem (&CommandPacket, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
+ ZeroMem (&Command, sizeof(NVM_EXPRESS_COMMAND));
+ ZeroMem (&Response, sizeof(NVM_EXPRESS_RESPONSE));
+
+ CommandPacket.NvmeCmd = &Command;
+ CommandPacket.NvmeResponse = &Response;
+
+ CommandPacket.NvmeCmd->Cdw0.Opcode = NVME_IO_WRITE_OPC;
+ CommandPacket.NvmeCmd->Cdw0.Cid = Nvme->Cid[NVME_IO_QUEUE]++;
+ CommandPacket.NvmeCmd->Nsid = Nvme->Nsid;
+ CommandPacket.TransferBuffer = Buffer;
+
+ CommandPacket.TransferLength = Bytes;
+ CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;
+ CommandPacket.QueueId = NVME_IO_QUEUE;
+
+ CommandPacket.NvmeCmd->Cdw10 = (UINT32)Lba;
+ CommandPacket.NvmeCmd->Cdw11 = (UINT32)(RShiftU64 (Lba, 32));
+ CommandPacket.NvmeCmd->Cdw12 = (Blocks - 1) & 0xFFFF;
+
+ CommandPacket.MetadataBuffer = (UINT64)(UINTN)NULL;
+ CommandPacket.MetadataLength = 0;
+
+ CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID | CDW12_VALID;
+
+ Status = NvmePassThru (
+ Nvme,
+ Nvme->Nsid,
+ 0,
+ &CommandPacket
+ );
+
+ return Status;
+}
+
+/**
+ Flushes all modified Data to the device.
+
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
+
+ @retval EFI_SUCCESS - Datum are written into the Buffer.
+ @retval Others - Fail to write all the datum.
+
+**/
+EFI_STATUS
+NvmeFlush (
+ IN NVME_CONTEXT *Nvme
+ )
+{
+ NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket;
+ NVM_EXPRESS_COMMAND Command;
+ NVM_EXPRESS_RESPONSE Response;
+ EFI_STATUS Status;
+
+ ZeroMem (&CommandPacket, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET));
+ ZeroMem (&Command, sizeof(NVM_EXPRESS_COMMAND));
+ ZeroMem (&Response, sizeof(NVM_EXPRESS_RESPONSE));
+
+ CommandPacket.NvmeCmd = &Command;
+ CommandPacket.NvmeResponse = &Response;
+
+ CommandPacket.NvmeCmd->Cdw0.Opcode = NVME_IO_FLUSH_OPC;
+ CommandPacket.NvmeCmd->Cdw0.Cid = Nvme->Cid[NVME_IO_QUEUE]++;
+ CommandPacket.NvmeCmd->Nsid = Nvme->Nsid;
+ CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT;
+ CommandPacket.QueueId = NVME_IO_QUEUE;
+
+ Status = NvmePassThru (
+ Nvme,
+ Nvme->Nsid,
+ 0,
+ &CommandPacket
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = NvmeWaitAllComplete (Nvme, CommandPacket.QueueId);
+ }
+
+ return Status;
+}
+
+/**
+ Read some blocks from the device.
+
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
+ @param[out] Buffer - The Buffer used to store the Data read from the device.
+ @param[in] Lba - The start block number.
+ @param[in] Blocks - Total block number to be read.
+
+ @retval EFI_SUCCESS - Datum are read from the device.
+ @retval Others - Fail to read all the datum.
+
+**/
+EFI_STATUS
+NvmeRead (
+ IN NVME_CONTEXT *Nvme,
+ OUT UINT64 Buffer,
+ IN UINT64 Lba,
+ IN UINTN Blocks
+ )
+{
+ EFI_STATUS Status;
+ UINT32 BlockSize;
+ UINT32 MaxTransferBlocks;
+
+ ASSERT (Blocks <= NVME_MAX_SECTORS);
+ Status = EFI_SUCCESS;
+ BlockSize = Nvme->BlockSize;
+ if (Nvme->ControllerData->Mdts != 0) {
+ MaxTransferBlocks = (1 << (Nvme->ControllerData->Mdts)) * (1 << (Nvme->Cap.Mpsmin + 12)) / BlockSize;
+ } else {
+ MaxTransferBlocks = 1024;
+ }
+
+ while (Blocks > 0) {
+ if (Blocks > MaxTransferBlocks) {
+ Status = NvmeReadSectors (Nvme, Buffer, Lba, MaxTransferBlocks);
+
+ Blocks -= MaxTransferBlocks;
+ Buffer += (MaxTransferBlocks * BlockSize);
+ Lba += MaxTransferBlocks;
+ } else {
+ Status = NvmeReadSectors (Nvme, Buffer, Lba, (UINT32) Blocks);
+ Blocks = 0;
+ }
+
+ if (EFI_ERROR(Status)) {
+ DEBUG ((DEBUG_ERROR, "NvmeRead fail, Status = %r\n", Status));
+ break;
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Write some blocks to the device.
+
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
+ @param[in] Buffer - The Buffer to be written into the device.
+ @param[in] Lba - The start block number.
+ @param[in] Blocks - Total block number to be written.
+
+ @retval EFI_SUCCESS - Datum are written into the Buffer.
+ @retval Others - Fail to write all the datum.
+
+**/
+EFI_STATUS
+NvmeWrite (
+ IN NVME_CONTEXT *Nvme,
+ IN UINT64 Buffer,
+ IN UINT64 Lba,
+ IN UINTN Blocks
+ )
+{
+ EFI_STATUS Status;
+ UINT32 BlockSize;
+ UINT32 MaxTransferBlocks;
+
+ ASSERT (Blocks <= NVME_MAX_SECTORS);
+ Status = EFI_SUCCESS;
+ BlockSize = Nvme->BlockSize;
+
+ if (Nvme->ControllerData->Mdts != 0) {
+ MaxTransferBlocks = (1 << (Nvme->ControllerData->Mdts)) * (1 << (Nvme->Cap.Mpsmin + 12)) / BlockSize;
+ } else {
+ MaxTransferBlocks = 1024;
+ }
+
+ while (Blocks > 0) {
+ if (Blocks > MaxTransferBlocks) {
+ Status = NvmeWriteSectors (Nvme, Buffer, Lba, MaxTransferBlocks);
+
+ Blocks -= MaxTransferBlocks;
+ Buffer += (MaxTransferBlocks * BlockSize);
+ Lba += MaxTransferBlocks;
+ } else {
+ Status = NvmeWriteSectors (Nvme, Buffer, Lba, (UINT32) Blocks);
+ Blocks = 0;
+ }
+
+ if (EFI_ERROR(Status)) {
+ DEBUG ((DEBUG_ERROR, "NvmeWrite fail, Status = %r\n", Status));
+ break;
+ }
+ }
+
+ return Status;
+}
diff --git a/Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalNvmeMode.h b/Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalNvmeMode.h
new file mode 100644
index 0000000000..bfa4f10413
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalNvmeMode.h
@@ -0,0 +1,456 @@
+/** @file
+ Header file for NVMe function definitions
+
+Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __OPAL_PASSWORD_NVME_MODE_H__
+#define __OPAL_PASSWORD_NVME_MODE_H__
+
+
+#include "OpalNvmeReg.h"
+
+#define NVME_MAX_SECTORS 0x10000
+//
+// QueueId
+//
+#define NVME_ADMIN_QUEUE 0x00
+#define NVME_IO_QUEUE 0x01
+
+typedef struct {
+ UINT8 Opcode;
+ UINT8 FusedOperation;
+ #define NORMAL_CMD 0x00
+ #define FUSED_FIRST_CMD 0x01
+ #define FUSED_SECOND_CMD 0x02
+ UINT16 Cid;
+} NVME_CDW0;
+
+typedef struct {
+ NVME_CDW0 Cdw0;
+ UINT8 Flags;
+ #define CDW10_VALID 0x01
+ #define CDW11_VALID 0x02
+ #define CDW12_VALID 0x04
+ #define CDW13_VALID 0x08
+ #define CDW14_VALID 0x10
+ #define CDW15_VALID 0x20
+ UINT32 Nsid;
+ UINT32 Cdw10;
+ UINT32 Cdw11;
+ UINT32 Cdw12;
+ UINT32 Cdw13;
+ UINT32 Cdw14;
+ UINT32 Cdw15;
+} NVM_EXPRESS_COMMAND;
+
+typedef struct {
+ UINT32 Cdw0;
+ UINT32 Cdw1;
+ UINT32 Cdw2;
+ UINT32 Cdw3;
+} NVM_EXPRESS_RESPONSE;
+
+typedef struct {
+ UINT64 CommandTimeout;
+ UINT64 TransferBuffer;
+ UINT32 TransferLength;
+ UINT64 MetadataBuffer;
+ UINT32 MetadataLength;
+ UINT8 QueueId;
+ NVM_EXPRESS_COMMAND *NvmeCmd;
+ NVM_EXPRESS_RESPONSE *NvmeResponse;
+} NVM_EXPRESS_PASS_THRU_COMMAND_PACKET;
+
+
+#pragma pack(1)
+
+// Internal fields
+typedef enum {
+ NvmeStatusUnknown,
+ NvmeStatusInit,
+ NvmeStatusInuse,
+ NvmeStatusMax,
+} NVME_STATUS;
+
+typedef struct {
+ UINT32 Nbar;
+ UINT32 BaseMem;
+ BOOLEAN PollCancellation;
+ UINT16 NvmeInitWaitTime;
+
+ NVME_STATUS State;
+ UINT8 BusID;
+ UINT8 DeviceID;
+ UINT8 FuncID;
+ UINTN PciBase;
+
+ UINT32 Nsid;
+ UINT64 Nsuuid;
+ UINT32 BlockSize;
+ EFI_LBA LastBlock;
+
+ //
+ // Pointers to 4kB aligned submission & completion queues.
+ //
+ NVME_SQ *SqBuffer[NVME_MAX_IO_QUEUES];
+ NVME_CQ *CqBuffer[NVME_MAX_IO_QUEUES];
+ UINT16 Cid[NVME_MAX_IO_QUEUES];
+
+ //
+ // Submission and completion queue indices.
+ //
+ NVME_SQTDBL SqTdbl[NVME_MAX_IO_QUEUES];
+ NVME_CQHDBL CqHdbl[NVME_MAX_IO_QUEUES];
+ UINT8 Pt[NVME_MAX_IO_QUEUES];
+
+ UINTN SqeCount[NVME_MAX_IO_QUEUES];
+
+ //
+ // Nvme controller capabilities
+ //
+ NVME_CAP Cap;
+
+ //
+ // pointer to identify controller Data
+ //
+ NVME_ADMIN_CONTROLLER_DATA *ControllerData;
+ NVME_ADMIN_NAMESPACE_DATA *NamespaceData;
+} NVME_CONTEXT;
+
+#pragma pack()
+
+/**
+ Transfer MMIO Data to memory.
+
+ @param[in,out] MemBuffer - Destination: Memory address
+ @param[in] MmioAddr - Source: MMIO address
+ @param[in] Size - Size for read
+
+ @retval EFI_SUCCESS - MMIO read sucessfully
+**/
+EFI_STATUS
+NvmeMmioRead (
+ IN OUT VOID *MemBuffer,
+ IN UINTN MmioAddr,
+ IN UINTN Size
+ );
+
+/**
+ Transfer memory Data to MMIO.
+
+ @param[in,out] MmioAddr - Destination: MMIO address
+ @param[in] MemBuffer - Source: Memory address
+ @param[in] Size - Size for write
+
+ @retval EFI_SUCCESS - MMIO write sucessfully
+**/
+EFI_STATUS
+NvmeMmioWrite (
+ IN OUT UINTN MmioAddr,
+ IN VOID *MemBuffer,
+ IN UINTN Size
+ );
+
+/**
+ Transfer memory data to MMIO.
+
+ @param[in,out] MmioAddr - Destination: MMIO address
+ @param[in] MemBuffer - Source: Memory address
+ @param[in] Size - Size for write
+
+ @retval EFI_SUCCESS - MMIO write sucessfully
+**/
+EFI_STATUS
+OpalPciWrite (
+ IN OUT UINTN MmioAddr,
+ IN VOID *MemBuffer,
+ IN UINTN Size
+ );
+
+/**
+ Transfer MMIO data to memory.
+
+ @param[in,out] MemBuffer - Destination: Memory address
+ @param[in] MmioAddr - Source: MMIO address
+ @param[in] Size - Size for read
+
+ @retval EFI_SUCCESS - MMIO read sucessfully
+**/
+EFI_STATUS
+OpalPciRead (
+ IN OUT VOID *MemBuffer,
+ IN UINTN MmioAddr,
+ IN UINTN Size
+ );
+
+/**
+ Allocate transfer-related Data struct which is used at Nvme.
+
+ @param[in] ImageHandle Image handle for this driver image
+ @param[in] Nvme The pointer to the NVME_CONTEXT Data structure.
+
+ @retval EFI_OUT_OF_RESOURCE The allocation is failure.
+ @retval EFI_SUCCESS Successful to allocate memory.
+
+**/
+EFI_STATUS
+EFIAPI
+NvmeAllocateResource (
+ IN EFI_HANDLE ImageHandle,
+ IN NVME_CONTEXT *Nvme
+ );
+
+/**
+ Free allocated transfer-related Data struct which is used at NVMe.
+
+ @param[in] Nvme The pointer to the NVME_CONTEXT Data structure.
+
+**/
+VOID
+EFIAPI
+NvmeFreeResource (
+ IN NVME_CONTEXT *Nvme
+ );
+
+/**
+ Sends an NVM Express Command Packet to an NVM Express controller or namespace. This function supports
+ both blocking I/O and nonblocking I/O. The blocking I/O functionality is required, and the nonblocking
+ I/O functionality is optional.
+
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
+ @param[in] NamespaceId - Is a 32 bit Namespace ID to which the Express HCI command packet will be sent.
+ A Value of 0 denotes the NVM Express controller, a Value of all 0FFh in the namespace
+ ID specifies that the command packet should be sent to all valid namespaces.
+ @param[in] NamespaceUuid - Is a 64 bit Namespace UUID to which the Express HCI command packet will be sent.
+ A Value of 0 denotes the NVM Express controller, a Value of all 0FFh in the namespace
+ UUID specifies that the command packet should be sent to all valid namespaces.
+ @param[in,out] Packet - A pointer to the NVM Express HCI Command Packet to send to the NVMe namespace specified
+ by NamespaceId.
+
+ @retval EFI_SUCCESS - The NVM Express Command Packet was sent by the host. TransferLength bytes were transferred
+ to, or from DataBuffer.
+ @retval EFI_NOT_READY - The NVM Express Command Packet could not be sent because the controller is not ready. The caller
+ may retry again later.
+ @retval EFI_DEVICE_ERROR - A device error occurred while attempting to send the NVM Express Command Packet.
+ @retval EFI_INVALID_PARAMETER - Namespace, or the contents of NVM_EXPRESS_PASS_THRU_COMMAND_PACKET are invalid. The NVM
+ Express Command Packet was not sent, so no additional status information is available.
+ @retval EFI_UNSUPPORTED - The command described by the NVM Express Command Packet is not supported by the host adapter.
+ The NVM Express Command Packet was not sent, so no additional status information is available.
+ @retval EFI_TIMEOUT - A timeout occurred while waiting for the NVM Express Command Packet to execute.
+
+**/
+EFI_STATUS
+NvmePassThru (
+ IN NVME_CONTEXT *Nvme,
+ IN UINT32 NamespaceId,
+ IN UINT64 NamespaceUuid,
+ IN OUT NVM_EXPRESS_PASS_THRU_COMMAND_PACKET *Packet
+ );
+
+/**
+ Waits until all NVME commands completed.
+
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
+ @param[in] Qid - Queue index
+
+ @retval EFI_SUCCESS - All NVME commands have completed
+ @retval EFI_TIMEOUT - Timeout occured
+ @retval EFI_NOT_READY - Not all NVME commands have completed
+ @retval others - Error occurred on device side.
+**/
+EFI_STATUS
+NvmeWaitAllComplete (
+ IN NVME_CONTEXT *Nvme,
+ IN UINT8 Qid
+ );
+
+/**
+ Initialize the Nvm Express controller.
+
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
+
+ @retval EFI_SUCCESS - The NVM Express Controller is initialized successfully.
+ @retval Others - A device error occurred while initializing the controller.
+
+**/
+EFI_STATUS
+NvmeControllerInit (
+ IN NVME_CONTEXT *Nvme
+ );
+
+/**
+ Un-initialize the Nvm Express controller.
+
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
+
+ @retval EFI_SUCCESS - The NVM Express Controller is un-initialized successfully.
+ @retval Others - A device error occurred while un-initializing the controller.
+
+**/
+EFI_STATUS
+NvmeControllerExit (
+ IN NVME_CONTEXT *Nvme
+ );
+
+/**
+ Check whether there are available command slots.
+
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
+ @param[in] Qid - Queue index
+
+ @retval EFI_SUCCESS - Available command slot is found
+ @retval EFI_NOT_READY - No available command slot is found
+ @retval EFI_DEVICE_ERROR - Error occurred on device side.
+
+**/
+EFI_STATUS
+NvmeHasFreeCmdSlot (
+ IN NVME_CONTEXT *Nvme,
+ IN UINT8 Qid
+ );
+
+/**
+ Check whether all command slots are clean.
+
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
+ @param[in] Qid - Queue index
+
+ @retval EFI_SUCCESS - All command slots are clean
+ @retval EFI_NOT_READY - Not all command slots are clean
+ @retval EFI_DEVICE_ERROR - Error occurred on device side.
+
+**/
+EFI_STATUS
+NvmeIsAllCmdSlotClean (
+ IN NVME_CONTEXT *Nvme,
+ IN UINT8 Qid
+ );
+
+/**
+ Read sector Data from the NVMe device.
+
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
+ @param[in,out] Buffer - The Buffer used to store the Data read from the device.
+ @param[in] Lba - The start block number.
+ @param[in] Blocks - Total block number to be read.
+
+ @retval EFI_SUCCESS - Datum are read from the device.
+ @retval Others - Fail to read all the datum.
+
+**/
+EFI_STATUS
+NvmeReadSectors (
+ IN NVME_CONTEXT *Nvme,
+ IN OUT UINT64 Buffer,
+ IN UINT64 Lba,
+ IN UINT32 Blocks
+ );
+
+/**
+ Write sector Data to the NVMe device.
+
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
+ @param[in] Buffer - The Buffer to be written into the device.
+ @param[in] Lba - The start block number.
+ @param[in] Blocks - Total block number to be written.
+
+ @retval EFI_SUCCESS - Datum are written into the Buffer.
+ @retval Others - Fail to write all the datum.
+
+**/
+EFI_STATUS
+NvmeWriteSectors (
+ IN NVME_CONTEXT *Nvme,
+ IN UINT64 Buffer,
+ IN UINT64 Lba,
+ IN UINT32 Blocks
+ );
+
+/**
+ Flushes all modified Data to the device.
+
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
+
+ @retval EFI_SUCCESS - Datum are written into the Buffer.
+ @retval Others - Fail to write all the datum.
+
+**/
+EFI_STATUS
+NvmeFlush (
+ IN NVME_CONTEXT *Nvme
+ );
+
+/**
+ Read some blocks from the device.
+
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
+ @param[out] Buffer - The Buffer used to store the Data read from the device.
+ @param[in] Lba - The start block number.
+ @param[in] Blocks - Total block number to be read.
+
+ @retval EFI_SUCCESS - Datum are read from the device.
+ @retval Others - Fail to read all the datum.
+
+**/
+EFI_STATUS
+NvmeRead (
+ IN NVME_CONTEXT *Nvme,
+ OUT UINT64 Buffer,
+ IN UINT64 Lba,
+ IN UINTN Blocks
+ );
+
+/**
+ Write some blocks to the device.
+
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
+ @param[in] Buffer - The Buffer to be written into the device.
+ @param[in] Lba - The start block number.
+ @param[in] Blocks - Total block number to be written.
+
+ @retval EFI_SUCCESS - Datum are written into the Buffer.
+ @retval Others - Fail to write all the datum.
+
+**/
+EFI_STATUS
+NvmeWrite (
+ IN NVME_CONTEXT *Nvme,
+ IN UINT64 Buffer,
+ IN UINT64 Lba,
+ IN UINTN Blocks
+ );
+
+/**
+ Security send and receive commands.
+
+ @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure.
+ @param[in] SendCommand - The flag to indicate the command type, TRUE for Send command and FALSE for receive command
+ @param[in] SecurityProtocol - Security Protocol
+ @param[in] SpSpecific - Security Protocol Specific
+ @param[in] TransferLength - Transfer Length of Buffer (in bytes) - always a multiple of 512
+ @param[in,out] TransferBuffer - Address of Data to transfer
+
+ @return EFI_SUCCESS - Successfully create io submission queue.
+ @return others - Fail to send/receive commands.
+
+**/
+EFI_STATUS
+NvmeSecuritySendReceive (
+ IN NVME_CONTEXT *Nvme,
+ IN BOOLEAN SendCommand,
+ IN UINT8 SecurityProtocol,
+ IN UINT16 SpSpecific,
+ IN UINTN TransferLength,
+ IN OUT VOID *TransferBuffer
+ );
+
+#endif
diff --git a/Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalNvmeReg.h b/Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalNvmeReg.h
new file mode 100644
index 0000000000..b5460cd42e
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalNvmeReg.h
@@ -0,0 +1,814 @@
+/** @file
+ Header file for Registers and Structure definitions
+
+Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+#ifndef __OPAL_PASSWORD_NVME_REG_H__
+#define __OPAL_PASSWORD_NVME_REG_H__
+
+//
+// PCI Header for PCIe root port configuration
+//
+#define NVME_PCIE_PCICMD 0x04
+#define NVME_PCIE_BNUM 0x18
+#define NVME_PCIE_SEC_BNUM 0x19
+#define NVME_PCIE_IOBL 0x1C
+#define NVME_PCIE_MBL 0x20
+#define NVME_PCIE_PMBL 0x24
+#define NVME_PCIE_PMBU32 0x28
+#define NVME_PCIE_PMLU32 0x2C
+#define NVME_PCIE_INTR 0x3C
+
+//
+// NVMe related definitions
+//
+#define PCI_CLASS_MASS_STORAGE_NVM 0x08 // mass storage sub-class non-volatile memory.
+#define PCI_IF_NVMHCI 0x02 // mass storage programming interface NVMHCI.
+
+#define NVME_ASQ_SIZE 1 // Number of admin submission queue entries, which is 0-based
+#define NVME_ACQ_SIZE 1 // Number of admin completion queue entries, which is 0-based
+
+#define NVME_CSQ_SIZE 63 // Number of I/O submission queue entries, which is 0-based
+#define NVME_CCQ_SIZE 63 // Number of I/O completion queue entries, which is 0-based
+
+#define NVME_MAX_IO_QUEUES 2 // Number of I/O queues supported by the driver, 1 for AQ, 1 for CQ
+
+#define NVME_CSQ_DEPTH (NVME_CSQ_SIZE+1)
+#define NVME_CCQ_DEPTH (NVME_CCQ_SIZE+1)
+#define NVME_PRP_SIZE (4) // Pages of PRP list
+
+#define NVME_CONTROLLER_ID 0
+
+//
+// Time out Value for Nvme transaction execution
+//
+#define NVME_GENERIC_TIMEOUT 5000000 ///< us
+#define NVME_CMD_WAIT 100 ///< us
+#define NVME_CMD_TIMEOUT 20000000 ///< us
+
+
+
+#define NVME_MEM_MAX_SIZE \
+ (( \
+ 1 /* Controller Data */ + \
+ 1 /* Identify Data */ + \
+ 1 /* ASQ */ + \
+ 1 /* ACQ */ + \
+ 1 /* SQs */ + \
+ 1 /* CQs */ + \
+ NVME_PRP_SIZE * NVME_CSQ_DEPTH /* PRPs */ \
+ ) * EFI_PAGE_SIZE)
+
+
+//
+// controller register offsets
+//
+#define NVME_CAP_OFFSET 0x0000 // Controller Capabilities
+#define NVME_VER_OFFSET 0x0008 // Version
+#define NVME_INTMS_OFFSET 0x000c // Interrupt Mask Set
+#define NVME_INTMC_OFFSET 0x0010 // Interrupt Mask Clear
+#define NVME_CC_OFFSET 0x0014 // Controller Configuration
+#define NVME_CSTS_OFFSET 0x001c // Controller Status
+#define NVME_AQA_OFFSET 0x0024 // Admin Queue Attributes
+#define NVME_ASQ_OFFSET 0x0028 // Admin Submission Queue Base Address
+#define NVME_ACQ_OFFSET 0x0030 // Admin Completion Queue Base Address
+#define NVME_SQ0_OFFSET 0x1000 // Submission Queue 0 (admin) Tail Doorbell
+#define NVME_CQ0_OFFSET 0x1004 // Completion Queue 0 (admin) Head Doorbell
+
+//
+// These register offsets are defined as 0x1000 + (N * (4 << CAP.DSTRD))
+// Get the doorbell stride bit shift Value from the controller capabilities.
+//
+#define NVME_SQTDBL_OFFSET(QID, DSTRD) 0x1000 + ((2 * (QID)) * (4 << (DSTRD))) // Submission Queue y (NVM) Tail Doorbell
+#define NVME_CQHDBL_OFFSET(QID, DSTRD) 0x1000 + (((2 * (QID)) + 1) * (4 << (DSTRD))) // Completion Queue y (NVM) Head Doorbell
+
+
+#pragma pack(1)
+
+//
+// 3.1.1 Offset 00h: CAP - Controller Capabilities
+//
+typedef struct {
+ UINT16 Mqes; // Maximum Queue Entries Supported
+ UINT8 Cqr:1; // Contiguous Queues Required
+ UINT8 Ams:2; // Arbitration Mechanism Supported
+ UINT8 Rsvd1:5;
+ UINT8 To; // Timeout
+ UINT16 Dstrd:4;
+ UINT16 Rsvd2:1;
+ UINT16 Css:4; // Command Sets Supported
+ UINT16 Rsvd3:7;
+ UINT8 Mpsmin:4;
+ UINT8 Mpsmax:4;
+ UINT8 Rsvd4;
+} NVME_CAP;
+
+//
+// 3.1.2 Offset 08h: VS - Version
+//
+typedef struct {
+ UINT16 Mnr; // Minor version number
+ UINT16 Mjr; // Major version number
+} NVME_VER;
+
+//
+// 3.1.5 Offset 14h: CC - Controller Configuration
+//
+typedef struct {
+ UINT16 En:1; // Enable
+ UINT16 Rsvd1:3;
+ UINT16 Css:3; // Command Set Selected
+ UINT16 Mps:4; // Memory Page Size
+ UINT16 Ams:3; // Arbitration Mechanism Selected
+ UINT16 Shn:2; // Shutdown Notification
+ UINT8 Iosqes:4; // I/O Submission Queue Entry Size
+ UINT8 Iocqes:4; // I/O Completion Queue Entry Size
+ UINT8 Rsvd2;
+} NVME_CC;
+
+//
+// 3.1.6 Offset 1Ch: CSTS - Controller Status
+//
+typedef struct {
+ UINT32 Rdy:1; // Ready
+ UINT32 Cfs:1; // Controller Fatal Status
+ UINT32 Shst:2; // Shutdown Status
+ UINT32 Nssro:1; // NVM Subsystem Reset Occurred
+ UINT32 Rsvd1:27;
+} NVME_CSTS;
+
+//
+// 3.1.8 Offset 24h: AQA - Admin Queue Attributes
+//
+typedef struct {
+ UINT16 Asqs:12; // Submission Queue Size
+ UINT16 Rsvd1:4;
+ UINT16 Acqs:12; // Completion Queue Size
+ UINT16 Rsvd2:4;
+} NVME_AQA;
+
+//
+// 3.1.9 Offset 28h: ASQ - Admin Submission Queue Base Address
+//
+#define NVME_ASQ UINT64
+
+//
+// 3.1.10 Offset 30h: ACQ - Admin Completion Queue Base Address
+//
+#define NVME_ACQ UINT64
+
+//
+// 3.1.11 Offset (1000h + ((2y) * (4 << CAP.DSTRD))): SQyTDBL - Submission Queue y Tail Doorbell
+//
+typedef struct {
+ UINT16 Sqt;
+ UINT16 Rsvd1;
+} NVME_SQTDBL;
+
+//
+// 3.1.12 Offset (1000h + ((2y + 1) * (4 << CAP.DSTRD))): CQyHDBL - Completion Queue y Head Doorbell
+//
+typedef struct {
+ UINT16 Cqh;
+ UINT16 Rsvd1;
+} NVME_CQHDBL;
+
+//
+// NVM command set structures
+//
+// Read Command
+//
+typedef struct {
+ //
+ // CDW 10, 11
+ //
+ UINT64 Slba; /* Starting Sector Address */
+ //
+ // CDW 12
+ //
+ UINT16 Nlb; /* Number of Sectors */
+ UINT16 Rsvd1:10;
+ UINT16 Prinfo:4; /* Protection Info Check */
+ UINT16 Fua:1; /* Force Unit Access */
+ UINT16 Lr:1; /* Limited Retry */
+ //
+ // CDW 13
+ //
+ UINT32 Af:4; /* Access Frequency */
+ UINT32 Al:2; /* Access Latency */
+ UINT32 Sr:1; /* Sequential Request */
+ UINT32 In:1; /* Incompressible */
+ UINT32 Rsvd2:24;
+ //
+ // CDW 14
+ //
+ UINT32 Eilbrt; /* Expected Initial Logical Block Reference Tag */
+ //
+ // CDW 15
+ //
+ UINT16 Elbat; /* Expected Logical Block Application Tag */
+ UINT16 Elbatm; /* Expected Logical Block Application Tag Mask */
+} NVME_READ;
+
+//
+// Write Command
+//
+typedef struct {
+ //
+ // CDW 10, 11
+ //
+ UINT64 Slba; /* Starting Sector Address */
+ //
+ // CDW 12
+ //
+ UINT16 Nlb; /* Number of Sectors */
+ UINT16 Rsvd1:10;
+ UINT16 Prinfo:4; /* Protection Info Check */
+ UINT16 Fua:1; /* Force Unit Access */
+ UINT16 Lr:1; /* Limited Retry */
+ //
+ // CDW 13
+ //
+ UINT32 Af:4; /* Access Frequency */
+ UINT32 Al:2; /* Access Latency */
+ UINT32 Sr:1; /* Sequential Request */
+ UINT32 In:1; /* Incompressible */
+ UINT32 Rsvd2:24;
+ //
+ // CDW 14
+ //
+ UINT32 Ilbrt; /* Initial Logical Block Reference Tag */
+ //
+ // CDW 15
+ //
+ UINT16 Lbat; /* Logical Block Application Tag */
+ UINT16 Lbatm; /* Logical Block Application Tag Mask */
+} NVME_WRITE;
+
+//
+// Flush
+//
+typedef struct {
+ //
+ // CDW 10
+ //
+ UINT32 Flush; /* Flush */
+} NVME_FLUSH;
+
+//
+// Write Uncorrectable command
+//
+typedef struct {
+ //
+ // CDW 10, 11
+ //
+ UINT64 Slba; /* Starting LBA */
+ //
+ // CDW 12
+ //
+ UINT32 Nlb:16; /* Number of Logical Blocks */
+ UINT32 Rsvd1:16;
+} NVME_WRITE_UNCORRECTABLE;
+
+//
+// Write Zeroes command
+//
+typedef struct {
+ //
+ // CDW 10, 11
+ //
+ UINT64 Slba; /* Starting LBA */
+ //
+ // CDW 12
+ //
+ UINT16 Nlb; /* Number of Logical Blocks */
+ UINT16 Rsvd1:10;
+ UINT16 Prinfo:4; /* Protection Info Check */
+ UINT16 Fua:1; /* Force Unit Access */
+ UINT16 Lr:1; /* Limited Retry */
+ //
+ // CDW 13
+ //
+ UINT32 Rsvd2;
+ //
+ // CDW 14
+ //
+ UINT32 Ilbrt; /* Initial Logical Block Reference Tag */
+ //
+ // CDW 15
+ //
+ UINT16 Lbat; /* Logical Block Application Tag */
+ UINT16 Lbatm; /* Logical Block Application Tag Mask */
+} NVME_WRITE_ZEROES;
+
+//
+// Compare command
+//
+typedef struct {
+ //
+ // CDW 10, 11
+ //
+ UINT64 Slba; /* Starting LBA */
+ //
+ // CDW 12
+ //
+ UINT16 Nlb; /* Number of Logical Blocks */
+ UINT16 Rsvd1:10;
+ UINT16 Prinfo:4; /* Protection Info Check */
+ UINT16 Fua:1; /* Force Unit Access */
+ UINT16 Lr:1; /* Limited Retry */
+ //
+ // CDW 13
+ //
+ UINT32 Rsvd2;
+ //
+ // CDW 14
+ //
+ UINT32 Eilbrt; /* Expected Initial Logical Block Reference Tag */
+ //
+ // CDW 15
+ //
+ UINT16 Elbat; /* Expected Logical Block Application Tag */
+ UINT16 Elbatm; /* Expected Logical Block Application Tag Mask */
+} NVME_COMPARE;
+
+typedef union {
+ NVME_READ Read;
+ NVME_WRITE Write;
+ NVME_FLUSH Flush;
+ NVME_WRITE_UNCORRECTABLE WriteUncorrectable;
+ NVME_WRITE_ZEROES WriteZeros;
+ NVME_COMPARE Compare;
+} NVME_CMD;
+
+typedef struct {
+ UINT16 Mp; /* Maximum Power */
+ UINT8 Rsvd1; /* Reserved as of Nvm Express 1.1 Spec */
+ UINT8 Mps:1; /* Max Power Scale */
+ UINT8 Nops:1; /* Non-Operational State */
+ UINT8 Rsvd2:6; /* Reserved as of Nvm Express 1.1 Spec */
+ UINT32 Enlat; /* Entry Latency */
+ UINT32 Exlat; /* Exit Latency */
+ UINT8 Rrt:5; /* Relative Read Throughput */
+ UINT8 Rsvd3:3; /* Reserved as of Nvm Express 1.1 Spec */
+ UINT8 Rrl:5; /* Relative Read Leatency */
+ UINT8 Rsvd4:3; /* Reserved as of Nvm Express 1.1 Spec */
+ UINT8 Rwt:5; /* Relative Write Throughput */
+ UINT8 Rsvd5:3; /* Reserved as of Nvm Express 1.1 Spec */
+ UINT8 Rwl:5; /* Relative Write Leatency */
+ UINT8 Rsvd6:3; /* Reserved as of Nvm Express 1.1 Spec */
+ UINT8 Rsvd7[16]; /* Reserved as of Nvm Express 1.1 Spec */
+} NVME_PSDESCRIPTOR;
+
+//
+// Identify Controller Data
+//
+typedef struct {
+ //
+ // Controller Capabilities and Features 0-255
+ //
+ UINT16 Vid; /* PCI Vendor ID */
+ UINT16 Ssvid; /* PCI sub-system vendor ID */
+ UINT8 Sn[20]; /* Produce serial number */
+
+ UINT8 Mn[40]; /* Proeduct model number */
+ UINT8 Fr[8]; /* Firmware Revision */
+ UINT8 Rab; /* Recommended Arbitration Burst */
+ UINT8 Ieee_oiu[3]; /* Organization Unique Identifier */
+ UINT8 Cmic; /* Multi-interface Capabilities */
+ UINT8 Mdts; /* Maximum Data Transfer Size */
+ UINT8 Cntlid[2]; /* Controller ID */
+ UINT8 Rsvd1[176]; /* Reserved as of Nvm Express 1.1 Spec */
+ //
+ // Admin Command Set Attributes
+ //
+ UINT16 Oacs; /* Optional Admin Command Support */
+ UINT8 Acl; /* Abort Command Limit */
+ UINT8 Aerl; /* Async Event Request Limit */
+ UINT8 Frmw; /* Firmware updates */
+ UINT8 Lpa; /* Log Page Attributes */
+ UINT8 Elpe; /* Error Log Page Entries */
+ UINT8 Npss; /* Number of Power States Support */
+ UINT8 Avscc; /* Admin Vendor Specific Command Configuration */
+ UINT8 Apsta; /* Autonomous Power State Transition Attributes */
+ UINT8 Rsvd2[246]; /* Reserved as of Nvm Express 1.1 Spec */
+ //
+ // NVM Command Set Attributes
+ //
+ UINT8 Sqes; /* Submission Queue Entry Size */
+ UINT8 Cqes; /* Completion Queue Entry Size */
+ UINT16 Rsvd3; /* Reserved as of Nvm Express 1.1 Spec */
+ UINT32 Nn; /* Number of Namespaces */
+ UINT16 Oncs; /* Optional NVM Command Support */
+ UINT16 Fuses; /* Fused Operation Support */
+ UINT8 Fna; /* Format NVM Attributes */
+ UINT8 Vwc; /* Volatile Write Cache */
+ UINT16 Awun; /* Atomic Write Unit Normal */
+ UINT16 Awupf; /* Atomic Write Unit Power Fail */
+ UINT8 Nvscc; /* NVM Vendor Specific Command Configuration */
+ UINT8 Rsvd4; /* Reserved as of Nvm Express 1.1 Spec */
+ UINT16 Acwu; /* Atomic Compare & Write Unit */
+ UINT16 Rsvd5; /* Reserved as of Nvm Express 1.1 Spec */
+ UINT32 Sgls; /* SGL Support */
+ UINT8 Rsvd6[164]; /* Reserved as of Nvm Express 1.1 Spec */
+ //
+ // I/O Command set Attributes
+ //
+ UINT8 Rsvd7[1344]; /* Reserved as of Nvm Express 1.1 Spec */
+ //
+ // Power State Descriptors
+ //
+ NVME_PSDESCRIPTOR PsDescriptor[32];
+
+ UINT8 VendorData[1024]; /* Vendor specific Data */
+} NVME_ADMIN_CONTROLLER_DATA;
+
+typedef struct {
+ UINT16 Security : 1; /* supports security send/receive commands */
+ UINT16 Format : 1; /* supports format nvm command */
+ UINT16 Firmware : 1; /* supports firmware activate/download commands */
+ UINT16 Oacs_rsvd : 13;
+ } OACS; // optional admin command support: NVME_ADMIN_CONTROLLER_DATA.Oacs
+
+typedef struct {
+ UINT16 Ms; /* Metadata Size */
+ UINT8 Lbads; /* LBA Data Size */
+ UINT8 Rp:2; /* Relative Performance */
+ #define LBAF_RP_BEST 00b
+ #define LBAF_RP_BETTER 01b
+ #define LBAF_RP_GOOD 10b
+ #define LBAF_RP_DEGRADED 11b
+ UINT8 Rsvd1:6; /* Reserved as of Nvm Express 1.1 Spec */
+} NVME_LBAFORMAT;
+
+//
+// Identify Namespace Data
+//
+typedef struct {
+ //
+ // NVM Command Set Specific
+ //
+ UINT64 Nsze; /* Namespace Size (total number of blocks in formatted namespace) */
+ UINT64 Ncap; /* Namespace Capacity (max number of logical blocks) */
+ UINT64 Nuse; /* Namespace Utilization */
+ UINT8 Nsfeat; /* Namespace Features */
+ UINT8 Nlbaf; /* Number of LBA Formats */
+ UINT8 Flbas; /* Formatted LBA Size */
+ UINT8 Mc; /* Metadata Capabilities */
+ UINT8 Dpc; /* End-to-end Data Protection capabilities */
+ UINT8 Dps; /* End-to-end Data Protection Type Settings */
+ UINT8 Nmic; /* Namespace Multi-path I/O and Namespace Sharing Capabilities */
+ UINT8 Rescap; /* Reservation Capabilities */
+ UINT8 Rsvd1[88]; /* Reserved as of Nvm Express 1.1 Spec */
+ UINT64 Eui64; /* IEEE Extended Unique Identifier */
+ //
+ // LBA Format
+ //
+ NVME_LBAFORMAT LbaFormat[16];
+
+ UINT8 Rsvd2[192]; /* Reserved as of Nvm Express 1.1 Spec */
+ UINT8 VendorData[3712]; /* Vendor specific Data */
+} NVME_ADMIN_NAMESPACE_DATA;
+
+//
+// NvmExpress Admin Identify Cmd
+//
+typedef struct {
+ //
+ // CDW 10
+ //
+ UINT32 Cns:2;
+ UINT32 Rsvd1:30;
+} NVME_ADMIN_IDENTIFY;
+
+//
+// NvmExpress Admin Create I/O Completion Queue
+//
+typedef struct {
+ //
+ // CDW 10
+ //
+ UINT32 Qid:16; /* Queue Identifier */
+ UINT32 Qsize:16; /* Queue Size */
+
+ //
+ // CDW 11
+ //
+ UINT32 Pc:1; /* Physically Contiguous */
+ UINT32 Ien:1; /* Interrupts Enabled */
+ UINT32 Rsvd1:14; /* reserved as of Nvm Express 1.1 Spec */
+ UINT32 Iv:16; /* Interrupt Vector */
+} NVME_ADMIN_CRIOCQ;
+
+//
+// NvmExpress Admin Create I/O Submission Queue
+//
+typedef struct {
+ //
+ // CDW 10
+ //
+ UINT32 Qid:16; /* Queue Identifier */
+ UINT32 Qsize:16; /* Queue Size */
+
+ //
+ // CDW 11
+ //
+ UINT32 Pc:1; /* Physically Contiguous */
+ UINT32 Qprio:2; /* Queue Priority */
+ UINT32 Rsvd1:13; /* Reserved as of Nvm Express 1.1 Spec */
+ UINT32 Cqid:16; /* Completion Queue ID */
+} NVME_ADMIN_CRIOSQ;
+
+//
+// NvmExpress Admin Delete I/O Completion Queue
+//
+typedef struct {
+ //
+ // CDW 10
+ //
+ UINT16 Qid;
+ UINT16 Rsvd1;
+} NVME_ADMIN_DEIOCQ;
+
+//
+// NvmExpress Admin Delete I/O Submission Queue
+//
+typedef struct {
+ //
+ // CDW 10
+ //
+ UINT16 Qid;
+ UINT16 Rsvd1;
+} NVME_ADMIN_DEIOSQ;
+
+//
+// NvmExpress Admin Security Send
+//
+typedef struct {
+ //
+ // CDW 10
+ //
+ UINT32 Resv:8; /* Reserve */
+ UINT32 Spsp:16; /* SP Specific */
+ UINT32 Secp:8; /* Security Protocol */
+
+ //
+ // CDW 11
+ //
+ UINT32 Tl; /* Transfer Length */
+} NVME_ADMIN_SECSEND;
+
+//
+// NvmExpress Admin Abort Command
+//
+typedef struct {
+ //
+ // CDW 10
+ //
+ UINT32 Sqid:16; /* Submission Queue identifier */
+ UINT32 Cid:16; /* Command Identifier */
+} NVME_ADMIN_ABORT;
+
+//
+// NvmExpress Admin Firmware Activate Command
+//
+typedef struct {
+ //
+ // CDW 10
+ //
+ UINT32 Fs:3; /* Submission Queue identifier */
+ UINT32 Aa:2; /* Command Identifier */
+ UINT32 Rsvd1:27;
+} NVME_ADMIN_FIRMWARE_ACTIVATE;
+
+//
+// NvmExpress Admin Firmware Image Download Command
+//
+typedef struct {
+ //
+ // CDW 10
+ //
+ UINT32 Numd; /* Number of Dwords */
+ //
+ // CDW 11
+ //
+ UINT32 Ofst; /* Offset */
+} NVME_ADMIN_FIRMWARE_IMAGE_DOWNLOAD;
+
+//
+// NvmExpress Admin Get Features Command
+//
+typedef struct {
+ //
+ // CDW 10
+ //
+ UINT32 Fid:8; /* Feature Identifier */
+ UINT32 Sel:3; /* Select */
+ UINT32 Rsvd1:21;
+} NVME_ADMIN_GET_FEATURES;
+
+//
+// NvmExpress Admin Get Log Page Command
+//
+typedef struct {
+ //
+ // CDW 10
+ //
+ UINT32 Lid:8; /* Log Page Identifier */
+ #define LID_ERROR_INFO
+ #define LID_SMART_INFO
+ #define LID_FW_SLOT_INFO
+ UINT32 Rsvd1:8;
+ UINT32 Numd:12; /* Number of Dwords */
+ UINT32 Rsvd2:4; /* Reserved as of Nvm Express 1.1 Spec */
+} NVME_ADMIN_GET_LOG_PAGE;
+
+//
+// NvmExpress Admin Set Features Command
+//
+typedef struct {
+ //
+ // CDW 10
+ //
+ UINT32 Fid:8; /* Feature Identifier */
+ UINT32 Rsvd1:23;
+ UINT32 Sv:1; /* Save */
+} NVME_ADMIN_SET_FEATURES;
+
+//
+// NvmExpress Admin Format NVM Command
+//
+typedef struct {
+ //
+ // CDW 10
+ //
+ UINT32 Lbaf:4; /* LBA Format */
+ UINT32 Ms:1; /* Metadata Settings */
+ UINT32 Pi:3; /* Protection Information */
+ UINT32 Pil:1; /* Protection Information Location */
+ UINT32 Ses:3; /* Secure Erase Settings */
+ UINT32 Rsvd1:20;
+} NVME_ADMIN_FORMAT_NVM;
+
+//
+// NvmExpress Admin Security Receive Command
+//
+typedef struct {
+ //
+ // CDW 10
+ //
+ UINT32 Rsvd1:8;
+ UINT32 Spsp:16; /* SP Specific */
+ UINT32 Secp:8; /* Security Protocol */
+ //
+ // CDW 11
+ //
+ UINT32 Al; /* Allocation Length */
+} NVME_ADMIN_SECURITY_RECEIVE;
+
+//
+// NvmExpress Admin Security Send Command
+//
+typedef struct {
+ //
+ // CDW 10
+ //
+ UINT32 Rsvd1:8;
+ UINT32 Spsp:16; /* SP Specific */
+ UINT32 Secp:8; /* Security Protocol */
+ //
+ // CDW 11
+ //
+ UINT32 Tl; /* Transfer Length */
+} NVME_ADMIN_SECURITY_SEND;
+
+typedef union {
+ NVME_ADMIN_IDENTIFY Identify;
+ NVME_ADMIN_CRIOCQ CrIoCq;
+ NVME_ADMIN_CRIOSQ CrIoSq;
+ NVME_ADMIN_DEIOCQ DeIoCq;
+ NVME_ADMIN_DEIOSQ DeIoSq;
+ NVME_ADMIN_ABORT Abort;
+ NVME_ADMIN_FIRMWARE_ACTIVATE Activate;
+ NVME_ADMIN_FIRMWARE_IMAGE_DOWNLOAD FirmwareImageDownload;
+ NVME_ADMIN_GET_FEATURES GetFeatures;
+ NVME_ADMIN_GET_LOG_PAGE GetLogPage;
+ NVME_ADMIN_SET_FEATURES SetFeatures;
+ NVME_ADMIN_FORMAT_NVM FormatNvm;
+ NVME_ADMIN_SECURITY_RECEIVE SecurityReceive;
+ NVME_ADMIN_SECURITY_SEND SecuritySend;
+} NVME_ADMIN_CMD;
+
+typedef struct {
+ UINT32 Cdw10;
+ UINT32 Cdw11;
+ UINT32 Cdw12;
+ UINT32 Cdw13;
+ UINT32 Cdw14;
+ UINT32 Cdw15;
+} NVME_RAW;
+
+typedef union {
+ NVME_ADMIN_CMD Admin; // Union of Admin commands
+ NVME_CMD Nvm; // Union of Nvm commands
+ NVME_RAW Raw;
+} NVME_PAYLOAD;
+
+//
+// Submission Queue
+//
+typedef struct {
+ //
+ // CDW 0, Common to all comnmands
+ //
+ UINT8 Opc; // Opcode
+ UINT8 Fuse:2; // Fused Operation
+ UINT8 Rsvd1:5;
+ UINT8 Psdt:1; // PRP or SGL for Data Transfer
+ UINT16 Cid; // Command Identifier
+
+ //
+ // CDW 1
+ //
+ UINT32 Nsid; // Namespace Identifier
+
+ //
+ // CDW 2,3
+ //
+ UINT64 Rsvd2;
+
+ //
+ // CDW 4,5
+ //
+ UINT64 Mptr; // Metadata Pointer
+
+ //
+ // CDW 6-9
+ //
+ UINT64 Prp[2]; // First and second PRP entries
+
+ NVME_PAYLOAD Payload;
+
+} NVME_SQ;
+
+//
+// Completion Queue
+//
+typedef struct {
+ //
+ // CDW 0
+ //
+ UINT32 Dword0;
+ //
+ // CDW 1
+ //
+ UINT32 Rsvd1;
+ //
+ // CDW 2
+ //
+ UINT16 Sqhd; // Submission Queue Head Pointer
+ UINT16 Sqid; // Submission Queue Identifier
+ //
+ // CDW 3
+ //
+ UINT16 Cid; // Command Identifier
+ UINT16 Pt:1; // Phase Tag
+ UINT16 Sc:8; // Status Code
+ UINT16 Sct:3; // Status Code Type
+ UINT16 Rsvd2:2;
+ UINT16 Mo:1; // More
+ UINT16 Dnr:1; // Retry
+} NVME_CQ;
+
+//
+// Nvm Express Admin cmd opcodes
+//
+#define NVME_ADMIN_DELIOSQ_OPC 0
+#define NVME_ADMIN_CRIOSQ_OPC 1
+#define NVME_ADMIN_DELIOCQ_OPC 4
+#define NVME_ADMIN_CRIOCQ_OPC 5
+#define NVME_ADMIN_IDENTIFY_OPC 6
+#define NVME_ADMIN_SECURITY_SEND_OPC 0x81
+#define NVME_ADMIN_SECURITY_RECV_OPC 0x82
+
+#define NVME_IO_FLUSH_OPC 0
+#define NVME_IO_WRITE_OPC 1
+#define NVME_IO_READ_OPC 2
+
+//
+// Offset from the beginning of private Data queue Buffer
+//
+#define NVME_ASQ_BUF_OFFSET EFI_PAGE_SIZE
+
+#pragma pack()
+
+#endif
+
diff --git a/Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalPasswordSmm.c b/Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalPasswordSmm.c
new file mode 100644
index 0000000000..2f2a1d9c13
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalPasswordSmm.c
@@ -0,0 +1,1139 @@
+/** @file
+ Opal password smm driver which is used to support Opal security feature at s3 path.
+
+Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "OpalPasswordSmm.h"
+
+#define SMM_SIZE_ALLOC_BYTES (512)
+#define RESPONSE_SIZE (200)
+
+#define PCI_CLASS_MASS_STORAGE_AHCI (0x06)
+
+#define OPAL_PCIE_ROOTPORT_SAVESIZE (0x40)
+#define STORE_INVALID_ROOTPORT_INDEX ((UINT8) -1)
+#define OPAL_DEVICE_TYPE_SATA 0x1
+#define OPAL_DEVICE_TYPE_NVME 0x2
+#define OPAL_DEVICE_TYPE_UNKNOWN 0xFF
+
+//
+// To unlock the Intel SATA controller at S3 Resume, restored the following registers.
+//
+const OPAL_HC_PCI_REGISTER_SAVE mSataHcRegisterSaveTemplate[] = {
+ {0x9, S3BootScriptWidthUint8},
+ {0x10, S3BootScriptWidthUint32},
+ {0x14, S3BootScriptWidthUint32},
+ {0x18, S3BootScriptWidthUint32},
+ {0x1C, S3BootScriptWidthUint32},
+ {0x20, S3BootScriptWidthUint32},
+ {0x24, S3BootScriptWidthUint32},
+ {0x3c, S3BootScriptWidthUint8},
+ {0x3d, S3BootScriptWidthUint8},
+ {0x40, S3BootScriptWidthUint16},
+ {0x42, S3BootScriptWidthUint16},
+ {0x92, S3BootScriptWidthUint16},
+ {0x94, S3BootScriptWidthUint32},
+ {0x9C, S3BootScriptWidthUint32},
+ {0x4, S3BootScriptWidthUint16},
+};
+
+
+UINT8 mSwSmiValue;
+LIST_ENTRY *mOpalDeviceList;
+LIST_ENTRY mSmmDeviceList = INITIALIZE_LIST_HEAD_VARIABLE (mSmmDeviceList);
+
+BOOLEAN mSendBlockSID = FALSE;
+
+// AHCI
+UINT32 mAhciBar = 0;
+EFI_AHCI_REGISTERS mAhciRegisters;
+VOID *mBuffer = NULL; // DMA can not read/write Data to smram, so we pre-allocates Buffer from AcpiNVS.
+//
+// NVME
+NVME_CONTEXT mNvmeContext;
+
+EFI_GCD_MEMORY_SPACE_DESCRIPTOR *mGcdMemSpace = NULL;
+UINTN mNumberOfDescriptors = 0;
+
+/**
+ Add new bridge node or nvme device info to the device list.
+
+ @param[in] BusNum The bus number.
+ @param[in] DevNum The device number.
+ @param[in] FuncNum The function number.
+ @param[in] Dev The device which need to add device node info.
+
+**/
+VOID
+AddPciDeviceNode (
+ UINT32 BusNum,
+ UINT32 DevNum,
+ UINT32 FuncNum,
+ OPAL_SMM_DEVICE *Dev
+ )
+{
+ UINT8 *DevList;
+ PCI_DEVICE *DeviceNode;
+
+ DevList = AllocateZeroPool (sizeof (PCI_DEVICE) + Dev->Length);
+ ASSERT (DevList != NULL);
+
+ if (Dev->Length != 0) {
+ CopyMem (DevList, Dev->PciBridgeNode, Dev->Length);
+ FreePool (Dev->PciBridgeNode);
+ }
+
+ DeviceNode = (PCI_DEVICE *) (DevList + Dev->Length);
+
+ DeviceNode->BusNum = BusNum;
+ DeviceNode->DevNum = DevNum;
+ DeviceNode->FuncNum = FuncNum;
+
+ Dev->Length += sizeof (PCI_DEVICE);
+ Dev->PciBridgeNode = (PCI_DEVICE *)DevList;
+}
+
+/**
+ Extract device info from the input device path.
+
+ @param[in] DevicePath Device path info for the device.
+ @param[in,out] Dev The device which new inputed.
+
+**/
+VOID
+ExtractDeviceInfoFromDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ IN OUT OPAL_SMM_DEVICE *Dev
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *TmpDevPath;
+ EFI_DEVICE_PATH_PROTOCOL *TmpDevPath2;
+ PCI_DEVICE_PATH *PciDevPath;
+ SATA_DEVICE_PATH *SataDevPath;
+ NVME_NAMESPACE_DEVICE_PATH *NvmeDevPath;
+ UINTN BusNum;
+
+ TmpDevPath = DevicePath;
+ Dev->DeviceType = OPAL_DEVICE_TYPE_UNKNOWN;
+
+ while (!IsDevicePathEnd(TmpDevPath)) {
+ if (TmpDevPath->Type == MESSAGING_DEVICE_PATH && TmpDevPath->SubType == MSG_SATA_DP) {
+ //
+ // SATA
+ //
+ SataDevPath = ( SATA_DEVICE_PATH* )TmpDevPath;
+ Dev->SataPort = SataDevPath->HBAPortNumber;
+ Dev->SataPortMultiplierPort = SataDevPath->PortMultiplierPortNumber;
+ Dev->DeviceType = OPAL_DEVICE_TYPE_SATA;
+ break;
+ } else if (TmpDevPath->Type == MESSAGING_DEVICE_PATH && TmpDevPath->SubType == MSG_NVME_NAMESPACE_DP) {
+ //
+ // NVMe
+ //
+ NvmeDevPath = ( NVME_NAMESPACE_DEVICE_PATH* )TmpDevPath;
+ Dev->NvmeNamespaceId = NvmeDevPath->NamespaceId;
+ Dev->DeviceType = OPAL_DEVICE_TYPE_NVME;
+ break;
+ }
+ TmpDevPath = NextDevicePathNode (TmpDevPath);
+ }
+
+ //
+ // Get bridge node info for the nvme device.
+ //
+ BusNum = 0;
+ TmpDevPath = DevicePath;
+ TmpDevPath2 = NextDevicePathNode (DevicePath);
+ while (!IsDevicePathEnd(TmpDevPath2)) {
+ if (TmpDevPath->Type == HARDWARE_DEVICE_PATH && TmpDevPath->SubType == HW_PCI_DP) {
+ PciDevPath = (PCI_DEVICE_PATH *) TmpDevPath;
+ if ((TmpDevPath2->Type == MESSAGING_DEVICE_PATH && TmpDevPath2->SubType == MSG_NVME_NAMESPACE_DP)||
+ (TmpDevPath2->Type == MESSAGING_DEVICE_PATH && TmpDevPath2->SubType == MSG_SATA_DP)) {
+ Dev->BusNum = (UINT32)BusNum;
+ Dev->DevNum = PciDevPath->Device;
+ Dev->FuncNum = PciDevPath->Function;
+ } else {
+ AddPciDeviceNode((UINT32)BusNum, PciDevPath->Device, PciDevPath->Function, Dev);
+ if (TmpDevPath2->Type == HARDWARE_DEVICE_PATH && TmpDevPath2->SubType == HW_PCI_DP) {
+ BusNum = PciRead8 (PCI_LIB_ADDRESS (BusNum, PciDevPath->Device, PciDevPath->Function, NVME_PCIE_SEC_BNUM));
+ }
+ }
+ }
+
+ TmpDevPath = NextDevicePathNode (TmpDevPath);
+ TmpDevPath2 = NextDevicePathNode (TmpDevPath2);
+ }
+}
+
+/**
+
+ The function returns whether or not the device is Opal Locked.
+ TRUE means that the device is partially or fully locked.
+ This will perform a Level 0 Discovery and parse the locking feature descriptor
+
+ @param[in] OpalDev Opal object to determine if locked
+ @param[out] BlockSidSupported Whether device support BlockSid feature.
+
+**/
+BOOLEAN
+IsOpalDeviceLocked(
+ OPAL_SMM_DEVICE *OpalDev,
+ BOOLEAN *BlockSidSupported
+ )
+{
+ OPAL_SESSION Session;
+ OPAL_DISK_SUPPORT_ATTRIBUTE SupportedAttributes;
+ TCG_LOCKING_FEATURE_DESCRIPTOR LockingFeature;
+ UINT16 OpalBaseComId;
+ TCG_RESULT Ret;
+
+ Session.Sscp = &OpalDev->Sscp;
+ Session.MediaId = 0;
+
+ Ret = OpalGetSupportedAttributesInfo (&Session, &SupportedAttributes, &OpalBaseComId);
+ if (Ret != TcgResultSuccess) {
+ return FALSE;
+ }
+
+ OpalDev->OpalBaseComId = OpalBaseComId;
+ Session.OpalBaseComId = OpalBaseComId;
+ *BlockSidSupported = SupportedAttributes.BlockSid == 1 ? TRUE : FALSE;
+
+ Ret = OpalGetLockingInfo(&Session, &LockingFeature);
+ if (Ret != TcgResultSuccess) {
+ return FALSE;
+ }
+
+ return OpalDeviceLocked (&SupportedAttributes, &LockingFeature);
+}
+
+/**
+ Save/Restore RootPort configuration space.
+
+ @param[in] DeviceNode - The device node.
+ @param[in] SaveAction - TRUE: Save, FALSE: Restore
+ @param[in,out] PcieConfBufferList - Configuration space data buffer for save/restore
+
+ @retval - PCIE base address of this RootPort
+**/
+UINTN
+SaveRestoreRootportConfSpace (
+ IN OPAL_SMM_DEVICE *DeviceNode,
+ IN BOOLEAN SaveAction,
+ IN OUT UINT8 **PcieConfBufferList
+ )
+{
+ UINTN RpBase;
+ UINTN Length;
+ PCI_DEVICE *DevNode;
+ UINT8 *StorePcieConfData;
+ UINTN Index;
+
+ Length = 0;
+ Index = 0;
+ RpBase = 0;
+
+ while (Length < DeviceNode->Length) {
+ DevNode = (PCI_DEVICE *)((UINT8*)DeviceNode->PciBridgeNode + Length);
+ RpBase = PCI_LIB_ADDRESS (DevNode->BusNum, DevNode->DevNum, DevNode->FuncNum, 0x0);
+
+ if (PcieConfBufferList != NULL) {
+ if (SaveAction) {
+ StorePcieConfData = (UINT8 *) AllocateZeroPool (OPAL_PCIE_ROOTPORT_SAVESIZE);
+ ASSERT (StorePcieConfData != NULL);
+ OpalPciRead (StorePcieConfData, RpBase, OPAL_PCIE_ROOTPORT_SAVESIZE);
+ PcieConfBufferList[Index] = StorePcieConfData;
+ } else {
+ // Skip PCIe Command & Status registers
+ StorePcieConfData = PcieConfBufferList[Index];
+ OpalPciWrite (RpBase, StorePcieConfData, 4);
+ OpalPciWrite (RpBase + 8, StorePcieConfData + 8, OPAL_PCIE_ROOTPORT_SAVESIZE - 8);
+
+ FreePool (StorePcieConfData);
+ }
+ }
+
+ Length += sizeof (PCI_DEVICE);
+ Index ++;
+ }
+
+ return RpBase;
+}
+
+/**
+ Configure RootPort for downstream PCIe NAND devices.
+
+ @param[in] RpBase - PCIe configuration space address of this RootPort
+ @param[in] BusNumber - Bus number
+ @param[in] MemoryBase - Memory base address
+ @param[in] MemoryLength - Memory size
+
+**/
+VOID
+ConfigureRootPortForPcieNand (
+ IN UINTN RpBase,
+ IN UINTN BusNumber,
+ IN UINT32 MemoryBase,
+ IN UINT32 MemoryLength
+ )
+{
+ UINT32 MemoryLimit;
+
+ DEBUG ((DEBUG_INFO, "ConfigureRootPortForPcieNand, BusNumber: %x, MemoryBase: %x, MemoryLength: %x\n",
+ BusNumber, MemoryBase, MemoryLength));
+
+ if (MemoryLength == 0) {
+ MemoryLimit = MemoryBase;
+ } else {
+ MemoryLimit = MemoryBase + MemoryLength + 0xFFFFF; // 1M
+ }
+
+ ///
+ /// Configue PCIE configuration space for RootPort
+ ///
+ PciWrite8 (RpBase + NVME_PCIE_BNUM + 1, (UINT8) BusNumber); // Secondary Bus Number registers
+ PciWrite8 (RpBase + NVME_PCIE_BNUM + 2, (UINT8) BusNumber); // Subordinate Bus Number registers
+ PciWrite8 (RpBase + NVME_PCIE_IOBL, 0xFF); // I/O Base registers
+ PciWrite8 (RpBase + NVME_PCIE_IOBL + 1, 0x00); // I/O Limit registers
+ PciWrite16 (RpBase + NVME_PCIE_MBL, (UINT16) RShiftU64 ((UINTN)MemoryBase, 16)); // Memory Base register
+ PciWrite16 (RpBase + NVME_PCIE_MBL + 2, (UINT16) RShiftU64 ((UINTN)MemoryLimit, 16)); // Memory Limit register
+ PciWrite16 (RpBase + NVME_PCIE_PMBL, 0xFFFF); // Prefetchable Memory Base registers
+ PciWrite16 (RpBase + NVME_PCIE_PMBL + 2, 0x0000); // Prefetchable Memory Limit registers
+ PciWrite32 (RpBase + NVME_PCIE_PMBU32, 0xFFFFFFFF); // Prefetchable Memory Upper Base registers
+ PciWrite32 (RpBase + NVME_PCIE_PMLU32, 0x00000000); // Prefetchable Memory Upper Limit registers
+}
+
+
+/**
+ Dispatch function for a Software SMI handler.
+
+ @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
+ @param[in] RegisterContext 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 and quiesced. No other handlers
+ should still be called.
+ @retval Others Other execution results.
+**/
+EFI_STATUS
+EFIAPI
+SmmUnlockOpalPassword (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *RegisterContext,
+ IN OUT VOID *CommBuffer,
+ IN OUT UINTN *CommBufferSize
+ )
+{
+ EFI_STATUS Status;
+ OPAL_SMM_DEVICE *OpalDev;
+ LIST_ENTRY *Entry;
+ UINT8 BaseClassCode;
+ UINT8 SubClassCode;
+ UINT8 ProgInt;
+ TCG_RESULT Result;
+ UINT8 SataCmdSt;
+ UINT8 *StorePcieConfDataList[16];
+ UINTN RpBase;
+ UINTN MemoryBase;
+ UINTN MemoryLength;
+ OPAL_SESSION Session;
+ BOOLEAN BlockSidSupport;
+
+ ZeroMem (StorePcieConfDataList, sizeof (StorePcieConfDataList));
+ Status = EFI_DEVICE_ERROR;
+
+ //
+ // try to unlock all locked hdd disks.
+ //
+ for (Entry = mSmmDeviceList.ForwardLink; Entry != &mSmmDeviceList; Entry = Entry->ForwardLink) {
+ OpalDev = BASE_CR(Entry, OPAL_SMM_DEVICE, Link);
+
+ RpBase = 0;
+ SataCmdSt = 0;
+
+ ///
+ /// Configure RootPort for PCIe AHCI/NVME devices.
+ ///
+ if (OpalDev->DeviceType == OPAL_DEVICE_TYPE_NVME) {
+ ///
+ /// Save original RootPort configuration space to heap
+ ///
+ RpBase = SaveRestoreRootportConfSpace (
+ OpalDev,
+ TRUE,
+ StorePcieConfDataList
+ );
+ MemoryBase = mNvmeContext.Nbar;
+ MemoryLength = 0;
+ ConfigureRootPortForPcieNand (RpBase, OpalDev->BusNum, (UINT32) MemoryBase, (UINT32) MemoryLength);
+
+ ///
+ /// Enable PCIE decode for RootPort
+ ///
+ SataCmdSt = PciRead8 (RpBase + NVME_PCIE_PCICMD);
+ PciWrite8 (RpBase + NVME_PCIE_PCICMD, 0x6);
+ } else {
+ SataCmdSt = PciRead8 (PCI_LIB_ADDRESS (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum, NVME_PCIE_PCICMD));
+ PciWrite8 (PCI_LIB_ADDRESS (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum, NVME_PCIE_PCICMD), 0x6);
+ }
+
+ BaseClassCode = PciRead8 (PCI_LIB_ADDRESS (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum, 0x0B));
+ SubClassCode = PciRead8 (PCI_LIB_ADDRESS (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum, 0x0A));
+ ProgInt = PciRead8 (PCI_LIB_ADDRESS (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum, 0x09));
+ if (BaseClassCode != PCI_CLASS_MASS_STORAGE) {
+ Status = EFI_INVALID_PARAMETER;
+ break;
+ }
+
+ Status = EFI_DEVICE_ERROR;
+ if (OpalDev->DeviceType == OPAL_DEVICE_TYPE_SATA) {
+ if ((SubClassCode == PCI_CLASS_MASS_STORAGE_AHCI) || (SubClassCode == PCI_CLASS_MASS_STORAGE_RAID)) {
+ Status = GetAhciBaseAddress (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "GetAhciBaseAddress error, Status: %r\n", Status));
+ goto done;
+ }
+ Status = AhciModeInitialize ((UINT8)OpalDev->SataPort);
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "AhciModeInitialize error, Status: %r\n", Status));
+ goto done;
+ }
+ } else {
+ DEBUG ((DEBUG_ERROR, "SubClassCode not support for SATA device\n"));
+ }
+ } else if (OpalDev->DeviceType == OPAL_DEVICE_TYPE_NVME) {
+ if (SubClassCode == PCI_CLASS_MASS_STORAGE_NVM) {
+ if (ProgInt != PCI_IF_NVMHCI) {
+ DEBUG ((DEBUG_ERROR, "PI not support, skipped\n"));
+ Status = EFI_NOT_FOUND;
+ goto done;
+ }
+
+ mNvmeContext.PciBase = PCI_LIB_ADDRESS (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum, 0x0);
+ mNvmeContext.NvmeInitWaitTime = 0;
+ mNvmeContext.Nsid = OpalDev->NvmeNamespaceId;
+ Status = NvmeControllerInit (&mNvmeContext);
+ } else {
+ DEBUG ((DEBUG_ERROR, "SubClassCode not support for NVME device\n"));
+ }
+ } else {
+ DEBUG ((DEBUG_ERROR, "Invalid Devicetype\n"));
+ goto done;
+ }
+
+ Status = EFI_DEVICE_ERROR;
+ BlockSidSupport = FALSE;
+ if (IsOpalDeviceLocked (OpalDev, &BlockSidSupport)) {
+ ZeroMem(&Session, sizeof(Session));
+ Session.Sscp = &OpalDev->Sscp;
+ Session.MediaId = 0;
+ Session.OpalBaseComId = OpalDev->OpalBaseComId;
+
+ Result = OpalSupportUnlock (&Session, OpalDev->Password, OpalDev->PasswordLength, NULL);
+ if (Result == TcgResultSuccess) {
+ Status = EFI_SUCCESS;
+ }
+ }
+
+ if (mSendBlockSID && BlockSidSupport) {
+ Result = OpalBlockSid (&Session, TRUE);
+ if (Result != TcgResultSuccess) {
+ break;
+ }
+ }
+
+ if (OpalDev->DeviceType == OPAL_DEVICE_TYPE_NVME) {
+ if (SubClassCode == PCI_CLASS_MASS_STORAGE_NVM) {
+ Status = NvmeControllerExit (&mNvmeContext);
+ }
+ }
+
+done:
+ if (OpalDev->DeviceType == OPAL_DEVICE_TYPE_NVME) {
+ ASSERT (RpBase != 0);
+ PciWrite8 (RpBase + NVME_PCIE_PCICMD, 0);
+ RpBase = SaveRestoreRootportConfSpace (
+ OpalDev,
+ FALSE, // restore
+ StorePcieConfDataList
+ );
+ PciWrite8 (RpBase + NVME_PCIE_PCICMD, SataCmdSt);
+ } else {
+ PciWrite8 (PCI_LIB_ADDRESS (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum, NVME_PCIE_PCICMD), SataCmdSt);
+ }
+
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ }
+
+ return Status;
+}
+
+/**
+ The function extracts device information from OpalDeviceList and creat SmmDeviceList used for S3.
+
+ @param[in] OpalDeviceList Opal device list created at POST which contains the information of OPAL_DISK_AND_PASSWORD_INFO
+ @param[in,out] SmmDeviceList Opal Smm device list to be created and used for unlocking devices at S3 resume.
+
+ @retval EFI_SUCCESS Create SmmDeviceList successfully.
+ @retval Others Other execution results.
+**/
+EFI_STATUS
+CreateSmmDeviceList (
+ IN LIST_ENTRY *OpalDeviceList,
+ IN OUT LIST_ENTRY *SmmDeviceList
+ )
+{
+ LIST_ENTRY *Entry;
+ OPAL_DISK_AND_PASSWORD_INFO *PciDev;
+ OPAL_SMM_DEVICE *SmmDev;
+
+ for (Entry = OpalDeviceList->ForwardLink; Entry != OpalDeviceList; Entry = Entry->ForwardLink) {
+ PciDev = BASE_CR (Entry, OPAL_DISK_AND_PASSWORD_INFO, Link);
+
+ SmmDev = AllocateZeroPool (sizeof (OPAL_SMM_DEVICE));
+ if (SmmDev == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ SmmDev->Signature = OPAL_SMM_DEVICE_SIGNATURE;
+
+ ExtractDeviceInfoFromDevicePath(&PciDev->OpalDevicePath, SmmDev);
+
+ SmmDev->PasswordLength = PciDev->PasswordLength;
+ CopyMem(&(SmmDev->Password), PciDev->Password, OPAL_PASSWORD_MAX_LENGTH);
+
+ SmmDev->Sscp.ReceiveData = SecurityReceiveData;
+ SmmDev->Sscp.SendData = SecuritySendData;
+
+ DEBUG ((DEBUG_INFO, "Opal SMM: Insert device node to SmmDeviceList:\n"));
+ DEBUG ((DEBUG_INFO, "DeviceType:%x, Bus:%d, Dev:%d, Fun:%d\n", \
+ SmmDev->DeviceType, SmmDev->BusNum, SmmDev->DevNum, SmmDev->FuncNum));
+ DEBUG ((DEBUG_INFO, "SataPort:%x, MultiplierPort:%x, NvmeNamespaceId:%x\n", \
+ SmmDev->SataPort, SmmDev->SataPortMultiplierPort, SmmDev->NvmeNamespaceId));
+
+ InsertHeadList (SmmDeviceList, &SmmDev->Link);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Main entry point for an SMM handler dispatch or communicate-based callback.
+
+ @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 and quiesced. No other handlers
+ should still be called.
+ @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has been quiesced but other handlers should
+ still be called.
+ @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other handlers should still
+ be called.
+ @retval EFI_INTERRUPT_PENDING The interrupt could not be quiesced.
+**/
+EFI_STATUS
+EFIAPI
+S3SleepEntryCallBack (
+ IN EFI_HANDLE DispatchHandle,
+ IN CONST VOID *Context OPTIONAL,
+ IN OUT VOID *CommBuffer OPTIONAL,
+ IN OUT UINTN *CommBufferSize OPTIONAL
+ )
+{
+ UINTN Bus;
+ UINTN Device;
+ UINTN Function;
+ UINTN Index;
+ EFI_STATUS Status;
+ LIST_ENTRY *Entry;
+ UINTN Offset;
+ UINT64 Address;
+ S3_BOOT_SCRIPT_LIB_WIDTH Width;
+ UINT32 Data;
+ OPAL_HC_PCI_REGISTER_SAVE *HcRegisterSaveListPtr;
+ UINTN Count;
+ OPAL_SMM_DEVICE *SmmDev;
+
+ Data = 0;
+ Status = EFI_SUCCESS;
+
+ mOpalDeviceList = OpalSupportGetOpalDeviceList();
+ if (IsListEmpty (mOpalDeviceList)) {
+ //
+ // No Opal enabled device. Do nothing.
+ //
+ return EFI_SUCCESS;
+ }
+
+ if (IsListEmpty (&mSmmDeviceList)) {
+ //
+ // mSmmDeviceList for S3 is empty, creat it by mOpalDeviceList.
+ //
+ Status = CreateSmmDeviceList (mOpalDeviceList, &mSmmDeviceList);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // Go through SmmDeviceList to save register data for S3
+ //
+ for (Entry = mSmmDeviceList.ForwardLink; Entry != &mSmmDeviceList; Entry = Entry->ForwardLink) {
+ SmmDev = BASE_CR (Entry, OPAL_SMM_DEVICE, Link);
+
+ if (SmmDev->DeviceType == OPAL_DEVICE_TYPE_NVME) {
+ continue;
+ }
+
+ //
+ // Save register Data for S3. Sata controller only.
+ //
+ Bus = SmmDev->BusNum;
+ Device = SmmDev->DevNum;
+ Function = SmmDev->FuncNum;
+
+ ASSERT (SmmDev->DeviceType == OPAL_DEVICE_TYPE_SATA);
+ HcRegisterSaveListPtr = (OPAL_HC_PCI_REGISTER_SAVE *) mSataHcRegisterSaveTemplate;
+ Count = sizeof (mSataHcRegisterSaveTemplate) / sizeof (OPAL_HC_PCI_REGISTER_SAVE);
+
+ for (Index = 0; Index < Count; Index += 1) {
+ Offset = HcRegisterSaveListPtr[Index].Address;
+ Width = HcRegisterSaveListPtr[Index].Width;
+
+ switch (Width) {
+ case S3BootScriptWidthUint8:
+ Data = (UINT32)PciRead8 (PCI_LIB_ADDRESS(Bus,Device,Function,Offset));
+ break;
+ case S3BootScriptWidthUint16:
+ Data = (UINT32)PciRead16 (PCI_LIB_ADDRESS(Bus,Device,Function,Offset));
+ break;
+ case S3BootScriptWidthUint32:
+ Data = PciRead32 (PCI_LIB_ADDRESS(Bus,Device,Function,Offset));
+ break;
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+
+ Address = S3_BOOT_SCRIPT_LIB_PCI_ADDRESS (Bus, Device, Function, Offset);
+ Status = S3BootScriptSavePciCfgWrite (Width, Address, 1, &Data);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ }
+
+ Status = S3BootScriptSaveIoWrite (S3BootScriptWidthUint8, 0xB2, 1, &mSwSmiValue);
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
+/**
+ OpalPassword Notification for SMM EndOfDxe protocol.
+
+ @param[in] Protocol Points to the protocol's unique identifier.
+ @param[in] Interface Points to the interface instance.
+ @param[in] Handle The handle on which the interface was installed.
+
+ @retval EFI_SUCCESS Notification runs successfully.
+**/
+EFI_STATUS
+EFIAPI
+OpalPasswordEndOfDxeNotification (
+ IN CONST EFI_GUID *Protocol,
+ IN VOID *Interface,
+ IN EFI_HANDLE Handle
+ )
+{
+ UINTN NumberOfDescriptors;
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemSpaceMap;
+ EFI_STATUS Status;
+
+ Status = gDS->GetMemorySpaceMap (&NumberOfDescriptors, &MemSpaceMap);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ mGcdMemSpace = AllocateCopyPool (NumberOfDescriptors * sizeof (EFI_GCD_MEMORY_SPACE_DESCRIPTOR), MemSpaceMap);
+ if (EFI_ERROR (Status)) {
+ gBS->FreePool (MemSpaceMap);
+ return Status;
+ }
+
+ mNumberOfDescriptors = NumberOfDescriptors;
+ gBS->FreePool (MemSpaceMap);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ 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
+OpalPasswordSmmInit (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_SMM_SW_DISPATCH2_PROTOCOL *SwDispatch;
+ EFI_SMM_SX_DISPATCH2_PROTOCOL *SxDispatch;
+ EFI_HANDLE SwHandle;
+ EFI_SMM_SW_REGISTER_CONTEXT Context;
+ EFI_HANDLE S3SleepEntryHandle;
+ EFI_SMM_SX_REGISTER_CONTEXT EntryRegisterContext;
+ EFI_SMM_VARIABLE_PROTOCOL *SmmVariable;
+ OPAL_EXTRA_INFO_VAR OpalExtraInfo;
+ UINTN DataSize;
+ EFI_EVENT EndOfDxeEvent;
+ EFI_PHYSICAL_ADDRESS Address;
+
+ mBuffer = NULL;
+ SwHandle = NULL;
+ S3SleepEntryHandle = NULL;
+ ZeroMem (&mNvmeContext, sizeof (NVME_CONTEXT));
+
+ Status = gSmst->SmmLocateProtocol (
+ &gEfiSmmSwDispatch2ProtocolGuid,
+ NULL,
+ (VOID **)&SwDispatch
+ );
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_ERROR, " SmmLocateProtocol gEfiSmmSwDispatch2ProtocolGuid fail, Status: %r\n", Status));
+ return Status;
+ }
+
+ Status = gSmst->SmmLocateProtocol (
+ &gEfiSmmSxDispatch2ProtocolGuid,
+ NULL,
+ (VOID **)&SxDispatch
+ );
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_ERROR, " SmmLocateProtocol gEfiSmmSxDispatch2ProtocolGuid fail, Status: %r\n", Status));
+ return Status;
+ }
+
+ //
+ // Preallocate a 512 bytes Buffer to perform trusted I/O.
+ // Assume this is big enough for unlock commands
+ // It's because DMA can not access smmram stack at the cmd execution.
+ //
+ Address = 0xFFFFFFFF;
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiACPIMemoryNVS,
+ EFI_SIZE_TO_PAGES (SMM_SIZE_ALLOC_BYTES),
+ &Address
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_ERROR, " AllocatePages for SATA DAM fail, Status: %r\n", Status));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ mBuffer = (VOID *)(UINTN)Address;
+ ZeroMem ((VOID *)(UINTN)mBuffer, SMM_SIZE_ALLOC_BYTES);
+
+ //
+ // Preallocate resource for AHCI transfer descriptor.
+ //
+ Status = AhciAllocateResource ();
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_ERROR, " AhciAllocateResource fail, Status: %r\n", Status));
+ Status = EFI_OUT_OF_RESOURCES;
+ goto EXIT;
+ }
+
+ //
+ // Preallocate resource for NVMe configuration space.
+ //
+ Status = NvmeAllocateResource (ImageHandle, &mNvmeContext);
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_ERROR, " NvmeAllocateResource fail, Status: %r\n", Status));
+ Status = EFI_OUT_OF_RESOURCES;
+ goto EXIT;
+ }
+
+ //
+ // Register a S3 entry callback function to store ATA host controller context to boot script.
+ // These boot scripts would be invoked at S3 path to recovery ATA host controller h/w context
+ // for executing HDD unlock cmd.
+ //
+ EntryRegisterContext.Type = SxS3;
+ EntryRegisterContext.Phase = SxEntry;
+ Status = SxDispatch->Register (
+ SxDispatch,
+ S3SleepEntryCallBack,
+ &EntryRegisterContext,
+ &S3SleepEntryHandle
+ );
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ goto EXIT;
+ }
+
+ //
+ // Register Opal password smm unlock handler
+ //
+ Context.SwSmiInputValue = (UINTN) -1;
+ Status = SwDispatch->Register (
+ SwDispatch,
+ SmmUnlockOpalPassword,
+ &Context,
+ &SwHandle
+ );
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_ERROR, " SwDispatch->Register fail, Status: %r\n", Status));
+ goto EXIT;
+ }
+
+ //
+ // trigger smi to unlock hdd if it's locked.
+ //
+ mSwSmiValue = (UINT8) Context.SwSmiInputValue;
+
+ //
+ // Create event to record GCD descriptors at end of dxe for judging AHCI/NVMe PCI Bar
+ // is in MMIO space to avoid attack.
+ //
+ Status = gSmst->SmmRegisterProtocolNotify (&gEfiSmmEndOfDxeProtocolGuid, OpalPasswordEndOfDxeNotification, &EndOfDxeEvent);
+ if (EFI_ERROR (Status)) {
+ DEBUG((DEBUG_ERROR, "OpalPasswordSmm: Register SmmEndOfDxe fail, Status: %r\n", Status));
+ goto EXIT;
+ }
+ Status = gSmst->SmmLocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID**)&SmmVariable);
+ if (!EFI_ERROR (Status)) {
+ DataSize = sizeof (OPAL_EXTRA_INFO_VAR);
+ Status = SmmVariable->SmmGetVariable (
+ OPAL_EXTRA_INFO_VAR_NAME,
+ &gOpalExtraInfoVariableGuid,
+ NULL,
+ &DataSize,
+ &OpalExtraInfo
+ );
+ if (!EFI_ERROR (Status)) {
+ mSendBlockSID = OpalExtraInfo.EnableBlockSid;
+ }
+ }
+
+ return EFI_SUCCESS;
+
+EXIT:
+ if (S3SleepEntryHandle != NULL) {
+ SxDispatch->UnRegister (SxDispatch, S3SleepEntryHandle);
+ }
+
+ AhciFreeResource ();
+
+ NvmeFreeResource (&mNvmeContext);
+
+ if (mBuffer != NULL) {
+ gBS->FreePages ((EFI_PHYSICAL_ADDRESS)(UINTN) mBuffer, EFI_SIZE_TO_PAGES (SMM_SIZE_ALLOC_BYTES));
+ }
+
+ return Status;
+}
+
+/**
+ Provide Io action support.
+
+ @param[in] SmmDev the opal device need to perform trust io.
+ @param[in] IoType OPAL_IO_TYPE indicating whether to perform a Trusted Send or Trusted Receive.
+ @param[in] SecurityProtocol Security Protocol
+ @param[in] SpSpecific Security Protocol Specific
+ @param[in] TransferLength Transfer Length of Buffer (in bytes) - always a multiple of 512
+ @param[in] Buffer Address of Data to transfer
+
+ @retval TcgResultSuccess Perform the io action success.
+ @retval TcgResultFailure Perform the io action failed.
+
+**/
+EFI_STATUS
+PerformTrustedIo (
+ OPAL_SMM_DEVICE *SmmDev,
+ OPAL_IO_TYPE IoType,
+ UINT8 SecurityProtocol,
+ UINT16 SpSpecific,
+ UINTN TransferLength,
+ VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINTN BufferSizeBlocks;
+ EFI_ATA_COMMAND_BLOCK AtaCommandBlock;
+
+ Status = EFI_DEVICE_ERROR;
+ if (SmmDev->DeviceType == OPAL_DEVICE_TYPE_SATA) {
+ BufferSizeBlocks = TransferLength / 512;
+
+ ZeroMem( &AtaCommandBlock, sizeof( EFI_ATA_COMMAND_BLOCK ) );
+ AtaCommandBlock.AtaCommand = ( IoType == OpalSend ) ? ATA_COMMAND_TRUSTED_SEND : ATA_COMMAND_TRUSTED_RECEIVE;
+ AtaCommandBlock.AtaSectorCount = ( UINT8 )BufferSizeBlocks;
+ AtaCommandBlock.AtaSectorNumber = ( UINT8 )( BufferSizeBlocks >> 8 );
+ AtaCommandBlock.AtaFeatures = SecurityProtocol;
+ AtaCommandBlock.AtaCylinderLow = ( UINT8 )( SpSpecific >> 8 );
+ AtaCommandBlock.AtaCylinderHigh = ( UINT8 )( SpSpecific );
+ AtaCommandBlock.AtaDeviceHead = ATA_DEVICE_LBA;
+
+
+ ZeroMem( mBuffer, HDD_PAYLOAD );
+ ASSERT( TransferLength <= HDD_PAYLOAD );
+
+ if (IoType == OpalSend) {
+ CopyMem( mBuffer, Buffer, TransferLength );
+ }
+
+ Status = AhciPioTransfer(
+ &mAhciRegisters,
+ (UINT8) SmmDev->SataPort,
+ (UINT8) SmmDev->SataPortMultiplierPort,
+ NULL,
+ 0,
+ ( IoType == OpalSend ) ? FALSE : TRUE, // i/o direction
+ &AtaCommandBlock,
+ NULL,
+ mBuffer,
+ (UINT32)TransferLength,
+ ATA_TIMEOUT
+ );
+
+ if (IoType == OpalRecv) {
+ CopyMem( Buffer, mBuffer, TransferLength );
+ }
+ } else if (SmmDev->DeviceType == OPAL_DEVICE_TYPE_NVME) {
+ Status = NvmeSecuritySendReceive (
+ &mNvmeContext,
+ IoType == OpalSend,
+ SecurityProtocol,
+ SwapBytes16(SpSpecific),
+ TransferLength,
+ Buffer
+ );
+ } else {
+ DEBUG((DEBUG_ERROR, "DeviceType(%x) not support.\n", SmmDev->DeviceType));
+ }
+
+ return Status;
+}
+
+/**
+ Send a security protocol command to a device that receives data and/or the result
+ of one or more commands sent by SendData.
+
+ The ReceiveData function sends a security protocol command to the given MediaId.
+ The security protocol command sent is defined by SecurityProtocolId and contains
+ the security protocol specific data SecurityProtocolSpecificData. The function
+ returns the data from the security protocol command in PayloadBuffer.
+
+ For devices supporting the SCSI command set, the security protocol command is sent
+ using the SECURITY PROTOCOL IN command defined in SPC-4.
+
+ For devices supporting the ATA command set, the security protocol command is sent
+ using one of the TRUSTED RECEIVE commands defined in ATA8-ACS if PayloadBufferSize
+ is non-zero.
+
+ If the PayloadBufferSize is zero, the security protocol command is sent using the
+ Trusted Non-Data command defined in ATA8-ACS.
+
+ If PayloadBufferSize is too small to store the available data from the security
+ protocol command, the function shall copy PayloadBufferSize bytes into the
+ PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL.
+
+ If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero,
+ the function shall return EFI_INVALID_PARAMETER.
+
+ If the given MediaId does not support security protocol commands, the function shall
+ return EFI_UNSUPPORTED. If there is no media in the device, the function returns
+ EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the device,
+ the function returns EFI_MEDIA_CHANGED.
+
+ If the security protocol fails to complete within the Timeout period, the function
+ shall return EFI_TIMEOUT.
+
+ If the security protocol command completes without an error, the function shall
+ return EFI_SUCCESS. If the security protocol command completes with an error, the
+ function shall return EFI_DEVICE_ERROR.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId ID of the medium to receive data from.
+ @param Timeout The timeout, in 100ns units, to use for the execution
+ of the security protocol command. A Timeout value of 0
+ means that this function will wait indefinitely for the
+ security protocol command to execute. If Timeout is greater
+ than zero, then this function will return EFI_TIMEOUT
+ if the time required to execute the receive data command
+ is greater than Timeout.
+ @param SecurityProtocolId The value of the "Security Protocol" parameter of
+ the security protocol command to be sent.
+ @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
+ of the security protocol command to be sent.
+ @param PayloadBufferSize Size in bytes of the payload data buffer.
+ @param PayloadBuffer A pointer to a destination buffer to store the security
+ protocol command specific payload data for the security
+ protocol command. The caller is responsible for having
+ either implicit or explicit ownership of the buffer.
+ @param PayloadTransferSize A pointer to a buffer to store the size in bytes of the
+ data written to the payload data buffer.
+
+ @retval EFI_SUCCESS The security protocol command completed successfully.
+ @retval EFI_WARN_BUFFER_TOO_SMALL The PayloadBufferSize was too small to store the available
+ data from the device. The PayloadBuffer contains the truncated data.
+ @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.
+ @retval EFI_DEVICE_ERROR The security protocol command completed with an error.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
+ @retval EFI_INVALID_PARAMETER The PayloadBuffer or PayloadTransferSize is NULL and
+ PayloadBufferSize is non-zero.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the security
+ protocol command to execute.
+
+**/
+EFI_STATUS
+EFIAPI
+SecurityReceiveData (
+ IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN UINT64 Timeout,
+ IN UINT8 SecurityProtocolId,
+ IN UINT16 SecurityProtocolSpecificData,
+ IN UINTN PayloadBufferSize,
+ OUT VOID *PayloadBuffer,
+ OUT UINTN *PayloadTransferSize
+ )
+{
+ OPAL_SMM_DEVICE *SmmDev;
+
+ SmmDev = OPAL_SMM_DEVICE_FROM_THIS (This);
+ if (SmmDev == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return PerformTrustedIo (
+ SmmDev,
+ OpalRecv,
+ SecurityProtocolId,
+ SecurityProtocolSpecificData,
+ PayloadBufferSize,
+ PayloadBuffer
+ );
+}
+
+/**
+ Send a security protocol command to a device.
+
+ The SendData function sends a security protocol command containing the payload
+ PayloadBuffer to the given MediaId. The security protocol command sent is
+ defined by SecurityProtocolId and contains the security protocol specific data
+ SecurityProtocolSpecificData. If the underlying protocol command requires a
+ specific padding for the command payload, the SendData function shall add padding
+ bytes to the command payload to satisfy the padding requirements.
+
+ For devices supporting the SCSI command set, the security protocol command is sent
+ using the SECURITY PROTOCOL OUT command defined in SPC-4.
+
+ For devices supporting the ATA command set, the security protocol command is sent
+ using one of the TRUSTED SEND commands defined in ATA8-ACS if PayloadBufferSize
+ is non-zero. If the PayloadBufferSize is zero, the security protocol command is
+ sent using the Trusted Non-Data command defined in ATA8-ACS.
+
+ If PayloadBuffer is NULL and PayloadBufferSize is non-zero, the function shall
+ return EFI_INVALID_PARAMETER.
+
+ If the given MediaId does not support security protocol commands, the function
+ shall return EFI_UNSUPPORTED. If there is no media in the device, the function
+ returns EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the
+ device, the function returns EFI_MEDIA_CHANGED.
+
+ If the security protocol fails to complete within the Timeout period, the function
+ shall return EFI_TIMEOUT.
+
+ If the security protocol command completes without an error, the function shall return
+ EFI_SUCCESS. If the security protocol command completes with an error, the function
+ shall return EFI_DEVICE_ERROR.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId ID of the medium to receive data from.
+ @param Timeout The timeout, in 100ns units, to use for the execution
+ of the security protocol command. A Timeout value of 0
+ means that this function will wait indefinitely for the
+ security protocol command to execute. If Timeout is greater
+ than zero, then this function will return EFI_TIMEOUT
+ if the time required to execute the send data command
+ is greater than Timeout.
+ @param SecurityProtocolId The value of the "Security Protocol" parameter of
+ the security protocol command to be sent.
+ @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
+ of the security protocol command to be sent.
+ @param PayloadBufferSize Size in bytes of the payload data buffer.
+ @param PayloadBuffer A pointer to a destination buffer to store the security
+ protocol command specific payload data for the security
+ protocol command.
+
+ @retval EFI_SUCCESS The security protocol command completed successfully.
+ @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.
+ @retval EFI_DEVICE_ERROR The security protocol command completed with an error.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
+ @retval EFI_INVALID_PARAMETER The PayloadBuffer is NULL and PayloadBufferSize is non-zero.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the security
+ protocol command to execute.
+
+**/
+EFI_STATUS
+EFIAPI
+SecuritySendData (
+ IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN UINT64 Timeout,
+ IN UINT8 SecurityProtocolId,
+ IN UINT16 SecurityProtocolSpecificData,
+ IN UINTN PayloadBufferSize,
+ IN VOID *PayloadBuffer
+ )
+{
+ OPAL_SMM_DEVICE *SmmDev;
+
+ SmmDev = OPAL_SMM_DEVICE_FROM_THIS (This);
+ if (SmmDev == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return PerformTrustedIo (
+ SmmDev,
+ OpalSend,
+ SecurityProtocolId,
+ SecurityProtocolSpecificData,
+ PayloadBufferSize,
+ PayloadBuffer
+ );
+
+}
+
diff --git a/Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalPasswordSmm.h b/Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalPasswordSmm.h
new file mode 100644
index 0000000000..ab31a6bfe7
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalPasswordSmm.h
@@ -0,0 +1,300 @@
+/** @file
+ Opal password smm driver which is used to support Opal security feature at s3 path.
+
+Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _OPAL_PASSWORD_SMM_H_
+#define _OPAL_PASSWORD_SMM_H_
+
+#include <PiSmm.h>
+#include <IndustryStandard/Atapi.h>
+
+#include <Protocol/SmmSwDispatch2.h>
+#include <Protocol/SmmSxDispatch2.h>
+#include <Protocol/AtaPassThru.h>
+#include <Protocol/PciIo.h>
+#include <Protocol/SmmReadyToLock.h>
+#include <Protocol/SmmVariable.h>
+#include <Protocol/VariableLock.h>
+#include <Protocol/SmmEndOfDxe.h>
+#include <Protocol/StorageSecurityCommand.h>
+
+#include <Library/OpalPasswordSupportLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PcdLib.h>
+#include <Library/IoLib.h>
+#include <Library/TimerLib.h>
+#include <Library/PciLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/SmmServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/S3BootScriptLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/DxeServicesTableLib.h>
+
+#include <IndustryStandard/Pci22.h>
+
+#include <Guid/OpalPasswordExtraInfoVariable.h>
+
+#include "OpalAhciMode.h"
+#include "OpalIdeMode.h"
+#include "OpalNvmeMode.h"
+
+//
+// Time out Value for ATA pass through protocol
+//
+#define ATA_TIMEOUT EFI_TIMER_PERIOD_SECONDS (3)
+
+//
+// The payload Length of HDD related ATA commands
+//
+#define HDD_PAYLOAD 512
+//
+// According to ATA spec, the max Length of hdd password is 32 bytes
+//
+#define OPAL_PASSWORD_MAX_LENGTH 32
+
+extern VOID *mBuffer;
+
+extern EFI_GCD_MEMORY_SPACE_DESCRIPTOR *mGcdMemSpace;
+extern UINTN mNumberOfDescriptors;
+#pragma pack(1)
+
+typedef struct {
+ UINT32 Address;
+ S3_BOOT_SCRIPT_LIB_WIDTH Width;
+} OPAL_HC_PCI_REGISTER_SAVE;
+
+
+typedef struct {
+ UINT32 SegNum;
+ UINT32 BusNum;
+ UINT32 DevNum;
+ UINT32 FuncNum;
+} PCI_DEVICE;
+
+/**
+* Opal I/O Type utilized by the Trusted IO callback
+*
+* The type indicates if the I/O is a send or receive
+*/
+typedef enum {
+ //
+ // I/O is a TCG Trusted Send command
+ //
+ OpalSend,
+
+ //
+ // I/O is a TCG Trusted Receive command
+ //
+ OpalRecv
+} OPAL_IO_TYPE;
+
+
+#define OPAL_SMM_DEVICE_SIGNATURE SIGNATURE_32 ('o', 's', 'd', 's')
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+
+ EFI_STORAGE_SECURITY_COMMAND_PROTOCOL Sscp;
+
+ UINT32 SegNum;
+ UINT32 BusNum;
+ UINT32 DevNum;
+ UINT32 FuncNum;
+
+ UINT8 DeviceType;
+
+ UINT32 SataPort;
+ UINT32 SataPortMultiplierPort;
+
+ UINT32 NvmeNamespaceId;
+
+ UINT8 Password[32];
+ UINT8 PasswordLength;
+
+ UINT32 Length;
+ PCI_DEVICE *PciBridgeNode;
+
+ UINT16 OpalBaseComId;
+} OPAL_SMM_DEVICE;
+
+#define OPAL_SMM_DEVICE_FROM_THIS(a) CR (a, OPAL_SMM_DEVICE, Sscp, OPAL_SMM_DEVICE_SIGNATURE)
+
+#pragma pack()
+
+/**
+ Send a security protocol command to a device that receives data and/or the result
+ of one or more commands sent by SendData.
+
+ The ReceiveData function sends a security protocol command to the given MediaId.
+ The security protocol command sent is defined by SecurityProtocolId and contains
+ the security protocol specific data SecurityProtocolSpecificData. The function
+ returns the data from the security protocol command in PayloadBuffer.
+
+ For devices supporting the SCSI command set, the security protocol command is sent
+ using the SECURITY PROTOCOL IN command defined in SPC-4.
+
+ For devices supporting the ATA command set, the security protocol command is sent
+ using one of the TRUSTED RECEIVE commands defined in ATA8-ACS if PayloadBufferSize
+ is non-zero.
+
+ If the PayloadBufferSize is zero, the security protocol command is sent using the
+ Trusted Non-Data command defined in ATA8-ACS.
+
+ If PayloadBufferSize is too small to store the available data from the security
+ protocol command, the function shall copy PayloadBufferSize bytes into the
+ PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL.
+
+ If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero,
+ the function shall return EFI_INVALID_PARAMETER.
+
+ If the given MediaId does not support security protocol commands, the function shall
+ return EFI_UNSUPPORTED. If there is no media in the device, the function returns
+ EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the device,
+ the function returns EFI_MEDIA_CHANGED.
+
+ If the security protocol fails to complete within the Timeout period, the function
+ shall return EFI_TIMEOUT.
+
+ If the security protocol command completes without an error, the function shall
+ return EFI_SUCCESS. If the security protocol command completes with an error, the
+ function shall return EFI_DEVICE_ERROR.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId ID of the medium to receive data from.
+ @param Timeout The timeout, in 100ns units, to use for the execution
+ of the security protocol command. A Timeout value of 0
+ means that this function will wait indefinitely for the
+ security protocol command to execute. If Timeout is greater
+ than zero, then this function will return EFI_TIMEOUT
+ if the time required to execute the receive data command
+ is greater than Timeout.
+ @param SecurityProtocolId The value of the "Security Protocol" parameter of
+ the security protocol command to be sent.
+ @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
+ of the security protocol command to be sent.
+ @param PayloadBufferSize Size in bytes of the payload data buffer.
+ @param PayloadBuffer A pointer to a destination buffer to store the security
+ protocol command specific payload data for the security
+ protocol command. The caller is responsible for having
+ either implicit or explicit ownership of the buffer.
+ @param PayloadTransferSize A pointer to a buffer to store the size in bytes of the
+ data written to the payload data buffer.
+
+ @retval EFI_SUCCESS The security protocol command completed successfully.
+ @retval EFI_WARN_BUFFER_TOO_SMALL The PayloadBufferSize was too small to store the available
+ data from the device. The PayloadBuffer contains the truncated data.
+ @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.
+ @retval EFI_DEVICE_ERROR The security protocol command completed with an error.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
+ @retval EFI_INVALID_PARAMETER The PayloadBuffer or PayloadTransferSize is NULL and
+ PayloadBufferSize is non-zero.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the security
+ protocol command to execute.
+
+**/
+EFI_STATUS
+EFIAPI
+SecurityReceiveData (
+ IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN UINT64 Timeout,
+ IN UINT8 SecurityProtocolId,
+ IN UINT16 SecurityProtocolSpecificData,
+ IN UINTN PayloadBufferSize,
+ OUT VOID *PayloadBuffer,
+ OUT UINTN *PayloadTransferSize
+ );
+
+/**
+ Send a security protocol command to a device.
+
+ The SendData function sends a security protocol command containing the payload
+ PayloadBuffer to the given MediaId. The security protocol command sent is
+ defined by SecurityProtocolId and contains the security protocol specific data
+ SecurityProtocolSpecificData. If the underlying protocol command requires a
+ specific padding for the command payload, the SendData function shall add padding
+ bytes to the command payload to satisfy the padding requirements.
+
+ For devices supporting the SCSI command set, the security protocol command is sent
+ using the SECURITY PROTOCOL OUT command defined in SPC-4.
+
+ For devices supporting the ATA command set, the security protocol command is sent
+ using one of the TRUSTED SEND commands defined in ATA8-ACS if PayloadBufferSize
+ is non-zero. If the PayloadBufferSize is zero, the security protocol command is
+ sent using the Trusted Non-Data command defined in ATA8-ACS.
+
+ If PayloadBuffer is NULL and PayloadBufferSize is non-zero, the function shall
+ return EFI_INVALID_PARAMETER.
+
+ If the given MediaId does not support security protocol commands, the function
+ shall return EFI_UNSUPPORTED. If there is no media in the device, the function
+ returns EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the
+ device, the function returns EFI_MEDIA_CHANGED.
+
+ If the security protocol fails to complete within the Timeout period, the function
+ shall return EFI_TIMEOUT.
+
+ If the security protocol command completes without an error, the function shall return
+ EFI_SUCCESS. If the security protocol command completes with an error, the function
+ shall return EFI_DEVICE_ERROR.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId ID of the medium to receive data from.
+ @param Timeout The timeout, in 100ns units, to use for the execution
+ of the security protocol command. A Timeout value of 0
+ means that this function will wait indefinitely for the
+ security protocol command to execute. If Timeout is greater
+ than zero, then this function will return EFI_TIMEOUT
+ if the time required to execute the receive data command
+ is greater than Timeout.
+ @param SecurityProtocolId The value of the "Security Protocol" parameter of
+ the security protocol command to be sent.
+ @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter
+ of the security protocol command to be sent.
+ @param PayloadBufferSize Size in bytes of the payload data buffer.
+ @param PayloadBuffer A pointer to a destination buffer to store the security
+ protocol command specific payload data for the security
+ protocol command.
+
+ @retval EFI_SUCCESS The security protocol command completed successfully.
+ @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands.
+ @retval EFI_DEVICE_ERROR The security protocol command completed with an error.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
+ @retval EFI_INVALID_PARAMETER The PayloadBuffer is NULL and PayloadBufferSize is non-zero.
+ @retval EFI_TIMEOUT A timeout occurred while waiting for the security
+ protocol command to execute.
+
+**/
+EFI_STATUS
+EFIAPI
+SecuritySendData (
+ IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN UINT64 Timeout,
+ IN UINT8 SecurityProtocolId,
+ IN UINT16 SecurityProtocolSpecificData,
+ IN UINTN PayloadBufferSize,
+ IN VOID *PayloadBuffer
+ );
+
+#endif // _OPAL_PASSWORD_SMM_H_
+
diff --git a/Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalPasswordSmm.inf b/Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalPasswordSmm.inf
new file mode 100644
index 0000000000..cab0fd5656
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalPasswordSmm.inf
@@ -0,0 +1,77 @@
+## @file
+# This is a Opal Password Smm driver.
+#
+# Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = OpalPasswordSmm
+ FILE_GUID = 7D24A234-A8C2-4718-BF60-A2EF070F414E
+ MODULE_TYPE = DXE_SMM_DRIVER
+ VERSION_STRING = 1.0
+ PI_SPECIFICATION_VERSION = 0x0001000A
+ ENTRY_POINT = OpalPasswordSmmInit
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ OpalPasswordSmm.c
+ OpalPasswordSmm.h
+ OpalAhciMode.c
+ OpalAhciMode.h
+ OpalIdeMode.c
+ OpalIdeMode.h
+ OpalNvmeMode.c
+ OpalNvmeMode.h
+ OpalNvmeReg.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ SecurityPkg/SecurityPkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ UefiRuntimeServicesTableLib
+ DebugLib
+ IoLib
+ PciLib
+ BaseLib
+ BaseMemoryLib
+ SmmServicesTableLib
+ MemoryAllocationLib
+ UefiLib
+ TimerLib
+ S3BootScriptLib
+ DxeServicesTableLib
+ DevicePathLib
+ OpalPasswordSupportLib
+
+[Guids]
+ gOpalExtraInfoVariableGuid ## CONSUMES ## GUID
+
+[Protocols]
+ gEfiSmmSwDispatch2ProtocolGuid ## CONSUMES
+ gEfiAtaPassThruProtocolGuid ## CONSUMES
+ gEfiPciIoProtocolGuid ## CONSUMES
+ gEfiSmmSxDispatch2ProtocolGuid ## CONSUMES
+ gEfiSmmVariableProtocolGuid ## CONSUMES
+ gEfiStorageSecurityCommandProtocolGuid ## CONSUMES
+ gEfiSmmEndOfDxeProtocolGuid ## CONSUMES
+
+[Depex]
+ gEfiSmmSwDispatch2ProtocolGuid AND
+ gEfiSmmSxDispatch2ProtocolGuid AND
+ gEfiSmmVariableProtocolGuid
diff --git a/Core/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePei.c b/Core/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePei.c
new file mode 100644
index 0000000000..e694db8cf1
--- /dev/null
+++ b/Core/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.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiPei.h>
+#include <Ppi/LockPhysicalPresence.h>
+#include <Ppi/ReadOnlyVariable2.h>
+#include <Guid/PhysicalPresenceData.h>
+#include <Library/PcdLib.h>
+#include <Library/PeiServicesLib.h>
+
+/**
+ 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/Core/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePei.inf b/Core/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePei.inf
new file mode 100644
index 0000000000..cac1abea34
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePei.inf
@@ -0,0 +1,64 @@
+## @file
+# Produces a PPI to indicate whether to lock TPM in PEI phase
+#
+# This module produces PEI_LOCK_PHYSICAL_PRESENCE_PPI to indicate whether
+# TPM physical presence needs to be locked. It can be replaced by a
+# platform specific module.
+#
+# Copyright (c) 2005 - 2014, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PhysicalPresencePei
+ MODULE_UNI_FILE = PhysicalPresencePei.uni
+ 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 ## PRODUCES
+ gEfiPeiReadOnlyVariable2PpiGuid ## CONSUMES
+
+[Guids]
+ gEfiPhysicalPresenceGuid ## SOMETIMES_CONSUMES ## Variable:L"PhysicalPresence"
+
+[Pcd]
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpmPhysicalPresence ## SOMETIMES_CONSUMES
+
+[Depex]
+ gEfiPeiMemoryDiscoveredPpiGuid AND
+ gEfiPeiReadOnlyVariable2PpiGuid AND
+ gPeiTpmInitializedPpiGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ PhysicalPresencePeiExtra.uni
+ \ No newline at end of file
diff --git a/Core/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePei.uni b/Core/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePei.uni
new file mode 100644
index 0000000000..8f701f6260
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePei.uni
@@ -0,0 +1,23 @@
+// /** @file
+// Produces a PPI to indicate whether to lock TPM in PEI phase
+//
+// This module produces PEI_LOCK_PHYSICAL_PRESENCE_PPI to indicate whether
+// TPM physical presence needs to be locked. It can be replaced by a
+// platform specific module.
+//
+// Copyright (c) 2005 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Produces a PPI to indicate whether to lock TPM in PEI phase"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This module produces PEI_LOCK_PHYSICAL_PRESENCE_PPI to indicate whether TPM physical presence needs to be locked. It can be replaced by a platform-specific module."
+
diff --git a/Core/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePeiExtra.uni b/Core/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePeiExtra.uni
new file mode 100644
index 0000000000..0fb38dba82
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePeiExtra.uni
@@ -0,0 +1,19 @@
+// /** @file
+// PhysicalPresencePei Localized Strings and Content
+//
+// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Physical Presence PEI"
+
+
diff --git a/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2Config.vfr b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2Config.vfr
new file mode 100644
index 0000000000..1d44c99109
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2Config.vfr
@@ -0,0 +1,250 @@
+/** @file
+ VFR file used by the TCG2 configuration component.
+
+Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "Tcg2ConfigNvData.h"
+
+formset
+ guid = TCG2_CONFIG_FORM_SET_GUID,
+ title = STRING_TOKEN(STR_TCG2_TITLE),
+ help = STRING_TOKEN(STR_TCG2_HELP),
+ classguid = EFI_HII_PLATFORM_SETUP_FORMSET_GUID,
+
+ efivarstore TCG2_CONFIGURATION_INFO,
+ varid = TCG2_CONFIGURATION_INFO_VARSTORE_ID,
+ attribute = 0x02, // EFI variable attribures EFI_VARIABLE_BOOTSERVICE_ACCESS
+ name = TCG2_CONFIGURATION_INFO,
+ guid = TCG2_CONFIG_FORM_SET_GUID;
+
+ efivarstore TCG2_CONFIGURATION,
+ varid = TCG2_CONFIGURATION_VARSTORE_ID,
+ attribute = 0x03, // EFI variable attribures EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE
+ name = TCG2_CONFIGURATION,
+ guid = TCG2_CONFIG_FORM_SET_GUID;
+
+ efivarstore TCG2_VERSION,
+ varid = TCG2_VERSION_VARSTORE_ID,
+ attribute = 0x03, // EFI variable attribures EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE
+ name = TCG2_VERSION,
+ guid = TCG2_CONFIG_FORM_SET_GUID;
+
+ form formid = TCG2_CONFIGURATION_FORM_ID,
+ title = STRING_TOKEN(STR_TCG2_TITLE);
+
+ subtitle text = STRING_TOKEN(STR_NULL);
+
+ text
+ help = STRING_TOKEN(STR_TCG2_DEVICE_STATE_HELP),
+ text = STRING_TOKEN(STR_TCG2_DEVICE_STATE_PROMPT),
+ text = STRING_TOKEN(STR_TCG2_DEVICE_STATE_CONTENT);
+
+ oneof varid = TCG2_CONFIGURATION.TpmDevice,
+ questionid = KEY_TPM_DEVICE,
+ prompt = STRING_TOKEN(STR_TCG2_DEVICE_PROMPT),
+ help = STRING_TOKEN(STR_TCG2_DEVICE_HELP),
+ flags = INTERACTIVE,
+ option text = STRING_TOKEN(STR_TCG2_TPM_1_2), value = TPM_DEVICE_1_2, flags = DEFAULT | MANUFACTURING | RESET_REQUIRED;
+ option text = STRING_TOKEN(STR_TCG2_TPM_2_0_DTPM), value = TPM_DEVICE_2_0_DTPM, flags = RESET_REQUIRED;
+ endoneof;
+
+ suppressif ideqvallist TCG2_CONFIGURATION.TpmDevice == TPM_DEVICE_NULL TPM_DEVICE_1_2;
+
+ subtitle text = STRING_TOKEN(STR_NULL);
+
+ text
+ help = STRING_TOKEN(STR_TPM2_ACPI_HID_HELP),
+ text = STRING_TOKEN(STR_TPM2_ACPI_HID_PROMPT),
+ text = STRING_TOKEN(STR_TPM2_ACPI_HID_CONTENT);
+
+ text
+ help = STRING_TOKEN(STR_TPM2_ACPI_REVISION_STATE_HELP),
+ text = STRING_TOKEN(STR_TPM2_ACPI_REVISION_STATE_PROMPT),
+ text = STRING_TOKEN(STR_TPM2_ACPI_REVISION_STATE_CONTENT);
+
+ oneof varid = TCG2_VERSION.Tpm2AcpiTableRev,
+ questionid = KEY_TPM2_ACPI_REVISION,
+ prompt = STRING_TOKEN(STR_TPM2_ACPI_REVISION_PROMPT),
+ help = STRING_TOKEN(STR_TPM2_ACPI_REVISION_HELP),
+ flags = INTERACTIVE,
+ option text = STRING_TOKEN(STR_TPM2_ACPI_REVISION_3), value = TPM2_ACPI_REVISION_3, flags = RESET_REQUIRED;
+ option text = STRING_TOKEN(STR_TPM2_ACPI_REVISION_4), value = TPM2_ACPI_REVISION_4, flags = DEFAULT | MANUFACTURING | RESET_REQUIRED;
+ endoneof;
+
+ subtitle text = STRING_TOKEN(STR_NULL);
+
+ text
+ help = STRING_TOKEN(STR_TCG2_DEVICE_INTERFACE_STATE_HELP),
+ text = STRING_TOKEN(STR_TCG2_DEVICE_INTERFACE_STATE_PROMPT),
+ text = STRING_TOKEN(STR_TCG2_DEVICE_INTERFACE_STATE_CONTENT);
+
+ text
+ help = STRING_TOKEN(STR_TCG2_DEVICE_INTERFACE_CAPABILITY_HELP),
+ text = STRING_TOKEN(STR_TCG2_DEVICE_INTERFACE_CAPABILITY_PROMPT),
+ text = STRING_TOKEN(STR_TCG2_DEVICE_INTERFACE_CAPABILITY_CONTENT);
+
+ suppressif ideqval TCG2_CONFIGURATION_INFO.TpmDeviceInterfacePtpFifoSupported == 0
+ OR ideqval TCG2_CONFIGURATION_INFO.TpmDeviceInterfacePtpCrbSupported == 0;
+ oneof varid = TCG2_CONFIGURATION_INFO.TpmDeviceInterfaceAttempt,
+ questionid = KEY_TPM_DEVICE_INTERFACE,
+ prompt = STRING_TOKEN(STR_TCG2_DEVICE_INTERFACE_PROMPT),
+ help = STRING_TOKEN(STR_TCG2_DEVICE_INTERFACE_HELP),
+ flags = INTERACTIVE,
+ option text = STRING_TOKEN(STR_TCG2_DEVICE_INTERFACE_TIS), value = TPM_DEVICE_INTERFACE_TIS, flags = RESET_REQUIRED;
+ option text = STRING_TOKEN(STR_TCG2_DEVICE_INTERFACE_PTP_FIFO), value = TPM_DEVICE_INTERFACE_PTP_FIFO, flags = RESET_REQUIRED;
+ option text = STRING_TOKEN(STR_TCG2_DEVICE_INTERFACE_PTP_CRB), value = TPM_DEVICE_INTERFACE_PTP_CRB, flags = DEFAULT | MANUFACTURING | RESET_REQUIRED;
+ endoneof;
+ endif;
+
+ endif;
+
+ subtitle text = STRING_TOKEN(STR_NULL);
+
+ suppressif ideqvallist TCG2_CONFIGURATION.TpmDevice == TPM_DEVICE_NULL TPM_DEVICE_1_2;
+ text
+ help = STRING_TOKEN(STR_TPM2_ACTIVE_HASH_ALGO_HELP),
+ text = STRING_TOKEN(STR_TPM2_ACTIVE_HASH_ALGO),
+ text = STRING_TOKEN(STR_TPM2_ACTIVE_HASH_ALGO_CONTENT);
+ text
+ help = STRING_TOKEN(STR_TPM2_SUPPORTED_HASH_ALGO_HELP),
+ text = STRING_TOKEN(STR_TPM2_SUPPORTED_HASH_ALGO),
+ text = STRING_TOKEN(STR_TPM2_SUPPORTED_HASH_ALGO_CONTENT);
+ text
+ help = STRING_TOKEN(STR_BIOS_HASH_ALGO_HELP),
+ text = STRING_TOKEN(STR_BIOS_HASH_ALGO),
+ text = STRING_TOKEN(STR_BIOS_HASH_ALGO_CONTENT);
+
+ subtitle text = STRING_TOKEN(STR_NULL);
+ subtitle text = STRING_TOKEN(STR_TCG2_PP_OPERATION);
+
+ text
+ help = STRING_TOKEN(STR_TCG2_PPI_VERSION_STATE_HELP),
+ text = STRING_TOKEN(STR_TCG2_PPI_VERSION_STATE_PROMPT),
+ text = STRING_TOKEN(STR_TCG2_PPI_VERSION_STATE_CONTENT);
+
+ oneof varid = TCG2_VERSION.PpiVersion,
+ questionid = KEY_TCG2_PPI_VERSION,
+ prompt = STRING_TOKEN(STR_TCG2_PPI_VERSION_PROMPT),
+ help = STRING_TOKEN(STR_TCG2_PPI_VERSION_HELP),
+ flags = INTERACTIVE,
+ option text = STRING_TOKEN(STR_TCG2_PPI_VERSION_1_2), value = TCG2_PPI_VERSION_1_2, flags = RESET_REQUIRED;
+ option text = STRING_TOKEN(STR_TCG2_PPI_VERSION_1_3), value = TCG2_PPI_VERSION_1_3, flags = DEFAULT | MANUFACTURING | RESET_REQUIRED;
+ endoneof;
+
+ oneof name = Tpm2Operation,
+ questionid = KEY_TPM2_OPERATION,
+ prompt = STRING_TOKEN(STR_TCG2_OPERATION),
+ help = STRING_TOKEN(STR_TCG2_OPERATION_HELP),
+ flags = INTERACTIVE | NUMERIC_SIZE_1,
+ option text = STRING_TOKEN(STR_TCG2_NO_ACTION), value = TCG2_PHYSICAL_PRESENCE_NO_ACTION, flags = DEFAULT | MANUFACTURING | RESET_REQUIRED;
+ option text = STRING_TOKEN(STR_TCG2_ENABLE), value = TCG2_PHYSICAL_PRESENCE_ENABLE, flags = RESET_REQUIRED;
+ option text = STRING_TOKEN(STR_TCG2_DISABLE), value = TCG2_PHYSICAL_PRESENCE_DISABLE, flags = RESET_REQUIRED;
+ option text = STRING_TOKEN(STR_TCG2_CLEAR), value = TCG2_PHYSICAL_PRESENCE_CLEAR, flags = RESET_REQUIRED;
+ option text = STRING_TOKEN(STR_TCG2_SET_PCD_BANKS), value = TCG2_PHYSICAL_PRESENCE_SET_PCR_BANKS, flags = RESET_REQUIRED;
+ option text = STRING_TOKEN(STR_TCG2_CHANGE_EPS), value = TCG2_PHYSICAL_PRESENCE_CHANGE_EPS, flags = RESET_REQUIRED;
+ option text = STRING_TOKEN(STR_TCG2_LOG_ALL_DIGESTS), value = TCG2_PHYSICAL_PRESENCE_LOG_ALL_DIGESTS, flags = RESET_REQUIRED;
+ option text = STRING_TOKEN(STR_TCG2_DISABLE_ENDORSEMENT_ENABLE_STORAGE_HIERARCHY), value = TCG2_PHYSICAL_PRESENCE_DISABLE_ENDORSEMENT_ENABLE_STORAGE_HIERARCHY, flags = RESET_REQUIRED;
+ endoneof;
+
+ suppressif NOT questionref(Tpm2Operation) == TCG2_PHYSICAL_PRESENCE_SET_PCR_BANKS;
+ numeric name = Tpm2OperationParameter,
+ questionid = KEY_TPM2_OPERATION_PARAMETER,
+ prompt = STRING_TOKEN(STR_TCG2_OPERATION_PARAMETER),
+ help = STRING_TOKEN(STR_TCG2_OPERATION_PARAMETER_HELP),
+ flags = DISPLAY_UINT_HEX | INTERACTIVE | NUMERIC_SIZE_4,
+ minimum = 0,
+ maximum = 0xFFFFFFFF,
+ step = 0,
+ default = 0,
+ endnumeric;
+ endif;
+
+ subtitle text = STRING_TOKEN(STR_NULL);
+ subtitle text = STRING_TOKEN(STR_TCG2_CONFIGURATION);
+
+ text
+ help = STRING_TOKEN(STR_TCG2_SUPPORTED_EVENT_LOG_FORMAT_HELP),
+ text = STRING_TOKEN(STR_TCG2_SUPPORTED_EVENT_LOG_FORMAT),
+ text = STRING_TOKEN(STR_TCG2_SUPPORTED_EVENT_LOG_FORMAT_CONTENT);
+
+ text
+ help = STRING_TOKEN(STR_TCG2_HASH_ALGO_BITMAP_HELP),
+ text = STRING_TOKEN(STR_TCG2_HASH_ALGO_BITMAP),
+ text = STRING_TOKEN(STR_TCG2_HASH_ALGO_BITMAP_CONTENT);
+
+ text
+ help = STRING_TOKEN(STR_TCG2_NUMBER_OF_PCR_BANKS_HELP),
+ text = STRING_TOKEN(STR_TCG2_NUMBER_OF_PCR_BANKS),
+ text = STRING_TOKEN(STR_TCG2_NUMBER_OF_PCR_BANKS_CONTENT);
+
+ text
+ help = STRING_TOKEN(STR_TCG2_ACTIVE_PCR_BANKS_HELP),
+ text = STRING_TOKEN(STR_TCG2_ACTIVE_PCR_BANKS),
+ text = STRING_TOKEN(STR_TCG2_ACTIVE_PCR_BANKS_CONTENT);
+
+ subtitle text = STRING_TOKEN(STR_NULL);
+
+ suppressif ideqval TCG2_CONFIGURATION_INFO.Sha1Supported == 0;
+ checkbox name = TCG2ActivatePCRBank0,
+ questionid = KEY_TPM2_PCR_BANKS_REQUEST_0,
+ prompt = STRING_TOKEN(STR_TCG2_PCR_BANK_SHA1),
+ help = STRING_TOKEN(STR_TCG2_PCR_BANK_SHA1_HELP),
+ flags = INTERACTIVE | RESET_REQUIRED,
+ default = 1,
+ endcheckbox;
+ endif;
+
+ suppressif ideqval TCG2_CONFIGURATION_INFO.Sha256Supported == 0;
+ checkbox name = TCG2ActivatePCRBank1,
+ questionid = KEY_TPM2_PCR_BANKS_REQUEST_1,
+ prompt = STRING_TOKEN(STR_TCG2_PCR_BANK_SHA256),
+ help = STRING_TOKEN(STR_TCG2_PCR_BANK_SHA256_HELP),
+ flags = INTERACTIVE | RESET_REQUIRED,
+ default = 0,
+ endcheckbox;
+ endif;
+
+ suppressif ideqval TCG2_CONFIGURATION_INFO.Sha384Supported == 0;
+ checkbox name = TCG2ActivatePCRBank2,
+ questionid = KEY_TPM2_PCR_BANKS_REQUEST_2,
+ prompt = STRING_TOKEN(STR_TCG2_PCR_BANK_SHA384),
+ help = STRING_TOKEN(STR_TCG2_PCR_BANK_SHA384_HELP),
+ flags = INTERACTIVE | RESET_REQUIRED,
+ default = 0,
+ endcheckbox;
+ endif;
+
+ suppressif ideqval TCG2_CONFIGURATION_INFO.Sha512Supported == 0;
+ checkbox name = TCG2ActivatePCRBank3,
+ questionid = KEY_TPM2_PCR_BANKS_REQUEST_3,
+ prompt = STRING_TOKEN(STR_TCG2_PCR_BANK_SHA512),
+ help = STRING_TOKEN(STR_TCG2_PCR_BANK_SHA512_HELP),
+ flags = INTERACTIVE | RESET_REQUIRED,
+ default = 0,
+ endcheckbox;
+ endif;
+
+ suppressif ideqval TCG2_CONFIGURATION_INFO.Sm3Supported == 0;
+ checkbox name = TCG2ActivatePCRBank4,
+ questionid = KEY_TPM2_PCR_BANKS_REQUEST_4,
+ prompt = STRING_TOKEN(STR_TCG2_PCR_BANK_SM3_256),
+ help = STRING_TOKEN(STR_TCG2_PCR_BANK_SM3_256_HELP),
+ flags = INTERACTIVE | RESET_REQUIRED,
+ default = 0,
+ endcheckbox;
+ endif;
+
+ endif;
+
+ endform;
+
+endformset;
diff --git a/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDriver.c b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDriver.c
new file mode 100644
index 0000000000..9c590dcb74
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDriver.c
@@ -0,0 +1,461 @@
+/** @file
+ The module entry point for Tcg2 configuration module.
+
+Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "Tcg2ConfigImpl.h"
+
+extern TPM_INSTANCE_ID mTpmInstanceId[TPM_DEVICE_MAX + 1];
+
+/**
+ Update default PCR banks data.
+
+ @param[in] HiiPackage HII Package.
+ @param[in] HiiPackageSize HII Package size.
+ @param[in] PCRBanks PCR Banks data.
+
+**/
+VOID
+UpdateDefaultPCRBanks (
+ IN VOID *HiiPackage,
+ IN UINTN HiiPackageSize,
+ IN UINT32 PCRBanks
+ )
+{
+ EFI_HII_PACKAGE_HEADER *HiiPackageHeader;
+ EFI_IFR_OP_HEADER *IfrOpCodeHeader;
+ EFI_IFR_CHECKBOX *IfrCheckBox;
+ EFI_IFR_DEFAULT *IfrDefault;
+
+ HiiPackageHeader = (EFI_HII_PACKAGE_HEADER *)HiiPackage;
+
+ switch (HiiPackageHeader->Type) {
+ case EFI_HII_PACKAGE_FORMS:
+ IfrOpCodeHeader = (EFI_IFR_OP_HEADER *)(HiiPackageHeader + 1);
+ while ((UINTN)IfrOpCodeHeader < (UINTN)HiiPackageHeader + HiiPackageHeader->Length) {
+ switch (IfrOpCodeHeader->OpCode) {
+ case EFI_IFR_CHECKBOX_OP:
+ IfrCheckBox = (EFI_IFR_CHECKBOX *)IfrOpCodeHeader;
+ if ((IfrCheckBox->Question.QuestionId >= KEY_TPM2_PCR_BANKS_REQUEST_0) && (IfrCheckBox->Question.QuestionId <= KEY_TPM2_PCR_BANKS_REQUEST_4)) {
+ IfrDefault = (EFI_IFR_DEFAULT *)(IfrCheckBox + 1);
+ ASSERT (IfrDefault->Header.OpCode == EFI_IFR_DEFAULT_OP);
+ ASSERT (IfrDefault->Type == EFI_IFR_TYPE_BOOLEAN);
+ IfrDefault->Value.b = (BOOLEAN)((PCRBanks >> (IfrCheckBox->Question.QuestionId - KEY_TPM2_PCR_BANKS_REQUEST_0)) & 0x1);
+ }
+ break;
+ }
+ IfrOpCodeHeader = (EFI_IFR_OP_HEADER *)((UINTN)IfrOpCodeHeader + IfrOpCodeHeader->Length);
+ }
+ break;
+ }
+ return ;
+}
+
+/**
+ Initialize TCG2 version information.
+
+ This function will initialize efi varstore configuration data for
+ TCG2_VERSION_NAME variable, check the value of related PCD with
+ the variable value and set string for the version state content
+ according to the PCD value.
+
+ @param[in] PrivateData Points to TCG2 configuration private data.
+
+**/
+VOID
+InitializeTcg2VersionInfo (
+ IN TCG2_CONFIG_PRIVATE_DATA *PrivateData
+ )
+{
+ EFI_STATUS Status;
+ EFI_STRING ConfigRequestHdr;
+ BOOLEAN ActionFlag;
+ TCG2_VERSION Tcg2Version;
+ UINTN DataSize;
+ UINT64 PcdTcg2PpiVersion;
+ UINT8 PcdTpm2AcpiTableRev;
+
+ //
+ // Get the PCD value before initializing efi varstore configuration data.
+ //
+ PcdTcg2PpiVersion = 0;
+ CopyMem (
+ &PcdTcg2PpiVersion,
+ PcdGetPtr (PcdTcgPhysicalPresenceInterfaceVer),
+ AsciiStrSize ((CHAR8 *) PcdGetPtr (PcdTcgPhysicalPresenceInterfaceVer))
+ );
+
+ PcdTpm2AcpiTableRev = PcdGet8 (PcdTpm2AcpiTableRev);
+
+ //
+ // Initialize efi varstore configuration data.
+ //
+ ZeroMem (&Tcg2Version, sizeof (Tcg2Version));
+ ConfigRequestHdr = HiiConstructConfigHdr (
+ &gTcg2ConfigFormSetGuid,
+ TCG2_VERSION_NAME,
+ PrivateData->DriverHandle
+ );
+ ASSERT (ConfigRequestHdr != NULL);
+ DataSize = sizeof (Tcg2Version);
+ Status = gRT->GetVariable (
+ TCG2_VERSION_NAME,
+ &gTcg2ConfigFormSetGuid,
+ NULL,
+ &DataSize,
+ &Tcg2Version
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // EFI variable does exist and validate current setting.
+ //
+ ActionFlag = HiiValidateSettings (ConfigRequestHdr);
+ if (!ActionFlag) {
+ //
+ // Current configuration is invalid, reset to defaults.
+ //
+ ActionFlag = HiiSetToDefaults (ConfigRequestHdr, EFI_HII_DEFAULT_CLASS_STANDARD);
+ ASSERT (ActionFlag);
+ //
+ // Get the default values from variable.
+ //
+ DataSize = sizeof (Tcg2Version);
+ Status = gRT->GetVariable (
+ TCG2_VERSION_NAME,
+ &gTcg2ConfigFormSetGuid,
+ NULL,
+ &DataSize,
+ &Tcg2Version
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+ } else {
+ //
+ // EFI variable doesn't exist or variable size is not expected.
+ //
+
+ //
+ // Store zero data Buffer Storage to EFI variable.
+ //
+ Status = gRT->SetVariable (
+ TCG2_VERSION_NAME,
+ &gTcg2ConfigFormSetGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ sizeof (Tcg2Version),
+ &Tcg2Version
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Tcg2ConfigDriver: Fail to set TCG2_VERSION_NAME\n"));
+ return;
+ } else {
+ //
+ // Build this variable based on default values stored in IFR.
+ //
+ ActionFlag = HiiSetToDefaults (ConfigRequestHdr, EFI_HII_DEFAULT_CLASS_STANDARD);
+ ASSERT (ActionFlag);
+ //
+ // Get the default values from variable.
+ //
+ DataSize = sizeof (Tcg2Version);
+ Status = gRT->GetVariable (
+ TCG2_VERSION_NAME,
+ &gTcg2ConfigFormSetGuid,
+ NULL,
+ &DataSize,
+ &Tcg2Version
+ );
+ ASSERT_EFI_ERROR (Status);
+ if (PcdTcg2PpiVersion != Tcg2Version.PpiVersion) {
+ DEBUG ((DEBUG_WARN, "WARNING: PcdTcgPhysicalPresenceInterfaceVer default value is not same with the default value in VFR\n"));
+ DEBUG ((DEBUG_WARN, "WARNING: The default value in VFR has be chosen\n"));
+ }
+ if (PcdTpm2AcpiTableRev != Tcg2Version.Tpm2AcpiTableRev) {
+ DEBUG ((DEBUG_WARN, "WARNING: PcdTpm2AcpiTableRev default value is not same with the default value in VFR\n"));
+ DEBUG ((DEBUG_WARN, "WARNING: The default value in VFR has be chosen\n"));
+ }
+ }
+ }
+ FreePool (ConfigRequestHdr);
+
+ //
+ // Get the PCD value again.
+ // If the PCD value is not equal to the value in variable,
+ // the PCD is not DynamicHii type and does not map to the setup option.
+ //
+ PcdTcg2PpiVersion = 0;
+ CopyMem (
+ &PcdTcg2PpiVersion,
+ PcdGetPtr (PcdTcgPhysicalPresenceInterfaceVer),
+ AsciiStrSize ((CHAR8 *) PcdGetPtr (PcdTcgPhysicalPresenceInterfaceVer))
+ );
+ if (PcdTcg2PpiVersion != Tcg2Version.PpiVersion) {
+ DEBUG ((DEBUG_WARN, "WARNING: PcdTcgPhysicalPresenceInterfaceVer is not DynamicHii type and does not map to TCG2_VERSION.PpiVersion\n"));
+ DEBUG ((DEBUG_WARN, "WARNING: The TCG2 PPI version configuring from setup page will not work\n"));
+ }
+
+ switch (PcdTcg2PpiVersion) {
+ case TCG2_PPI_VERSION_1_2:
+ HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_TCG2_PPI_VERSION_STATE_CONTENT), L"1.2", NULL);
+ break;
+ case TCG2_PPI_VERSION_1_3:
+ HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_TCG2_PPI_VERSION_STATE_CONTENT), L"1.3", NULL);
+ break;
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+
+ //
+ // Get the PcdTpm2AcpiTableRev value again.
+ // If the PCD value is not equal to the value in variable,
+ // the PCD is not DynamicHii type and does not map to TCG2_VERSION Variable.
+ //
+ PcdTpm2AcpiTableRev = PcdGet8 (PcdTpm2AcpiTableRev);
+ if (PcdTpm2AcpiTableRev != Tcg2Version.Tpm2AcpiTableRev) {
+ DEBUG ((DEBUG_WARN, "WARNING: PcdTpm2AcpiTableRev is not DynamicHii type and does not map to TCG2_VERSION.Tpm2AcpiTableRev\n"));
+ DEBUG ((DEBUG_WARN, "WARNING: The Tpm2 ACPI Revision configuring from setup page will not work\n"));
+ }
+
+ switch (PcdTpm2AcpiTableRev) {
+ case EFI_TPM2_ACPI_TABLE_REVISION_3:
+ HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_TPM2_ACPI_REVISION_STATE_CONTENT), L"Rev 3", NULL);
+ break;
+ case EFI_TPM2_ACPI_TABLE_REVISION_4:
+ HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_TPM2_ACPI_REVISION_STATE_CONTENT), L"Rev 4", NULL);
+ break;
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+}
+
+/**
+ The entry point for Tcg2 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
+Tcg2ConfigDriverEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ TCG2_CONFIG_PRIVATE_DATA *PrivateData;
+ TCG2_CONFIGURATION Tcg2Configuration;
+ TCG2_DEVICE_DETECTION Tcg2DeviceDetection;
+ UINTN Index;
+ UINTN DataSize;
+ EDKII_VARIABLE_LOCK_PROTOCOL *VariableLockProtocol;
+ UINT32 CurrentActivePCRBanks;
+
+ Status = gBS->OpenProtocol (
+ ImageHandle,
+ &gEfiCallerIdGuid,
+ NULL,
+ ImageHandle,
+ ImageHandle,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+ if (!EFI_ERROR (Status)) {
+ return EFI_ALREADY_STARTED;
+ }
+
+ //
+ // Create a private data structure.
+ //
+ PrivateData = AllocateCopyPool (sizeof (TCG2_CONFIG_PRIVATE_DATA), &mTcg2ConfigPrivateDateTemplate);
+ ASSERT (PrivateData != NULL);
+ mTcg2ConfigPrivateDate = PrivateData;
+ //
+ // Install private GUID.
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &ImageHandle,
+ &gEfiCallerIdGuid,
+ PrivateData,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->LocateProtocol (&gEfiTcg2ProtocolGuid, NULL, (VOID **) &PrivateData->Tcg2Protocol);
+ ASSERT_EFI_ERROR (Status);
+
+ PrivateData->ProtocolCapability.Size = sizeof(PrivateData->ProtocolCapability);
+ Status = PrivateData->Tcg2Protocol->GetCapability (
+ PrivateData->Tcg2Protocol,
+ &PrivateData->ProtocolCapability
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ DataSize = sizeof(Tcg2Configuration);
+ Status = gRT->GetVariable (
+ TCG2_STORAGE_NAME,
+ &gTcg2ConfigFormSetGuid,
+ NULL,
+ &DataSize,
+ &Tcg2Configuration
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Variable not ready, set default value
+ //
+ Tcg2Configuration.TpmDevice = TPM_DEVICE_DEFAULT;
+ }
+
+ //
+ // Validation
+ //
+ if ((Tcg2Configuration.TpmDevice > TPM_DEVICE_MAX) || (Tcg2Configuration.TpmDevice < TPM_DEVICE_MIN)) {
+ Tcg2Configuration.TpmDevice = TPM_DEVICE_DEFAULT;
+ }
+
+ //
+ // Set value for Tcg2CurrentActivePCRBanks
+ // Search Tcg2ConfigBin[] and update default value there
+ //
+ Status = PrivateData->Tcg2Protocol->GetActivePcrBanks (PrivateData->Tcg2Protocol, &CurrentActivePCRBanks);
+ ASSERT_EFI_ERROR (Status);
+ PrivateData->PCRBanksDesired = CurrentActivePCRBanks;
+ UpdateDefaultPCRBanks (Tcg2ConfigBin + sizeof(UINT32), ReadUnaligned32((UINT32 *)Tcg2ConfigBin) - sizeof(UINT32), CurrentActivePCRBanks);
+
+ //
+ // Sync data from PCD to variable, so that we do not need detect again in S3 phase.
+ //
+ Tcg2DeviceDetection.TpmDeviceDetected = TPM_DEVICE_NULL;
+ for (Index = 0; Index < sizeof(mTpmInstanceId)/sizeof(mTpmInstanceId[0]); Index++) {
+ if (CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &mTpmInstanceId[Index].TpmInstanceGuid)) {
+ Tcg2DeviceDetection.TpmDeviceDetected = mTpmInstanceId[Index].TpmDevice;
+ break;
+ }
+ }
+
+ PrivateData->TpmDeviceDetected = Tcg2DeviceDetection.TpmDeviceDetected;
+ Tcg2Configuration.TpmDevice = Tcg2DeviceDetection.TpmDeviceDetected;
+
+ //
+ // Save to variable so platform driver can get it.
+ //
+ Status = gRT->SetVariable (
+ TCG2_DEVICE_DETECTION_NAME,
+ &gTcg2ConfigFormSetGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ sizeof(Tcg2DeviceDetection),
+ &Tcg2DeviceDetection
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Tcg2ConfigDriver: Fail to set TCG2_DEVICE_DETECTION_NAME\n"));
+ Status = gRT->SetVariable (
+ TCG2_DEVICE_DETECTION_NAME,
+ &gTcg2ConfigFormSetGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ 0,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ //
+ // Save to variable so platform driver can get it.
+ //
+ Status = gRT->SetVariable (
+ TCG2_STORAGE_NAME,
+ &gTcg2ConfigFormSetGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ sizeof(Tcg2Configuration),
+ &Tcg2Configuration
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Tcg2ConfigDriver: Fail to set TCG2_STORAGE_NAME\n"));
+ }
+
+ //
+ // We should lock Tcg2DeviceDetection, because it contains information needed at S3.
+ //
+ Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **)&VariableLockProtocol);
+ if (!EFI_ERROR (Status)) {
+ Status = VariableLockProtocol->RequestToLock (
+ VariableLockProtocol,
+ TCG2_DEVICE_DETECTION_NAME,
+ &gTcg2ConfigFormSetGuid
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ //
+ // Install Tcg2 configuration form
+ //
+ Status = InstallTcg2ConfigForm (PrivateData);
+ if (EFI_ERROR (Status)) {
+ goto ErrorExit;
+ }
+
+ InitializeTcg2VersionInfo (PrivateData);
+
+ return EFI_SUCCESS;
+
+ErrorExit:
+ if (PrivateData != NULL) {
+ UninstallTcg2ConfigForm (PrivateData);
+ }
+
+ return Status;
+}
+
+/**
+ Unload the Tcg2 configuration form.
+
+ @param[in] ImageHandle The driver's image handle.
+
+ @retval EFI_SUCCESS The Tcg2 configuration form is unloaded.
+ @retval Others Failed to unload the form.
+
+**/
+EFI_STATUS
+EFIAPI
+Tcg2ConfigDriverUnload (
+ IN EFI_HANDLE ImageHandle
+ )
+{
+ EFI_STATUS Status;
+ TCG2_CONFIG_PRIVATE_DATA *PrivateData;
+
+ Status = gBS->HandleProtocol (
+ ImageHandle,
+ &gEfiCallerIdGuid,
+ (VOID **) &PrivateData
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ASSERT (PrivateData->Signature == TCG2_CONFIG_PRIVATE_DATA_SIGNATURE);
+
+ gBS->UninstallMultipleProtocolInterfaces (
+ &ImageHandle,
+ &gEfiCallerIdGuid,
+ PrivateData,
+ NULL
+ );
+
+ UninstallTcg2ConfigForm (PrivateData);
+
+ return EFI_SUCCESS;
+}
diff --git a/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDxe.inf b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDxe.inf
new file mode 100644
index 0000000000..38fa331701
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDxe.inf
@@ -0,0 +1,91 @@
+## @file
+# TPM device configuration for TPM 2.0
+#
+# By this module, user may select TPM device, clear TPM state, etc.
+# NOTE: This module is only for reference only, each platform should have its own setup page.
+#
+# Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = Tcg2ConfigDxe
+ MODULE_UNI_FILE = Tcg2ConfigDxe.uni
+ FILE_GUID = 4D9CBEF0-15A0-4D0C-83DB-5213E710C23F
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = Tcg2ConfigDriverEntryPoint
+ UNLOAD_IMAGE = Tcg2ConfigDriverUnload
+
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ Tcg2ConfigDriver.c
+ Tcg2ConfigImpl.c
+ Tcg2ConfigImpl.h
+ Tcg2Config.vfr
+ Tcg2ConfigStrings.uni
+ Tcg2ConfigNvData.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ MemoryAllocationLib
+ UefiLib
+ UefiBootServicesTableLib
+ UefiRuntimeServicesTableLib
+ UefiDriverEntryPoint
+ UefiHiiServicesLib
+ DebugLib
+ HiiLib
+ PcdLib
+ PrintLib
+ Tpm2DeviceLib
+ Tpm2CommandLib
+ Tcg2PhysicalPresenceLib
+ IoLib
+
+[Guids]
+ ## PRODUCES ## HII
+ ## SOMETIMES_PRODUCES ## Variable:L"TCG2_CONFIGURATION"
+ ## SOMETIMES_CONSUMES ## Variable:L"TCG2_CONFIGURATION"
+ ## PRODUCES ## Variable:L"TCG2_DEVICE_DETECTION"
+ ## SOMETIMES_CONSUMES ## Variable:L"TCG2_DEVICE_DETECTION"
+ gTcg2ConfigFormSetGuid
+
+[Protocols]
+ gEfiHiiConfigAccessProtocolGuid ## PRODUCES
+ gEfiDevicePathProtocolGuid ## PRODUCES
+ gEdkiiVariableLockProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiTcg2ProtocolGuid ## CONSUMES
+
+[Pcd]
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpmInstanceGuid ## CONSUMES
+ gEfiSecurityPkgTokenSpaceGuid.PcdTcg2HashAlgorithmBitmap ## CONSUMES
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpmBaseAddress ## CONSUMES
+ gEfiSecurityPkgTokenSpaceGuid.PcdTcgPhysicalPresenceInterfaceVer ## CONSUMES
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpm2AcpiTableRev ## CONSUMES
+
+[Depex]
+ gEfiTcg2ProtocolGuid AND
+ gEfiHiiConfigRoutingProtocolGuid AND
+ gEfiHiiDatabaseProtocolGuid AND
+ gEfiVariableArchProtocolGuid AND
+ gEfiVariableWriteArchProtocolGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ Tcg2ConfigDxeExtra.uni
diff --git a/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDxe.uni b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDxe.uni
new file mode 100644
index 0000000000..ee7219ee5b
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDxe.uni
@@ -0,0 +1,22 @@
+// /** @file
+// TPM device configuration for TPM 2.0
+//
+// By this module, user may select TPM device, clear TPM state, etc.
+// NOTE: This module is only for reference only, each platform should have its own setup page.
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "TPM device configuration for TPM 2.0"
+
+#string STR_MODULE_DESCRIPTION #language en-US "By this module, user may select TPM device, clear TPM state, etc. NOTE: This module is only for reference only, each platform should have its own setup page."
+
diff --git a/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDxeExtra.uni b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDxeExtra.uni
new file mode 100644
index 0000000000..37f81e17bd
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDxeExtra.uni
@@ -0,0 +1,19 @@
+// /** @file
+// Tcg2ConfigDxe Localized Strings and Content
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"TCG2 (Trusted Computing Group) Configuration DXE"
+
+
diff --git a/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigImpl.c b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigImpl.c
new file mode 100644
index 0000000000..b3a849e918
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigImpl.c
@@ -0,0 +1,1032 @@
+/** @file
+ HII Config Access protocol implementation of TCG2 configuration module.
+ NOTE: This module is only for reference only, each platform should have its own setup page.
+
+Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "Tcg2ConfigImpl.h"
+#include <Library/PcdLib.h>
+#include <Library/Tpm2CommandLib.h>
+#include <Library/IoLib.h>
+#include <Guid/TpmInstance.h>
+
+#include <IndustryStandard/TpmPtp.h>
+
+#define EFI_TCG2_EVENT_LOG_FORMAT_ALL (EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2 | EFI_TCG2_EVENT_LOG_FORMAT_TCG_2)
+
+TPM_INSTANCE_ID mTpmInstanceId[TPM_DEVICE_MAX + 1] = TPM_INSTANCE_ID_LIST;
+
+TCG2_CONFIG_PRIVATE_DATA *mTcg2ConfigPrivateDate;
+TCG2_CONFIG_PRIVATE_DATA mTcg2ConfigPrivateDateTemplate = {
+ TCG2_CONFIG_PRIVATE_DATA_SIGNATURE,
+ {
+ Tcg2ExtractConfig,
+ Tcg2RouteConfig,
+ Tcg2Callback
+ }
+};
+
+HII_VENDOR_DEVICE_PATH mTcg2HiiVendorDevicePath = {
+ {
+ {
+ HARDWARE_DEVICE_PATH,
+ HW_VENDOR_DP,
+ {
+ (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
+ (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
+ }
+ },
+ TCG2_CONFIG_FORM_SET_GUID
+ },
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ (UINT8) (END_DEVICE_PATH_LENGTH),
+ (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
+ }
+ }
+};
+
+UINT8 mCurrentPpRequest;
+
+/**
+ Return PTP interface type.
+
+ @param[in] Register Pointer to PTP register.
+
+ @return PTP interface type.
+**/
+UINT8
+GetPtpInterface (
+ IN VOID *Register
+ )
+{
+ PTP_CRB_INTERFACE_IDENTIFIER InterfaceId;
+ PTP_FIFO_INTERFACE_CAPABILITY InterfaceCapability;
+
+ //
+ // Check interface id
+ //
+ InterfaceId.Uint32 = MmioRead32 ((UINTN)&((PTP_CRB_REGISTERS *)Register)->InterfaceId);
+ InterfaceCapability.Uint32 = MmioRead32 ((UINTN)&((PTP_FIFO_REGISTERS *)Register)->InterfaceCapability);
+
+ if ((InterfaceId.Bits.InterfaceType == PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_CRB) &&
+ (InterfaceId.Bits.InterfaceVersion == PTP_INTERFACE_IDENTIFIER_INTERFACE_VERSION_CRB) &&
+ (InterfaceId.Bits.CapCRB != 0)) {
+ return TPM_DEVICE_INTERFACE_PTP_CRB;
+ }
+ if ((InterfaceId.Bits.InterfaceType == PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_FIFO) &&
+ (InterfaceId.Bits.InterfaceVersion == PTP_INTERFACE_IDENTIFIER_INTERFACE_VERSION_FIFO) &&
+ (InterfaceId.Bits.CapFIFO != 0) &&
+ (InterfaceCapability.Bits.InterfaceVersion == INTERFACE_CAPABILITY_INTERFACE_VERSION_PTP)) {
+ return TPM_DEVICE_INTERFACE_PTP_FIFO;
+ }
+ return TPM_DEVICE_INTERFACE_TIS;
+}
+
+/**
+ Return if PTP CRB is supported.
+
+ @param[in] Register Pointer to PTP register.
+
+ @retval TRUE PTP CRB is supported.
+ @retval FALSE PTP CRB is unsupported.
+**/
+BOOLEAN
+IsPtpCrbSupported (
+ IN VOID *Register
+ )
+{
+ PTP_CRB_INTERFACE_IDENTIFIER InterfaceId;
+
+ //
+ // Check interface id
+ //
+ InterfaceId.Uint32 = MmioRead32 ((UINTN)&((PTP_CRB_REGISTERS *)Register)->InterfaceId);
+
+ if (((InterfaceId.Bits.InterfaceType == PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_CRB) ||
+ (InterfaceId.Bits.InterfaceType == PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_FIFO)) &&
+ (InterfaceId.Bits.CapCRB != 0)) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ Return if PTP FIFO is supported.
+
+ @param[in] Register Pointer to PTP register.
+
+ @retval TRUE PTP FIFO is supported.
+ @retval FALSE PTP FIFO is unsupported.
+**/
+BOOLEAN
+IsPtpFifoSupported (
+ IN VOID *Register
+ )
+{
+ PTP_CRB_INTERFACE_IDENTIFIER InterfaceId;
+
+ //
+ // Check interface id
+ //
+ InterfaceId.Uint32 = MmioRead32 ((UINTN)&((PTP_CRB_REGISTERS *)Register)->InterfaceId);
+
+ if (((InterfaceId.Bits.InterfaceType == PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_CRB) ||
+ (InterfaceId.Bits.InterfaceType == PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_FIFO)) &&
+ (InterfaceId.Bits.CapFIFO != 0)) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ Set PTP interface type.
+
+ @param[in] Register Pointer to PTP register.
+ @param[in] PtpInterface PTP interface type.
+
+ @retval EFI_SUCCESS PTP interface type is set.
+ @retval EFI_INVALID_PARAMETER PTP interface type is invalid.
+ @retval EFI_UNSUPPORTED PTP interface type is unsupported.
+ @retval EFI_WRITE_PROTECTED PTP interface is locked.
+**/
+EFI_STATUS
+SetPtpInterface (
+ IN VOID *Register,
+ IN UINT8 PtpInterface
+ )
+{
+ UINT8 PtpInterfaceCurrent;
+ PTP_CRB_INTERFACE_IDENTIFIER InterfaceId;
+
+ PtpInterfaceCurrent = GetPtpInterface (Register);
+ if ((PtpInterfaceCurrent != TPM_DEVICE_INTERFACE_PTP_FIFO) &&
+ (PtpInterfaceCurrent != TPM_DEVICE_INTERFACE_PTP_CRB)) {
+ return EFI_UNSUPPORTED;
+ }
+ InterfaceId.Uint32 = MmioRead32 ((UINTN)&((PTP_CRB_REGISTERS *)Register)->InterfaceId);
+ if (InterfaceId.Bits.IntfSelLock != 0) {
+ return EFI_WRITE_PROTECTED;
+ }
+
+ switch (PtpInterface) {
+ case TPM_DEVICE_INTERFACE_PTP_FIFO:
+ if (InterfaceId.Bits.CapFIFO == 0) {
+ return EFI_UNSUPPORTED;
+ }
+ InterfaceId.Bits.InterfaceSelector = PTP_INTERFACE_IDENTIFIER_INTERFACE_SELECTOR_FIFO;
+ MmioWrite32 ((UINTN)&((PTP_CRB_REGISTERS *)Register)->InterfaceId, InterfaceId.Uint32);
+ return EFI_SUCCESS;
+ case TPM_DEVICE_INTERFACE_PTP_CRB:
+ if (InterfaceId.Bits.CapCRB == 0) {
+ return EFI_UNSUPPORTED;
+ }
+ InterfaceId.Bits.InterfaceSelector = PTP_INTERFACE_IDENTIFIER_INTERFACE_SELECTOR_CRB;
+ MmioWrite32 ((UINTN)&((PTP_CRB_REGISTERS *)Register)->InterfaceId, InterfaceId.Uint32);
+ return EFI_SUCCESS;
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+}
+
+/**
+ This function allows a caller to extract the current configuration for one
+ or more named elements from the target driver.
+
+ @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param[in] Request A null-terminated Unicode string in
+ <ConfigRequest> format.
+ @param[out] Progress On return, points to a character in the Request
+ string. Points to the string's null terminator if
+ request was successful. Points to the most recent
+ '&' before the first failing name/value pair (or
+ the beginning of the string if the failure is in
+ the first name/value pair) if the request was not
+ successful.
+ @param[out] Results A null-terminated Unicode string in
+ <ConfigAltResp> format which has all values filled
+ in for the names in the Request string. String to
+ be allocated by the called function.
+
+ @retval EFI_SUCCESS The Results is filled with the requested values.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results.
+ @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name.
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in this
+ driver.
+
+**/
+EFI_STATUS
+EFIAPI
+Tcg2ExtractConfig (
+ 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;
+}
+
+/**
+ 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
+SaveTcg2PpRequest (
+ IN UINT8 PpRequest
+ )
+{
+ UINT32 ReturnCode;
+ EFI_STATUS Status;
+
+ ReturnCode = Tcg2PhysicalPresenceLibSubmitRequestToPreOSFunction (PpRequest, 0);
+ if (ReturnCode == TCG_PP_SUBMIT_REQUEST_TO_PREOS_SUCCESS) {
+ mCurrentPpRequest = PpRequest;
+ Status = EFI_SUCCESS;
+ } else if (ReturnCode == TCG_PP_SUBMIT_REQUEST_TO_PREOS_GENERAL_FAILURE) {
+ Status = EFI_OUT_OF_RESOURCES;
+ } else if (ReturnCode == TCG_PP_SUBMIT_REQUEST_TO_PREOS_NOT_IMPLEMENTED) {
+ Status = EFI_UNSUPPORTED;
+ } else {
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ return Status;
+}
+
+/**
+ Save TPM request to variable space.
+
+ @param[in] PpRequestParameter Physical Presence request parameter.
+
+ @retval EFI_SUCCESS The operation is finished successfully.
+ @retval Others Other errors as indicated.
+
+**/
+EFI_STATUS
+SaveTcg2PpRequestParameter (
+ IN UINT32 PpRequestParameter
+ )
+{
+ UINT32 ReturnCode;
+ EFI_STATUS Status;
+
+ ReturnCode = Tcg2PhysicalPresenceLibSubmitRequestToPreOSFunction (mCurrentPpRequest, PpRequestParameter);
+ if (ReturnCode == TCG_PP_SUBMIT_REQUEST_TO_PREOS_SUCCESS) {
+ Status = EFI_SUCCESS;
+ } else if (ReturnCode == TCG_PP_SUBMIT_REQUEST_TO_PREOS_GENERAL_FAILURE) {
+ Status = EFI_OUT_OF_RESOURCES;
+ } else if (ReturnCode == TCG_PP_SUBMIT_REQUEST_TO_PREOS_NOT_IMPLEMENTED) {
+ Status = EFI_UNSUPPORTED;
+ } else {
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ return Status;
+}
+
+/**
+ Save Tcg2 PCR Banks request request to variable space.
+
+ @param[in] PCRBankIndex PCR Bank Index.
+ @param[in] Enable Enable or disable this PCR Bank.
+
+ @retval EFI_SUCCESS The operation is finished successfully.
+ @retval Others Other errors as indicated.
+
+**/
+EFI_STATUS
+SaveTcg2PCRBanksRequest (
+ IN UINTN PCRBankIndex,
+ IN BOOLEAN Enable
+ )
+{
+ UINT32 ReturnCode;
+ EFI_STATUS Status;
+
+ if (Enable) {
+ mTcg2ConfigPrivateDate->PCRBanksDesired |= (0x1 << PCRBankIndex);
+ } else {
+ mTcg2ConfigPrivateDate->PCRBanksDesired &= ~(0x1 << PCRBankIndex);
+ }
+
+ ReturnCode = Tcg2PhysicalPresenceLibSubmitRequestToPreOSFunction (TCG2_PHYSICAL_PRESENCE_SET_PCR_BANKS, mTcg2ConfigPrivateDate->PCRBanksDesired);
+ if (ReturnCode == TCG_PP_SUBMIT_REQUEST_TO_PREOS_SUCCESS) {
+ Status = EFI_SUCCESS;
+ } else if (ReturnCode == TCG_PP_SUBMIT_REQUEST_TO_PREOS_GENERAL_FAILURE) {
+ Status = EFI_OUT_OF_RESOURCES;
+ } else if (ReturnCode == TCG_PP_SUBMIT_REQUEST_TO_PREOS_NOT_IMPLEMENTED) {
+ Status = EFI_UNSUPPORTED;
+ } else {
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ 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 <ConfigResp>
+ 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
+Tcg2RouteConfig (
+ 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;
+}
+
+/**
+ Get HID string of TPM2 ACPI device object
+
+ @param[in] Hid Points to HID String Buffer.
+ @param[in] Size HID String size in bytes. Must >= TPM_HID_ACPI_SIZE
+
+ @return HID String get status.
+
+**/
+EFI_STATUS
+GetTpm2HID(
+ CHAR8 *Hid,
+ UINTN Size
+ )
+{
+ EFI_STATUS Status;
+ UINT32 ManufacturerID;
+ UINT32 FirmwareVersion1;
+ UINT32 FirmwareVersion2;
+ BOOLEAN PnpHID;
+
+ PnpHID = TRUE;
+
+ ZeroMem(Hid, Size);
+
+ //
+ // Get Manufacturer ID
+ //
+ Status = Tpm2GetCapabilityManufactureID(&ManufacturerID);
+ if (!EFI_ERROR(Status)) {
+ DEBUG((DEBUG_INFO, "TPM_PT_MANUFACTURER 0x%08x\n", ManufacturerID));
+ //
+ // ManufacturerID defined in TCG Vendor ID Registry
+ // may tailed with 0x00 or 0x20
+ //
+ if ((ManufacturerID >> 24) == 0x00 || ((ManufacturerID >> 24) == 0x20)) {
+ //
+ // HID containing PNP ID "NNN####"
+ // NNN is uppercase letter for Vendor ID specified by manufacturer
+ //
+ CopyMem(Hid, &ManufacturerID, 3);
+ } else {
+ //
+ // HID containing ACP ID "NNNN####"
+ // NNNN is uppercase letter for Vendor ID specified by manufacturer
+ //
+ CopyMem(Hid, &ManufacturerID, 4);
+ PnpHID = FALSE;
+ }
+ } else {
+ DEBUG ((DEBUG_ERROR, "Get TPM_PT_MANUFACTURER failed %x!\n", Status));
+ ASSERT(FALSE);
+ return Status;
+ }
+
+ Status = Tpm2GetCapabilityFirmwareVersion(&FirmwareVersion1, &FirmwareVersion2);
+ if (!EFI_ERROR(Status)) {
+ DEBUG((DEBUG_INFO, "TPM_PT_FIRMWARE_VERSION_1 0x%x\n", FirmwareVersion1));
+ DEBUG((DEBUG_INFO, "TPM_PT_FIRMWARE_VERSION_2 0x%x\n", FirmwareVersion2));
+ //
+ // #### is Firmware Version 1
+ //
+ if (PnpHID) {
+ AsciiSPrint(Hid + 3, TPM_HID_PNP_SIZE - 3, "%02d%02d", ((FirmwareVersion1 & 0xFFFF0000) >> 16), (FirmwareVersion1 & 0x0000FFFF));
+ } else {
+ AsciiSPrint(Hid + 4, TPM_HID_ACPI_SIZE - 4, "%02d%02d", ((FirmwareVersion1 & 0xFFFF0000) >> 16), (FirmwareVersion1 & 0x0000FFFF));
+ }
+
+ } else {
+ DEBUG ((DEBUG_ERROR, "Get TPM_PT_FIRMWARE_VERSION_X failed %x!\n", Status));
+ ASSERT(FALSE);
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function processes the results of changes in configuration
+ for TCG2 version information.
+
+ @param[in] Action Specifies the type of action taken by the browser.
+ ASSERT if the Action is not EFI_BROWSER_ACTION_SUBMITTED.
+ @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.
+
+ @retval EFI_SUCCESS The callback successfully handled the action.
+
+**/
+EFI_STATUS
+Tcg2VersionInfoCallback (
+ IN EFI_BROWSER_ACTION Action,
+ IN EFI_QUESTION_ID QuestionId,
+ IN UINT8 Type,
+ IN EFI_IFR_TYPE_VALUE *Value
+ )
+{
+ EFI_INPUT_KEY Key;
+ UINT64 PcdTcg2PpiVersion;
+ UINT8 PcdTpm2AcpiTableRev;
+
+ ASSERT (Action == EFI_BROWSER_ACTION_SUBMITTED);
+
+ if (QuestionId == KEY_TCG2_PPI_VERSION) {
+ //
+ // Get the PCD value after EFI_BROWSER_ACTION_SUBMITTED,
+ // the SetVariable to TCG2_VERSION_NAME should have been done.
+ // If the PCD value is not equal to the value set to variable,
+ // the PCD is not DynamicHii type and does not map to the setup option.
+ //
+ PcdTcg2PpiVersion = 0;
+ CopyMem (
+ &PcdTcg2PpiVersion,
+ PcdGetPtr (PcdTcgPhysicalPresenceInterfaceVer),
+ AsciiStrSize ((CHAR8 *) PcdGetPtr (PcdTcgPhysicalPresenceInterfaceVer))
+ );
+ if (PcdTcg2PpiVersion != Value->u64) {
+ CreatePopUp (
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
+ &Key,
+ L"WARNING: PcdTcgPhysicalPresenceInterfaceVer is not DynamicHii type and does not map to this option!",
+ L"The version configuring by this setup option will not work!",
+ NULL
+ );
+ }
+ } else if (QuestionId == KEY_TPM2_ACPI_REVISION){
+ //
+ // Get the PCD value after EFI_BROWSER_ACTION_SUBMITTED,
+ // the SetVariable to TCG2_VERSION_NAME should have been done.
+ // If the PCD value is not equal to the value set to variable,
+ // the PCD is not DynamicHii type and does not map to the setup option.
+ //
+ PcdTpm2AcpiTableRev = PcdGet8 (PcdTpm2AcpiTableRev);
+
+ if (PcdTpm2AcpiTableRev != Value->u8) {
+ CreatePopUp (
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
+ &Key,
+ L"WARNING: PcdTpm2AcpiTableRev is not DynamicHii type and does not map to this option!",
+ L"The Revision configuring by this setup option will not work!",
+ 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
+Tcg2Callback (
+ 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 HidStr[16];
+ CHAR16 UnHidStr[16];
+ TCG2_CONFIG_PRIVATE_DATA *Private;
+
+ if ((This == NULL) || (Value == NULL) || (ActionRequest == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = TCG2_CONFIG_PRIVATE_DATA_FROM_THIS (This);
+
+ if (Action == EFI_BROWSER_ACTION_FORM_OPEN) {
+ //
+ // Update TPM2 HID info
+ //
+ if (QuestionId == KEY_TPM_DEVICE) {
+ Status = GetTpm2HID(HidStr, 16);
+
+ if (EFI_ERROR(Status)) {
+ //
+ // Fail to get TPM2 HID
+ //
+ HiiSetString (Private->HiiHandle, STRING_TOKEN (STR_TPM2_ACPI_HID_CONTENT), L"Unknown", NULL);
+ } else {
+ AsciiStrToUnicodeStrS(HidStr, UnHidStr, 16);
+ HiiSetString (Private->HiiHandle, STRING_TOKEN (STR_TPM2_ACPI_HID_CONTENT), UnHidStr, NULL);
+ }
+ }
+ return EFI_SUCCESS;
+ }
+
+ if (Action == EFI_BROWSER_ACTION_CHANGING) {
+ if (QuestionId == KEY_TPM_DEVICE_INTERFACE) {
+ Status = SetPtpInterface ((VOID *) (UINTN) PcdGet64 (PcdTpmBaseAddress), Value->u8);
+ if (EFI_ERROR (Status)) {
+ CreatePopUp (
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
+ &Key,
+ L"Error: Fail to set PTP interface!",
+ NULL
+ );
+ return EFI_DEVICE_ERROR;
+ }
+ }
+ }
+
+ if (Action == EFI_BROWSER_ACTION_CHANGED) {
+ if (QuestionId == KEY_TPM_DEVICE) {
+ return EFI_SUCCESS;
+ }
+ if (QuestionId == KEY_TPM2_OPERATION) {
+ return SaveTcg2PpRequest (Value->u8);
+ }
+ if (QuestionId == KEY_TPM2_OPERATION_PARAMETER) {
+ return SaveTcg2PpRequestParameter (Value->u32);
+ }
+ if ((QuestionId >= KEY_TPM2_PCR_BANKS_REQUEST_0) && (QuestionId <= KEY_TPM2_PCR_BANKS_REQUEST_4)) {
+ return SaveTcg2PCRBanksRequest (QuestionId - KEY_TPM2_PCR_BANKS_REQUEST_0, Value->b);
+ }
+ }
+
+ if (Action == EFI_BROWSER_ACTION_SUBMITTED) {
+ if (QuestionId == KEY_TCG2_PPI_VERSION || QuestionId == KEY_TPM2_ACPI_REVISION) {
+ return Tcg2VersionInfoCallback (Action, QuestionId, Type, Value);
+ }
+ }
+
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Append Buffer With TpmAlgHash.
+
+ @param[in] Buffer Buffer to be appended.
+ @param[in] BufferSize Size of buffer.
+ @param[in] TpmAlgHash TpmAlgHash.
+
+**/
+VOID
+AppendBufferWithTpmAlgHash (
+ IN UINT16 *Buffer,
+ IN UINTN BufferSize,
+ IN UINT32 TpmAlgHash
+ )
+{
+ switch (TpmAlgHash) {
+ case TPM_ALG_SHA1:
+ if (Buffer[0] != 0) {
+ StrCatS (Buffer, BufferSize / sizeof (CHAR16), L", ");
+ }
+ StrCatS (Buffer, BufferSize / sizeof (CHAR16), L"SHA1");
+ break;
+ case TPM_ALG_SHA256:
+ if (Buffer[0] != 0) {
+ StrCatS (Buffer, BufferSize / sizeof (CHAR16), L", ");
+ }
+ StrCatS (Buffer, BufferSize / sizeof (CHAR16), L"SHA256");
+ break;
+ case TPM_ALG_SHA384:
+ if (Buffer[0] != 0) {
+ StrCatS (Buffer, BufferSize / sizeof (CHAR16), L", ");
+ }
+ StrCatS (Buffer, BufferSize / sizeof (CHAR16), L"SHA384");
+ break;
+ case TPM_ALG_SHA512:
+ if (Buffer[0] != 0) {
+ StrCatS (Buffer, BufferSize / sizeof (CHAR16), L", ");
+ }
+ StrCatS (Buffer, BufferSize / sizeof (CHAR16), L"SHA512");
+ break;
+ case TPM_ALG_SM3_256:
+ if (Buffer[0] != 0) {
+ StrCatS (Buffer, BufferSize / sizeof (CHAR16), L", ");
+ }
+ StrCatS (Buffer, BufferSize / sizeof (CHAR16), L"SM3_256");
+ break;
+ }
+}
+
+/**
+ Fill Buffer With BootHashAlg.
+
+ @param[in] Buffer Buffer to be filled.
+ @param[in] BufferSize Size of buffer.
+ @param[in] BootHashAlg BootHashAlg.
+
+**/
+VOID
+FillBufferWithBootHashAlg (
+ IN UINT16 *Buffer,
+ IN UINTN BufferSize,
+ IN UINT32 BootHashAlg
+ )
+{
+ Buffer[0] = 0;
+ if ((BootHashAlg & EFI_TCG2_BOOT_HASH_ALG_SHA1) != 0) {
+ if (Buffer[0] != 0) {
+ StrCatS (Buffer, BufferSize / sizeof (CHAR16), L", ");
+ }
+ StrCatS (Buffer, BufferSize / sizeof (CHAR16), L"SHA1");
+ }
+ if ((BootHashAlg & EFI_TCG2_BOOT_HASH_ALG_SHA256) != 0) {
+ if (Buffer[0] != 0) {
+ StrCatS (Buffer, BufferSize / sizeof (CHAR16), L", ");
+ }
+ StrCatS (Buffer, BufferSize / sizeof (CHAR16), L"SHA256");
+ }
+ if ((BootHashAlg & EFI_TCG2_BOOT_HASH_ALG_SHA384) != 0) {
+ if (Buffer[0] != 0) {
+ StrCatS (Buffer, BufferSize / sizeof (CHAR16), L", ");
+ }
+ StrCatS (Buffer, BufferSize / sizeof (CHAR16), L"SHA384");
+ }
+ if ((BootHashAlg & EFI_TCG2_BOOT_HASH_ALG_SHA512) != 0) {
+ if (Buffer[0] != 0) {
+ StrCatS (Buffer, BufferSize / sizeof (CHAR16), L", ");
+ }
+ StrCatS (Buffer, BufferSize / sizeof (CHAR16), L"SHA512");
+ }
+ if ((BootHashAlg & EFI_TCG2_BOOT_HASH_ALG_SM3_256) != 0) {
+ if (Buffer[0] != 0) {
+ StrCatS (Buffer, BufferSize / sizeof (CHAR16), L", ");
+ }
+ StrCatS (Buffer, BufferSize / sizeof (CHAR16), L"SM3_256");
+ }
+}
+
+/**
+ Set ConfigInfo according to TpmAlgHash.
+
+ @param[in,out] Tcg2ConfigInfo TCG2 config info.
+ @param[in] TpmAlgHash TpmAlgHash.
+
+**/
+VOID
+SetConfigInfo (
+ IN OUT TCG2_CONFIGURATION_INFO *Tcg2ConfigInfo,
+ IN UINT32 TpmAlgHash
+ )
+{
+ switch (TpmAlgHash) {
+ case TPM_ALG_SHA1:
+ Tcg2ConfigInfo->Sha1Supported = TRUE;
+ break;
+ case TPM_ALG_SHA256:
+ Tcg2ConfigInfo->Sha256Supported = TRUE;
+ break;
+ case TPM_ALG_SHA384:
+ Tcg2ConfigInfo->Sha384Supported = TRUE;
+ break;
+ case TPM_ALG_SHA512:
+ Tcg2ConfigInfo->Sha512Supported = TRUE;
+ break;
+ case TPM_ALG_SM3_256:
+ Tcg2ConfigInfo->Sm3Supported = TRUE;
+ break;
+ }
+}
+
+/**
+ Fill Buffer With TCG2EventLogFormat.
+
+ @param[in] Buffer Buffer to be filled.
+ @param[in] BufferSize Size of buffer.
+ @param[in] TCG2EventLogFormat TCG2EventLogFormat.
+
+**/
+VOID
+FillBufferWithTCG2EventLogFormat (
+ IN UINT16 *Buffer,
+ IN UINTN BufferSize,
+ IN UINT32 TCG2EventLogFormat
+ )
+{
+ Buffer[0] = 0;
+ if ((TCG2EventLogFormat & EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2) != 0) {
+ if (Buffer[0] != 0) {
+ StrCatS (Buffer, BufferSize / sizeof (CHAR16), L", ");
+ }
+ StrCatS (Buffer, BufferSize / sizeof (CHAR16), L"TCG_1_2");
+ }
+ if ((TCG2EventLogFormat & EFI_TCG2_EVENT_LOG_FORMAT_TCG_2) != 0) {
+ if (Buffer[0] != 0) {
+ StrCatS (Buffer, BufferSize / sizeof (CHAR16), L", ");
+ }
+ StrCatS (Buffer, BufferSize / sizeof (CHAR16), L"TCG_2");
+ }
+ if ((TCG2EventLogFormat & (~EFI_TCG2_EVENT_LOG_FORMAT_ALL)) != 0) {
+ if (Buffer[0] != 0) {
+ StrCatS (Buffer, BufferSize / sizeof (CHAR16), L", ");
+ }
+ StrCatS (Buffer, BufferSize / sizeof (CHAR16), L"UNKNOWN");
+ }
+}
+
+/**
+ This function publish the TCG2 configuration Form for TPM device.
+
+ @param[in, out] PrivateData Points to TCG2 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
+InstallTcg2ConfigForm (
+ IN OUT TCG2_CONFIG_PRIVATE_DATA *PrivateData
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_HANDLE HiiHandle;
+ EFI_HANDLE DriverHandle;
+ EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
+ UINTN Index;
+ TPML_PCR_SELECTION Pcrs;
+ CHAR16 TempBuffer[1024];
+ TCG2_CONFIGURATION_INFO Tcg2ConfigInfo;
+ UINT8 TpmDeviceInterfaceDetected;
+
+ DriverHandle = NULL;
+ ConfigAccess = &PrivateData->ConfigAccess;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &DriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mTcg2HiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ ConfigAccess,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ PrivateData->DriverHandle = DriverHandle;
+
+ //
+ // Publish the HII package list
+ //
+ HiiHandle = HiiAddPackages (
+ &gTcg2ConfigFormSetGuid,
+ DriverHandle,
+ Tcg2ConfigDxeStrings,
+ Tcg2ConfigBin,
+ NULL
+ );
+ if (HiiHandle == NULL) {
+ gBS->UninstallMultipleProtocolInterfaces (
+ DriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mTcg2HiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ ConfigAccess,
+ NULL
+ );
+
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ PrivateData->HiiHandle = HiiHandle;
+
+ //
+ // Update static data
+ //
+ switch (PrivateData->TpmDeviceDetected) {
+ case TPM_DEVICE_NULL:
+ HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_TCG2_DEVICE_STATE_CONTENT), L"Not Found", NULL);
+ break;
+ case TPM_DEVICE_1_2:
+ HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_TCG2_DEVICE_STATE_CONTENT), L"TPM 1.2", NULL);
+ break;
+ case TPM_DEVICE_2_0_DTPM:
+ HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_TCG2_DEVICE_STATE_CONTENT), L"TPM 2.0", NULL);
+ break;
+ default:
+ HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_TCG2_DEVICE_STATE_CONTENT), L"Unknown", NULL);
+ break;
+ }
+
+ ZeroMem (&Tcg2ConfigInfo, sizeof(Tcg2ConfigInfo));
+ Status = Tpm2GetCapabilityPcrs (&Pcrs);
+ if (EFI_ERROR (Status)) {
+ HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_TPM2_ACTIVE_HASH_ALGO_CONTENT), L"[Unknown]", NULL);
+ HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_TPM2_SUPPORTED_HASH_ALGO_CONTENT), L"[Unknown]", NULL);
+ } else {
+ TempBuffer[0] = 0;
+ for (Index = 0; Index < Pcrs.count; Index++) {
+ if (!IsZeroBuffer (Pcrs.pcrSelections[Index].pcrSelect, Pcrs.pcrSelections[Index].sizeofSelect)) {
+ AppendBufferWithTpmAlgHash (TempBuffer, sizeof(TempBuffer), Pcrs.pcrSelections[Index].hash);
+ }
+ }
+ HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_TPM2_ACTIVE_HASH_ALGO_CONTENT), TempBuffer, NULL);
+
+ TempBuffer[0] = 0;
+ for (Index = 0; Index < Pcrs.count; Index++) {
+ AppendBufferWithTpmAlgHash (TempBuffer, sizeof(TempBuffer), Pcrs.pcrSelections[Index].hash);
+ SetConfigInfo (&Tcg2ConfigInfo, Pcrs.pcrSelections[Index].hash);
+ }
+ HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_TPM2_SUPPORTED_HASH_ALGO_CONTENT), TempBuffer, NULL);
+ }
+
+ FillBufferWithBootHashAlg (TempBuffer, sizeof(TempBuffer), PcdGet32 (PcdTcg2HashAlgorithmBitmap));
+ HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_BIOS_HASH_ALGO_CONTENT), TempBuffer, NULL);
+
+ //
+ // Tcg2 Capability
+ //
+ FillBufferWithTCG2EventLogFormat (TempBuffer, sizeof(TempBuffer), PrivateData->ProtocolCapability.SupportedEventLogs);
+ HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_TCG2_SUPPORTED_EVENT_LOG_FORMAT_CONTENT), TempBuffer, NULL);
+
+ FillBufferWithBootHashAlg (TempBuffer, sizeof(TempBuffer), PrivateData->ProtocolCapability.HashAlgorithmBitmap);
+ HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_TCG2_HASH_ALGO_BITMAP_CONTENT), TempBuffer, NULL);
+
+ UnicodeSPrint (TempBuffer, sizeof (TempBuffer), L"%d", PrivateData->ProtocolCapability.NumberOfPCRBanks);
+ HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_TCG2_NUMBER_OF_PCR_BANKS_CONTENT), TempBuffer, NULL);
+
+ FillBufferWithBootHashAlg (TempBuffer, sizeof(TempBuffer), PrivateData->ProtocolCapability.ActivePcrBanks);
+ HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_TCG2_ACTIVE_PCR_BANKS_CONTENT), TempBuffer, NULL);
+
+ //
+ // Update TPM device interface type
+ //
+ if (PrivateData->TpmDeviceDetected == TPM_DEVICE_2_0_DTPM) {
+ TpmDeviceInterfaceDetected = GetPtpInterface ((VOID *) (UINTN) PcdGet64 (PcdTpmBaseAddress));
+ switch (TpmDeviceInterfaceDetected) {
+ case TPM_DEVICE_INTERFACE_TIS:
+ HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_TCG2_DEVICE_INTERFACE_STATE_CONTENT), L"TIS", NULL);
+ break;
+ case TPM_DEVICE_INTERFACE_PTP_FIFO:
+ HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_TCG2_DEVICE_INTERFACE_STATE_CONTENT), L"PTP FIFO", NULL);
+ break;
+ case TPM_DEVICE_INTERFACE_PTP_CRB:
+ HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_TCG2_DEVICE_INTERFACE_STATE_CONTENT), L"PTP CRB", NULL);
+ break;
+ default:
+ HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_TCG2_DEVICE_INTERFACE_STATE_CONTENT), L"Unknown", NULL);
+ break;
+ }
+
+ Tcg2ConfigInfo.TpmDeviceInterfaceAttempt = TpmDeviceInterfaceDetected;
+ switch (TpmDeviceInterfaceDetected) {
+ case TPM_DEVICE_INTERFACE_TIS:
+ Tcg2ConfigInfo.TpmDeviceInterfacePtpFifoSupported = FALSE;
+ Tcg2ConfigInfo.TpmDeviceInterfacePtpCrbSupported = FALSE;
+ HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_TCG2_DEVICE_INTERFACE_CAPABILITY_CONTENT), L"TIS", NULL);
+ break;
+ case TPM_DEVICE_INTERFACE_PTP_FIFO:
+ case TPM_DEVICE_INTERFACE_PTP_CRB:
+ Tcg2ConfigInfo.TpmDeviceInterfacePtpFifoSupported = IsPtpFifoSupported((VOID *) (UINTN) PcdGet64 (PcdTpmBaseAddress));
+ Tcg2ConfigInfo.TpmDeviceInterfacePtpCrbSupported = IsPtpCrbSupported((VOID *) (UINTN) PcdGet64 (PcdTpmBaseAddress));
+ TempBuffer[0] = 0;
+ if (Tcg2ConfigInfo.TpmDeviceInterfacePtpFifoSupported) {
+ if (TempBuffer[0] != 0) {
+ StrCatS (TempBuffer, sizeof(TempBuffer) / sizeof (CHAR16), L", ");
+ }
+ StrCatS (TempBuffer, sizeof(TempBuffer) / sizeof (CHAR16), L"PTP FIFO");
+ }
+ if (Tcg2ConfigInfo.TpmDeviceInterfacePtpCrbSupported) {
+ if (TempBuffer[0] != 0) {
+ StrCatS (TempBuffer, sizeof(TempBuffer) / sizeof (CHAR16), L", ");
+ }
+ StrCatS (TempBuffer, sizeof(TempBuffer) / sizeof (CHAR16), L"PTP CRB");
+ }
+ HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_TCG2_DEVICE_INTERFACE_CAPABILITY_CONTENT), TempBuffer, NULL);
+ break;
+ default:
+ Tcg2ConfigInfo.TpmDeviceInterfacePtpFifoSupported = FALSE;
+ Tcg2ConfigInfo.TpmDeviceInterfacePtpCrbSupported = FALSE;
+ HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_TCG2_DEVICE_INTERFACE_CAPABILITY_CONTENT), L"Unknown", NULL);
+ break;
+ }
+ }
+
+ //
+ // Set ConfigInfo, to control the check box.
+ //
+ Status = gRT->SetVariable (
+ TCG2_STORAGE_INFO_NAME,
+ &gTcg2ConfigFormSetGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ sizeof(Tcg2ConfigInfo),
+ &Tcg2ConfigInfo
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Tcg2ConfigDriver: Fail to set TCG2_STORAGE_INFO_NAME\n"));
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function removes TCG2 configuration Form.
+
+ @param[in, out] PrivateData Points to TCG2 configuration private data.
+
+**/
+VOID
+UninstallTcg2ConfigForm (
+ IN OUT TCG2_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,
+ &mTcg2HiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ &PrivateData->ConfigAccess,
+ NULL
+ );
+ PrivateData->DriverHandle = NULL;
+ }
+
+ FreePool (PrivateData);
+}
diff --git a/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigImpl.h b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigImpl.h
new file mode 100644
index 0000000000..504212baa8
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigImpl.h
@@ -0,0 +1,201 @@
+/** @file
+ The header file of HII Config Access protocol implementation of TCG2
+ configuration module.
+
+Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __TCG2_CONFIG_IMPL_H__
+#define __TCG2_CONFIG_IMPL_H__
+
+#include <Uefi.h>
+
+#include <IndustryStandard/Tpm2Acpi.h>
+
+#include <Protocol/HiiConfigAccess.h>
+#include <Protocol/HiiConfigRouting.h>
+#include <Protocol/Tcg2Protocol.h>
+#include <Protocol/VariableLock.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiHiiServicesLib.h>
+#include <Library/UefiLib.h>
+#include <Library/HiiLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PrintLib.h>
+#include <Library/Tcg2PhysicalPresenceLib.h>
+
+#include <Guid/MdeModuleHii.h>
+
+#include "Tcg2ConfigNvData.h"
+
+//
+// Tool generated IFR binary data and String package data
+//
+extern UINT8 Tcg2ConfigBin[];
+extern UINT8 Tcg2ConfigDxeStrings[];
+
+///
+/// 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;
+
+ UINT8 TpmDeviceDetected;
+ EFI_TCG2_PROTOCOL *Tcg2Protocol;
+ EFI_TCG2_BOOT_SERVICE_CAPABILITY ProtocolCapability;
+ UINT32 PCRBanksDesired;
+} TCG2_CONFIG_PRIVATE_DATA;
+
+extern TCG2_CONFIG_PRIVATE_DATA mTcg2ConfigPrivateDateTemplate;
+extern TCG2_CONFIG_PRIVATE_DATA *mTcg2ConfigPrivateDate;
+#define TCG2_CONFIG_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('T', 'r', 'E', 'D')
+#define TCG2_CONFIG_PRIVATE_DATA_FROM_THIS(a) CR (a, TCG2_CONFIG_PRIVATE_DATA, ConfigAccess, TCG2_CONFIG_PRIVATE_DATA_SIGNATURE)
+
+#define TPM_HID_PNP_SIZE 8
+#define TPM_HID_ACPI_SIZE 9
+
+/**
+ This function publish the TCG2 configuration Form for TPM device.
+
+ @param[in, out] PrivateData Points to TCG2 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
+InstallTcg2ConfigForm (
+ IN OUT TCG2_CONFIG_PRIVATE_DATA *PrivateData
+ );
+
+/**
+ This function removes TCG2 configuration Form.
+
+ @param[in, out] PrivateData Points to TCG2 configuration private data.
+
+**/
+VOID
+UninstallTcg2ConfigForm (
+ IN OUT TCG2_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
+ <ConfigRequest> format.
+ @param[out] Progress On return, points to a character in the Request
+ string. Points to the string's null terminator if
+ request was successful. Points to the most recent
+ '&' before the first failing name/value pair (or
+ the beginning of the string if the failure is in
+ the first name/value pair) if the request was not
+ successful.
+ @param[out] Results A null-terminated Unicode string in
+ <ConfigAltResp> format which has all values filled
+ in for the names in the Request string. String to
+ be allocated by the called function.
+
+ @retval EFI_SUCCESS The Results is filled with the requested values.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results.
+ @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name.
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in this
+ driver.
+
+**/
+EFI_STATUS
+EFIAPI
+Tcg2ExtractConfig (
+ 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 <ConfigResp>
+ 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
+Tcg2RouteConfig (
+ 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
+Tcg2Callback (
+ 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/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigNvData.h b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigNvData.h
new file mode 100644
index 0000000000..5960446421
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigNvData.h
@@ -0,0 +1,129 @@
+/** @file
+ Header file for NV data structure definition.
+
+Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __TCG2_CONFIG_NV_DATA_H__
+#define __TCG2_CONFIG_NV_DATA_H__
+
+#include <Guid/HiiPlatformSetupFormset.h>
+#include <Guid/Tcg2ConfigHii.h>
+#include <IndustryStandard/TcgPhysicalPresence.h>
+
+//
+// BUGBUG: In order to pass VfrCompiler, we have to redefine below MACRO, which already in <Protocol/Tcg2Protocol.h>.
+//
+#ifndef __TCG2_H__
+#define EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2 0x00000001
+#define EFI_TCG2_EVENT_LOG_FORMAT_TCG_2 0x00000002
+#endif
+#define EFI_TCG2_EVENT_LOG_FORMAT_ALL (EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2 | EFI_TCG2_EVENT_LOG_FORMAT_TCG_2)
+
+#define TCG2_CONFIGURATION_VARSTORE_ID 0x0001
+#define TCG2_CONFIGURATION_INFO_VARSTORE_ID 0x0002
+#define TCG2_VERSION_VARSTORE_ID 0x0003
+#define TCG2_CONFIGURATION_FORM_ID 0x0001
+
+#define KEY_TPM_DEVICE 0x2000
+#define KEY_TPM2_OPERATION 0x2001
+#define KEY_TPM2_OPERATION_PARAMETER 0x2002
+#define KEY_TPM2_PCR_BANKS_REQUEST_0 0x2003
+#define KEY_TPM2_PCR_BANKS_REQUEST_1 0x2004
+#define KEY_TPM2_PCR_BANKS_REQUEST_2 0x2005
+#define KEY_TPM2_PCR_BANKS_REQUEST_3 0x2006
+#define KEY_TPM2_PCR_BANKS_REQUEST_4 0x2007
+#define KEY_TPM_DEVICE_INTERFACE 0x2008
+#define KEY_TCG2_PPI_VERSION 0x2009
+#define KEY_TPM2_ACPI_REVISION 0x200A
+
+#define TPM_DEVICE_NULL 0
+#define TPM_DEVICE_1_2 1
+#define TPM_DEVICE_2_0_DTPM 2
+#define TPM_DEVICE_MIN TPM_DEVICE_1_2
+#define TPM_DEVICE_MAX TPM_DEVICE_2_0_DTPM
+#define TPM_DEVICE_DEFAULT TPM_DEVICE_1_2
+
+#define TPM2_ACPI_REVISION_3 3
+#define TPM2_ACPI_REVISION_4 4
+
+#define TPM_DEVICE_INTERFACE_TIS 0
+#define TPM_DEVICE_INTERFACE_PTP_FIFO 1
+#define TPM_DEVICE_INTERFACE_PTP_CRB 2
+#define TPM_DEVICE_INTERFACE_MAX TPM_DEVICE_INTERFACE_PTP_FIFO
+#define TPM_DEVICE_INTERFACE_DEFAULT TPM_DEVICE_INTERFACE_PTP_CRB
+
+#define TCG2_PROTOCOL_VERSION_DEFAULT 0x0001
+#define EFI_TCG2_EVENT_LOG_FORMAT_DEFAULT EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2
+
+#define TCG2_PPI_VERSION_1_2 0x322E31 // "1.2"
+#define TCG2_PPI_VERSION_1_3 0x332E31 // "1.3"
+
+//
+// Nv Data structure referenced by IFR, TPM device user desired
+//
+typedef struct {
+ UINT8 TpmDevice;
+} TCG2_CONFIGURATION;
+
+typedef struct {
+ UINT64 PpiVersion;
+ UINT8 Tpm2AcpiTableRev;
+} TCG2_VERSION;
+
+typedef struct {
+ BOOLEAN Sha1Supported;
+ BOOLEAN Sha256Supported;
+ BOOLEAN Sha384Supported;
+ BOOLEAN Sha512Supported;
+ BOOLEAN Sm3Supported;
+ UINT8 TpmDeviceInterfaceAttempt;
+ BOOLEAN TpmDeviceInterfacePtpFifoSupported;
+ BOOLEAN TpmDeviceInterfacePtpCrbSupported;
+} TCG2_CONFIGURATION_INFO;
+
+//
+// Variable saved for S3, TPM detected, only valid in S3 path.
+// This variable is ReadOnly.
+//
+typedef struct {
+ UINT8 TpmDeviceDetected;
+} TCG2_DEVICE_DETECTION;
+
+#define TCG2_STORAGE_NAME L"TCG2_CONFIGURATION"
+#define TCG2_STORAGE_INFO_NAME L"TCG2_CONFIGURATION_INFO"
+#define TCG2_DEVICE_DETECTION_NAME L"TCG2_DEVICE_DETECTION"
+#define TCG2_VERSION_NAME L"TCG2_VERSION"
+
+#define TPM_INSTANCE_ID_LIST { \
+ {TPM_DEVICE_INTERFACE_NONE, TPM_DEVICE_NULL}, \
+ {TPM_DEVICE_INTERFACE_TPM12, TPM_DEVICE_1_2}, \
+ {TPM_DEVICE_INTERFACE_TPM20_DTPM, TPM_DEVICE_2_0_DTPM}, \
+}
+
+//
+// BUGBUG: In order to pass VfrCompiler, we have to redefine GUID here.
+//
+#ifndef __BASE_H__
+typedef struct {
+ UINT32 Data1;
+ UINT16 Data2;
+ UINT16 Data3;
+ UINT8 Data4[8];
+} GUID;
+#endif
+
+typedef struct {
+ GUID TpmInstanceGuid;
+ UINT8 TpmDevice;
+} TPM_INSTANCE_ID;
+
+#endif
diff --git a/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPei.inf b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPei.inf
new file mode 100644
index 0000000000..8dd0b63e48
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPei.inf
@@ -0,0 +1,77 @@
+## @file
+# Set TPM device type
+#
+# This module initializes TPM device type based on variable and detection.
+# NOTE: This module is only for reference only, each platform should have its own setup page.
+#
+# Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = Tcg2ConfigPei
+ MODULE_UNI_FILE = Tcg2ConfigPei.uni
+ FILE_GUID = EADD5061-93EF-4CCC-8450-F78A7F0820F0
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ ENTRY_POINT = Tcg2ConfigPeimEntryPoint
+
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+# [BootMode]
+# S3_RESUME ## SOMETIMES_CONSUMES
+#
+
+[Sources]
+ Tcg2ConfigPeim.c
+ Tcg2ConfigNvData.h
+ TpmDetection.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ MemoryAllocationLib
+ PeiServicesLib
+ PeimEntryPoint
+ DebugLib
+ PcdLib
+ TimerLib
+ Tpm12CommandLib
+ Tpm12DeviceLib
+
+[Guids]
+ ## SOMETIMES_CONSUMES ## Variable:L"TCG2_CONFIGURATION"
+ ## SOMETIMES_CONSUMES ## Variable:L"TCG2_DEVICE_DETECTION"
+ gTcg2ConfigFormSetGuid
+ gEfiTpmDeviceSelectedGuid ## PRODUCES ## GUID # Used as a PPI GUID
+ gEfiTpmDeviceInstanceNoneGuid ## SOMETIMES_CONSUMES ## GUID # TPM device identifier
+
+[Ppis]
+ gEfiPeiReadOnlyVariable2PpiGuid ## CONSUMES
+ gPeiTpmInitializationDonePpiGuid ## SOMETIMES_PRODUCES
+
+[Pcd]
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpmInstanceGuid ## PRODUCES
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpmInitializationPolicy ## PRODUCES
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpmAutoDetection ## CONSUMES
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpmBaseAddress ## SOMETIMES_CONSUMES
+
+[Depex]
+ gEfiPeiMasterBootModePpiGuid AND
+ gEfiPeiReadOnlyVariable2PpiGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ Tcg2ConfigPeiExtra.uni
diff --git a/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPei.uni b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPei.uni
new file mode 100644
index 0000000000..02eaf8faad
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPei.uni
@@ -0,0 +1,23 @@
+// /** @file
+// Set TPM device type
+//
+// This module initializes TPM device type based on variable and detection.
+// NOTE: This module is only for reference only, each platform should have its own setup page.
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Set TPM device type"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This module initializes TPM device type based on variable and detection.\n"
+ "NOTE: This module is only for reference only, each platform should have its own setup page."
+
diff --git a/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPeiExtra.uni b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPeiExtra.uni
new file mode 100644
index 0000000000..37f81e17bd
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPeiExtra.uni
@@ -0,0 +1,19 @@
+// /** @file
+// Tcg2ConfigDxe Localized Strings and Content
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"TCG2 (Trusted Computing Group) Configuration DXE"
+
+
diff --git a/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPeim.c b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPeim.c
new file mode 100644
index 0000000000..004c7efe70
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPeim.c
@@ -0,0 +1,159 @@
+/** @file
+ The module entry point for Tcg2 configuration module.
+
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+
+#include <PiPei.h>
+
+#include <Guid/TpmInstance.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/PcdLib.h>
+
+#include <Ppi/ReadOnlyVariable2.h>
+#include <Ppi/TpmInitialized.h>
+#include <Protocol/Tcg2Protocol.h>
+
+#include "Tcg2ConfigNvData.h"
+
+TPM_INSTANCE_ID mTpmInstanceId[] = TPM_INSTANCE_ID_LIST;
+
+CONST EFI_PEI_PPI_DESCRIPTOR gTpmSelectedPpi = {
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEfiTpmDeviceSelectedGuid,
+ NULL
+};
+
+EFI_PEI_PPI_DESCRIPTOR mTpmInitializationDonePpiList = {
+ EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
+ &gPeiTpmInitializationDonePpiGuid,
+ NULL
+};
+
+/**
+ This routine check both SetupVariable and real TPM device, and return final TpmDevice configuration.
+
+ @param SetupTpmDevice TpmDevice configuration in setup driver
+
+ @return TpmDevice configuration
+**/
+UINT8
+DetectTpmDevice (
+ IN UINT8 SetupTpmDevice
+ );
+
+/**
+ The entry point for Tcg2 configuration driver.
+
+ @param FileHandle Handle of the file being invoked.
+ @param PeiServices Describes the list of possible PEI Services.
+
+ @retval EFI_SUCCES Convert variable to PCD successfully.
+ @retval Others Fail to convert variable to PCD.
+**/
+EFI_STATUS
+EFIAPI
+Tcg2ConfigPeimEntryPoint (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ UINTN Size;
+ EFI_STATUS Status;
+ EFI_STATUS Status2;
+ EFI_PEI_READ_ONLY_VARIABLE2_PPI *VariablePpi;
+ TCG2_CONFIGURATION Tcg2Configuration;
+ UINTN Index;
+ UINT8 TpmDevice;
+
+ Status = PeiServicesLocatePpi (&gEfiPeiReadOnlyVariable2PpiGuid, 0, NULL, (VOID **) &VariablePpi);
+ ASSERT_EFI_ERROR (Status);
+
+ Size = sizeof(Tcg2Configuration);
+ Status = VariablePpi->GetVariable (
+ VariablePpi,
+ TCG2_STORAGE_NAME,
+ &gTcg2ConfigFormSetGuid,
+ NULL,
+ &Size,
+ &Tcg2Configuration
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Variable not ready, set default value
+ //
+ Tcg2Configuration.TpmDevice = TPM_DEVICE_DEFAULT;
+ }
+
+ //
+ // Validation
+ //
+ if ((Tcg2Configuration.TpmDevice > TPM_DEVICE_MAX) || (Tcg2Configuration.TpmDevice < TPM_DEVICE_MIN)) {
+ Tcg2Configuration.TpmDevice = TPM_DEVICE_DEFAULT;
+ }
+
+ //
+ // Although we have SetupVariable info, we still need detect TPM device manually.
+ //
+ DEBUG ((EFI_D_INFO, "Tcg2Configuration.TpmDevice from Setup: %x\n", Tcg2Configuration.TpmDevice));
+
+ if (PcdGetBool (PcdTpmAutoDetection)) {
+ TpmDevice = DetectTpmDevice (Tcg2Configuration.TpmDevice);
+ DEBUG ((EFI_D_INFO, "TpmDevice final: %x\n", TpmDevice));
+ if (TpmDevice != TPM_DEVICE_NULL) {
+ Tcg2Configuration.TpmDevice = TpmDevice;
+ }
+ } else {
+ TpmDevice = Tcg2Configuration.TpmDevice;
+ }
+
+ //
+ // Convert variable to PCD.
+ // This is work-around because there is no gurantee DynamicHiiPcd can return correct value in DXE phase.
+ // Using DynamicPcd instead.
+ //
+ // NOTE: Tcg2Configuration variable contains the desired TpmDevice type,
+ // while PcdTpmInstanceGuid PCD contains the real detected TpmDevice type
+ //
+ for (Index = 0; Index < sizeof(mTpmInstanceId)/sizeof(mTpmInstanceId[0]); Index++) {
+ if (TpmDevice == mTpmInstanceId[Index].TpmDevice) {
+ Size = sizeof(mTpmInstanceId[Index].TpmInstanceGuid);
+ Status = PcdSetPtrS (PcdTpmInstanceGuid, &Size, &mTpmInstanceId[Index].TpmInstanceGuid);
+ ASSERT_EFI_ERROR (Status);
+ DEBUG ((EFI_D_INFO, "TpmDevice PCD: %g\n", &mTpmInstanceId[Index].TpmInstanceGuid));
+ break;
+ }
+ }
+
+ //
+ // Selection done
+ //
+ Status = PeiServicesInstallPpi (&gTpmSelectedPpi);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Even if no TPM is selected or detected, we still need intall TpmInitializationDonePpi.
+ // Because TcgPei or Tcg2Pei will not run, but we still need a way to notify other driver.
+ // Other driver can know TPM initialization state by TpmInitializedPpi.
+ //
+ if (CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceNoneGuid)) {
+ Status2 = PeiServicesInstallPpi (&mTpmInitializationDonePpiList);
+ ASSERT_EFI_ERROR (Status2);
+ }
+
+ return Status;
+}
diff --git a/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigStrings.uni b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigStrings.uni
new file mode 100644
index 0000000000..a7d62bcbe6
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigStrings.uni
@@ -0,0 +1,138 @@
+/** @file
+ String definitions for TCG2 configuration form.
+
+Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#langdef en-US "English"
+
+#string STR_TCG2_TITLE #language en-US "TCG2 Configuration"
+#string STR_TCG2_HELP #language en-US "Press <Enter> to select TCG2 Setup options."
+
+#string STR_TCG2_DEVICE_STATE_PROMPT #language en-US "Current TPM Device"
+#string STR_TCG2_DEVICE_STATE_HELP #language en-US "Current TPM Device: Disable, TPM1.2, or TPM2.0"
+#string STR_TCG2_DEVICE_STATE_CONTENT #language en-US ""
+
+#string STR_TCG2_DEVICE_PROMPT #language en-US "Attempt TPM Device"
+#string STR_TCG2_DEVICE_HELP #language en-US "Attempt TPM Device: TPM1.2, or TPM2.0"
+#string STR_TCG2_DEVICE_CONTENT #language en-US ""
+
+#string STR_TCG2_PPI_VERSION_STATE_PROMPT #language en-US "Current PPI Version"
+#string STR_TCG2_PPI_VERSION_STATE_HELP #language en-US "Current PPI Version: 1.2 or 1.3"
+#string STR_TCG2_PPI_VERSION_STATE_CONTENT #language en-US ""
+
+#string STR_TCG2_PPI_VERSION_PROMPT #language en-US "Attempt PPI Version"
+#string STR_TCG2_PPI_VERSION_HELP #language en-US "Attempt PPI Version: 1.2 or 1.3\n"
+ "PcdTcgPhysicalPresenceInterfaceVer needs to be DynamicHii type and map to this option\n"
+ "Otherwise the version configuring by this setup option will not work"
+
+#string STR_TPM2_ACPI_HID_PROMPT #language en-US "HID from TPM2 ACPI Table"
+#string STR_TPM2_ACPI_HID_HELP #language en-US "HID from TPM2 ACPI Table: ManufacturerID + FirmwareVersion_1"
+#string STR_TPM2_ACPI_HID_CONTENT #language en-US ""
+
+#string STR_TPM2_ACPI_REVISION_STATE_PROMPT #language en-US "Current Rev of TPM2 ACPI Table"
+#string STR_TPM2_ACPI_REVISION_STATE_HELP #language en-US "Current Rev of TPM2 ACPI Table: Rev 3 or Rev 4"
+#string STR_TPM2_ACPI_REVISION_STATE_CONTENT #language en-US ""
+
+#string STR_TPM2_ACPI_REVISION_PROMPT #language en-US "Attempt Rev of TPM2 ACPI Table"
+#string STR_TPM2_ACPI_REVISION_HELP #language en-US "Rev 3 or Rev 4 (Rev 4 is defined in TCG ACPI Spec 00.37)"
+ "PcdTpm2AcpiTableRev needs to be DynamicHii type and map to this option\n"
+ "Otherwise the version configuring by this setup option will not work"
+
+#string STR_TCG2_DEVICE_INTERFACE_STATE_PROMPT #language en-US "Current TPM Device Interface"
+#string STR_TCG2_DEVICE_INTERFACE_STATE_HELP #language en-US "Current TPM Device Interface: TIS, PTP FIFO, PTP CRB"
+#string STR_TCG2_DEVICE_INTERFACE_STATE_CONTENT #language en-US ""
+
+#string STR_TCG2_DEVICE_INTERFACE_CAPABILITY_PROMPT #language en-US "PTP TPM Device Interface Capability"
+#string STR_TCG2_DEVICE_INTERFACE_CAPABILITY_HELP #language en-US "PTP TPM Device Interface Capability: PTP FIFO, PTP CRB"
+#string STR_TCG2_DEVICE_INTERFACE_CAPABILITY_CONTENT #language en-US ""
+
+#string STR_TCG2_DEVICE_INTERFACE_PROMPT #language en-US "Attempt PTP TPM Device Interface"
+#string STR_TCG2_DEVICE_INTERFACE_HELP #language en-US "Attempt PTP TPM Device Interface: PTP FIFO, PTP CRB"
+#string STR_TCG2_DEVICE_INTERFACE_CONTENT #language en-US ""
+
+#string STR_TCG2_DEVICE_INTERFACE_TIS #language en-US "TIS"
+#string STR_TCG2_DEVICE_INTERFACE_PTP_FIFO #language en-US "PTP FIFO"
+#string STR_TCG2_DEVICE_INTERFACE_PTP_CRB #language en-US "PTP CRB"
+
+#string STR_TCG2_PP_OPERATION #language en-US "TPM2 Physical Presence Operation"
+
+#string STR_TCG2_OPERATION #language en-US "TPM2 Operation"
+#string STR_TCG2_OPERATION_HELP #language en-US "Select one of the supported operation to change TPM2 state."
+
+#string STR_TCG2_NO_ACTION #language en-US "No Action"
+#string STR_TCG2_ENABLE #language en-US "TPM2 HierarchyControl (TPM_RH_OWNER YES, TPM_RH_ENDORSEMENT YES)"
+#string STR_TCG2_DISABLE #language en-US "TPM2 HierarchyControl (TPM_RH_OWNER NO, TPM_RH_ENDORSEMENT NO)"
+#string STR_TCG2_CLEAR #language en-US "TPM2 ClearControl(NO) + Clear"
+#string STR_TCG2_SET_PCD_BANKS #language en-US "TPM2 PCR_Allocate(Algorithm IDs)"
+#string STR_TCG2_CHANGE_EPS #language en-US "TPM2 ChangeEPS"
+#string STR_TCG2_LOG_ALL_DIGESTS #language en-US "TCG2 LogAllDigests"
+#string STR_TCG2_DISABLE_ENDORSEMENT_ENABLE_STORAGE_HIERARCHY #language en-US "TPM2 HierarchyControl (TPM_RH_OWNER NO, TPM_RH_ENDORSEMENT YES)"
+
+#string STR_TCG2_OPERATION_PARAMETER #language en-US "TPM2 Operation Parameter"
+#string STR_TCG2_OPERATION_PARAMETER_HELP #language en-US "Additional TPM2 Operation Parameter need be sent with Operation Code (required for SetPCRBanks)"
+
+#string STR_TCG2_TPM_1_2 #language en-US "TPM 1.2"
+#string STR_TCG2_TPM_2_0_DTPM #language en-US "TPM 2.0"
+
+#string STR_TPM2_ACPI_REVISION_3 #language en-US "Rev 3"
+#string STR_TPM2_ACPI_REVISION_4 #language en-US "Rev 4"
+
+#string STR_TCG2_PPI_VERSION_1_2 #language en-US "1.2"
+#string STR_TCG2_PPI_VERSION_1_3 #language en-US "1.3"
+
+#string STR_TPM2_ACTIVE_HASH_ALGO #language en-US "TPM2 Active PCR Hash Algorithm"
+#string STR_TPM2_ACTIVE_HASH_ALGO_HELP #language en-US "TPM2 Active PCR Hash Algorithm: SHA1, SHA256, SHA384, SHA512, SM3_256"
+#string STR_TPM2_ACTIVE_HASH_ALGO_CONTENT #language en-US ""
+
+#string STR_TPM2_SUPPORTED_HASH_ALGO #language en-US "TPM2 Hardware Supported Hash Algorithm"
+#string STR_TPM2_SUPPORTED_HASH_ALGO_HELP #language en-US "TPM2 Hardware Supported Hash Algorithm: SHA1, SHA256, SHA384, SHA512, SM3_256"
+#string STR_TPM2_SUPPORTED_HASH_ALGO_CONTENT #language en-US ""
+
+#string STR_BIOS_HASH_ALGO #language en-US "BIOS Supported Hash Algorithm"
+#string STR_BIOS_HASH_ALGO_HELP #language en-US "BIOS Supported Hash Algorithm: SHA1, SHA256, SHA384, SHA512, SM3_256"
+#string STR_BIOS_HASH_ALGO_CONTENT #language en-US ""
+
+#string STR_TCG2_CONFIGURATION #language en-US "TCG2 Protocol Configuration"
+
+#string STR_TCG2_PROTOCOL_VERSION #language en-US "TCG2 Protocol Version"
+#string STR_TCG2_PROTOCOL_VERSION_HELP #language en-US "TCG2 Protocol Version: 1.0 or 1.1"
+#string STR_TCG2_PROTOCOL_VERSION_1_0 #language en-US "1.0"
+#string STR_TCG2_PROTOCOL_VERSION_1_1 #language en-US "1.1"
+
+#string STR_TCG2_SUPPORTED_EVENT_LOG_FORMAT #language en-US "Supported Event Log Format"
+#string STR_TCG2_SUPPORTED_EVENT_LOG_FORMAT_HELP #language en-US "TCG2 Supported Event Log Format: TCG_1_2, TCG_2"
+#string STR_TCG2_SUPPORTED_EVENT_LOG_FORMAT_CONTENT #language en-US ""
+
+#string STR_TCG2_HASH_ALGO_BITMAP #language en-US "Hash Algorithm Bitmap"
+#string STR_TCG2_HASH_ALGO_BITMAP_HELP #language en-US "TCG2 Supported Hash Algorithm Bitmap: SHA1, SHA256, SHA384, SHA512"
+#string STR_TCG2_HASH_ALGO_BITMAP_CONTENT #language en-US ""
+
+#string STR_TCG2_NUMBER_OF_PCR_BANKS #language en-US "Number of PCR Banks"
+#string STR_TCG2_NUMBER_OF_PCR_BANKS_HELP #language en-US "TCG2 Number of PCR Banks"
+#string STR_TCG2_NUMBER_OF_PCR_BANKS_CONTENT #language en-US ""
+
+#string STR_TCG2_ACTIVE_PCR_BANKS #language en-US "Active PCR Banks"
+#string STR_TCG2_ACTIVE_PCR_BANKS_HELP #language en-US "TCG2 Active PCR Banks: SHA1, SHA256, SHA384, SHA512"
+#string STR_TCG2_ACTIVE_PCR_BANKS_CONTENT #language en-US ""
+
+#string STR_TCG2_PCR_BANK_SHA1 #language en-US " PCR Bank: SHA1"
+#string STR_TCG2_PCR_BANK_SHA1_HELP #language en-US "TCG2 Request PCR Bank: SHA1"
+#string STR_TCG2_PCR_BANK_SHA256 #language en-US " PCR Bank: SHA256"
+#string STR_TCG2_PCR_BANK_SHA256_HELP #language en-US "TCG2 Request PCR Bank: SHA256"
+#string STR_TCG2_PCR_BANK_SHA384 #language en-US " PCR Bank: SHA384"
+#string STR_TCG2_PCR_BANK_SHA384_HELP #language en-US "TCG2 Request PCR Bank: SHA384"
+#string STR_TCG2_PCR_BANK_SHA512 #language en-US " PCR Bank: SHA512"
+#string STR_TCG2_PCR_BANK_SHA512_HELP #language en-US "TCG2 Request PCR Bank: SHA512"
+#string STR_TCG2_PCR_BANK_SM3_256 #language en-US " PCR Bank: SM3_256"
+#string STR_TCG2_PCR_BANK_SM3_256_HELP #language en-US "TCG2 Request PCR Bank: SM3_256"
+
+#string STR_NULL #language en-US ""
diff --git a/Core/SecurityPkg/Tcg/Tcg2Config/TpmDetection.c b/Core/SecurityPkg/Tcg/Tcg2Config/TpmDetection.c
new file mode 100644
index 0000000000..7e6ca44205
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Tcg2Config/TpmDetection.c
@@ -0,0 +1,105 @@
+/** @file
+ TPM1.2/dTPM2.0 auto detection.
+
+Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+
+#include <PiPei.h>
+#include <Ppi/ReadOnlyVariable2.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/PcdLib.h>
+#include <Library/Tpm12DeviceLib.h>
+#include <Library/Tpm12CommandLib.h>
+#include <IndustryStandard/Tpm12.h>
+
+#include "Tcg2ConfigNvData.h"
+
+/**
+ This routine check both SetupVariable and real TPM device, and return final TpmDevice configuration.
+
+ @param SetupTpmDevice TpmDevice configuration in setup driver
+
+ @return TpmDevice configuration
+**/
+UINT8
+DetectTpmDevice (
+ IN UINT8 SetupTpmDevice
+ )
+{
+ EFI_STATUS Status;
+ EFI_BOOT_MODE BootMode;
+ TCG2_DEVICE_DETECTION Tcg2DeviceDetection;
+ EFI_PEI_READ_ONLY_VARIABLE2_PPI *VariablePpi;
+ UINTN Size;
+
+ Status = PeiServicesGetBootMode (&BootMode);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // In S3, we rely on normal boot Detection, because we save to ReadOnly Variable in normal boot.
+ //
+ if (BootMode == BOOT_ON_S3_RESUME) {
+ DEBUG ((EFI_D_INFO, "DetectTpmDevice: S3 mode\n"));
+
+ Status = PeiServicesLocatePpi (&gEfiPeiReadOnlyVariable2PpiGuid, 0, NULL, (VOID **) &VariablePpi);
+ ASSERT_EFI_ERROR (Status);
+
+ Size = sizeof(TCG2_DEVICE_DETECTION);
+ ZeroMem (&Tcg2DeviceDetection, sizeof(Tcg2DeviceDetection));
+ Status = VariablePpi->GetVariable (
+ VariablePpi,
+ TCG2_DEVICE_DETECTION_NAME,
+ &gTcg2ConfigFormSetGuid,
+ NULL,
+ &Size,
+ &Tcg2DeviceDetection
+ );
+ if (!EFI_ERROR (Status) &&
+ (Tcg2DeviceDetection.TpmDeviceDetected >= TPM_DEVICE_MIN) &&
+ (Tcg2DeviceDetection.TpmDeviceDetected <= TPM_DEVICE_MAX)) {
+ DEBUG ((EFI_D_ERROR, "TpmDevice from DeviceDetection: %x\n", Tcg2DeviceDetection.TpmDeviceDetected));
+ return Tcg2DeviceDetection.TpmDeviceDetected;
+ }
+ }
+
+ DEBUG ((EFI_D_INFO, "DetectTpmDevice:\n"));
+
+ // dTPM available and not disabled by setup
+ // We need check if it is TPM1.2 or TPM2.0
+ // So try TPM1.2 command at first
+
+ Status = Tpm12RequestUseTpm ();
+ if (EFI_ERROR (Status)) {
+ //
+ // dTPM not available
+ //
+ return TPM_DEVICE_NULL;
+ }
+
+ if (BootMode == BOOT_ON_S3_RESUME) {
+ Status = Tpm12Startup (TPM_ST_STATE);
+ } else {
+ Status = Tpm12Startup (TPM_ST_CLEAR);
+ }
+ if (EFI_ERROR (Status)) {
+ return TPM_DEVICE_2_0_DTPM;
+ }
+
+ // NO initialization needed again.
+ Status = PcdSet8S (PcdTpmInitializationPolicy, 0);
+ ASSERT_EFI_ERROR (Status);
+ return TPM_DEVICE_1_2;
+}
diff --git a/Core/SecurityPkg/Tcg/Tcg2Dxe/MeasureBootPeCoff.c b/Core/SecurityPkg/Tcg/Tcg2Dxe/MeasureBootPeCoff.c
new file mode 100644
index 0000000000..8ee34a702e
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Tcg2Dxe/MeasureBootPeCoff.c
@@ -0,0 +1,427 @@
+/** @file
+ This module implements measuring PeCoff image for Tcg2 Protocol.
+
+ Caution: This file requires additional review when modified.
+ This driver will have external input - PE/COFF image.
+ This external input must be validated carefully to avoid security issue like
+ buffer overflow, integer overflow.
+
+Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiDxe.h>
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/PeCoffLib.h>
+#include <Library/Tpm2CommandLib.h>
+#include <Library/HashLib.h>
+
+UINTN mTcg2DxeImageSize = 0;
+
+/**
+ Reads contents of a PE/COFF image in memory buffer.
+
+ Caution: This function may receive untrusted input.
+ PE/COFF image is external input, so this function will make sure the PE/COFF image content
+ read is within the image 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
+Tcg2DxeImageRead (
+ IN VOID *FileHandle,
+ IN UINTN FileOffset,
+ IN OUT UINTN *ReadSize,
+ OUT VOID *Buffer
+ )
+{
+ UINTN EndPosition;
+
+ if (FileHandle == NULL || ReadSize == NULL || Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (MAX_ADDRESS - FileOffset < *ReadSize) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ EndPosition = FileOffset + *ReadSize;
+ if (EndPosition > mTcg2DxeImageSize) {
+ *ReadSize = (UINT32)(mTcg2DxeImageSize - FileOffset);
+ }
+
+ if (FileOffset >= mTcg2DxeImageSize) {
+ *ReadSize = 0;
+ }
+
+ CopyMem (Buffer, (UINT8 *)((UINTN) FileHandle + FileOffset), *ReadSize);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Measure PE image into TPM log based on the authenticode image hashing in
+ PE/COFF Specification 8.0 Appendix A.
+
+ Caution: This function may receive untrusted input.
+ PE/COFF image is external input, so this function will validate its data structure
+ within this image buffer before use.
+
+ Notes: PE/COFF image is checked by BasePeCoffLib PeCoffLoaderGetImageInfo().
+
+ @param[in] PCRIndex TPM PCR index
+ @param[in] ImageAddress Start address of image buffer.
+ @param[in] ImageSize Image size
+ @param[out] DigestList Digeest list of this image.
+
+ @retval EFI_SUCCESS Successfully measure image.
+ @retval EFI_OUT_OF_RESOURCES No enough resource to measure image.
+ @retval other error value
+**/
+EFI_STATUS
+MeasurePeImageAndExtend (
+ IN UINT32 PCRIndex,
+ IN EFI_PHYSICAL_ADDRESS ImageAddress,
+ IN UINTN ImageSize,
+ OUT TPML_DIGEST_VALUES *DigestList
+ )
+{
+ EFI_STATUS Status;
+ 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;
+ UINTN Pos;
+ UINT16 Magic;
+ EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
+ UINT32 NumberOfRvaAndSizes;
+ UINT32 CertSize;
+ HASH_HANDLE HashHandle;
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
+
+ HashHandle = 0xFFFFFFFF; // Know bad value
+
+ Status = EFI_UNSUPPORTED;
+ SectionHeader = NULL;
+
+ //
+ // Check PE/COFF image
+ //
+ ZeroMem (&ImageContext, sizeof (ImageContext));
+ ImageContext.Handle = (VOID *) (UINTN) ImageAddress;
+ mTcg2DxeImageSize = ImageSize;
+ ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) Tcg2DxeImageRead;
+
+ //
+ // Get information about the image being loaded
+ //
+ Status = PeCoffLoaderGetImageInfo (&ImageContext);
+ if (EFI_ERROR (Status)) {
+ //
+ // The information can't be got from the invalid PeImage
+ //
+ DEBUG ((DEBUG_INFO, "Tcg2Dxe: PeImage invalid. Cannot retrieve image information.\n"));
+ goto Finish;
+ }
+
+ DosHdr = (EFI_IMAGE_DOS_HEADER *) (UINTN) ImageAddress;
+ PeCoffHeaderOffset = 0;
+ if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
+ PeCoffHeaderOffset = DosHdr->e_lfanew;
+ }
+
+ Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINT8 *) (UINTN) ImageAddress + PeCoffHeaderOffset);
+ if (Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {
+ Status = EFI_UNSUPPORTED;
+ 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.
+
+ Status = HashStart (&HashHandle);
+ if (EFI_ERROR (Status)) {
+ goto Finish;
+ }
+
+ //
+ // Measuring PE/COFF Image Header;
+ // But CheckSum field and SECURITY data directory (certificate) are excluded
+ //
+ if (Hdr.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ //
+ // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value
+ // in the PE/COFF Header. If the MachineType is Itanium(IA64) and the
+ // Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
+ // then override the magic value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
+ //
+ Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;
+ } else {
+ //
+ // Get the magic value from the PE/COFF Optional Header
+ //
+ 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
+ //
+ NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
+ HashSize = (UINTN) (&Hdr.Pe32->OptionalHeader.CheckSum) - (UINTN) HashBase;
+ } else {
+ //
+ // Use PE32+ offset
+ //
+ NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
+ HashSize = (UINTN) (&Hdr.Pe32Plus->OptionalHeader.CheckSum) - (UINTN) HashBase;
+ }
+
+ Status = HashUpdate (HashHandle, HashBase, HashSize);
+ if (EFI_ERROR (Status)) {
+ goto Finish;
+ }
+
+ //
+ // 5. Skip over the image checksum (it occupies a single ULONG).
+ //
+ if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {
+ //
+ // 6. Since there is no Cert Directory in optional header, hash everything
+ // from the end of the checksum to the end of image header.
+ //
+ if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ //
+ // Use PE32 offset.
+ //
+ HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);
+ HashSize = Hdr.Pe32->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress);
+ } else {
+ //
+ // Use PE32+ offset.
+ //
+ HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);
+ HashSize = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress);
+ }
+
+ if (HashSize != 0) {
+ Status = HashUpdate (HashHandle, HashBase, HashSize);
+ if (EFI_ERROR (Status)) {
+ goto Finish;
+ }
+ }
+ } else {
+ //
+ // 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) (&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - (UINTN) HashBase;
+ } else {
+ //
+ // Use PE32+ offset
+ //
+ HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);
+ HashSize = (UINTN) (&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - (UINTN) HashBase;
+ }
+
+ if (HashSize != 0) {
+ Status = HashUpdate (HashHandle, HashBase, HashSize);
+ if (EFI_ERROR (Status)) {
+ goto Finish;
+ }
+ }
+
+ //
+ // 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) (HashBase - ImageAddress);
+ } else {
+ //
+ // Use PE32+ offset
+ //
+ HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];
+ HashSize = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress);
+ }
+
+ if (HashSize != 0) {
+ Status = HashUpdate (HashHandle, HashBase, HashSize);
+ if (EFI_ERROR (Status)) {
+ goto Finish;
+ }
+ }
+ }
+
+ //
+ // 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;
+
+ Status = HashUpdate (HashHandle, HashBase, HashSize);
+ if (EFI_ERROR (Status)) {
+ goto Finish;
+ }
+
+ 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 (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {
+ CertSize = 0;
+ } else {
+ if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ //
+ // Use PE32 offset.
+ //
+ CertSize = Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size;
+ } else {
+ //
+ // Use PE32+ offset.
+ //
+ CertSize = Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size;
+ }
+ }
+
+ if (ImageSize > CertSize + SumOfBytesHashed) {
+ HashSize = (UINTN) (ImageSize - CertSize - SumOfBytesHashed);
+
+ Status = HashUpdate (HashHandle, HashBase, HashSize);
+ if (EFI_ERROR (Status)) {
+ goto Finish;
+ }
+ } else if (ImageSize < CertSize + SumOfBytesHashed) {
+ Status = EFI_UNSUPPORTED;
+ goto Finish;
+ }
+ }
+
+ //
+ // 17. Finalize the SHA hash.
+ //
+ Status = HashCompleteAndExtend (HashHandle, PCRIndex, NULL, 0, DigestList);
+ if (EFI_ERROR (Status)) {
+ goto Finish;
+ }
+
+Finish:
+ if (SectionHeader != NULL) {
+ FreePool (SectionHeader);
+ }
+
+ return Status;
+}
diff --git a/Core/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c b/Core/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c
new file mode 100644
index 0000000000..c2c52e32b8
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c
@@ -0,0 +1,2621 @@
+/** @file
+ This module implements Tcg2 Protocol.
+
+Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
+(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiDxe.h>
+#include <IndustryStandard/Acpi.h>
+#include <IndustryStandard/PeImage.h>
+#include <IndustryStandard/TcpaAcpi.h>
+
+#include <Guid/GlobalVariable.h>
+#include <Guid/HobList.h>
+#include <Guid/TcgEventHob.h>
+#include <Guid/EventGroup.h>
+#include <Guid/EventExitBootServiceFailed.h>
+#include <Guid/ImageAuthentication.h>
+#include <Guid/TpmInstance.h>
+
+#include <Protocol/DevicePath.h>
+#include <Protocol/MpService.h>
+#include <Protocol/VariableWrite.h>
+#include <Protocol/Tcg2Protocol.h>
+#include <Protocol/TrEEProtocol.h>
+
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/HobLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/BaseLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PrintLib.h>
+#include <Library/Tpm2CommandLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiLib.h>
+#include <Library/Tpm2DeviceLib.h>
+#include <Library/HashLib.h>
+#include <Library/PerformanceLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/Tcg2PhysicalPresenceLib.h>
+
+#define PERF_ID_TCG2_DXE 0x3120
+
+typedef struct {
+ CHAR16 *VariableName;
+ EFI_GUID *VendorGuid;
+} VARIABLE_TYPE;
+
+#define TCG2_DEFAULT_MAX_COMMAND_SIZE 0x1000
+#define TCG2_DEFAULT_MAX_RESPONSE_SIZE 0x1000
+
+typedef struct {
+ EFI_GUID *EventGuid;
+ EFI_TCG2_EVENT_LOG_FORMAT LogFormat;
+} TCG2_EVENT_INFO_STRUCT;
+
+TCG2_EVENT_INFO_STRUCT mTcg2EventInfo[] = {
+ {&gTcgEventEntryHobGuid, EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2},
+ {&gTcgEvent2EntryHobGuid, EFI_TCG2_EVENT_LOG_FORMAT_TCG_2},
+};
+
+#define TCG_EVENT_LOG_AREA_COUNT_MAX 2
+
+typedef struct {
+ EFI_TCG2_EVENT_LOG_FORMAT EventLogFormat;
+ EFI_PHYSICAL_ADDRESS Lasa;
+ UINT64 Laml;
+ UINTN EventLogSize;
+ UINT8 *LastEvent;
+ BOOLEAN EventLogStarted;
+ BOOLEAN EventLogTruncated;
+} TCG_EVENT_LOG_AREA_STRUCT;
+
+typedef struct _TCG_DXE_DATA {
+ EFI_TCG2_BOOT_SERVICE_CAPABILITY BsCap;
+ TCG_EVENT_LOG_AREA_STRUCT EventLogAreaStruct[TCG_EVENT_LOG_AREA_COUNT_MAX];
+ BOOLEAN GetEventLogCalled[TCG_EVENT_LOG_AREA_COUNT_MAX];
+ TCG_EVENT_LOG_AREA_STRUCT FinalEventLogAreaStruct[TCG_EVENT_LOG_AREA_COUNT_MAX];
+ EFI_TCG2_FINAL_EVENTS_TABLE *FinalEventsTable[TCG_EVENT_LOG_AREA_COUNT_MAX];
+} TCG_DXE_DATA;
+
+TCG_DXE_DATA mTcgDxeData = {
+ {
+ sizeof (EFI_TCG2_BOOT_SERVICE_CAPABILITY), // Size
+ { 1, 1 }, // StructureVersion
+ { 1, 1 }, // ProtocolVersion
+ EFI_TCG2_BOOT_HASH_ALG_SHA1, // HashAlgorithmBitmap
+ EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2, // SupportedEventLogs
+ TRUE, // TPMPresentFlag
+ TCG2_DEFAULT_MAX_COMMAND_SIZE, // MaxCommandSize
+ TCG2_DEFAULT_MAX_RESPONSE_SIZE, // MaxResponseSize
+ 0, // ManufacturerID
+ 0, // NumberOfPCRBanks
+ 0, // ActivePcrBanks
+ },
+};
+
+UINTN mBootAttempts = 0;
+CHAR16 mBootVarName[] = L"BootOrder";
+
+VARIABLE_TYPE mVariableType[] = {
+ {EFI_SECURE_BOOT_MODE_NAME, &gEfiGlobalVariableGuid},
+ {EFI_PLATFORM_KEY_NAME, &gEfiGlobalVariableGuid},
+ {EFI_KEY_EXCHANGE_KEY_NAME, &gEfiGlobalVariableGuid},
+ {EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid},
+ {EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid},
+};
+
+EFI_HANDLE mImageHandle;
+
+/**
+ Measure PE image into TPM log based on the authenticode image hashing in
+ PE/COFF Specification 8.0 Appendix A.
+
+ Caution: This function may receive untrusted input.
+ PE/COFF image is external input, so this function will validate its data structure
+ within this image buffer before use.
+
+ Notes: PE/COFF image is checked by BasePeCoffLib PeCoffLoaderGetImageInfo().
+
+ @param[in] PCRIndex TPM PCR index
+ @param[in] ImageAddress Start address of image buffer.
+ @param[in] ImageSize Image size
+ @param[out] DigestList Digeest list of this image.
+
+ @retval EFI_SUCCESS Successfully measure image.
+ @retval EFI_OUT_OF_RESOURCES No enough resource to measure image.
+ @retval other error value
+**/
+EFI_STATUS
+MeasurePeImageAndExtend (
+ IN UINT32 PCRIndex,
+ IN EFI_PHYSICAL_ADDRESS ImageAddress,
+ IN UINTN ImageSize,
+ OUT TPML_DIGEST_VALUES *DigestList
+ );
+
+/**
+
+ This function dump raw data.
+
+ @param Data raw data
+ @param Size raw data size
+
+**/
+VOID
+InternalDumpData (
+ IN UINT8 *Data,
+ IN UINTN Size
+ )
+{
+ UINTN Index;
+ for (Index = 0; Index < Size; Index++) {
+ DEBUG ((EFI_D_INFO, "%02x", (UINTN)Data[Index]));
+ }
+}
+
+/**
+
+ This function initialize TCG_PCR_EVENT2_HDR for EV_NO_ACTION Event Type other than EFI Specification ID event
+ The behavior is defined by TCG PC Client PFP Spec. Section 9.3.4 EV_NO_ACTION Event Types
+
+ @param[in, out] NoActionEvent Event Header of EV_NO_ACTION Event
+ @param[in] EventSize Event Size of the EV_NO_ACTION Event
+
+**/
+VOID
+InitNoActionEvent (
+ IN OUT TCG_PCR_EVENT2_HDR *NoActionEvent,
+ IN UINT32 EventSize
+ )
+{
+ UINT32 DigestListCount;
+ TPMI_ALG_HASH HashAlgId;
+ UINT8 *DigestBuffer;
+
+ DigestBuffer = (UINT8 *)NoActionEvent->Digests.digests;
+ DigestListCount = 0;
+
+ NoActionEvent->PCRIndex = 0;
+ NoActionEvent->EventType = EV_NO_ACTION;
+
+ //
+ // Set Hash count & hashAlg accordingly, while Digest.digests[n].digest to all 0
+ //
+ ZeroMem (&NoActionEvent->Digests, sizeof(NoActionEvent->Digests));
+
+ if ((mTcgDxeData.BsCap.ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SHA1) != 0) {
+ HashAlgId = TPM_ALG_SHA1;
+ CopyMem (DigestBuffer, &HashAlgId, sizeof(TPMI_ALG_HASH));
+ DigestBuffer += sizeof(TPMI_ALG_HASH) + GetHashSizeFromAlgo (HashAlgId);
+ DigestListCount++;
+ }
+
+ if ((mTcgDxeData.BsCap.ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SHA256) != 0) {
+ HashAlgId = TPM_ALG_SHA256;
+ CopyMem (DigestBuffer, &HashAlgId, sizeof(TPMI_ALG_HASH));
+ DigestBuffer += sizeof(TPMI_ALG_HASH) + GetHashSizeFromAlgo (HashAlgId);
+ DigestListCount++;
+ }
+
+ if ((mTcgDxeData.BsCap.ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SHA384) != 0) {
+ HashAlgId = TPM_ALG_SHA384;
+ CopyMem (DigestBuffer, &HashAlgId, sizeof(TPMI_ALG_HASH));
+ DigestBuffer += sizeof(TPMI_ALG_HASH) + GetHashSizeFromAlgo (HashAlgId);
+ DigestListCount++;
+ }
+
+ if ((mTcgDxeData.BsCap.ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SHA512) != 0) {
+ HashAlgId = TPM_ALG_SHA512;
+ CopyMem (DigestBuffer, &HashAlgId, sizeof(TPMI_ALG_HASH));
+ DigestBuffer += sizeof(TPMI_ALG_HASH) + GetHashSizeFromAlgo (HashAlgId);
+ DigestListCount++;
+ }
+
+ if ((mTcgDxeData.BsCap.ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SM3_256) != 0) {
+ HashAlgId = TPM_ALG_SM3_256;
+ CopyMem (DigestBuffer, &HashAlgId, sizeof(TPMI_ALG_HASH));
+ DigestBuffer += sizeof(TPMI_ALG_HASH) + GetHashSizeFromAlgo (HashAlgId);
+ DigestListCount++;
+ }
+
+ //
+ // Set Digests Count
+ //
+ WriteUnaligned32 ((UINT32 *)&NoActionEvent->Digests.count, DigestListCount);
+
+ //
+ // Set Event Size
+ //
+ WriteUnaligned32((UINT32 *)DigestBuffer, EventSize);
+}
+
+/**
+
+ This function dump raw data with colume format.
+
+ @param Data raw data
+ @param Size raw data size
+
+**/
+VOID
+InternalDumpHex (
+ IN UINT8 *Data,
+ IN UINTN Size
+ )
+{
+ UINTN Index;
+ UINTN Count;
+ UINTN Left;
+
+#define COLUME_SIZE (16 * 2)
+
+ Count = Size / COLUME_SIZE;
+ Left = Size % COLUME_SIZE;
+ for (Index = 0; Index < Count; Index++) {
+ DEBUG ((EFI_D_INFO, "%04x: ", Index * COLUME_SIZE));
+ InternalDumpData (Data + Index * COLUME_SIZE, COLUME_SIZE);
+ DEBUG ((EFI_D_INFO, "\n"));
+ }
+
+ if (Left != 0) {
+ DEBUG ((EFI_D_INFO, "%04x: ", Index * COLUME_SIZE));
+ InternalDumpData (Data + Index * COLUME_SIZE, Left);
+ DEBUG ((EFI_D_INFO, "\n"));
+ }
+}
+
+/**
+ Get All processors EFI_CPU_LOCATION in system. LocationBuf is allocated inside the function
+ Caller is responsible to free LocationBuf.
+
+ @param[out] LocationBuf Returns Processor Location Buffer.
+ @param[out] Num Returns processor number.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_UNSUPPORTED MpService protocol not found.
+
+**/
+EFI_STATUS
+GetProcessorsCpuLocation (
+ OUT EFI_CPU_PHYSICAL_LOCATION **LocationBuf,
+ OUT UINTN *Num
+ )
+{
+ EFI_STATUS Status;
+ EFI_MP_SERVICES_PROTOCOL *MpProtocol;
+ UINTN ProcessorNum;
+ UINTN EnabledProcessorNum;
+ EFI_PROCESSOR_INFORMATION ProcessorInfo;
+ EFI_CPU_PHYSICAL_LOCATION *ProcessorLocBuf;
+ UINTN Index;
+
+ Status = gBS->LocateProtocol (&gEfiMpServiceProtocolGuid, NULL, (VOID **) &MpProtocol);
+ if (EFI_ERROR (Status)) {
+ //
+ // MP protocol is not installed
+ //
+ return EFI_UNSUPPORTED;
+ }
+
+ Status = MpProtocol->GetNumberOfProcessors(
+ MpProtocol,
+ &ProcessorNum,
+ &EnabledProcessorNum
+ );
+ if (EFI_ERROR(Status)){
+ return Status;
+ }
+
+ Status = gBS->AllocatePool(
+ EfiBootServicesData,
+ sizeof(EFI_CPU_PHYSICAL_LOCATION) * ProcessorNum,
+ (VOID **) &ProcessorLocBuf
+ );
+ if (EFI_ERROR(Status)){
+ return Status;
+ }
+
+ //
+ // Get each processor Location info
+ //
+ for (Index = 0; Index < ProcessorNum; Index++) {
+ Status = MpProtocol->GetProcessorInfo(
+ MpProtocol,
+ Index,
+ &ProcessorInfo
+ );
+ if (EFI_ERROR(Status)){
+ FreePool(ProcessorLocBuf);
+ return Status;
+ }
+
+ //
+ // Get all Processor Location info & measure
+ //
+ CopyMem(
+ &ProcessorLocBuf[Index],
+ &ProcessorInfo.Location,
+ sizeof(EFI_CPU_PHYSICAL_LOCATION)
+ );
+ }
+
+ *LocationBuf = ProcessorLocBuf;
+ *Num = ProcessorNum;
+
+ return Status;
+}
+
+/**
+ The EFI_TCG2_PROTOCOL GetCapability function call provides protocol
+ capability information and state information.
+
+ @param[in] This Indicates the calling context
+ @param[in, out] ProtocolCapability The caller allocates memory for a EFI_TCG2_BOOT_SERVICE_CAPABILITY
+ structure and sets the size field to the size of the structure allocated.
+ The callee fills in the fields with the EFI protocol capability information
+ and the current EFI TCG2 state information up to the number of fields which
+ fit within the size of the structure passed in.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+ The ProtocolCapability variable will not be populated.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters are incorrect.
+ The ProtocolCapability variable will not be populated.
+ @retval EFI_BUFFER_TOO_SMALL The ProtocolCapability variable is too small to hold the full response.
+ It will be partially populated (required Size field will be set).
+**/
+EFI_STATUS
+EFIAPI
+Tcg2GetCapability (
+ IN EFI_TCG2_PROTOCOL *This,
+ IN OUT EFI_TCG2_BOOT_SERVICE_CAPABILITY *ProtocolCapability
+ )
+{
+ DEBUG ((DEBUG_VERBOSE, "Tcg2GetCapability ...\n"));
+
+ if ((This == NULL) || (ProtocolCapability == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ DEBUG ((DEBUG_VERBOSE, "Size - 0x%x\n", ProtocolCapability->Size));
+ DEBUG ((DEBUG_VERBOSE, " 1.1 - 0x%x, 1.0 - 0x%x\n", sizeof(EFI_TCG2_BOOT_SERVICE_CAPABILITY), sizeof(TREE_BOOT_SERVICE_CAPABILITY_1_0)));
+
+ if (ProtocolCapability->Size < mTcgDxeData.BsCap.Size) {
+ //
+ // Handle the case that firmware support 1.1 but OS only support 1.0.
+ //
+ if ((mTcgDxeData.BsCap.ProtocolVersion.Major > 0x01) ||
+ ((mTcgDxeData.BsCap.ProtocolVersion.Major == 0x01) && ((mTcgDxeData.BsCap.ProtocolVersion.Minor > 0x00)))) {
+ if (ProtocolCapability->Size >= sizeof(TREE_BOOT_SERVICE_CAPABILITY_1_0)) {
+ CopyMem (ProtocolCapability, &mTcgDxeData.BsCap, sizeof(TREE_BOOT_SERVICE_CAPABILITY_1_0));
+ ProtocolCapability->Size = sizeof(TREE_BOOT_SERVICE_CAPABILITY_1_0);
+ ProtocolCapability->StructureVersion.Major = 1;
+ ProtocolCapability->StructureVersion.Minor = 0;
+ ProtocolCapability->ProtocolVersion.Major = 1;
+ ProtocolCapability->ProtocolVersion.Minor = 0;
+ DEBUG ((EFI_D_ERROR, "TreeGetCapability (Compatible) - %r\n", EFI_SUCCESS));
+ return EFI_SUCCESS;
+ }
+ }
+ ProtocolCapability->Size = mTcgDxeData.BsCap.Size;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ CopyMem (ProtocolCapability, &mTcgDxeData.BsCap, mTcgDxeData.BsCap.Size);
+ DEBUG ((DEBUG_VERBOSE, "Tcg2GetCapability - %r\n", EFI_SUCCESS));
+ return EFI_SUCCESS;
+}
+
+/**
+ This function dump PCR event.
+
+ @param[in] EventHdr TCG PCR event structure.
+**/
+VOID
+DumpEvent (
+ IN TCG_PCR_EVENT_HDR *EventHdr
+ )
+{
+ UINTN Index;
+
+ DEBUG ((EFI_D_INFO, " Event:\n"));
+ DEBUG ((EFI_D_INFO, " PCRIndex - %d\n", EventHdr->PCRIndex));
+ DEBUG ((EFI_D_INFO, " EventType - 0x%08x\n", EventHdr->EventType));
+ DEBUG ((EFI_D_INFO, " Digest - "));
+ for (Index = 0; Index < sizeof(TCG_DIGEST); Index++) {
+ DEBUG ((EFI_D_INFO, "%02x ", EventHdr->Digest.digest[Index]));
+ }
+ DEBUG ((EFI_D_INFO, "\n"));
+ DEBUG ((EFI_D_INFO, " EventSize - 0x%08x\n", EventHdr->EventSize));
+ InternalDumpHex ((UINT8 *)(EventHdr + 1), EventHdr->EventSize);
+}
+
+/**
+ This function dump TCG_EfiSpecIDEventStruct.
+
+ @param[in] TcgEfiSpecIdEventStruct A pointer to TCG_EfiSpecIDEventStruct.
+**/
+VOID
+DumpTcgEfiSpecIdEventStruct (
+ IN TCG_EfiSpecIDEventStruct *TcgEfiSpecIdEventStruct
+ )
+{
+ TCG_EfiSpecIdEventAlgorithmSize *DigestSize;
+ UINTN Index;
+ UINT8 *VendorInfoSize;
+ UINT8 *VendorInfo;
+ UINT32 NumberOfAlgorithms;
+
+ DEBUG ((EFI_D_INFO, " TCG_EfiSpecIDEventStruct:\n"));
+ DEBUG ((EFI_D_INFO, " signature - '"));
+ for (Index = 0; Index < sizeof(TcgEfiSpecIdEventStruct->signature); Index++) {
+ DEBUG ((EFI_D_INFO, "%c", TcgEfiSpecIdEventStruct->signature[Index]));
+ }
+ DEBUG ((EFI_D_INFO, "'\n"));
+ DEBUG ((EFI_D_INFO, " platformClass - 0x%08x\n", TcgEfiSpecIdEventStruct->platformClass));
+ DEBUG ((EFI_D_INFO, " specVersion - %d.%d%d\n", TcgEfiSpecIdEventStruct->specVersionMajor, TcgEfiSpecIdEventStruct->specVersionMinor, TcgEfiSpecIdEventStruct->specErrata));
+ DEBUG ((EFI_D_INFO, " uintnSize - 0x%02x\n", TcgEfiSpecIdEventStruct->uintnSize));
+
+ CopyMem (&NumberOfAlgorithms, TcgEfiSpecIdEventStruct + 1, sizeof(NumberOfAlgorithms));
+ DEBUG ((EFI_D_INFO, " NumberOfAlgorithms - 0x%08x\n", NumberOfAlgorithms));
+
+ DigestSize = (TCG_EfiSpecIdEventAlgorithmSize *)((UINT8 *)TcgEfiSpecIdEventStruct + sizeof(*TcgEfiSpecIdEventStruct) + sizeof(NumberOfAlgorithms));
+ for (Index = 0; Index < NumberOfAlgorithms; Index++) {
+ DEBUG ((EFI_D_INFO, " digest(%d)\n", Index));
+ DEBUG ((EFI_D_INFO, " algorithmId - 0x%04x\n", DigestSize[Index].algorithmId));
+ DEBUG ((EFI_D_INFO, " digestSize - 0x%04x\n", DigestSize[Index].digestSize));
+ }
+ VendorInfoSize = (UINT8 *)&DigestSize[NumberOfAlgorithms];
+ DEBUG ((EFI_D_INFO, " VendorInfoSize - 0x%02x\n", *VendorInfoSize));
+ VendorInfo = VendorInfoSize + 1;
+ DEBUG ((EFI_D_INFO, " VendorInfo - "));
+ for (Index = 0; Index < *VendorInfoSize; Index++) {
+ DEBUG ((EFI_D_INFO, "%02x ", VendorInfo[Index]));
+ }
+ DEBUG ((EFI_D_INFO, "\n"));
+}
+
+/**
+ This function get size of TCG_EfiSpecIDEventStruct.
+
+ @param[in] TcgEfiSpecIdEventStruct A pointer to TCG_EfiSpecIDEventStruct.
+**/
+UINTN
+GetTcgEfiSpecIdEventStructSize (
+ IN TCG_EfiSpecIDEventStruct *TcgEfiSpecIdEventStruct
+ )
+{
+ TCG_EfiSpecIdEventAlgorithmSize *DigestSize;
+ UINT8 *VendorInfoSize;
+ UINT32 NumberOfAlgorithms;
+
+ CopyMem (&NumberOfAlgorithms, TcgEfiSpecIdEventStruct + 1, sizeof(NumberOfAlgorithms));
+
+ DigestSize = (TCG_EfiSpecIdEventAlgorithmSize *)((UINT8 *)TcgEfiSpecIdEventStruct + sizeof(*TcgEfiSpecIdEventStruct) + sizeof(NumberOfAlgorithms));
+ VendorInfoSize = (UINT8 *)&DigestSize[NumberOfAlgorithms];
+ return sizeof(TCG_EfiSpecIDEventStruct) + sizeof(UINT32) + (NumberOfAlgorithms * sizeof(TCG_EfiSpecIdEventAlgorithmSize)) + sizeof(UINT8) + (*VendorInfoSize);
+}
+
+/**
+ This function dump PCR event 2.
+
+ @param[in] TcgPcrEvent2 TCG PCR event 2 structure.
+**/
+VOID
+DumpEvent2 (
+ IN TCG_PCR_EVENT2 *TcgPcrEvent2
+ )
+{
+ UINTN Index;
+ UINT32 DigestIndex;
+ UINT32 DigestCount;
+ TPMI_ALG_HASH HashAlgo;
+ UINT32 DigestSize;
+ UINT8 *DigestBuffer;
+ UINT32 EventSize;
+ UINT8 *EventBuffer;
+
+ DEBUG ((EFI_D_INFO, " Event:\n"));
+ DEBUG ((EFI_D_INFO, " PCRIndex - %d\n", TcgPcrEvent2->PCRIndex));
+ DEBUG ((EFI_D_INFO, " EventType - 0x%08x\n", TcgPcrEvent2->EventType));
+
+ DEBUG ((EFI_D_INFO, " DigestCount: 0x%08x\n", TcgPcrEvent2->Digest.count));
+
+ DigestCount = TcgPcrEvent2->Digest.count;
+ HashAlgo = TcgPcrEvent2->Digest.digests[0].hashAlg;
+ DigestBuffer = (UINT8 *)&TcgPcrEvent2->Digest.digests[0].digest;
+ for (DigestIndex = 0; DigestIndex < DigestCount; DigestIndex++) {
+ DEBUG ((EFI_D_INFO, " HashAlgo : 0x%04x\n", HashAlgo));
+ DEBUG ((EFI_D_INFO, " Digest(%d): ", DigestIndex));
+ DigestSize = GetHashSizeFromAlgo (HashAlgo);
+ for (Index = 0; Index < DigestSize; Index++) {
+ DEBUG ((EFI_D_INFO, "%02x ", DigestBuffer[Index]));
+ }
+ DEBUG ((EFI_D_INFO, "\n"));
+ //
+ // Prepare next
+ //
+ CopyMem (&HashAlgo, DigestBuffer + DigestSize, sizeof(TPMI_ALG_HASH));
+ DigestBuffer = DigestBuffer + DigestSize + sizeof(TPMI_ALG_HASH);
+ }
+ DEBUG ((EFI_D_INFO, "\n"));
+ DigestBuffer = DigestBuffer - sizeof(TPMI_ALG_HASH);
+
+ CopyMem (&EventSize, DigestBuffer, sizeof(TcgPcrEvent2->EventSize));
+ DEBUG ((EFI_D_INFO, " EventSize - 0x%08x\n", EventSize));
+ EventBuffer = DigestBuffer + sizeof(TcgPcrEvent2->EventSize);
+ InternalDumpHex (EventBuffer, EventSize);
+}
+
+/**
+ This function returns size of TCG PCR event 2.
+
+ @param[in] TcgPcrEvent2 TCG PCR event 2 structure.
+
+ @return size of TCG PCR event 2.
+**/
+UINTN
+GetPcrEvent2Size (
+ IN TCG_PCR_EVENT2 *TcgPcrEvent2
+ )
+{
+ UINT32 DigestIndex;
+ UINT32 DigestCount;
+ TPMI_ALG_HASH HashAlgo;
+ UINT32 DigestSize;
+ UINT8 *DigestBuffer;
+ UINT32 EventSize;
+ UINT8 *EventBuffer;
+
+ DigestCount = TcgPcrEvent2->Digest.count;
+ HashAlgo = TcgPcrEvent2->Digest.digests[0].hashAlg;
+ DigestBuffer = (UINT8 *)&TcgPcrEvent2->Digest.digests[0].digest;
+ for (DigestIndex = 0; DigestIndex < DigestCount; DigestIndex++) {
+ DigestSize = GetHashSizeFromAlgo (HashAlgo);
+ //
+ // Prepare next
+ //
+ CopyMem (&HashAlgo, DigestBuffer + DigestSize, sizeof(TPMI_ALG_HASH));
+ DigestBuffer = DigestBuffer + DigestSize + sizeof(TPMI_ALG_HASH);
+ }
+ DigestBuffer = DigestBuffer - sizeof(TPMI_ALG_HASH);
+
+ CopyMem (&EventSize, DigestBuffer, sizeof(TcgPcrEvent2->EventSize));
+ EventBuffer = DigestBuffer + sizeof(TcgPcrEvent2->EventSize);
+
+ return (UINTN)EventBuffer + EventSize - (UINTN)TcgPcrEvent2;
+}
+
+/**
+ This function dump event log.
+
+ @param[in] EventLogFormat The type of the event log for which the information is requested.
+ @param[in] EventLogLocation A pointer to the memory address of the event log.
+ @param[in] 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.
+ @param[in] FinalEventsTable A pointer to the memory address of the final event table.
+**/
+VOID
+DumpEventLog (
+ IN EFI_TCG2_EVENT_LOG_FORMAT EventLogFormat,
+ IN EFI_PHYSICAL_ADDRESS EventLogLocation,
+ IN EFI_PHYSICAL_ADDRESS EventLogLastEntry,
+ IN EFI_TCG2_FINAL_EVENTS_TABLE *FinalEventsTable
+ )
+{
+ TCG_PCR_EVENT_HDR *EventHdr;
+ TCG_PCR_EVENT2 *TcgPcrEvent2;
+ TCG_EfiSpecIDEventStruct *TcgEfiSpecIdEventStruct;
+ UINTN NumberOfEvents;
+
+ DEBUG ((EFI_D_INFO, "EventLogFormat: (0x%x)\n", EventLogFormat));
+
+ switch (EventLogFormat) {
+ case EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2:
+ EventHdr = (TCG_PCR_EVENT_HDR *)(UINTN)EventLogLocation;
+ while ((UINTN)EventHdr <= EventLogLastEntry) {
+ DumpEvent (EventHdr);
+ EventHdr = (TCG_PCR_EVENT_HDR *)((UINTN)EventHdr + sizeof(TCG_PCR_EVENT_HDR) + EventHdr->EventSize);
+ }
+ if (FinalEventsTable == NULL) {
+ DEBUG ((EFI_D_INFO, "FinalEventsTable: NOT FOUND\n"));
+ } else {
+ DEBUG ((EFI_D_INFO, "FinalEventsTable: (0x%x)\n", FinalEventsTable));
+ DEBUG ((EFI_D_INFO, " Version: (0x%x)\n", FinalEventsTable->Version));
+ DEBUG ((EFI_D_INFO, " NumberOfEvents: (0x%x)\n", FinalEventsTable->NumberOfEvents));
+
+ EventHdr = (TCG_PCR_EVENT_HDR *)(UINTN)(FinalEventsTable + 1);
+ for (NumberOfEvents = 0; NumberOfEvents < FinalEventsTable->NumberOfEvents; NumberOfEvents++) {
+ DumpEvent (EventHdr);
+ EventHdr = (TCG_PCR_EVENT_HDR *)((UINTN)EventHdr + sizeof(TCG_PCR_EVENT_HDR) + EventHdr->EventSize);
+ }
+ }
+ break;
+ case EFI_TCG2_EVENT_LOG_FORMAT_TCG_2:
+ //
+ // Dump first event
+ //
+ EventHdr = (TCG_PCR_EVENT_HDR *)(UINTN)EventLogLocation;
+ DumpEvent (EventHdr);
+
+ TcgEfiSpecIdEventStruct = (TCG_EfiSpecIDEventStruct *)(EventHdr + 1);
+ DumpTcgEfiSpecIdEventStruct (TcgEfiSpecIdEventStruct);
+
+ TcgPcrEvent2 = (TCG_PCR_EVENT2 *)((UINTN)TcgEfiSpecIdEventStruct + GetTcgEfiSpecIdEventStructSize (TcgEfiSpecIdEventStruct));
+ while ((UINTN)TcgPcrEvent2 <= EventLogLastEntry) {
+ DumpEvent2 (TcgPcrEvent2);
+ TcgPcrEvent2 = (TCG_PCR_EVENT2 *)((UINTN)TcgPcrEvent2 + GetPcrEvent2Size (TcgPcrEvent2));
+ }
+
+ if (FinalEventsTable == NULL) {
+ DEBUG ((EFI_D_INFO, "FinalEventsTable: NOT FOUND\n"));
+ } else {
+ DEBUG ((EFI_D_INFO, "FinalEventsTable: (0x%x)\n", FinalEventsTable));
+ DEBUG ((EFI_D_INFO, " Version: (0x%x)\n", FinalEventsTable->Version));
+ DEBUG ((EFI_D_INFO, " NumberOfEvents: (0x%x)\n", FinalEventsTable->NumberOfEvents));
+
+ TcgPcrEvent2 = (TCG_PCR_EVENT2 *)(UINTN)(FinalEventsTable + 1);
+ for (NumberOfEvents = 0; NumberOfEvents < FinalEventsTable->NumberOfEvents; NumberOfEvents++) {
+ DumpEvent2 (TcgPcrEvent2);
+ TcgPcrEvent2 = (TCG_PCR_EVENT2 *)((UINTN)TcgPcrEvent2 + GetPcrEvent2Size (TcgPcrEvent2));
+ }
+ }
+ break;
+ }
+
+ return ;
+}
+
+/**
+ The EFI_TCG2_PROTOCOL Get Event Log function call allows a caller to
+ retrieve the address of a given event log and its last entry.
+
+ @param[in] This Indicates the calling context
+ @param[in] EventLogFormat The type of the event log for which the information is requested.
+ @param[out] EventLogLocation A pointer to the memory address of the event log.
+ @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.
+ @param[out] EventLogTruncated If the Event Log is missing at least one entry because an event would
+ have exceeded the area allocated for events, this value is set to TRUE.
+ Otherwise, the value will be FALSE and the Event Log will be complete.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters are incorrect
+ (e.g. asking for an event log whose format is not supported).
+**/
+EFI_STATUS
+EFIAPI
+Tcg2GetEventLog (
+ IN EFI_TCG2_PROTOCOL *This,
+ IN EFI_TCG2_EVENT_LOG_FORMAT EventLogFormat,
+ OUT EFI_PHYSICAL_ADDRESS *EventLogLocation,
+ OUT EFI_PHYSICAL_ADDRESS *EventLogLastEntry,
+ OUT BOOLEAN *EventLogTruncated
+ )
+{
+ UINTN Index;
+
+ DEBUG ((EFI_D_INFO, "Tcg2GetEventLog ... (0x%x)\n", EventLogFormat));
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ for (Index = 0; Index < sizeof(mTcg2EventInfo)/sizeof(mTcg2EventInfo[0]); Index++) {
+ if (EventLogFormat == mTcg2EventInfo[Index].LogFormat) {
+ break;
+ }
+ }
+
+ if (Index == sizeof(mTcg2EventInfo)/sizeof(mTcg2EventInfo[0])) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((mTcg2EventInfo[Index].LogFormat & mTcgDxeData.BsCap.SupportedEventLogs) == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!mTcgDxeData.BsCap.TPMPresentFlag) {
+ if (EventLogLocation != NULL) {
+ *EventLogLocation = 0;
+ }
+ if (EventLogLastEntry != NULL) {
+ *EventLogLastEntry = 0;
+ }
+ if (EventLogTruncated != NULL) {
+ *EventLogTruncated = FALSE;
+ }
+ return EFI_SUCCESS;
+ }
+
+ if (EventLogLocation != NULL) {
+ *EventLogLocation = mTcgDxeData.EventLogAreaStruct[Index].Lasa;
+ DEBUG ((EFI_D_INFO, "Tcg2GetEventLog (EventLogLocation - %x)\n", *EventLogLocation));
+ }
+
+ if (EventLogLastEntry != NULL) {
+ if (!mTcgDxeData.EventLogAreaStruct[Index].EventLogStarted) {
+ *EventLogLastEntry = (EFI_PHYSICAL_ADDRESS)(UINTN)0;
+ } else {
+ *EventLogLastEntry = (EFI_PHYSICAL_ADDRESS)(UINTN)mTcgDxeData.EventLogAreaStruct[Index].LastEvent;
+ }
+ DEBUG ((EFI_D_INFO, "Tcg2GetEventLog (EventLogLastEntry - %x)\n", *EventLogLastEntry));
+ }
+
+ if (EventLogTruncated != NULL) {
+ *EventLogTruncated = mTcgDxeData.EventLogAreaStruct[Index].EventLogTruncated;
+ DEBUG ((EFI_D_INFO, "Tcg2GetEventLog (EventLogTruncated - %x)\n", *EventLogTruncated));
+ }
+
+ DEBUG ((EFI_D_INFO, "Tcg2GetEventLog - %r\n", EFI_SUCCESS));
+
+ // Dump Event Log for debug purpose
+ if ((EventLogLocation != NULL) && (EventLogLastEntry != NULL)) {
+ DumpEventLog (EventLogFormat, *EventLogLocation, *EventLogLastEntry, mTcgDxeData.FinalEventsTable[Index]);
+ }
+
+ //
+ // All events generated after the invocation of EFI_TCG2_GET_EVENT_LOG SHALL be stored
+ // in an instance of an EFI_CONFIGURATION_TABLE named by the VendorGuid of EFI_TCG2_FINAL_EVENTS_TABLE_GUID.
+ //
+ mTcgDxeData.GetEventLogCalled[Index] = TRUE;
+
+ 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/TCG_PCR_EVENT_EX data structure.
+ @param[in] NewEventHdrSize New event header size.
+ @param[in] NewEventData Pointer to the new event data.
+ @param[in] NewEventSize New event data size.
+
+ @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
+TcgCommLogEvent (
+ IN OUT UINT8 **EventLogPtr,
+ IN OUT UINTN *LogSize,
+ IN UINTN MaxSize,
+ IN VOID *NewEventHdr,
+ IN UINT32 NewEventHdrSize,
+ IN UINT8 *NewEventData,
+ IN UINT32 NewEventSize
+ )
+{
+ UINTN NewLogSize;
+
+ if (NewEventSize > MAX_ADDRESS - NewEventHdrSize) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NewLogSize = NewEventHdrSize + NewEventSize;
+
+ if (NewLogSize > MAX_ADDRESS - *LogSize) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (NewLogSize + *LogSize > MaxSize) {
+ DEBUG ((EFI_D_INFO, " MaxSize - 0x%x\n", MaxSize));
+ DEBUG ((EFI_D_INFO, " NewLogSize - 0x%x\n", NewLogSize));
+ DEBUG ((EFI_D_INFO, " LogSize - 0x%x\n", *LogSize));
+ DEBUG ((EFI_D_INFO, "TcgCommLogEvent - %r\n", EFI_OUT_OF_RESOURCES));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ *EventLogPtr += *LogSize;
+ *LogSize += NewLogSize;
+ CopyMem (*EventLogPtr, NewEventHdr, NewEventHdrSize);
+ CopyMem (
+ *EventLogPtr + NewEventHdrSize,
+ NewEventData,
+ NewEventSize
+ );
+ return EFI_SUCCESS;
+}
+
+/**
+ Add a new entry to the Event Log.
+
+ @param[in] EventLogFormat The type of the event log for which the information is requested.
+ @param[in] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR/TCG_PCR_EVENT_EX data structure.
+ @param[in] NewEventHdrSize New event header size.
+ @param[in] NewEventData Pointer to the new event data.
+ @param[in] NewEventSize New event data size.
+
+ @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
+TcgDxeLogEvent (
+ IN EFI_TCG2_EVENT_LOG_FORMAT EventLogFormat,
+ IN VOID *NewEventHdr,
+ IN UINT32 NewEventHdrSize,
+ IN UINT8 *NewEventData,
+ IN UINT32 NewEventSize
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ TCG_EVENT_LOG_AREA_STRUCT *EventLogAreaStruct;
+
+ for (Index = 0; Index < sizeof(mTcg2EventInfo)/sizeof(mTcg2EventInfo[0]); Index++) {
+ if (EventLogFormat == mTcg2EventInfo[Index].LogFormat) {
+ break;
+ }
+ }
+
+ if (Index == sizeof(mTcg2EventInfo)/sizeof(mTcg2EventInfo[0])) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Record to normal event log
+ //
+ EventLogAreaStruct = &mTcgDxeData.EventLogAreaStruct[Index];
+
+ if (EventLogAreaStruct->EventLogTruncated) {
+ return EFI_VOLUME_FULL;
+ }
+
+ EventLogAreaStruct->LastEvent = (UINT8*)(UINTN)EventLogAreaStruct->Lasa;
+ Status = TcgCommLogEvent (
+ &EventLogAreaStruct->LastEvent,
+ &EventLogAreaStruct->EventLogSize,
+ (UINTN)EventLogAreaStruct->Laml,
+ NewEventHdr,
+ NewEventHdrSize,
+ NewEventData,
+ NewEventSize
+ );
+
+ if (Status == EFI_OUT_OF_RESOURCES) {
+ EventLogAreaStruct->EventLogTruncated = TRUE;
+ return EFI_VOLUME_FULL;
+ } else if (Status == EFI_SUCCESS) {
+ EventLogAreaStruct->EventLogStarted = TRUE;
+ }
+
+ //
+ // If GetEventLog is called, record to FinalEventsTable, too.
+ //
+ if (mTcgDxeData.GetEventLogCalled[Index]) {
+ if (mTcgDxeData.FinalEventsTable[Index] == NULL) {
+ //
+ // no need for FinalEventsTable
+ //
+ return EFI_SUCCESS;
+ }
+ EventLogAreaStruct = &mTcgDxeData.FinalEventLogAreaStruct[Index];
+
+ if (EventLogAreaStruct->EventLogTruncated) {
+ return EFI_VOLUME_FULL;
+ }
+
+ EventLogAreaStruct->LastEvent = (UINT8*)(UINTN)EventLogAreaStruct->Lasa;
+ Status = TcgCommLogEvent (
+ &EventLogAreaStruct->LastEvent,
+ &EventLogAreaStruct->EventLogSize,
+ (UINTN)EventLogAreaStruct->Laml,
+ NewEventHdr,
+ NewEventHdrSize,
+ NewEventData,
+ NewEventSize
+ );
+ if (Status == EFI_OUT_OF_RESOURCES) {
+ EventLogAreaStruct->EventLogTruncated = TRUE;
+ return EFI_VOLUME_FULL;
+ } else if (Status == EFI_SUCCESS) {
+ EventLogAreaStruct->EventLogStarted = TRUE;
+ //
+ // Increase the NumberOfEvents in FinalEventsTable
+ //
+ (mTcgDxeData.FinalEventsTable[Index])->NumberOfEvents ++;
+ DEBUG ((EFI_D_INFO, "FinalEventsTable->NumberOfEvents - 0x%x\n", (mTcgDxeData.FinalEventsTable[Index])->NumberOfEvents));
+ DEBUG ((EFI_D_INFO, " Size - 0x%x\n", (UINTN)EventLogAreaStruct->EventLogSize));
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Get TPML_DIGEST_VALUES compact binary buffer size.
+
+ @param[in] DigestListBin TPML_DIGEST_VALUES compact binary buffer.
+
+ @return TPML_DIGEST_VALUES compact binary buffer size.
+**/
+UINT32
+GetDigestListBinSize (
+ IN VOID *DigestListBin
+ )
+{
+ UINTN Index;
+ UINT16 DigestSize;
+ UINT32 TotalSize;
+ UINT32 Count;
+ TPMI_ALG_HASH HashAlg;
+
+ Count = ReadUnaligned32 (DigestListBin);
+ TotalSize = sizeof(Count);
+ DigestListBin = (UINT8 *)DigestListBin + sizeof(Count);
+ for (Index = 0; Index < Count; Index++) {
+ HashAlg = ReadUnaligned16 (DigestListBin);
+ TotalSize += sizeof(HashAlg);
+ DigestListBin = (UINT8 *)DigestListBin + sizeof(HashAlg);
+
+ DigestSize = GetHashSizeFromAlgo (HashAlg);
+ TotalSize += DigestSize;
+ DigestListBin = (UINT8 *)DigestListBin + DigestSize;
+ }
+
+ return TotalSize;
+}
+
+/**
+ Copy TPML_DIGEST_VALUES compact binary into a buffer
+
+ @param[in,out] Buffer Buffer to hold copied TPML_DIGEST_VALUES compact binary.
+ @param[in] DigestListBin TPML_DIGEST_VALUES compact binary buffer.
+ @param[in] HashAlgorithmMask HASH bits corresponding to the desired digests to copy.
+ @param[out] HashAlgorithmMaskCopied Pointer to HASH bits corresponding to the digests copied.
+
+ @return The end of buffer to hold TPML_DIGEST_VALUES compact binary.
+**/
+VOID *
+CopyDigestListBinToBuffer (
+ IN OUT VOID *Buffer,
+ IN VOID *DigestListBin,
+ IN UINT32 HashAlgorithmMask,
+ OUT UINT32 *HashAlgorithmMaskCopied
+ )
+{
+ UINTN Index;
+ UINT16 DigestSize;
+ UINT32 Count;
+ TPMI_ALG_HASH HashAlg;
+ UINT32 DigestListCount;
+ UINT32 *DigestListCountPtr;
+
+ DigestListCountPtr = (UINT32 *) Buffer;
+ DigestListCount = 0;
+ (*HashAlgorithmMaskCopied) = 0;
+
+ Count = ReadUnaligned32 (DigestListBin);
+ Buffer = (UINT8 *)Buffer + sizeof(Count);
+ DigestListBin = (UINT8 *)DigestListBin + sizeof(Count);
+ for (Index = 0; Index < Count; Index++) {
+ HashAlg = ReadUnaligned16 (DigestListBin);
+ DigestListBin = (UINT8 *)DigestListBin + sizeof(HashAlg);
+ DigestSize = GetHashSizeFromAlgo (HashAlg);
+
+ if (IsHashAlgSupportedInHashAlgorithmMask(HashAlg, HashAlgorithmMask)) {
+ CopyMem (Buffer, &HashAlg, sizeof(HashAlg));
+ Buffer = (UINT8 *)Buffer + sizeof(HashAlg);
+ CopyMem (Buffer, DigestListBin, DigestSize);
+ Buffer = (UINT8 *)Buffer + DigestSize;
+ DigestListCount++;
+ (*HashAlgorithmMaskCopied) |= GetHashMaskFromAlgo (HashAlg);
+ } else {
+ DEBUG ((DEBUG_ERROR, "WARNING: CopyDigestListBinToBuffer Event log has HashAlg unsupported by PCR bank (0x%x)\n", HashAlg));
+ }
+ DigestListBin = (UINT8 *)DigestListBin + DigestSize;
+ }
+ WriteUnaligned32 (DigestListCountPtr, DigestListCount);
+
+ return Buffer;
+}
+
+/**
+ Add a new entry to the Event Log.
+
+ @param[in] DigestList A list of digest.
+ @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 The new event log entry was added.
+ @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.
+**/
+EFI_STATUS
+TcgDxeLogHashEvent (
+ IN TPML_DIGEST_VALUES *DigestList,
+ IN OUT TCG_PCR_EVENT_HDR *NewEventHdr,
+ IN UINT8 *NewEventData
+ )
+{
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+ UINTN Index;
+ EFI_STATUS RetStatus;
+ TCG_PCR_EVENT2 TcgPcrEvent2;
+ UINT8 *DigestBuffer;
+ UINT32 *EventSizePtr;
+
+ DEBUG ((EFI_D_INFO, "SupportedEventLogs - 0x%08x\n", mTcgDxeData.BsCap.SupportedEventLogs));
+
+ RetStatus = EFI_SUCCESS;
+ for (Index = 0; Index < sizeof(mTcg2EventInfo)/sizeof(mTcg2EventInfo[0]); Index++) {
+ if ((mTcgDxeData.BsCap.SupportedEventLogs & mTcg2EventInfo[Index].LogFormat) != 0) {
+ DEBUG ((EFI_D_INFO, " LogFormat - 0x%08x\n", mTcg2EventInfo[Index].LogFormat));
+ switch (mTcg2EventInfo[Index].LogFormat) {
+ case EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2:
+ Status = GetDigestFromDigestList (TPM_ALG_SHA1, DigestList, &NewEventHdr->Digest);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Enter critical region
+ //
+ OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
+ Status = TcgDxeLogEvent (
+ mTcg2EventInfo[Index].LogFormat,
+ NewEventHdr,
+ sizeof(TCG_PCR_EVENT_HDR),
+ NewEventData,
+ NewEventHdr->EventSize
+ );
+ if (Status != EFI_SUCCESS) {
+ RetStatus = Status;
+ }
+ gBS->RestoreTPL (OldTpl);
+ //
+ // Exit critical region
+ //
+ }
+ break;
+ case EFI_TCG2_EVENT_LOG_FORMAT_TCG_2:
+ ZeroMem (&TcgPcrEvent2, sizeof(TcgPcrEvent2));
+ TcgPcrEvent2.PCRIndex = NewEventHdr->PCRIndex;
+ TcgPcrEvent2.EventType = NewEventHdr->EventType;
+ DigestBuffer = (UINT8 *)&TcgPcrEvent2.Digest;
+ EventSizePtr = CopyDigestListToBuffer (DigestBuffer, DigestList, mTcgDxeData.BsCap.ActivePcrBanks);
+ CopyMem (EventSizePtr, &NewEventHdr->EventSize, sizeof(NewEventHdr->EventSize));
+
+ //
+ // Enter critical region
+ //
+ OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
+ Status = TcgDxeLogEvent (
+ mTcg2EventInfo[Index].LogFormat,
+ &TcgPcrEvent2,
+ sizeof(TcgPcrEvent2.PCRIndex) + sizeof(TcgPcrEvent2.EventType) + GetDigestListBinSize (DigestBuffer) + sizeof(TcgPcrEvent2.EventSize),
+ NewEventData,
+ NewEventHdr->EventSize
+ );
+ if (Status != EFI_SUCCESS) {
+ RetStatus = Status;
+ }
+ gBS->RestoreTPL (OldTpl);
+ //
+ // Exit critical region
+ //
+ break;
+ }
+ }
+ }
+
+ return RetStatus;
+}
+
+/**
+ 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] Flags Bitmap providing additional information.
+ @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
+TcgDxeHashLogExtendEvent (
+ IN UINT64 Flags,
+ IN UINT8 *HashData,
+ IN UINT64 HashDataLen,
+ IN OUT TCG_PCR_EVENT_HDR *NewEventHdr,
+ IN UINT8 *NewEventData
+ )
+{
+ EFI_STATUS Status;
+ TPML_DIGEST_VALUES DigestList;
+
+ if (!mTcgDxeData.BsCap.TPMPresentFlag) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = HashAndExtend (
+ NewEventHdr->PCRIndex,
+ HashData,
+ (UINTN)HashDataLen,
+ &DigestList
+ );
+ if (!EFI_ERROR (Status)) {
+ if ((Flags & EFI_TCG2_EXTEND_ONLY) == 0) {
+ Status = TcgDxeLogHashEvent (&DigestList, NewEventHdr, NewEventData);
+ }
+ }
+
+ if (Status == EFI_DEVICE_ERROR) {
+ DEBUG ((EFI_D_ERROR, "TcgDxeHashLogExtendEvent - %r. Disable TPM.\n", Status));
+ mTcgDxeData.BsCap.TPMPresentFlag = FALSE;
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ (PcdGet32 (PcdStatusCodeSubClassTpmDevice) | EFI_P_EC_INTERFACE_ERROR)
+ );
+ }
+
+ return Status;
+}
+
+/**
+ The EFI_TCG2_PROTOCOL HashLogExtendEvent function call provides callers with
+ an opportunity to extend and optionally log events without requiring
+ knowledge of actual TPM commands.
+ The extend operation will occur even if this function cannot create an event
+ log entry (e.g. due to the event log being full).
+
+ @param[in] This Indicates the calling context
+ @param[in] Flags Bitmap providing additional information.
+ @param[in] DataToHash Physical address of the start of the data buffer to be hashed.
+ @param[in] DataToHashLen The length in bytes of the buffer referenced by DataToHash.
+ @param[in] Event Pointer to data buffer containing information about the event.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+ @retval EFI_VOLUME_FULL The extend operation occurred, but the event could not be written to one or more event logs.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters are incorrect.
+ @retval EFI_UNSUPPORTED The PE/COFF image type is not supported.
+**/
+EFI_STATUS
+EFIAPI
+Tcg2HashLogExtendEvent (
+ IN EFI_TCG2_PROTOCOL *This,
+ IN UINT64 Flags,
+ IN EFI_PHYSICAL_ADDRESS DataToHash,
+ IN UINT64 DataToHashLen,
+ IN EFI_TCG2_EVENT *Event
+ )
+{
+ EFI_STATUS Status;
+ TCG_PCR_EVENT_HDR NewEventHdr;
+ TPML_DIGEST_VALUES DigestList;
+
+ DEBUG ((DEBUG_VERBOSE, "Tcg2HashLogExtendEvent ...\n"));
+
+ if ((This == NULL) || (DataToHash == 0) || (Event == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!mTcgDxeData.BsCap.TPMPresentFlag) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (Event->Size < Event->Header.HeaderSize + sizeof(UINT32)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Event->Header.PCRIndex > MAX_PCR_INDEX) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ NewEventHdr.PCRIndex = Event->Header.PCRIndex;
+ NewEventHdr.EventType = Event->Header.EventType;
+ NewEventHdr.EventSize = Event->Size - sizeof(UINT32) - Event->Header.HeaderSize;
+ if ((Flags & PE_COFF_IMAGE) != 0) {
+ Status = MeasurePeImageAndExtend (
+ NewEventHdr.PCRIndex,
+ DataToHash,
+ (UINTN)DataToHashLen,
+ &DigestList
+ );
+ if (!EFI_ERROR (Status)) {
+ if ((Flags & EFI_TCG2_EXTEND_ONLY) == 0) {
+ Status = TcgDxeLogHashEvent (&DigestList, &NewEventHdr, Event->Event);
+ }
+ }
+ if (Status == EFI_DEVICE_ERROR) {
+ DEBUG ((EFI_D_ERROR, "MeasurePeImageAndExtend - %r. Disable TPM.\n", Status));
+ mTcgDxeData.BsCap.TPMPresentFlag = FALSE;
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ (PcdGet32 (PcdStatusCodeSubClassTpmDevice) | EFI_P_EC_INTERFACE_ERROR)
+ );
+ }
+ } else {
+ Status = TcgDxeHashLogExtendEvent (
+ Flags,
+ (UINT8 *) (UINTN) DataToHash,
+ DataToHashLen,
+ &NewEventHdr,
+ Event->Event
+ );
+ }
+ DEBUG ((DEBUG_VERBOSE, "Tcg2HashLogExtendEvent - %r\n", Status));
+ return Status;
+}
+
+/**
+ This service enables the sending of commands to the TPM.
+
+ @param[in] This Indicates the calling context
+ @param[in] InputParameterBlockSize Size of the TPM input parameter block.
+ @param[in] InputParameterBlock Pointer to the TPM input parameter block.
+ @param[in] OutputParameterBlockSize Size of the TPM output parameter block.
+ @param[in] OutputParameterBlock Pointer to the TPM output parameter block.
+
+ @retval EFI_SUCCESS The command byte stream was successfully sent to the device and a response was successfully received.
+ @retval EFI_DEVICE_ERROR The command was not successfully sent to the device or a response was not successfully received from the device.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters are incorrect.
+ @retval EFI_BUFFER_TOO_SMALL The output parameter block is too small.
+**/
+EFI_STATUS
+EFIAPI
+Tcg2SubmitCommand (
+ IN EFI_TCG2_PROTOCOL *This,
+ IN UINT32 InputParameterBlockSize,
+ IN UINT8 *InputParameterBlock,
+ IN UINT32 OutputParameterBlockSize,
+ IN UINT8 *OutputParameterBlock
+ )
+{
+ EFI_STATUS Status;
+
+ DEBUG ((EFI_D_INFO, "Tcg2SubmitCommand ...\n"));
+
+ if ((This == NULL) ||
+ (InputParameterBlockSize == 0) || (InputParameterBlock == NULL) ||
+ (OutputParameterBlockSize == 0) || (OutputParameterBlock == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!mTcgDxeData.BsCap.TPMPresentFlag) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (InputParameterBlockSize > mTcgDxeData.BsCap.MaxCommandSize) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (OutputParameterBlockSize > mTcgDxeData.BsCap.MaxResponseSize) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = Tpm2SubmitCommand (
+ InputParameterBlockSize,
+ InputParameterBlock,
+ &OutputParameterBlockSize,
+ OutputParameterBlock
+ );
+ DEBUG ((EFI_D_INFO, "Tcg2SubmitCommand - %r\n", Status));
+ return Status;
+}
+
+/**
+ This service returns the currently active PCR banks.
+
+ @param[in] This Indicates the calling context
+ @param[out] ActivePcrBanks Pointer to the variable receiving the bitmap of currently active PCR banks.
+
+ @retval EFI_SUCCESS The bitmap of active PCR banks was stored in the ActivePcrBanks parameter.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters are incorrect.
+**/
+EFI_STATUS
+EFIAPI
+Tcg2GetActivePCRBanks (
+ IN EFI_TCG2_PROTOCOL *This,
+ OUT UINT32 *ActivePcrBanks
+ )
+{
+ if (ActivePcrBanks == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ *ActivePcrBanks = mTcgDxeData.BsCap.ActivePcrBanks;
+ return EFI_SUCCESS;
+}
+
+/**
+ This service sets the currently active PCR banks.
+
+ @param[in] This Indicates the calling context
+ @param[in] ActivePcrBanks Bitmap of the requested active PCR banks. At least one bit SHALL be set.
+
+ @retval EFI_SUCCESS The bitmap in ActivePcrBank parameter is already active.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters are incorrect.
+**/
+EFI_STATUS
+EFIAPI
+Tcg2SetActivePCRBanks (
+ IN EFI_TCG2_PROTOCOL *This,
+ IN UINT32 ActivePcrBanks
+ )
+{
+ EFI_STATUS Status;
+ UINT32 ReturnCode;
+
+ DEBUG ((EFI_D_INFO, "Tcg2SetActivePCRBanks ... (0x%x)\n", ActivePcrBanks));
+
+ if (ActivePcrBanks == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if ((ActivePcrBanks & (~mTcgDxeData.BsCap.HashAlgorithmBitmap)) != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (ActivePcrBanks == mTcgDxeData.BsCap.ActivePcrBanks) {
+ //
+ // Need clear previous SET_PCR_BANKS setting
+ //
+ ReturnCode = Tcg2PhysicalPresenceLibSubmitRequestToPreOSFunction (TCG2_PHYSICAL_PRESENCE_NO_ACTION, 0);
+ } else {
+ ReturnCode = Tcg2PhysicalPresenceLibSubmitRequestToPreOSFunction (TCG2_PHYSICAL_PRESENCE_SET_PCR_BANKS, ActivePcrBanks);
+ }
+
+ if (ReturnCode == TCG_PP_SUBMIT_REQUEST_TO_PREOS_SUCCESS) {
+ Status = EFI_SUCCESS;
+ } else if (ReturnCode == TCG_PP_SUBMIT_REQUEST_TO_PREOS_GENERAL_FAILURE) {
+ Status = EFI_OUT_OF_RESOURCES;
+ } else if (ReturnCode == TCG_PP_SUBMIT_REQUEST_TO_PREOS_NOT_IMPLEMENTED) {
+ Status = EFI_UNSUPPORTED;
+ } else {
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ DEBUG ((EFI_D_INFO, "Tcg2SetActivePCRBanks - %r\n", Status));
+
+ return Status;
+}
+
+/**
+ This service retrieves the result of a previous invocation of SetActivePcrBanks.
+
+ @param[in] This Indicates the calling context
+ @param[out] OperationPresent Non-zero value to indicate a SetActivePcrBank operation was invoked during the last boot.
+ @param[out] Response The response from the SetActivePcrBank request.
+
+ @retval EFI_SUCCESS The result value could be returned.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters are incorrect.
+**/
+EFI_STATUS
+EFIAPI
+Tcg2GetResultOfSetActivePcrBanks (
+ IN EFI_TCG2_PROTOCOL *This,
+ OUT UINT32 *OperationPresent,
+ OUT UINT32 *Response
+ )
+{
+ UINT32 ReturnCode;
+
+ if ((OperationPresent == NULL) || (Response == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ReturnCode = Tcg2PhysicalPresenceLibReturnOperationResponseToOsFunction (OperationPresent, Response);
+ if (ReturnCode == TCG_PP_RETURN_TPM_OPERATION_RESPONSE_SUCCESS) {
+ return EFI_SUCCESS;
+ } else {
+ return EFI_UNSUPPORTED;
+ }
+}
+
+EFI_TCG2_PROTOCOL mTcg2Protocol = {
+ Tcg2GetCapability,
+ Tcg2GetEventLog,
+ Tcg2HashLogExtendEvent,
+ Tcg2SubmitCommand,
+ Tcg2GetActivePCRBanks,
+ Tcg2SetActivePCRBanks,
+ Tcg2GetResultOfSetActivePcrBanks,
+};
+
+/**
+ 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
+SetupEventLog (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ VOID *TcgEvent;
+ EFI_PEI_HOB_POINTERS GuidHob;
+ EFI_PHYSICAL_ADDRESS Lasa;
+ UINTN Index;
+ VOID *DigestListBin;
+ TPML_DIGEST_VALUES TempDigestListBin;
+ UINT32 DigestListBinSize;
+ UINT8 *Event;
+ UINT32 EventSize;
+ UINT32 *EventSizePtr;
+ UINT32 HashAlgorithmMaskCopied;
+ TCG_EfiSpecIDEventStruct *TcgEfiSpecIdEventStruct;
+ UINT8 TempBuf[sizeof(TCG_EfiSpecIDEventStruct) + sizeof(UINT32) + (HASH_COUNT * sizeof(TCG_EfiSpecIdEventAlgorithmSize)) + sizeof(UINT8)];
+ TCG_PCR_EVENT_HDR SpecIdEvent;
+ TCG_PCR_EVENT2_HDR NoActionEvent;
+ TCG_EfiSpecIdEventAlgorithmSize *DigestSize;
+ TCG_EfiSpecIdEventAlgorithmSize *TempDigestSize;
+ UINT8 *VendorInfoSize;
+ UINT32 NumberOfAlgorithms;
+ TCG_EfiStartupLocalityEvent StartupLocalityEvent;
+
+ DEBUG ((EFI_D_INFO, "SetupEventLog\n"));
+
+ //
+ // 1. Create Log Area
+ //
+ for (Index = 0; Index < sizeof(mTcg2EventInfo)/sizeof(mTcg2EventInfo[0]); Index++) {
+ if ((mTcgDxeData.BsCap.SupportedEventLogs & mTcg2EventInfo[Index].LogFormat) != 0) {
+ mTcgDxeData.EventLogAreaStruct[Index].EventLogFormat = mTcg2EventInfo[Index].LogFormat;
+ Status = gBS->AllocatePages (
+ AllocateAnyPages,
+ EfiBootServicesData,
+ EFI_SIZE_TO_PAGES (PcdGet32 (PcdTcgLogAreaMinLen)),
+ &Lasa
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ mTcgDxeData.EventLogAreaStruct[Index].Lasa = Lasa;
+ mTcgDxeData.EventLogAreaStruct[Index].Laml = PcdGet32 (PcdTcgLogAreaMinLen);
+ //
+ // To initialize them as 0xFF is recommended
+ // because the OS can know the last entry for that.
+ //
+ SetMem ((VOID *)(UINTN)Lasa, PcdGet32 (PcdTcgLogAreaMinLen), 0xFF);
+ //
+ // Create first entry for Log Header Entry Data
+ //
+ if (mTcg2EventInfo[Index].LogFormat != EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2) {
+ //
+ // TcgEfiSpecIdEventStruct
+ //
+ TcgEfiSpecIdEventStruct = (TCG_EfiSpecIDEventStruct *)TempBuf;
+ CopyMem (TcgEfiSpecIdEventStruct->signature, TCG_EfiSpecIDEventStruct_SIGNATURE_03, sizeof(TcgEfiSpecIdEventStruct->signature));
+ TcgEfiSpecIdEventStruct->platformClass = PcdGet8 (PcdTpmPlatformClass);
+ TcgEfiSpecIdEventStruct->specVersionMajor = TCG_EfiSpecIDEventStruct_SPEC_VERSION_MAJOR_TPM2;
+ TcgEfiSpecIdEventStruct->specVersionMinor = TCG_EfiSpecIDEventStruct_SPEC_VERSION_MINOR_TPM2;
+ TcgEfiSpecIdEventStruct->specErrata = TCG_EfiSpecIDEventStruct_SPEC_ERRATA_TPM2;
+ TcgEfiSpecIdEventStruct->uintnSize = sizeof(UINTN)/sizeof(UINT32);
+ NumberOfAlgorithms = 0;
+ DigestSize = (TCG_EfiSpecIdEventAlgorithmSize *)((UINT8 *)TcgEfiSpecIdEventStruct + sizeof(*TcgEfiSpecIdEventStruct) + sizeof(NumberOfAlgorithms));
+ if ((mTcgDxeData.BsCap.ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SHA1) != 0) {
+ TempDigestSize = DigestSize;
+ TempDigestSize += NumberOfAlgorithms;
+ TempDigestSize->algorithmId = TPM_ALG_SHA1;
+ TempDigestSize->digestSize = SHA1_DIGEST_SIZE;
+ NumberOfAlgorithms++;
+ }
+ if ((mTcgDxeData.BsCap.ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SHA256) != 0) {
+ TempDigestSize = DigestSize;
+ TempDigestSize += NumberOfAlgorithms;
+ TempDigestSize->algorithmId = TPM_ALG_SHA256;
+ TempDigestSize->digestSize = SHA256_DIGEST_SIZE;
+ NumberOfAlgorithms++;
+ }
+ if ((mTcgDxeData.BsCap.ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SHA384) != 0) {
+ TempDigestSize = DigestSize;
+ TempDigestSize += NumberOfAlgorithms;
+ TempDigestSize->algorithmId = TPM_ALG_SHA384;
+ TempDigestSize->digestSize = SHA384_DIGEST_SIZE;
+ NumberOfAlgorithms++;
+ }
+ if ((mTcgDxeData.BsCap.ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SHA512) != 0) {
+ TempDigestSize = DigestSize;
+ TempDigestSize += NumberOfAlgorithms;
+ TempDigestSize->algorithmId = TPM_ALG_SHA512;
+ TempDigestSize->digestSize = SHA512_DIGEST_SIZE;
+ NumberOfAlgorithms++;
+ }
+ if ((mTcgDxeData.BsCap.ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SM3_256) != 0) {
+ TempDigestSize = DigestSize;
+ TempDigestSize += NumberOfAlgorithms;
+ TempDigestSize->algorithmId = TPM_ALG_SM3_256;
+ TempDigestSize->digestSize = SM3_256_DIGEST_SIZE;
+ NumberOfAlgorithms++;
+ }
+ CopyMem (TcgEfiSpecIdEventStruct + 1, &NumberOfAlgorithms, sizeof(NumberOfAlgorithms));
+ TempDigestSize = DigestSize;
+ TempDigestSize += NumberOfAlgorithms;
+ VendorInfoSize = (UINT8 *)TempDigestSize;
+ *VendorInfoSize = 0;
+
+ SpecIdEvent.PCRIndex = 0;
+ SpecIdEvent.EventType = EV_NO_ACTION;
+ ZeroMem (&SpecIdEvent.Digest, sizeof(SpecIdEvent.Digest));
+ SpecIdEvent.EventSize = (UINT32)GetTcgEfiSpecIdEventStructSize (TcgEfiSpecIdEventStruct);
+
+ //
+ // Log TcgEfiSpecIdEventStruct as the first Event. Event format is TCG_PCR_EVENT.
+ // TCG EFI Protocol Spec. Section 5.3 Event Log Header
+ // TCG PC Client PFP spec. Section 9.2 Measurement Event Entries and Log
+ //
+ Status = TcgDxeLogEvent (
+ mTcg2EventInfo[Index].LogFormat,
+ &SpecIdEvent,
+ sizeof(SpecIdEvent),
+ (UINT8 *)TcgEfiSpecIdEventStruct,
+ SpecIdEvent.EventSize
+ );
+
+ //
+ // EfiStartupLocalityEvent. Event format is TCG_PCR_EVENT2
+ //
+ GuidHob.Guid = GetFirstGuidHob (&gTpm2StartupLocalityHobGuid);
+ if (GuidHob.Guid != NULL) {
+ //
+ // Get Locality Indicator from StartupLocality HOB
+ //
+ StartupLocalityEvent.StartupLocality = *(UINT8 *)(GET_GUID_HOB_DATA (GuidHob.Guid));
+ CopyMem (StartupLocalityEvent.Signature, TCG_EfiStartupLocalityEvent_SIGNATURE, sizeof(StartupLocalityEvent.Signature));
+ DEBUG ((DEBUG_INFO, "SetupEventLog: Set Locality from HOB into StartupLocalityEvent 0x%02x\n", StartupLocalityEvent.StartupLocality));
+
+ //
+ // Initialize StartupLocalityEvent
+ //
+ InitNoActionEvent(&NoActionEvent, sizeof(StartupLocalityEvent));
+
+ //
+ // Log EfiStartupLocalityEvent as the second Event
+ // TCG PC Client PFP spec. Section 9.3.4.3 Startup Locality Event
+ //
+ Status = TcgDxeLogEvent (
+ mTcg2EventInfo[Index].LogFormat,
+ &NoActionEvent,
+ sizeof(NoActionEvent.PCRIndex) + sizeof(NoActionEvent.EventType) + GetDigestListBinSize (&NoActionEvent.Digests) + sizeof(NoActionEvent.EventSize),
+ (UINT8 *)&StartupLocalityEvent,
+ sizeof(StartupLocalityEvent)
+ );
+
+ }
+ }
+ }
+ }
+
+ //
+ // 2. Create Final Log Area
+ //
+ for (Index = 0; Index < sizeof(mTcg2EventInfo)/sizeof(mTcg2EventInfo[0]); Index++) {
+ if ((mTcgDxeData.BsCap.SupportedEventLogs & mTcg2EventInfo[Index].LogFormat) != 0) {
+ if (mTcg2EventInfo[Index].LogFormat == EFI_TCG2_EVENT_LOG_FORMAT_TCG_2) {
+ Status = gBS->AllocatePages (
+ AllocateAnyPages,
+ EfiACPIMemoryNVS,
+ EFI_SIZE_TO_PAGES (PcdGet32 (PcdTcg2FinalLogAreaLen)),
+ &Lasa
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ SetMem ((VOID *)(UINTN)Lasa, PcdGet32 (PcdTcg2FinalLogAreaLen), 0xFF);
+
+ //
+ // Initialize
+ //
+ mTcgDxeData.FinalEventsTable[Index] = (VOID *)(UINTN)Lasa;
+ (mTcgDxeData.FinalEventsTable[Index])->Version = EFI_TCG2_FINAL_EVENTS_TABLE_VERSION;
+ (mTcgDxeData.FinalEventsTable[Index])->NumberOfEvents = 0;
+
+ mTcgDxeData.FinalEventLogAreaStruct[Index].EventLogFormat = mTcg2EventInfo[Index].LogFormat;
+ mTcgDxeData.FinalEventLogAreaStruct[Index].Lasa = Lasa + sizeof(EFI_TCG2_FINAL_EVENTS_TABLE);
+ mTcgDxeData.FinalEventLogAreaStruct[Index].Laml = PcdGet32 (PcdTcg2FinalLogAreaLen) - sizeof(EFI_TCG2_FINAL_EVENTS_TABLE);
+ mTcgDxeData.FinalEventLogAreaStruct[Index].EventLogSize = 0;
+ mTcgDxeData.FinalEventLogAreaStruct[Index].LastEvent = (VOID *)(UINTN)mTcgDxeData.FinalEventLogAreaStruct[Index].Lasa;
+ mTcgDxeData.FinalEventLogAreaStruct[Index].EventLogStarted = FALSE;
+ mTcgDxeData.FinalEventLogAreaStruct[Index].EventLogTruncated = FALSE;
+
+ //
+ // Install to configuration table for EFI_TCG2_EVENT_LOG_FORMAT_TCG_2
+ //
+ Status = gBS->InstallConfigurationTable (&gEfiTcg2FinalEventsTableGuid, (VOID *)mTcgDxeData.FinalEventsTable[Index]);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } else {
+ //
+ // No need to handle EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2
+ //
+ mTcgDxeData.FinalEventsTable[Index] = NULL;
+ mTcgDxeData.FinalEventLogAreaStruct[Index].EventLogFormat = mTcg2EventInfo[Index].LogFormat;
+ mTcgDxeData.FinalEventLogAreaStruct[Index].Lasa = 0;
+ mTcgDxeData.FinalEventLogAreaStruct[Index].Laml = 0;
+ mTcgDxeData.FinalEventLogAreaStruct[Index].EventLogSize = 0;
+ mTcgDxeData.FinalEventLogAreaStruct[Index].LastEvent = 0;
+ mTcgDxeData.FinalEventLogAreaStruct[Index].EventLogStarted = FALSE;
+ mTcgDxeData.FinalEventLogAreaStruct[Index].EventLogTruncated = FALSE;
+ }
+ }
+ }
+
+ //
+ // 3. Sync data from PEI to DXE
+ //
+ Status = EFI_SUCCESS;
+ for (Index = 0; Index < sizeof(mTcg2EventInfo)/sizeof(mTcg2EventInfo[0]); Index++) {
+ if ((mTcgDxeData.BsCap.SupportedEventLogs & mTcg2EventInfo[Index].LogFormat) != 0) {
+ GuidHob.Raw = GetHobList ();
+ Status = EFI_SUCCESS;
+ while (!EFI_ERROR (Status) &&
+ (GuidHob.Raw = GetNextGuidHob (mTcg2EventInfo[Index].EventGuid, GuidHob.Raw)) != NULL) {
+ TcgEvent = AllocateCopyPool (GET_GUID_HOB_DATA_SIZE (GuidHob.Guid), GET_GUID_HOB_DATA (GuidHob.Guid));
+ ASSERT (TcgEvent != NULL);
+ GuidHob.Raw = GET_NEXT_HOB (GuidHob);
+ switch (mTcg2EventInfo[Index].LogFormat) {
+ case EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2:
+ Status = TcgDxeLogEvent (
+ mTcg2EventInfo[Index].LogFormat,
+ TcgEvent,
+ sizeof(TCG_PCR_EVENT_HDR),
+ ((TCG_PCR_EVENT*)TcgEvent)->Event,
+ ((TCG_PCR_EVENT_HDR*)TcgEvent)->EventSize
+ );
+ break;
+ case EFI_TCG2_EVENT_LOG_FORMAT_TCG_2:
+ DigestListBin = (UINT8 *)TcgEvent + sizeof(TCG_PCRINDEX) + sizeof(TCG_EVENTTYPE);
+ DigestListBinSize = GetDigestListBinSize (DigestListBin);
+ //
+ // Save event size.
+ //
+ CopyMem (&EventSize, (UINT8 *)DigestListBin + DigestListBinSize, sizeof(UINT32));
+ Event = (UINT8 *)DigestListBin + DigestListBinSize + sizeof(UINT32);
+ //
+ // Filter inactive digest in the event2 log from PEI HOB.
+ //
+ CopyMem (&TempDigestListBin, DigestListBin, GetDigestListBinSize (DigestListBin));
+ EventSizePtr = CopyDigestListBinToBuffer (
+ DigestListBin,
+ &TempDigestListBin,
+ mTcgDxeData.BsCap.ActivePcrBanks,
+ &HashAlgorithmMaskCopied
+ );
+ if (HashAlgorithmMaskCopied != mTcgDxeData.BsCap.ActivePcrBanks) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "ERROR: The event2 log includes digest hash mask 0x%x, but required digest hash mask is 0x%x\n",
+ HashAlgorithmMaskCopied,
+ mTcgDxeData.BsCap.ActivePcrBanks
+ ));
+ }
+ //
+ // Restore event size.
+ //
+ CopyMem (EventSizePtr, &EventSize, sizeof(UINT32));
+ DigestListBinSize = GetDigestListBinSize (DigestListBin);
+
+ Status = TcgDxeLogEvent (
+ mTcg2EventInfo[Index].LogFormat,
+ TcgEvent,
+ sizeof(TCG_PCRINDEX) + sizeof(TCG_EVENTTYPE) + DigestListBinSize + sizeof(UINT32),
+ Event,
+ EventSize
+ );
+ break;
+ }
+ FreePool (TcgEvent);
+ }
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Measure and log an action string, and extend the measurement result into PCR[PCRIndex].
+
+ @param[in] PCRIndex PCRIndex to extend
+ @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
+TcgMeasureAction (
+ IN TPM_PCRINDEX PCRIndex,
+ IN CHAR8 *String
+ )
+{
+ TCG_PCR_EVENT_HDR TcgEvent;
+
+ TcgEvent.PCRIndex = PCRIndex;
+ TcgEvent.EventType = EV_EFI_ACTION;
+ TcgEvent.EventSize = (UINT32)AsciiStrLen (String);
+ return TcgDxeHashLogExtendEvent (
+ 0,
+ (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
+MeasureHandoffTables (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ TCG_PCR_EVENT_HDR TcgEvent;
+ EFI_HANDOFF_TABLE_POINTERS HandoffTables;
+ UINTN ProcessorNum;
+ EFI_CPU_PHYSICAL_LOCATION *ProcessorLocBuf;
+
+ ProcessorLocBuf = NULL;
+ Status = EFI_SUCCESS;
+
+ if (PcdGet8 (PcdTpmPlatformClass) == TCG_PLATFORM_TYPE_SERVER) {
+ //
+ // Tcg Server spec.
+ // Measure each processor EFI_CPU_PHYSICAL_LOCATION with EV_TABLE_OF_DEVICES to PCR[1]
+ //
+ Status = GetProcessorsCpuLocation(&ProcessorLocBuf, &ProcessorNum);
+
+ if (!EFI_ERROR(Status)){
+ TcgEvent.PCRIndex = 1;
+ TcgEvent.EventType = EV_TABLE_OF_DEVICES;
+ TcgEvent.EventSize = sizeof (HandoffTables);
+
+ HandoffTables.NumberOfTables = 1;
+ HandoffTables.TableEntry[0].VendorGuid = gEfiMpServiceProtocolGuid;
+ HandoffTables.TableEntry[0].VendorTable = ProcessorLocBuf;
+
+ Status = TcgDxeHashLogExtendEvent (
+ 0,
+ (UINT8*)(UINTN)ProcessorLocBuf,
+ sizeof(EFI_CPU_PHYSICAL_LOCATION) * ProcessorNum,
+ &TcgEvent,
+ (UINT8*)&HandoffTables
+ );
+
+ FreePool(ProcessorLocBuf);
+ }
+ }
+
+ 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
+MeasureSeparatorEvent (
+ IN TPM_PCRINDEX PCRIndex
+ )
+{
+ TCG_PCR_EVENT_HDR TcgEvent;
+ UINT32 EventData;
+
+ DEBUG ((EFI_D_INFO, "MeasureSeparatorEvent Pcr - %x\n", PCRIndex));
+
+ EventData = 0;
+ TcgEvent.PCRIndex = PCRIndex;
+ TcgEvent.EventType = EV_SEPARATOR;
+ TcgEvent.EventSize = (UINT32)sizeof (EventData);
+ return TcgDxeHashLogExtendEvent (
+ 0,
+ (UINT8 *)&EventData,
+ sizeof (EventData),
+ &TcgEvent,
+ (UINT8 *)&EventData
+ );
+}
+
+/**
+ 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
+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;
+ UEFI_VARIABLE_DATA *VarLog;
+
+ DEBUG ((EFI_D_INFO, "Tcg2Dxe: MeasureVariable (Pcr - %x, EventType - %x, ", (UINTN)PCRIndex, (UINTN)EventType));
+ DEBUG ((EFI_D_INFO, "VariableName - %s, VendorGuid - %g)\n", VarName, VendorGuid));
+
+ 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 = (UEFI_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)
+ );
+ if (VarSize != 0 && VarData != NULL) {
+ CopyMem (
+ (CHAR16 *)VarLog->UnicodeName + VarNameLength,
+ VarData,
+ VarSize
+ );
+ }
+
+ if (EventType == EV_EFI_VARIABLE_DRIVER_CONFIG) {
+ //
+ // Digest is the event data (UEFI_VARIABLE_DATA)
+ //
+ Status = TcgDxeHashLogExtendEvent (
+ 0,
+ (UINT8*)VarLog,
+ TcgEvent.EventSize,
+ &TcgEvent,
+ (UINT8*)VarLog
+ );
+ } else {
+ ASSERT (VarData != NULL);
+ Status = TcgDxeHashLogExtendEvent (
+ 0,
+ (UINT8*)VarData,
+ VarSize,
+ &TcgEvent,
+ (UINT8*)VarLog
+ );
+ }
+ FreePool (VarLog);
+ return Status;
+}
+
+/**
+ Read then 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[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
+ReadAndMeasureVariable (
+ IN TPM_PCRINDEX PCRIndex,
+ IN TCG_EVENTTYPE EventType,
+ IN CHAR16 *VarName,
+ IN EFI_GUID *VendorGuid,
+ OUT UINTN *VarSize,
+ OUT VOID **VarData
+ )
+{
+ EFI_STATUS Status;
+
+ Status = GetVariable2 (VarName, VendorGuid, VarData, VarSize);
+ if (EventType == EV_EFI_VARIABLE_DRIVER_CONFIG) {
+ if (EFI_ERROR (Status)) {
+ //
+ // It is valid case, so we need handle it.
+ //
+ *VarData = NULL;
+ *VarSize = 0;
+ }
+ } else {
+ //
+ // if status error, VarData is freed and set NULL by GetVariable2
+ //
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ Status = MeasureVariable (
+ PCRIndex,
+ EventType,
+ VarName,
+ VendorGuid,
+ *VarData,
+ *VarSize
+ );
+ return Status;
+}
+
+/**
+ Read then Measure and log an EFI boot variable, and extend the measurement result into PCR[1].
+according to TCG PC Client PFP spec 0021 Section 2.4.4.2
+
+ @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
+ReadAndMeasureBootVariable (
+ IN CHAR16 *VarName,
+ IN EFI_GUID *VendorGuid,
+ OUT UINTN *VarSize,
+ OUT VOID **VarData
+ )
+{
+ return ReadAndMeasureVariable (
+ 1,
+ EV_EFI_VARIABLE_BOOT,
+ VarName,
+ VendorGuid,
+ VarSize,
+ VarData
+ );
+}
+
+/**
+ Read then Measure and log an EFI Secure variable, and extend the measurement result into PCR[7].
+
+ @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
+ReadAndMeasureSecureVariable (
+ IN CHAR16 *VarName,
+ IN EFI_GUID *VendorGuid,
+ OUT UINTN *VarSize,
+ OUT VOID **VarData
+ )
+{
+ return ReadAndMeasureVariable (
+ 7,
+ EV_EFI_VARIABLE_DRIVER_CONFIG,
+ VarName,
+ VendorGuid,
+ VarSize,
+ VarData
+ );
+}
+
+/**
+ 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
+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 || BootOrder == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ if (EFI_ERROR (Status)) {
+ //
+ // BootOrder can't be NULL if status is not EFI_NOT_FOUND
+ //
+ 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;
+}
+
+/**
+ Measure and log all EFI Secure 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
+MeasureAllSecureVariables (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ VOID *Data;
+ UINTN DataSize;
+ UINTN Index;
+
+ Status = EFI_NOT_FOUND;
+ for (Index = 0; Index < sizeof(mVariableType)/sizeof(mVariableType[0]); Index++) {
+ Status = ReadAndMeasureSecureVariable (
+ mVariableType[Index].VariableName,
+ mVariableType[Index].VendorGuid,
+ &DataSize,
+ &Data
+ );
+ if (!EFI_ERROR (Status)) {
+ if (Data != NULL) {
+ FreePool (Data);
+ }
+ }
+ }
+
+ //
+ // Measure DBT if present and not empty
+ //
+ Status = GetVariable2 (EFI_IMAGE_SECURITY_DATABASE2, &gEfiImageSecurityDatabaseGuid, &Data, &DataSize);
+ if (!EFI_ERROR(Status)) {
+ Status = MeasureVariable (
+ 7,
+ EV_EFI_VARIABLE_DRIVER_CONFIG,
+ EFI_IMAGE_SECURITY_DATABASE2,
+ &gEfiImageSecurityDatabaseGuid,
+ Data,
+ DataSize
+ );
+ FreePool(Data);
+ } else {
+ DEBUG((DEBUG_INFO, "Skip measuring variable %s since it's deleted\n", EFI_IMAGE_SECURITY_DATABASE2));
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Measure and log launch of FirmwareDebugger, and extend the measurement result into a specific PCR.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_OUT_OF_RESOURCES Out of memory.
+ @retval EFI_DEVICE_ERROR The operation was unsuccessful.
+
+**/
+EFI_STATUS
+MeasureLaunchOfFirmwareDebugger (
+ VOID
+ )
+{
+ TCG_PCR_EVENT_HDR TcgEvent;
+
+ TcgEvent.PCRIndex = 7;
+ TcgEvent.EventType = EV_EFI_ACTION;
+ TcgEvent.EventSize = sizeof(FIRMWARE_DEBUGGER_EVENT_STRING) - 1;
+ return TcgDxeHashLogExtendEvent (
+ 0,
+ (UINT8 *)FIRMWARE_DEBUGGER_EVENT_STRING,
+ sizeof(FIRMWARE_DEBUGGER_EVENT_STRING) - 1,
+ &TcgEvent,
+ (UINT8 *)FIRMWARE_DEBUGGER_EVENT_STRING
+ );
+}
+
+/**
+ Measure and log all Secure Boot Policy, and extend the measurement result into a specific PCR.
+
+ Platform firmware adhering to the policy must therefore measure the following values into PCR[7]: (in order listed)
+ - The contents of the SecureBoot variable
+ - The contents of the PK variable
+ - The contents of the KEK variable
+ - The contents of the EFI_IMAGE_SECURITY_DATABASE variable
+ - The contents of the EFI_IMAGE_SECURITY_DATABASE1 variable
+ - Separator
+ - Entries in the EFI_IMAGE_SECURITY_DATABASE that are used to validate EFI Drivers or EFI Boot Applications in the boot path
+
+ NOTE: Because of the above, UEFI variables PK, KEK, EFI_IMAGE_SECURITY_DATABASE,
+ EFI_IMAGE_SECURITY_DATABASE1 and SecureBoot SHALL NOT be measured into PCR[3].
+
+ @param[in] Event Event whose notification function is being invoked
+ @param[in] Context Pointer to the notification function's context
+**/
+VOID
+EFIAPI
+MeasureSecureBootPolicy (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ VOID *Protocol;
+
+ Status = gBS->LocateProtocol (&gEfiVariableWriteArchProtocolGuid, NULL, (VOID **)&Protocol);
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ if (PcdGetBool (PcdFirmwareDebuggerInitialized)) {
+ Status = MeasureLaunchOfFirmwareDebugger ();
+ DEBUG ((EFI_D_INFO, "MeasureLaunchOfFirmwareDebugger - %r\n", Status));
+ }
+
+ Status = MeasureAllSecureVariables ();
+ DEBUG ((EFI_D_INFO, "MeasureAllSecureVariables - %r\n", Status));
+
+ //
+ // We need measure Separator(7) here, because this event must be between SecureBootPolicy (Configure)
+ // and ImageVerification (Authority)
+ // There might be a case that we need measure UEFI image from DriverOrder, besides BootOrder. So
+ // the Authority measurement happen before ReadToBoot event.
+ //
+ Status = MeasureSeparatorEvent (7);
+ DEBUG ((EFI_D_INFO, "MeasureSeparatorEvent - %r\n", Status));
+ return ;
+}
+
+/**
+ 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;
+
+ PERF_START_EX (mImageHandle, "EventRec", "Tcg2Dxe", 0, PERF_ID_TCG2_DXE);
+ 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 (
+ 4,
+ EFI_CALLING_EFI_APPLICATION
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "%a not Measured. Error!\n", EFI_CALLING_EFI_APPLICATION));
+ }
+
+ //
+ // 2. Draw a line between pre-boot env and entering post-boot env.
+ // PCR[7] is already done.
+ //
+ for (PcrIndex = 0; PcrIndex < 7; PcrIndex++) {
+ Status = MeasureSeparatorEvent (PcrIndex);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Separator Event not Measured. Error!\n"));
+ }
+ }
+
+ //
+ // 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 (
+ 4,
+ EFI_RETURNING_FROM_EFI_APPLICATOIN
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "%a not Measured. Error!\n", EFI_RETURNING_FROM_EFI_APPLICATOIN));
+ }
+
+ //
+ // 7. Next boot attempt, measure "Calling EFI Application from Boot Option" again
+ // TCG PC Client PFP spec Section 2.4.4.5 Step 4
+ //
+ Status = TcgMeasureAction (
+ 4,
+ EFI_CALLING_EFI_APPLICATION
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "%a not Measured. Error!\n", EFI_CALLING_EFI_APPLICATION));
+ }
+ }
+
+ DEBUG ((EFI_D_INFO, "TPM2 Tcg2Dxe Measure Data when ReadyToBoot\n"));
+ //
+ // Increase boot attempt counter.
+ //
+ mBootAttempts++;
+ PERF_END_EX (mImageHandle, "EventRec", "Tcg2Dxe", 0, PERF_ID_TCG2_DXE + 1);
+}
+
+/**
+ 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 (
+ 5,
+ EFI_EXIT_BOOT_SERVICES_INVOCATION
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "%a not Measured. Error!\n", EFI_EXIT_BOOT_SERVICES_INVOCATION));
+ }
+
+ //
+ // Measure success of ExitBootServices
+ //
+ Status = TcgMeasureAction (
+ 5,
+ EFI_EXIT_BOOT_SERVICES_SUCCEEDED
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "%a not Measured. Error!\n", EFI_EXIT_BOOT_SERVICES_SUCCEEDED));
+ }
+}
+
+/**
+ Exit Boot Services Failed Event notification handler.
+
+ Measure Failure of ExitBootServices.
+
+ @param[in] Event Event whose notification function is being invoked
+ @param[in] Context Pointer to the notification function's context
+
+**/
+VOID
+EFIAPI
+OnExitBootServicesFailed (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Measure Failure of ExitBootServices,
+ //
+ Status = TcgMeasureAction (
+ 5,
+ EFI_EXIT_BOOT_SERVICES_FAILED
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "%a not Measured. Error!\n", EFI_EXIT_BOOT_SERVICES_FAILED));
+ }
+
+}
+
+/**
+ The function install Tcg2 protocol.
+
+ @retval EFI_SUCCESS Tcg2 protocol is installed.
+ @retval other Some error occurs.
+**/
+EFI_STATUS
+InstallTcg2 (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE Handle;
+
+ Handle = NULL;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Handle,
+ &gEfiTcg2ProtocolGuid,
+ &mTcg2Protocol,
+ NULL
+ );
+ return Status;
+}
+
+/**
+ The driver's entry point. It publishes EFI Tcg2 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;
+ UINT32 MaxCommandSize;
+ UINT32 MaxResponseSize;
+ UINTN Index;
+ EFI_TCG2_EVENT_ALGORITHM_BITMAP TpmHashAlgorithmBitmap;
+ UINT32 ActivePCRBanks;
+ UINT32 NumberOfPCRBanks;
+
+ mImageHandle = ImageHandle;
+
+ if (CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceNoneGuid) ||
+ CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceTpm12Guid)){
+ DEBUG ((DEBUG_INFO, "No TPM2 instance required!\n"));
+ return EFI_UNSUPPORTED;
+ }
+
+ if (GetFirstGuidHob (&gTpmErrorHobGuid) != NULL) {
+ DEBUG ((EFI_D_ERROR, "TPM2 error!\n"));
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = Tpm2RequestUseTpm ();
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "TPM2 not detected!\n"));
+ return Status;
+ }
+
+ //
+ // Fill information
+ //
+ ASSERT (TCG_EVENT_LOG_AREA_COUNT_MAX == sizeof(mTcg2EventInfo)/sizeof(mTcg2EventInfo[0]));
+
+ mTcgDxeData.BsCap.Size = sizeof(EFI_TCG2_BOOT_SERVICE_CAPABILITY);
+ mTcgDxeData.BsCap.ProtocolVersion.Major = 1;
+ mTcgDxeData.BsCap.ProtocolVersion.Minor = 1;
+ mTcgDxeData.BsCap.StructureVersion.Major = 1;
+ mTcgDxeData.BsCap.StructureVersion.Minor = 1;
+
+ DEBUG ((EFI_D_INFO, "Tcg2.ProtocolVersion - %02x.%02x\n", mTcgDxeData.BsCap.ProtocolVersion.Major, mTcgDxeData.BsCap.ProtocolVersion.Minor));
+ DEBUG ((EFI_D_INFO, "Tcg2.StructureVersion - %02x.%02x\n", mTcgDxeData.BsCap.StructureVersion.Major, mTcgDxeData.BsCap.StructureVersion.Minor));
+
+ Status = Tpm2GetCapabilityManufactureID (&mTcgDxeData.BsCap.ManufacturerID);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Tpm2GetCapabilityManufactureID fail!\n"));
+ } else {
+ DEBUG ((EFI_D_INFO, "Tpm2GetCapabilityManufactureID - %08x\n", mTcgDxeData.BsCap.ManufacturerID));
+ }
+
+ DEBUG_CODE (
+ UINT32 FirmwareVersion1;
+ UINT32 FirmwareVersion2;
+
+ Status = Tpm2GetCapabilityFirmwareVersion (&FirmwareVersion1, &FirmwareVersion2);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Tpm2GetCapabilityFirmwareVersion fail!\n"));
+ } else {
+ DEBUG ((EFI_D_INFO, "Tpm2GetCapabilityFirmwareVersion - %08x %08x\n", FirmwareVersion1, FirmwareVersion2));
+ }
+ );
+
+ Status = Tpm2GetCapabilityMaxCommandResponseSize (&MaxCommandSize, &MaxResponseSize);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Tpm2GetCapabilityMaxCommandResponseSize fail!\n"));
+ } else {
+ mTcgDxeData.BsCap.MaxCommandSize = (UINT16)MaxCommandSize;
+ mTcgDxeData.BsCap.MaxResponseSize = (UINT16)MaxResponseSize;
+ DEBUG ((EFI_D_INFO, "Tpm2GetCapabilityMaxCommandResponseSize - %08x, %08x\n", MaxCommandSize, MaxResponseSize));
+ }
+
+ //
+ // Get supported PCR and current Active PCRs
+ //
+ Status = Tpm2GetCapabilitySupportedAndActivePcrs (&TpmHashAlgorithmBitmap, &ActivePCRBanks);
+ ASSERT_EFI_ERROR (Status);
+
+ mTcgDxeData.BsCap.HashAlgorithmBitmap = TpmHashAlgorithmBitmap & PcdGet32 (PcdTcg2HashAlgorithmBitmap);
+ mTcgDxeData.BsCap.ActivePcrBanks = ActivePCRBanks & PcdGet32 (PcdTcg2HashAlgorithmBitmap);
+
+ //
+ // Need calculate NumberOfPCRBanks here, because HashAlgorithmBitmap might be removed by PCD.
+ //
+ NumberOfPCRBanks = 0;
+ for (Index = 0; Index < 32; Index++) {
+ if ((mTcgDxeData.BsCap.HashAlgorithmBitmap & (1u << Index)) != 0) {
+ NumberOfPCRBanks++;
+ }
+ }
+
+ if (PcdGet32 (PcdTcg2NumberOfPCRBanks) == 0) {
+ mTcgDxeData.BsCap.NumberOfPCRBanks = NumberOfPCRBanks;
+ } else {
+ mTcgDxeData.BsCap.NumberOfPCRBanks = PcdGet32 (PcdTcg2NumberOfPCRBanks);
+ if (PcdGet32 (PcdTcg2NumberOfPCRBanks) > NumberOfPCRBanks) {
+ DEBUG ((EFI_D_ERROR, "ERROR: PcdTcg2NumberOfPCRBanks(0x%x) > NumberOfPCRBanks(0x%x)\n", PcdGet32 (PcdTcg2NumberOfPCRBanks), NumberOfPCRBanks));
+ mTcgDxeData.BsCap.NumberOfPCRBanks = NumberOfPCRBanks;
+ }
+ }
+
+ mTcgDxeData.BsCap.SupportedEventLogs = EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2 | EFI_TCG2_EVENT_LOG_FORMAT_TCG_2;
+ if ((mTcgDxeData.BsCap.ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SHA1) == 0) {
+ //
+ // No need to expose TCG1.2 event log if SHA1 bank does not exist.
+ //
+ mTcgDxeData.BsCap.SupportedEventLogs &= ~EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2;
+ }
+
+ DEBUG ((EFI_D_INFO, "Tcg2.SupportedEventLogs - 0x%08x\n", mTcgDxeData.BsCap.SupportedEventLogs));
+ DEBUG ((EFI_D_INFO, "Tcg2.HashAlgorithmBitmap - 0x%08x\n", mTcgDxeData.BsCap.HashAlgorithmBitmap));
+ DEBUG ((EFI_D_INFO, "Tcg2.NumberOfPCRBanks - 0x%08x\n", mTcgDxeData.BsCap.NumberOfPCRBanks));
+ DEBUG ((EFI_D_INFO, "Tcg2.ActivePcrBanks - 0x%08x\n", mTcgDxeData.BsCap.ActivePcrBanks));
+
+ if (mTcgDxeData.BsCap.TPMPresentFlag) {
+ //
+ // 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
+ );
+
+ //
+ // Measure Exit Boot Service failed
+ //
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ OnExitBootServicesFailed,
+ NULL,
+ &gEventExitBootServicesFailedGuid,
+ &Event
+ );
+
+ //
+ // Create event callback, because we need access variable on SecureBootPolicyVariable
+ // We should use VariableWriteArch instead of VariableArch, because Variable driver
+ // may update SecureBoot value based on last setting.
+ //
+ EfiCreateProtocolNotifyEvent (&gEfiVariableWriteArchProtocolGuid, TPL_CALLBACK, MeasureSecureBootPolicy, NULL, &Registration);
+ }
+
+ //
+ // Install Tcg2Protocol
+ //
+ Status = InstallTcg2 ();
+ DEBUG ((EFI_D_INFO, "InstallTcg2 - %r\n", Status));
+
+ return Status;
+}
diff --git a/Core/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.inf b/Core/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.inf
new file mode 100644
index 0000000000..8efc4e3aad
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.inf
@@ -0,0 +1,112 @@
+## @file
+# Produces Tcg2 protocol and measure boot environment
+# This module will produce Tcg2 protocol and measure boot environment.
+#
+# Caution: This module requires additional review when modified.
+# This driver will have external input - PE/COFF image.
+# This external input must be validated carefully to avoid security issue like
+# buffer overflow, integer overflow.
+#
+# Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = Tcg2Dxe
+ MODULE_UNI_FILE = Tcg2Dxe.uni
+ FILE_GUID = FDFF263D-5F68-4591-87BA-B768F445A9AF
+ 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]
+ Tcg2Dxe.c
+ MeasureBootPeCoff.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ SecurityPkg/SecurityPkg.dec
+ CryptoPkg/CryptoPkg.dec
+
+[LibraryClasses]
+ MemoryAllocationLib
+ BaseLib
+ UefiBootServicesTableLib
+ HobLib
+ UefiDriverEntryPoint
+ UefiRuntimeServicesTableLib
+ BaseMemoryLib
+ DebugLib
+ Tpm2CommandLib
+ PrintLib
+ UefiLib
+ Tpm2DeviceLib
+ HashLib
+ PerformanceLib
+ ReportStatusCodeLib
+ Tcg2PhysicalPresenceLib
+ PeCoffLib
+
+[Guids]
+ ## SOMETIMES_CONSUMES ## Variable:L"SecureBoot"
+ ## SOMETIMES_CONSUMES ## Variable:L"PK"
+ ## SOMETIMES_CONSUMES ## Variable:L"KEK"
+ ## SOMETIMES_CONSUMES ## Variable:L"BootXXXX"
+ gEfiGlobalVariableGuid
+
+ ## SOMETIMES_CONSUMES ## Variable:L"db"
+ ## SOMETIMES_CONSUMES ## Variable:L"dbx"
+ gEfiImageSecurityDatabaseGuid
+
+ gTcgEventEntryHobGuid ## SOMETIMES_CONSUMES ## HOB
+ gTpmErrorHobGuid ## SOMETIMES_CONSUMES ## HOB
+ gEfiEventExitBootServicesGuid ## CONSUMES ## Event
+ gEventExitBootServicesFailedGuid ## SOMETIMES_CONSUMES ## Event
+ gEfiTpmDeviceInstanceNoneGuid ## SOMETIMES_CONSUMES ## GUID # TPM device identifier
+ gEfiTpmDeviceInstanceTpm12Guid ## SOMETIMES_CONSUMES ## GUID # TPM device identifier
+
+ gTcgEvent2EntryHobGuid ## SOMETIMES_CONSUMES ## HOB
+ gTpm2StartupLocalityHobGuid ## SOMETIMES_CONSUMES ## HOB
+
+[Protocols]
+ gEfiTcg2ProtocolGuid ## PRODUCES
+ gEfiTcg2FinalEventsTableGuid ## PRODUCES
+ gEfiAcpiTableProtocolGuid ## NOTIFY
+ gEfiMpServiceProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiVariableWriteArchProtocolGuid ## NOTIFY
+
+[Pcd]
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpmPlatformClass ## SOMETIMES_CONSUMES
+ gEfiSecurityPkgTokenSpaceGuid.PcdFirmwareDebuggerInitialized ## SOMETIMES_CONSUMES
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpmInstanceGuid ## CONSUMES
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpmBaseAddress ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemId ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemTableId ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemRevision ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorId ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorRevision ## SOMETIMES_CONSUMES
+ gEfiSecurityPkgTokenSpaceGuid.PcdStatusCodeSubClassTpmDevice ## SOMETIMES_CONSUMES
+ gEfiSecurityPkgTokenSpaceGuid.PcdTcg2HashAlgorithmBitmap ## CONSUMES
+ gEfiSecurityPkgTokenSpaceGuid.PcdTcg2NumberOfPCRBanks ## CONSUMES
+ gEfiSecurityPkgTokenSpaceGuid.PcdTcgLogAreaMinLen ## CONSUMES
+ gEfiSecurityPkgTokenSpaceGuid.PcdTcg2FinalLogAreaLen ## CONSUMES
+
+[Depex]
+ TRUE
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ Tcg2DxeExtra.uni
diff --git a/Core/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.uni b/Core/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.uni
new file mode 100644
index 0000000000..dadcd1a79e
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.uni
@@ -0,0 +1,26 @@
+// /** @file
+// Produces TCG2 protocol and measure boot environment
+//
+// This module will produce TCG2 protocol and measure boot environment.
+//
+// Caution: This module requires additional review when modified.
+// This driver will have external input - PE/COFF image.
+// This external input must be validated carefully to avoid security issue like
+// buffer overflow, integer overflow.
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Produces TCG2 protocol and measure boot environment"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This module will produce TCG2 protocol and measure boot environment."
+
diff --git a/Core/SecurityPkg/Tcg/Tcg2Dxe/Tcg2DxeExtra.uni b/Core/SecurityPkg/Tcg/Tcg2Dxe/Tcg2DxeExtra.uni
new file mode 100644
index 0000000000..1cd59a33a3
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Tcg2Dxe/Tcg2DxeExtra.uni
@@ -0,0 +1,17 @@
+// /** @file
+// Tcg2Dxe Localized Strings and Content
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"TCG2 (Trusted Computing Group) DXE"
diff --git a/Core/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.c b/Core/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.c
new file mode 100644
index 0000000000..69adad43aa
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.c
@@ -0,0 +1,854 @@
+/** @file
+ Initialize TPM2 device and measure FVs before handing off control to DXE.
+
+Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiPei.h>
+
+#include <IndustryStandard/UefiTcgPlatform.h>
+#include <Ppi/FirmwareVolumeInfo.h>
+#include <Ppi/FirmwareVolumeInfo2.h>
+#include <Ppi/LockPhysicalPresence.h>
+#include <Ppi/TpmInitialized.h>
+#include <Ppi/FirmwareVolume.h>
+#include <Ppi/EndOfPeiPhase.h>
+#include <Ppi/FirmwareVolumeInfoMeasurementExcluded.h>
+
+#include <Guid/TcgEventHob.h>
+#include <Guid/MeasuredFvHob.h>
+#include <Guid/TpmInstance.h>
+
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/PeimEntryPoint.h>
+#include <Library/Tpm2CommandLib.h>
+#include <Library/Tpm2DeviceLib.h>
+#include <Library/HashLib.h>
+#include <Library/HobLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PeiServicesTablePointerLib.h>
+#include <Protocol/Tcg2Protocol.h>
+#include <Library/PerformanceLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/ResetSystemLib.h>
+#include <Library/Tcg2PhysicalPresenceLib.h>
+
+#define PERF_ID_TCG2_PEI 0x3080
+
+typedef struct {
+ EFI_GUID *EventGuid;
+ EFI_TCG2_EVENT_LOG_FORMAT LogFormat;
+} TCG2_EVENT_INFO_STRUCT;
+
+TCG2_EVENT_INFO_STRUCT mTcg2EventInfo[] = {
+ {&gTcgEventEntryHobGuid, EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2},
+ {&gTcgEvent2EntryHobGuid, EFI_TCG2_EVENT_LOG_FORMAT_TCG_2},
+};
+
+BOOLEAN mImageInMemory = FALSE;
+EFI_PEI_FILE_HANDLE mFileHandle;
+
+EFI_PEI_PPI_DESCRIPTOR mTpmInitializedPpiList = {
+ EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
+ &gPeiTpmInitializedPpiGuid,
+ NULL
+};
+
+EFI_PEI_PPI_DESCRIPTOR mTpmInitializationDonePpiList = {
+ EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
+ &gPeiTpmInitializationDonePpiGuid,
+ NULL
+};
+
+EFI_PLATFORM_FIRMWARE_BLOB *mMeasuredBaseFvInfo;
+UINT32 mMeasuredBaseFvIndex = 0;
+
+EFI_PLATFORM_FIRMWARE_BLOB *mMeasuredChildFvInfo;
+UINT32 mMeasuredChildFvIndex = 0;
+
+/**
+ 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
+ );
+
+/**
+ Record all measured Firmware Volum Information into a Guid Hob
+
+ @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
+EndofPeiSignalNotifyCallBack (
+ 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,
+ &gEfiPeiFirmwareVolumeInfoPpiGuid,
+ FirmwareVolmeInfoPpiNotifyCallback
+ },
+ {
+ EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,
+ &gEfiPeiFirmwareVolumeInfo2PpiGuid,
+ FirmwareVolmeInfoPpiNotifyCallback
+ },
+ {
+ (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEfiEndOfPeiSignalPpiGuid,
+ EndofPeiSignalNotifyCallBack
+ }
+};
+
+EFI_PEI_FIRMWARE_VOLUME_INFO_MEASUREMENT_EXCLUDED_PPI *mMeasurementExcludedFvPpi;
+
+/**
+ Record all measured Firmware Volum Information into a Guid Hob
+ Guid Hob payload layout is
+
+ UINT32 *************************** FIRMWARE_BLOB number
+ EFI_PLATFORM_FIRMWARE_BLOB******** BLOB Array
+
+ @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
+EndofPeiSignalNotifyCallBack (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *Ppi
+ )
+{
+ MEASURED_HOB_DATA *MeasuredHobData;
+
+ MeasuredHobData = NULL;
+
+ //
+ // Create a Guid hob to save all measured Fv
+ //
+ MeasuredHobData = BuildGuidHob(
+ &gMeasuredFvHobGuid,
+ sizeof(UINTN) + sizeof(EFI_PLATFORM_FIRMWARE_BLOB) * (mMeasuredBaseFvIndex + mMeasuredChildFvIndex)
+ );
+
+ if (MeasuredHobData != NULL){
+ //
+ // Save measured FV info enty number
+ //
+ MeasuredHobData->Num = mMeasuredBaseFvIndex + mMeasuredChildFvIndex;
+
+ //
+ // Save measured base Fv info
+ //
+ CopyMem (MeasuredHobData->MeasuredFvBuf, mMeasuredBaseFvInfo, sizeof(EFI_PLATFORM_FIRMWARE_BLOB) * (mMeasuredBaseFvIndex));
+
+ //
+ // Save measured child Fv info
+ //
+ CopyMem (&MeasuredHobData->MeasuredFvBuf[mMeasuredBaseFvIndex] , mMeasuredChildFvInfo, sizeof(EFI_PLATFORM_FIRMWARE_BLOB) * (mMeasuredChildFvIndex));
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Make sure that the current PCR allocations, the TPM supported PCRs,
+ and the PcdTpm2HashMask are all in agreement.
+**/
+VOID
+SyncPcrAllocationsAndPcrMask (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_TCG2_EVENT_ALGORITHM_BITMAP TpmHashAlgorithmBitmap;
+ UINT32 TpmActivePcrBanks;
+ UINT32 NewTpmActivePcrBanks;
+ UINT32 Tpm2PcrMask;
+ UINT32 NewTpm2PcrMask;
+
+ DEBUG ((EFI_D_ERROR, "SyncPcrAllocationsAndPcrMask!\n"));
+
+ //
+ // Determine the current TPM support and the Platform PCR mask.
+ //
+ Status = Tpm2GetCapabilitySupportedAndActivePcrs (&TpmHashAlgorithmBitmap, &TpmActivePcrBanks);
+ ASSERT_EFI_ERROR (Status);
+
+ Tpm2PcrMask = PcdGet32 (PcdTpm2HashMask);
+
+ //
+ // Find the intersection of Pcd support and TPM support.
+ // If banks are missing from the TPM support that are in the PCD, update the PCD.
+ // If banks are missing from the PCD that are active in the TPM, reallocate the banks and reboot.
+ //
+
+ //
+ // If there are active PCR banks that are not supported by the Platform mask,
+ // update the TPM allocations and reboot the machine.
+ //
+ if ((TpmActivePcrBanks & Tpm2PcrMask) != TpmActivePcrBanks) {
+ NewTpmActivePcrBanks = TpmActivePcrBanks & Tpm2PcrMask;
+
+ DEBUG ((EFI_D_INFO, "%a - Reallocating PCR banks from 0x%X to 0x%X.\n", __FUNCTION__, TpmActivePcrBanks, NewTpmActivePcrBanks));
+ if (NewTpmActivePcrBanks == 0) {
+ DEBUG ((EFI_D_ERROR, "%a - No viable PCRs active! Please set a less restrictive value for PcdTpm2HashMask!\n", __FUNCTION__));
+ ASSERT (FALSE);
+ } else {
+ Status = Tpm2PcrAllocateBanks (NULL, (UINT32)TpmHashAlgorithmBitmap, NewTpmActivePcrBanks);
+ if (EFI_ERROR (Status)) {
+ //
+ // We can't do much here, but we hope that this doesn't happen.
+ //
+ DEBUG ((EFI_D_ERROR, "%a - Failed to reallocate PCRs!\n", __FUNCTION__));
+ ASSERT_EFI_ERROR (Status);
+ }
+ //
+ // Need reset system, since we just called Tpm2PcrAllocateBanks().
+ //
+ ResetCold();
+ }
+ }
+
+ //
+ // If there are any PCRs that claim support in the Platform mask that are
+ // not supported by the TPM, update the mask.
+ //
+ if ((Tpm2PcrMask & TpmHashAlgorithmBitmap) != Tpm2PcrMask) {
+ NewTpm2PcrMask = Tpm2PcrMask & TpmHashAlgorithmBitmap;
+
+ DEBUG ((EFI_D_INFO, "%a - Updating PcdTpm2HashMask from 0x%X to 0x%X.\n", __FUNCTION__, Tpm2PcrMask, NewTpm2PcrMask));
+ if (NewTpm2PcrMask == 0) {
+ DEBUG ((EFI_D_ERROR, "%a - No viable PCRs supported! Please set a less restrictive value for PcdTpm2HashMask!\n", __FUNCTION__));
+ ASSERT (FALSE);
+ }
+
+ Status = PcdSet32S (PcdTpm2HashMask, NewTpm2PcrMask);
+ ASSERT_EFI_ERROR (Status);
+ }
+}
+
+/**
+ Add a new entry to the Event Log.
+
+ @param[in] DigestList A list of digest.
+ @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 The new event log entry was added.
+ @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.
+**/
+EFI_STATUS
+LogHashEvent (
+ IN TPML_DIGEST_VALUES *DigestList,
+ IN OUT TCG_PCR_EVENT_HDR *NewEventHdr,
+ IN UINT8 *NewEventData
+ )
+{
+ VOID *HobData;
+ EFI_STATUS Status;
+ UINTN Index;
+ EFI_STATUS RetStatus;
+ UINT32 SupportedEventLogs;
+ TCG_PCR_EVENT2 *TcgPcrEvent2;
+ UINT8 *DigestBuffer;
+
+ SupportedEventLogs = EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2 | EFI_TCG2_EVENT_LOG_FORMAT_TCG_2;
+
+ RetStatus = EFI_SUCCESS;
+ for (Index = 0; Index < sizeof(mTcg2EventInfo)/sizeof(mTcg2EventInfo[0]); Index++) {
+ if ((SupportedEventLogs & mTcg2EventInfo[Index].LogFormat) != 0) {
+ DEBUG ((EFI_D_INFO, " LogFormat - 0x%08x\n", mTcg2EventInfo[Index].LogFormat));
+ switch (mTcg2EventInfo[Index].LogFormat) {
+ case EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2:
+ Status = GetDigestFromDigestList (TPM_ALG_SHA1, DigestList, &NewEventHdr->Digest);
+ if (!EFI_ERROR (Status)) {
+ HobData = BuildGuidHob (
+ &gTcgEventEntryHobGuid,
+ sizeof (*NewEventHdr) + NewEventHdr->EventSize
+ );
+ if (HobData == NULL) {
+ RetStatus = EFI_OUT_OF_RESOURCES;
+ break;
+ }
+
+ CopyMem (HobData, NewEventHdr, sizeof (*NewEventHdr));
+ HobData = (VOID *) ((UINT8*)HobData + sizeof (*NewEventHdr));
+ CopyMem (HobData, NewEventData, NewEventHdr->EventSize);
+ }
+ break;
+ case EFI_TCG2_EVENT_LOG_FORMAT_TCG_2:
+ //
+ // Use GetDigestListSize (DigestList) in the GUID HOB DataLength calculation
+ // to reserve enough buffer to hold TPML_DIGEST_VALUES compact binary.
+ //
+ HobData = BuildGuidHob (
+ &gTcgEvent2EntryHobGuid,
+ sizeof(TcgPcrEvent2->PCRIndex) + sizeof(TcgPcrEvent2->EventType) + GetDigestListSize (DigestList) + sizeof(TcgPcrEvent2->EventSize) + NewEventHdr->EventSize
+ );
+ if (HobData == NULL) {
+ RetStatus = EFI_OUT_OF_RESOURCES;
+ break;
+ }
+
+ TcgPcrEvent2 = HobData;
+ TcgPcrEvent2->PCRIndex = NewEventHdr->PCRIndex;
+ TcgPcrEvent2->EventType = NewEventHdr->EventType;
+ DigestBuffer = (UINT8 *)&TcgPcrEvent2->Digest;
+ DigestBuffer = CopyDigestListToBuffer (DigestBuffer, DigestList, PcdGet32 (PcdTpm2HashMask));
+ CopyMem (DigestBuffer, &NewEventHdr->EventSize, sizeof(TcgPcrEvent2->EventSize));
+ DigestBuffer = DigestBuffer + sizeof(TcgPcrEvent2->EventSize);
+ CopyMem (DigestBuffer, NewEventData, NewEventHdr->EventSize);
+ break;
+ }
+ }
+ }
+
+ return RetStatus;
+}
+
+/**
+ 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] Flags Bitmap providing additional information.
+ @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] 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 UINT64 Flags,
+ IN UINT8 *HashData,
+ IN UINTN HashDataLen,
+ IN TCG_PCR_EVENT_HDR *NewEventHdr,
+ IN UINT8 *NewEventData
+ )
+{
+ EFI_STATUS Status;
+ TPML_DIGEST_VALUES DigestList;
+
+ if (GetFirstGuidHob (&gTpmErrorHobGuid) != NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = HashAndExtend (
+ NewEventHdr->PCRIndex,
+ HashData,
+ HashDataLen,
+ &DigestList
+ );
+ if (!EFI_ERROR (Status)) {
+ if ((Flags & EFI_TCG2_EXTEND_ONLY) == 0) {
+ Status = LogHashEvent (&DigestList, NewEventHdr, NewEventData);
+ }
+ }
+
+ if (Status == EFI_DEVICE_ERROR) {
+ DEBUG ((EFI_D_ERROR, "HashLogExtendEvent - %r. Disable TPM.\n", Status));
+ BuildGuidHob (&gTpmErrorHobGuid,0);
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ (PcdGet32 (PcdStatusCodeSubClassTpmDevice) | EFI_P_EC_INTERFACE_ERROR)
+ );
+ }
+
+ return Status;
+}
+
+/**
+ Measure CRTM version.
+
+ @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
+MeasureCRTMVersion (
+ VOID
+ )
+{
+ TCG_PCR_EVENT_HDR TcgEventHdr;
+
+ //
+ // Use FirmwareVersion string to represent CRTM version.
+ // OEMs should get real CRTM version string and measure it.
+ //
+
+ TcgEventHdr.PCRIndex = 0;
+ TcgEventHdr.EventType = EV_S_CRTM_VERSION;
+ TcgEventHdr.EventSize = (UINT32) StrSize((CHAR16*)PcdGetPtr (PcdFirmwareVersionString));
+
+ return HashLogExtendEvent (
+ 0,
+ (UINT8*)PcdGetPtr (PcdFirmwareVersionString),
+ TcgEventHdr.EventSize,
+ &TcgEventHdr,
+ (UINT8*)PcdGetPtr (PcdFirmwareVersionString)
+ );
+}
+
+/**
+ 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
+MeasureFvImage (
+ IN EFI_PHYSICAL_ADDRESS FvBase,
+ IN UINT64 FvLength
+ )
+{
+ UINT32 Index;
+ EFI_STATUS Status;
+ EFI_PLATFORM_FIRMWARE_BLOB FvBlob;
+ TCG_PCR_EVENT_HDR TcgEventHdr;
+
+ //
+ // Check if it is in Excluded FV list
+ //
+ if (mMeasurementExcludedFvPpi != NULL) {
+ for (Index = 0; Index < mMeasurementExcludedFvPpi->Count; Index ++) {
+ if (mMeasurementExcludedFvPpi->Fv[Index].FvBase == FvBase) {
+ DEBUG ((DEBUG_INFO, "The FV which is excluded by Tcg2Pei starts at: 0x%x\n", FvBase));
+ DEBUG ((DEBUG_INFO, "The FV which is excluded by Tcg2Pei has the size: 0x%x\n", FvLength));
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ //
+ // Check whether FV is in the measured FV list.
+ //
+ for (Index = 0; Index < mMeasuredBaseFvIndex; Index ++) {
+ if (mMeasuredBaseFvInfo[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 Tcg2Pei starts at: 0x%x\n", FvBlob.BlobBase));
+ DEBUG ((DEBUG_INFO, "The FV which is measured by Tcg2Pei has the size: 0x%x\n", FvBlob.BlobLength));
+
+ TcgEventHdr.PCRIndex = 0;
+ TcgEventHdr.EventType = EV_EFI_PLATFORM_FIRMWARE_BLOB;
+ TcgEventHdr.EventSize = sizeof (FvBlob);
+
+ Status = HashLogExtendEvent (
+ 0,
+ (UINT8*) (UINTN) FvBlob.BlobBase,
+ (UINTN) FvBlob.BlobLength,
+ &TcgEventHdr,
+ (UINT8*) &FvBlob
+ );
+
+ //
+ // Add new FV into the measured FV list.
+ //
+ ASSERT (mMeasuredBaseFvIndex < PcdGet32 (PcdPeiCoreMaxFvSupported));
+ if (mMeasuredBaseFvIndex < PcdGet32 (PcdPeiCoreMaxFvSupported)) {
+ mMeasuredBaseFvInfo[mMeasuredBaseFvIndex].BlobBase = FvBase;
+ mMeasuredBaseFvInfo[mMeasuredBaseFvIndex].BlobLength = FvLength;
+ mMeasuredBaseFvIndex++;
+ }
+
+ return Status;
+}
+
+/**
+ Measure main BIOS.
+
+ @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
+MeasureMainBios (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINT32 FvInstances;
+ EFI_PEI_FV_HANDLE VolumeHandle;
+ EFI_FV_INFO VolumeInfo;
+ EFI_PEI_FIRMWARE_VOLUME_PPI *FvPpi;
+
+ PERF_START_EX (mFileHandle, "EventRec", "Tcg2Pei", 0, PERF_ID_TCG2_PEI);
+ 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++;
+ }
+ PERF_END_EX (mFileHandle, "EventRec", "Tcg2Pei", 0, PERF_ID_TCG2_PEI + 1);
+
+ 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;
+ UINTN Index;
+
+ 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 record the FV and return
+ //
+ if (Fv->ParentFvName != NULL || Fv->ParentFileName != NULL ) {
+
+ ASSERT (mMeasuredChildFvIndex < PcdGet32 (PcdPeiCoreMaxFvSupported));
+ if (mMeasuredChildFvIndex < PcdGet32 (PcdPeiCoreMaxFvSupported)) {
+ //
+ // Check whether FV is in the measured child FV list.
+ //
+ for (Index = 0; Index < mMeasuredChildFvIndex; Index++) {
+ if (mMeasuredChildFvInfo[Index].BlobBase == (EFI_PHYSICAL_ADDRESS) (UINTN) Fv->FvInfo) {
+ return EFI_SUCCESS;
+ }
+ }
+ mMeasuredChildFvInfo[mMeasuredChildFvIndex].BlobBase = (EFI_PHYSICAL_ADDRESS) (UINTN) Fv->FvInfo;
+ mMeasuredChildFvInfo[mMeasuredChildFvIndex].BlobLength = Fv->FvInfoSize;
+ mMeasuredChildFvIndex++;
+ }
+ return EFI_SUCCESS;
+ }
+
+ return MeasureFvImage ((EFI_PHYSICAL_ADDRESS) (UINTN) Fv->FvInfo, Fv->FvInfoSize);
+}
+
+/**
+ 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
+PeimEntryMP (
+ IN EFI_PEI_SERVICES **PeiServices
+ )
+{
+ EFI_STATUS Status;
+
+ Status = PeiServicesLocatePpi (
+ &gEfiPeiFirmwareVolumeInfoMeasurementExcludedPpiGuid,
+ 0,
+ NULL,
+ (VOID**)&mMeasurementExcludedFvPpi
+ );
+ // Do not check status, because it is optional
+
+ mMeasuredBaseFvInfo = (EFI_PLATFORM_FIRMWARE_BLOB *) AllocateZeroPool (sizeof (EFI_PLATFORM_FIRMWARE_BLOB) * PcdGet32 (PcdPeiCoreMaxFvSupported));
+ ASSERT (mMeasuredBaseFvInfo != NULL);
+ mMeasuredChildFvInfo = (EFI_PLATFORM_FIRMWARE_BLOB *) AllocateZeroPool (sizeof (EFI_PLATFORM_FIRMWARE_BLOB) * PcdGet32 (PcdPeiCoreMaxFvSupported));
+ ASSERT (mMeasuredChildFvInfo != NULL);
+
+ if (PcdGet8 (PcdTpm2ScrtmPolicy) == 1) {
+ Status = MeasureCRTMVersion ();
+ }
+
+ Status = MeasureMainBios ();
+
+ //
+ // Post callbacks:
+ // for the FvInfoPpi services to measure and record
+ // the additional Fvs to TPM
+ //
+ Status = PeiServicesNotifyPpi (&mNotifyList[0]);
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
+/**
+ Measure and log Separator event with error, 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
+MeasureSeparatorEventWithError (
+ IN TPM_PCRINDEX PCRIndex
+ )
+{
+ TCG_PCR_EVENT_HDR TcgEvent;
+ UINT32 EventData;
+
+ //
+ // Use EventData 0x1 to indicate there is error.
+ //
+ EventData = 0x1;
+ TcgEvent.PCRIndex = PCRIndex;
+ TcgEvent.EventType = EV_SEPARATOR;
+ TcgEvent.EventSize = (UINT32)sizeof (EventData);
+ return HashLogExtendEvent(0,(UINT8 *)&EventData, TcgEvent.EventSize, &TcgEvent,(UINT8 *)&EventData);
+}
+
+/**
+ 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_STATUS Status2;
+ EFI_BOOT_MODE BootMode;
+ TPM_PCRINDEX PcrIndex;
+ BOOLEAN S3ErrorReport;
+
+ if (CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceNoneGuid) ||
+ CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceTpm12Guid)){
+ DEBUG ((DEBUG_INFO, "No TPM2 instance required!\n"));
+ return EFI_UNSUPPORTED;
+ }
+
+ if (GetFirstGuidHob (&gTpmErrorHobGuid) != NULL) {
+ DEBUG ((EFI_D_ERROR, "TPM2 error!\n"));
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = PeiServicesGetBootMode (&BootMode);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // In S3 path, skip shadow logic. no measurement is required
+ //
+ if (BootMode != BOOT_ON_S3_RESUME) {
+ Status = (**PeiServices).RegisterForShadow(FileHandle);
+ if (Status == EFI_ALREADY_STARTED) {
+ mImageInMemory = TRUE;
+ mFileHandle = FileHandle;
+ } else if (Status == EFI_NOT_FOUND) {
+ ASSERT_EFI_ERROR (Status);
+ }
+ }
+
+ if (!mImageInMemory) {
+ //
+ // Initialize TPM device
+ //
+ Status = Tpm2RequestUseTpm ();
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "TPM2 not detected!\n"));
+ goto Done;
+ }
+
+ S3ErrorReport = FALSE;
+ if (PcdGet8 (PcdTpm2InitializationPolicy) == 1) {
+ if (BootMode == BOOT_ON_S3_RESUME) {
+ Status = Tpm2Startup (TPM_SU_STATE);
+ if (EFI_ERROR (Status) ) {
+ Status = Tpm2Startup (TPM_SU_CLEAR);
+ if (!EFI_ERROR(Status)) {
+ S3ErrorReport = TRUE;
+ }
+ }
+ } else {
+ Status = Tpm2Startup (TPM_SU_CLEAR);
+ }
+ if (EFI_ERROR (Status) ) {
+ goto Done;
+ }
+ }
+
+ //
+ // Update Tpm2HashMask according to PCR bank.
+ //
+ SyncPcrAllocationsAndPcrMask ();
+
+ if (S3ErrorReport) {
+ //
+ // The system firmware that resumes from S3 MUST deal with a
+ // TPM2_Startup error appropriately.
+ // For example, issue a TPM2_Startup(TPM_SU_CLEAR) command and
+ // configuring the device securely by taking actions like extending a
+ // separator with an error digest (0x01) into PCRs 0 through 7.
+ //
+ for (PcrIndex = 0; PcrIndex < 8; PcrIndex++) {
+ Status = MeasureSeparatorEventWithError (PcrIndex);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Separator Event with Error not Measured. Error!\n"));
+ }
+ }
+ }
+
+ //
+ // TpmSelfTest is optional on S3 path, skip it to save S3 time
+ //
+ if (BootMode != BOOT_ON_S3_RESUME) {
+ if (PcdGet8 (PcdTpm2SelfTestPolicy) == 1) {
+ Status = Tpm2SelfTest (NO);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ }
+ }
+
+ //
+ // Only intall TpmInitializedPpi on success
+ //
+ Status = PeiServicesInstallPpi (&mTpmInitializedPpiList);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ if (mImageInMemory) {
+ Status = PeimEntryMP ((EFI_PEI_SERVICES**)PeiServices);
+ return Status;
+ }
+
+Done:
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "TPM2 error! Build Hob\n"));
+ BuildGuidHob (&gTpmErrorHobGuid,0);
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ (PcdGet32 (PcdStatusCodeSubClassTpmDevice) | EFI_P_EC_INTERFACE_ERROR)
+ );
+ }
+ //
+ // Always intall TpmInitializationDonePpi no matter success or fail.
+ // Other driver can know TPM initialization state by TpmInitializedPpi.
+ //
+ Status2 = PeiServicesInstallPpi (&mTpmInitializationDonePpiList);
+ ASSERT_EFI_ERROR (Status2);
+
+ return Status;
+}
diff --git a/Core/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.inf b/Core/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.inf
new file mode 100644
index 0000000000..3477d8206a
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.inf
@@ -0,0 +1,92 @@
+## @file
+# Initializes TPM 2.0 device and measure FVs in PEI phase
+#
+# This module will initialize TPM device, measure reported FVs and BIOS version.
+#
+# Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = Tcg2Pei
+ MODULE_UNI_FILE = Tcg2Pei.uni
+ FILE_GUID = A0C98B77-CBA5-4BB8-993B-4AF6CE33ECE4
+ 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
+#
+# [BootMode]
+# S3_RESUME ## SOMETIMES_CONSUMES
+#
+
+[Sources]
+ Tcg2Pei.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+ HobLib
+ PeimEntryPoint
+ PeiServicesLib
+ BaseMemoryLib
+ DebugLib
+ Tpm2CommandLib
+ PeiServicesTablePointerLib
+ Tpm2DeviceLib
+ HashLib
+ PerformanceLib
+ MemoryAllocationLib
+ ReportStatusCodeLib
+ Tcg2PhysicalPresenceLib
+ ResetSystemLib
+
+[Guids]
+ gTcgEventEntryHobGuid ## PRODUCES ## HOB
+ gTpmErrorHobGuid ## SOMETIMES_PRODUCES ## HOB
+ gMeasuredFvHobGuid ## PRODUCES ## HOB
+ gTcgEvent2EntryHobGuid ## PRODUCES ## HOB
+ gEfiTpmDeviceInstanceNoneGuid ## SOMETIMES_PRODUCES ## GUID # TPM device identifier
+ gEfiTpmDeviceInstanceTpm12Guid ## SOMETIMES_PRODUCES ## GUID # TPM device identifier
+
+[Ppis]
+ gEfiPeiFirmwareVolumeInfoPpiGuid ## SOMETIMES_CONSUMES ## NOTIFY
+ gEfiPeiFirmwareVolumeInfo2PpiGuid ## SOMETIMES_CONSUMES ## NOTIFY
+ gEfiPeiFirmwareVolumeInfoMeasurementExcludedPpiGuid ## SOMETIMES_CONSUMES
+ gPeiTpmInitializedPpiGuid ## SOMETIMES_PRODUCES
+ gPeiTpmInitializationDonePpiGuid ## PRODUCES
+ gEfiEndOfPeiSignalPpiGuid ## SOMETIMES_CONSUMES ## NOTIFY
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFirmwareVersionString ## SOMETIMES_CONSUMES
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpmInstanceGuid ## CONSUMES
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpm2InitializationPolicy ## CONSUMES
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpm2SelfTestPolicy ## SOMETIMES_CONSUMES
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpm2ScrtmPolicy ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdPeiCoreMaxFvSupported ## CONSUMES
+ gEfiSecurityPkgTokenSpaceGuid.PcdStatusCodeSubClassTpmDevice ## SOMETIMES_CONSUMES
+ ## SOMETIMES_CONSUMES
+ ## SOMETIMES_PRODUCES
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpm2HashMask
+
+[Depex]
+ gEfiPeiMasterBootModePpiGuid AND
+ gEfiPeiReadOnlyVariable2PpiGuid AND
+ gEfiTpmDeviceSelectedGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ Tcg2PeiExtra.uni
diff --git a/Core/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.uni b/Core/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.uni
new file mode 100644
index 0000000000..4622dffaa8
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.uni
@@ -0,0 +1,21 @@
+// /** @file
+// Initializes TPM 2.0 device and measure FVs in PEI phase
+//
+// This module will initialize TPM device, measure reported FVs and BIOS version.
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Initializes TPM 2.0 device and measure FVs in PEI phase"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This module will initialize TPM device, measure reported FVs and BIOS version."
+
diff --git a/Core/SecurityPkg/Tcg/Tcg2Pei/Tcg2PeiExtra.uni b/Core/SecurityPkg/Tcg/Tcg2Pei/Tcg2PeiExtra.uni
new file mode 100644
index 0000000000..dea6dcc0e3
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Tcg2Pei/Tcg2PeiExtra.uni
@@ -0,0 +1,19 @@
+// /** @file
+// Tcg2Pei Localized Strings and Content
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"TCG2 (Trusted Computing Group) PEI"
+
+
diff --git a/Core/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.c b/Core/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.c
new file mode 100644
index 0000000000..5a1fd3e363
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.c
@@ -0,0 +1,649 @@
+/** @file
+ It updates TPM2 items in ACPI table and registers SMI2 callback
+ functions for Tcg2 physical presence, ClearMemory, and sample
+ for dTPM StartMethod.
+
+ Caution: This module requires additional review when modified.
+ This driver will have external input - variable and ACPINvs data in SMM mode.
+ This external input must be validated carefully to avoid security issue.
+
+ PhysicalPresenceCallback() and MemoryClearCallback() will receive untrusted input and do some check.
+
+Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "Tcg2Smm.h"
+
+typedef enum {
+ PtpInterfaceTis,
+ PtpInterfaceFifo,
+ PtpInterfaceCrb,
+ PtpInterfaceMax,
+} PTP_INTERFACE_TYPE;
+
+/**
+ Return PTP interface type.
+
+ @param[in] Register Pointer to PTP register.
+
+ @return PTP interface type.
+**/
+PTP_INTERFACE_TYPE
+GetPtpInterface (
+ IN VOID *Register
+ )
+{
+ PTP_CRB_INTERFACE_IDENTIFIER InterfaceId;
+ PTP_FIFO_INTERFACE_CAPABILITY InterfaceCapability;
+
+ //
+ // Check interface id
+ //
+ InterfaceId.Uint32 = MmioRead32 ((UINTN)&((PTP_CRB_REGISTERS *)Register)->InterfaceId);
+ InterfaceCapability.Uint32 = MmioRead32 ((UINTN)&((PTP_FIFO_REGISTERS *)Register)->InterfaceCapability);
+
+ if (InterfaceId.Bits.InterfaceType == PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_TIS) {
+ return PtpInterfaceTis;
+ }
+
+ if ((InterfaceId.Bits.InterfaceType == PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_CRB) &&
+ (InterfaceId.Bits.InterfaceVersion == PTP_INTERFACE_IDENTIFIER_INTERFACE_VERSION_CRB) &&
+ (InterfaceId.Bits.CapCRB != 0)) {
+ return PtpInterfaceCrb;
+ }
+
+ if ((InterfaceId.Bits.InterfaceType == PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_FIFO) &&
+ (InterfaceId.Bits.InterfaceVersion == PTP_INTERFACE_IDENTIFIER_INTERFACE_VERSION_FIFO) &&
+ (InterfaceId.Bits.CapFIFO != 0) &&
+ (InterfaceCapability.Bits.InterfaceVersion == INTERFACE_CAPABILITY_INTERFACE_VERSION_PTP)) {
+ return PtpInterfaceFifo;
+ }
+
+ //
+ // No Ptp interface available
+ //
+ return PtpInterfaceMax;
+}
+
+EFI_TPM2_ACPI_TABLE mTpm2AcpiTemplate = {
+ {
+ EFI_ACPI_5_0_TRUSTED_COMPUTING_PLATFORM_2_TABLE_SIGNATURE,
+ sizeof (mTpm2AcpiTemplate),
+ EFI_TPM2_ACPI_TABLE_REVISION,
+ //
+ // Compiler initializes the remaining bytes to 0
+ // These fields should be filled in in production
+ //
+ },
+ 0, // BIT0~15: PlatformClass
+ // BIT16~31: Reserved
+ 0, // Control Area
+ EFI_TPM2_ACPI_TABLE_START_METHOD_TIS, // StartMethod
+};
+
+EFI_SMM_VARIABLE_PROTOCOL *mSmmVariable;
+TCG_NVS *mTcgNvs;
+
+/**
+ Software SMI callback for TPM physical presence which is called from ACPI method.
+
+ Caution: This function may receive untrusted input.
+ Variable and ACPINvs are external input, so this function will validate
+ its data structure to be valid value.
+
+ @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
+ )
+{
+ UINT32 MostRecentRequest;
+ UINT32 Response;
+ UINT32 OperationRequest;
+ UINT32 RequestParameter;
+
+
+ if (mTcgNvs->PhysicalPresence.Parameter == TCG_ACPI_FUNCTION_RETURN_REQUEST_RESPONSE_TO_OS) {
+ mTcgNvs->PhysicalPresence.ReturnCode = Tcg2PhysicalPresenceLibReturnOperationResponseToOsFunction (
+ &MostRecentRequest,
+ &Response
+ );
+ mTcgNvs->PhysicalPresence.LastRequest = MostRecentRequest;
+ mTcgNvs->PhysicalPresence.Response = Response;
+ return EFI_SUCCESS;
+ } else if ((mTcgNvs->PhysicalPresence.Parameter == TCG_ACPI_FUNCTION_SUBMIT_REQUEST_TO_BIOS)
+ || (mTcgNvs->PhysicalPresence.Parameter == TCG_ACPI_FUNCTION_SUBMIT_REQUEST_TO_BIOS_2)) {
+
+ OperationRequest = mTcgNvs->PhysicalPresence.Request;
+ RequestParameter = mTcgNvs->PhysicalPresence.RequestParameter;
+ mTcgNvs->PhysicalPresence.ReturnCode = Tcg2PhysicalPresenceLibSubmitRequestToPreOSFunctionEx (
+ &OperationRequest,
+ &RequestParameter
+ );
+ mTcgNvs->PhysicalPresence.Request = OperationRequest;
+ mTcgNvs->PhysicalPresence.RequestParameter = RequestParameter;
+ } else if (mTcgNvs->PhysicalPresence.Parameter == TCG_ACPI_FUNCTION_GET_USER_CONFIRMATION_STATUS_FOR_REQUEST) {
+ mTcgNvs->PhysicalPresence.ReturnCode = Tcg2PhysicalPresenceLibGetUserConfirmationStatusFunction (mTcgNvs->PPRequestUserConfirm);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Software SMI callback for MemoryClear which is called from ACPI method.
+
+ Caution: This function may receive untrusted input.
+ Variable and ACPINvs are external input, so this function will validate
+ its data structure to be valid value.
+
+ @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;
+
+ mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_SUCCESS;
+ if (mTcgNvs->MemoryClear.Parameter == ACPI_FUNCTION_DSM_MEMORY_CLEAR_INTERFACE) {
+ MorControl = (UINT8) mTcgNvs->MemoryClear.Request;
+ } else if (mTcgNvs->MemoryClear.Parameter == ACPI_FUNCTION_PTS_CLEAR_MOR_BIT) {
+ DataSize = sizeof (UINT8);
+ Status = mSmmVariable->SmmGetVariable (
+ MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,
+ &gEfiMemoryOverwriteControlDataGuid,
+ NULL,
+ &DataSize,
+ &MorControl
+ );
+ if (EFI_ERROR (Status)) {
+ mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_GENERAL_FAILURE;
+ DEBUG ((EFI_D_ERROR, "[TPM] Get MOR variable failure! Status = %r\n", Status));
+ 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
+ );
+ if (EFI_ERROR (Status)) {
+ mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_GENERAL_FAILURE;
+ DEBUG ((EFI_D_ERROR, "[TPM] Set MOR variable failure! Status = %r\n", 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_EXT_REGION_OP) &&
+ (OpRegion->NameString == Name) &&
+ (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;
+ OpRegion->RegionLen = (UINT8) Size;
+ break;
+ }
+ }
+
+ return (VOID *) (UINTN) MemoryAddress;
+}
+
+/**
+ Patch version string of Physical Presence interface supported by platform. The initial string tag in TPM
+ACPI table is "$PV".
+
+ @param[in, out] Table The TPM item in ACPI table.
+ @param[in] PPVer Version string of Physical Presence interface supported by platform.
+
+ @return The allocated address for the found region.
+
+**/
+EFI_STATUS
+UpdatePPVersion (
+ EFI_ACPI_DESCRIPTION_HEADER *Table,
+ CHAR8 *PPVer
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *DataPtr;
+
+ //
+ // Patch some pointers for the ASL code before loading the SSDT.
+ //
+ for (DataPtr = (UINT8 *)(Table + 1);
+ DataPtr <= (UINT8 *) ((UINT8 *) Table + Table->Length - PHYSICAL_PRESENCE_VERSION_SIZE);
+ DataPtr += 1) {
+ if (AsciiStrCmp((CHAR8 *)DataPtr, PHYSICAL_PRESENCE_VERSION_TAG) == 0) {
+ Status = AsciiStrCpyS((CHAR8 *)DataPtr, PHYSICAL_PRESENCE_VERSION_SIZE, PPVer);
+ DEBUG((EFI_D_INFO, "TPM2 Physical Presence Interface Version update status 0x%x\n", Status));
+ return Status;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Patch TPM2 device HID string. The initial string tag in TPM2 ACPI table is "NNN0000".
+
+ @param[in, out] Table The TPM2 SSDT ACPI table.
+
+ @return HID Update status.
+
+**/
+EFI_STATUS
+UpdateHID (
+ EFI_ACPI_DESCRIPTION_HEADER *Table
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *DataPtr;
+ CHAR8 Hid[TPM_HID_ACPI_SIZE];
+ UINT32 ManufacturerID;
+ UINT32 FirmwareVersion1;
+ UINT32 FirmwareVersion2;
+ BOOLEAN PnpHID;
+
+ PnpHID = TRUE;
+
+ //
+ // Initialize HID with Default PNP string
+ //
+ ZeroMem(Hid, TPM_HID_ACPI_SIZE);
+
+ //
+ // Get Manufacturer ID
+ //
+ Status = Tpm2GetCapabilityManufactureID(&ManufacturerID);
+ if (!EFI_ERROR(Status)) {
+ DEBUG((EFI_D_INFO, "TPM_PT_MANUFACTURER 0x%08x\n", ManufacturerID));
+ //
+ // ManufacturerID defined in TCG Vendor ID Registry
+ // may tailed with 0x00 or 0x20
+ //
+ if ((ManufacturerID >> 24) == 0x00 || ((ManufacturerID >> 24) == 0x20)) {
+ //
+ // HID containing PNP ID "NNN####"
+ // NNN is uppercase letter for Vendor ID specified by manufacturer
+ //
+ CopyMem(Hid, &ManufacturerID, 3);
+ } else {
+ //
+ // HID containing ACP ID "NNNN####"
+ // NNNN is uppercase letter for Vendor ID specified by manufacturer
+ //
+ CopyMem(Hid, &ManufacturerID, 4);
+ PnpHID = FALSE;
+ }
+ } else {
+ DEBUG ((EFI_D_ERROR, "Get TPM_PT_MANUFACTURER failed %x!\n", Status));
+ ASSERT(FALSE);
+ return Status;
+ }
+
+ Status = Tpm2GetCapabilityFirmwareVersion(&FirmwareVersion1, &FirmwareVersion2);
+ if (!EFI_ERROR(Status)) {
+ DEBUG((EFI_D_INFO, "TPM_PT_FIRMWARE_VERSION_1 0x%x\n", FirmwareVersion1));
+ DEBUG((EFI_D_INFO, "TPM_PT_FIRMWARE_VERSION_2 0x%x\n", FirmwareVersion2));
+ //
+ // #### is Firmware Version 1
+ //
+ if (PnpHID) {
+ AsciiSPrint(Hid + 3, TPM_HID_PNP_SIZE - 3, "%02d%02d", ((FirmwareVersion1 & 0xFFFF0000) >> 16), (FirmwareVersion1 & 0x0000FFFF));
+ } else {
+ AsciiSPrint(Hid + 4, TPM_HID_ACPI_SIZE - 4, "%02d%02d", ((FirmwareVersion1 & 0xFFFF0000) >> 16), (FirmwareVersion1 & 0x0000FFFF));
+ }
+
+ } else {
+ DEBUG ((EFI_D_ERROR, "Get TPM_PT_FIRMWARE_VERSION_X failed %x!\n", Status));
+ ASSERT(FALSE);
+ return Status;
+ }
+
+ //
+ // Patch HID in ASL code before loading the SSDT.
+ //
+ for (DataPtr = (UINT8 *)(Table + 1);
+ DataPtr <= (UINT8 *) ((UINT8 *) Table + Table->Length - TPM_HID_PNP_SIZE);
+ DataPtr += 1) {
+ if (AsciiStrCmp((CHAR8 *)DataPtr, TPM_HID_TAG) == 0) {
+ if (PnpHID) {
+ CopyMem(DataPtr, Hid, TPM_HID_PNP_SIZE);
+ //
+ // if HID is PNP ID, patch the last byte in HID TAG to Noop
+ //
+ *(DataPtr + TPM_HID_PNP_SIZE) = AML_NOOP_OP;
+ } else {
+
+ CopyMem(DataPtr, Hid, TPM_HID_ACPI_SIZE);
+ }
+ DEBUG((DEBUG_INFO, "TPM2 ACPI _HID is patched to %a\n", DataPtr));
+
+ return Status;
+ }
+ }
+
+ DEBUG((EFI_D_ERROR, "TPM2 ACPI HID TAG for patch not found!\n"));
+ return EFI_NOT_FOUND;
+}
+
+/**
+ 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);
+
+ //
+ // Update Table version before measuring it to PCR
+ //
+ Status = UpdatePPVersion(Table, (CHAR8 *)PcdGetPtr(PcdTcgPhysicalPresenceInterfaceVer));
+ ASSERT_EFI_ERROR (Status);
+
+ DEBUG ((
+ DEBUG_INFO,
+ "Current physical presence interface version - %a\n",
+ (CHAR8 *) PcdGetPtr(PcdTcgPhysicalPresenceInterfaceVer)
+ ));
+
+ //
+ // Update TPM2 HID before measuring it to PCR
+ //
+ Status = UpdateHID(Table);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ //
+ // Measure to PCR[0] with event EV_POST_CODE ACPI DATA
+ //
+ TpmMeasureAndLogData(
+ 0,
+ EV_POST_CODE,
+ EV_POSTCODE_INFO_ACPI_DATA,
+ ACPI_DATA_LEN,
+ Table,
+ TableSize
+ );
+
+
+ ASSERT (Table->OemTableId == SIGNATURE_64 ('T', 'p', 'm', '2', 'T', 'a', 'b', 'l'));
+ CopyMem (Table->OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (Table->OemId) );
+ mTcgNvs = AssignOpRegion (Table, SIGNATURE_32 ('T', 'N', 'V', 'S'), (UINT16) sizeof (TCG_NVS));
+ ASSERT (mTcgNvs != NULL);
+
+ //
+ // Publish the TPM ACPI table. Table is re-checksumed.
+ //
+ 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;
+}
+
+/**
+ Publish TPM2 ACPI table
+
+ @retval EFI_SUCCESS The TPM2 ACPI table is published successfully.
+ @retval Others The TPM2 ACPI table is not published.
+
+**/
+EFI_STATUS
+PublishTpm2 (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_ACPI_TABLE_PROTOCOL *AcpiTable;
+ UINTN TableKey;
+ UINT64 OemTableId;
+ EFI_TPM2_ACPI_CONTROL_AREA *ControlArea;
+ PTP_INTERFACE_TYPE InterfaceType;
+
+ mTpm2AcpiTemplate.Header.Revision = PcdGet8(PcdTpm2AcpiTableRev);
+ DEBUG((DEBUG_INFO, "Tpm2 ACPI table revision is %d\n", mTpm2AcpiTemplate.Header.Revision));
+
+ //
+ // PlatformClass is only valid for version 4 and above
+ // BIT0~15: PlatformClass
+ // BIT16~31: Reserved
+ //
+ if (mTpm2AcpiTemplate.Header.Revision >= EFI_TPM2_ACPI_TABLE_REVISION_4) {
+ mTpm2AcpiTemplate.Flags = (mTpm2AcpiTemplate.Flags & 0xFFFF0000) | PcdGet8(PcdTpmPlatformClass);
+ DEBUG((DEBUG_INFO, "Tpm2 ACPI table PlatformClass is %d\n", (mTpm2AcpiTemplate.Flags & 0x0000FFFF)));
+ }
+
+ //
+ // Measure to PCR[0] with event EV_POST_CODE ACPI DATA
+ //
+ TpmMeasureAndLogData(
+ 0,
+ EV_POST_CODE,
+ EV_POSTCODE_INFO_ACPI_DATA,
+ ACPI_DATA_LEN,
+ &mTpm2AcpiTemplate,
+ sizeof(mTpm2AcpiTemplate)
+ );
+
+ InterfaceType = GetPtpInterface ((VOID *) (UINTN) PcdGet64 (PcdTpmBaseAddress));
+ switch (InterfaceType) {
+ case PtpInterfaceCrb:
+ mTpm2AcpiTemplate.StartMethod = EFI_TPM2_ACPI_TABLE_START_METHOD_COMMAND_RESPONSE_BUFFER_INTERFACE;
+ mTpm2AcpiTemplate.AddressOfControlArea = PcdGet64 (PcdTpmBaseAddress) + 0x40;
+ ControlArea = (EFI_TPM2_ACPI_CONTROL_AREA *)(UINTN)mTpm2AcpiTemplate.AddressOfControlArea;
+ ControlArea->CommandSize = 0xF80;
+ ControlArea->ResponseSize = 0xF80;
+ ControlArea->Command = PcdGet64 (PcdTpmBaseAddress) + 0x80;
+ ControlArea->Response = PcdGet64 (PcdTpmBaseAddress) + 0x80;
+ break;
+ case PtpInterfaceFifo:
+ case PtpInterfaceTis:
+ break;
+ default:
+ DEBUG((EFI_D_ERROR, "TPM2 InterfaceType get error! %d\n", InterfaceType));
+ break;
+ }
+
+ CopyMem (mTpm2AcpiTemplate.Header.OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (mTpm2AcpiTemplate.Header.OemId));
+ OemTableId = PcdGet64 (PcdAcpiDefaultOemTableId);
+ CopyMem (&mTpm2AcpiTemplate.Header.OemTableId, &OemTableId, sizeof (UINT64));
+ mTpm2AcpiTemplate.Header.OemRevision = PcdGet32 (PcdAcpiDefaultOemRevision);
+ mTpm2AcpiTemplate.Header.CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId);
+ mTpm2AcpiTemplate.Header.CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision);
+
+ //
+ // Construct ACPI table
+ //
+ Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTable);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = AcpiTable->InstallAcpiTable (
+ AcpiTable,
+ &mTpm2AcpiTemplate,
+ sizeof(mTpm2AcpiTemplate),
+ &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;
+
+ if (!CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceTpm20DtpmGuid)){
+ DEBUG ((EFI_D_ERROR, "No TPM2 DTPM instance required!\n"));
+ return EFI_UNSUPPORTED;
+ }
+
+ 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);
+
+ //
+ // Set TPM2 ACPI table
+ //
+ Status = PublishTpm2 ();
+ ASSERT_EFI_ERROR (Status);
+
+
+ return EFI_SUCCESS;
+}
+
diff --git a/Core/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.h b/Core/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.h
new file mode 100644
index 0000000000..100804cf2a
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.h
@@ -0,0 +1,105 @@
+/** @file
+ The header file for Tcg2 SMM driver.
+
+Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __TCG2_SMM_H__
+#define __TCG2_SMM_H__
+
+#include <PiDxe.h>
+#include <IndustryStandard/Acpi.h>
+#include <IndustryStandard/Tpm2Acpi.h>
+
+#include <Guid/MemoryOverwriteControl.h>
+#include <Guid/TpmInstance.h>
+
+#include <Protocol/SmmSwDispatch2.h>
+#include <Protocol/AcpiTable.h>
+#include <Protocol/SmmVariable.h>
+#include <Protocol/Tcg2Protocol.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/SmmServicesTableLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DxeServicesLib.h>
+#include <Library/TpmMeasurementLib.h>
+#include <Library/Tpm2CommandLib.h>
+#include <Library/Tcg2PhysicalPresenceLib.h>
+#include <Library/IoLib.h>
+#include <Library/PrintLib.h>
+
+#include <IndustryStandard/TpmPtp.h>
+
+#pragma pack(1)
+typedef struct {
+ UINT8 SoftwareSmi;
+ UINT32 Parameter;
+ UINT32 Response;
+ UINT32 Request;
+ UINT32 RequestParameter;
+ UINT32 LastRequest;
+ UINT32 ReturnCode;
+} PHYSICAL_PRESENCE_NVS;
+
+typedef struct {
+ UINT8 SoftwareSmi;
+ UINT32 Parameter;
+ UINT32 Request;
+ UINT32 ReturnCode;
+} MEMORY_CLEAR_NVS;
+
+typedef struct {
+ PHYSICAL_PRESENCE_NVS PhysicalPresence;
+ MEMORY_CLEAR_NVS MemoryClear;
+ UINT32 PPRequestUserConfirm;
+} 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()
+
+//
+// The definition for TCG MOR
+//
+#define ACPI_FUNCTION_DSM_MEMORY_CLEAR_INTERFACE 1
+#define ACPI_FUNCTION_PTS_CLEAR_MOR_BIT 2
+
+//
+// The return code for Memory Clear Interface Functions
+//
+#define MOR_REQUEST_SUCCESS 0
+#define MOR_REQUEST_GENERAL_FAILURE 1
+
+//
+// Physical Presence Interface Version supported by Platform
+//
+#define PHYSICAL_PRESENCE_VERSION_TAG "$PV"
+#define PHYSICAL_PRESENCE_VERSION_SIZE 4
+
+//
+// PNP _HID for TPM2 device
+//
+#define TPM_HID_TAG "NNNN0000"
+#define TPM_HID_PNP_SIZE 8
+#define TPM_HID_ACPI_SIZE 9
+
+#endif // __TCG_SMM_H__
diff --git a/Core/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.inf b/Core/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.inf
new file mode 100644
index 0000000000..c4efa2a188
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.inf
@@ -0,0 +1,86 @@
+## @file
+# Provides ACPI metholds for TPM 2.0 support
+#
+# This driver implements TPM 2.0 definition block in ACPI table and
+# registers SMI callback functions for Tcg2 physical presence and
+# MemoryClear to handle the requests from ACPI method.
+#
+# Caution: This module requires additional review when modified.
+# This driver will have external input - variable and ACPINvs data in SMM mode.
+# This external input must be validated carefully to avoid security issue.
+#
+# Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = Tcg2Smm
+ MODULE_UNI_FILE = Tcg2Smm.uni
+ FILE_GUID = 44A20657-10B8-4049-A148-ACD8812AF257
+ MODULE_TYPE = DXE_SMM_DRIVER
+ PI_SPECIFICATION_VERSION = 0x0001000A
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializeTcgSmm
+
+[Sources]
+ Tcg2Smm.h
+ Tcg2Smm.c
+ Tpm.asl
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ UefiDriverEntryPoint
+ SmmServicesTableLib
+ UefiBootServicesTableLib
+ DebugLib
+ DxeServicesLib
+ TpmMeasurementLib
+ Tpm2CommandLib
+ Tcg2PhysicalPresenceLib
+ IoLib
+
+[Guids]
+ ## SOMETIMES_PRODUCES ## Variable:L"MemoryOverwriteRequestControl"
+ ## SOMETIMES_CONSUMES ## Variable:L"MemoryOverwriteRequestControl"
+ gEfiMemoryOverwriteControlDataGuid
+
+ gEfiTpmDeviceInstanceTpm20DtpmGuid ## PRODUCES ## GUID # TPM device identifier
+
+[Protocols]
+ gEfiSmmSwDispatch2ProtocolGuid ## CONSUMES
+ gEfiSmmVariableProtocolGuid ## CONSUMES
+ gEfiAcpiTableProtocolGuid ## CONSUMES
+
+[Pcd]
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpmInstanceGuid ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemId ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemTableId ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemRevision ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorId ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorRevision ## SOMETIMES_CONSUMES
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpmBaseAddress ## CONSUMES
+ gEfiSecurityPkgTokenSpaceGuid.PcdTcgPhysicalPresenceInterfaceVer ## CONSUMES
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpm2AcpiTableRev ## CONSUMES
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpmPlatformClass ## SOMETIMES_CONSUMES
+
+[Depex]
+ gEfiAcpiTableProtocolGuid AND
+ gEfiSmmSwDispatch2ProtocolGuid AND
+ gEfiSmmVariableProtocolGuid AND
+ gEfiTcg2ProtocolGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ Tcg2SmmExtra.uni
diff --git a/Core/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.uni b/Core/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.uni
new file mode 100644
index 0000000000..297e71a06d
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.uni
@@ -0,0 +1,28 @@
+// /** @file
+// Provides ACPI metholds for TPM 2.0 support
+//
+// This driver implements TPM 2.0 definition block in ACPI table and
+// registers SMI callback functions for TCG2 physical presence and
+// MemoryClear to handle the requests from ACPI method.
+//
+// Caution: This module requires additional review when modified.
+// This driver will have external input - variable and ACPINvs data in SMM mode.
+// This external input must be validated carefully to avoid security issue.
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides ACPI metholds for TPM 2.0 support"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This driver implements TPM 2.0 definition block in ACPI table and registers SMI callback functions for TCG2 physical presence and MemoryClear to handle the requests from ACPI method.\n"
+ "Caution: This module requires additional review when modified. This driver will have external input - variable and ACPINvs data in SMM mode. This external input must be validated carefully to avoid security issues."
+
diff --git a/Core/SecurityPkg/Tcg/Tcg2Smm/Tcg2SmmExtra.uni b/Core/SecurityPkg/Tcg/Tcg2Smm/Tcg2SmmExtra.uni
new file mode 100644
index 0000000000..e2a7b1d02f
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Tcg2Smm/Tcg2SmmExtra.uni
@@ -0,0 +1,19 @@
+// /** @file
+// Tcg2Smm Localized Strings and Content
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"TCG2 (Trusted Computing Group) SMM"
+
+
diff --git a/Core/SecurityPkg/Tcg/Tcg2Smm/Tpm.asl b/Core/SecurityPkg/Tcg/Tcg2Smm/Tpm.asl
new file mode 100644
index 0000000000..cf0642e104
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Tcg2Smm/Tpm.asl
@@ -0,0 +1,368 @@
+/** @file
+ The TPM2 definition block in ACPI table for TCG2 physical presence
+ and MemoryClear.
+
+Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
+(c)Copyright 2016 HP Development Company, L.P.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+DefinitionBlock (
+ "Tpm.aml",
+ "SSDT",
+ 2,
+ "INTEL ",
+ "Tpm2Tabl",
+ 0x1000
+ )
+{
+ Scope (\_SB)
+ {
+ Device (TPM)
+ {
+ //
+ // TCG2
+ //
+
+ //
+ // TAG for patching TPM2.0 _HID
+ //
+ Name (_HID, "NNNN0000")
+
+ Name (_CID, "MSFT0101")
+
+ //
+ // Readable name of this device, don't know if this way is correct yet
+ //
+ Name (_STR, Unicode ("TPM 2.0 Device"))
+
+ //
+ // Return the resource consumed by TPM device
+ //
+ Name (_CRS, ResourceTemplate () {
+ Memory32Fixed (ReadWrite, 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 0xFFFF0000 and Length 0xF0 will be fixed in C code.
+ //
+ OperationRegion (TNVS, SystemMemory, 0xFFFF0000, 0xF0)
+ 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
+ PPRM, 32, // Physical Presence request operation parameter
+ 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
+ MRET, 32, // Memory Overwrite function return code
+ UCRQ, 32 // Phyical Presence request operation to Get User Confirmation Status
+ }
+
+ 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}, {UnknownObj, UnknownObj, UnknownObj}) // 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 () {0x2, 0x0}})
+ 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}, {UnknownObj, UnknownObj, UnknownObj}) // 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 ("$PV")
+ }
+ Case (2)
+ {
+ //
+ // b) Submit TPM Operation Request to Pre-OS Environment
+ //
+
+ Store (DerefOf (Index (Arg2, 0x00)), PPRQ)
+ Store (0, PPRM)
+ 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)
+ Store (0, PPRM)
+ If (LEqual (PPRQ, 23)) {
+ Store (DerefOf (Index (Arg2, 0x01)), PPRM)
+ }
+
+ //
+ // 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)), UCRQ)
+
+ //
+ // Triggle the SMI interrupt
+ //
+ Store (PPIN, IOB2)
+
+ Return (FRET)
+ }
+
+ Default {BreakPoint}
+ }
+ Return (1)
+ }
+
+ Method (TMCI, 3, Serialized, 0, IntObj, {UnknownObj, UnknownObj, UnknownObj}) // 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 (MRET)
+ }
+ 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/Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfig.vfr b/Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfig.vfr
new file mode 100644
index 0000000000..94e3229e88
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfig.vfr
@@ -0,0 +1,74 @@
+/** @file
+ VFR file used by the TCG configuration component.
+
+Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "TcgConfigNvData.h"
+
+formset
+ guid = TCG_CONFIG_FORM_SET_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_FORM_SET_GUID;
+
+ form formid = TCG_CONFIGURATION_FORM_ID,
+ title = STRING_TOKEN(STR_TPM_TITLE);
+
+ subtitle text = STRING_TOKEN(STR_NULL);
+
+ 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);
+
+ oneof varid = TCG_CONFIGURATION.TpmOperation,
+ questionid = KEY_TPM_ACTION,
+ prompt = STRING_TOKEN(STR_TPM_OPERATION),
+ help = STRING_TOKEN(STR_TPM_OPERATION_HELP),
+ flags = INTERACTIVE | RESET_REQUIRED,
+ //
+ // 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 = PHYSICAL_PRESENCE_DISABLE, flags = 0;
+ option text = STRING_TOKEN(STR_TPM_ACTIVATE), value = PHYSICAL_PRESENCE_ACTIVATE, flags = 0;
+ option text = STRING_TOKEN(STR_TPM_DEACTIVATE), value = PHYSICAL_PRESENCE_DEACTIVATE, flags = 0;
+ option text = STRING_TOKEN(STR_TPM_DEACTIVATE_DISABLE), value = PHYSICAL_PRESENCE_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 = PHYSICAL_PRESENCE_CLEAR, flags = 0;
+ option text = STRING_TOKEN(STR_TPM_CLEAR_ENABLE_ACTIVATE), value = PHYSICAL_PRESENCE_CLEAR_ENABLE_ACTIVATE, flags = 0;
+ endif
+
+ option text = STRING_TOKEN(STR_ENABLE), value = PHYSICAL_PRESENCE_ENABLE, flags = DEFAULT;
+ option text = STRING_TOKEN(STR_TPM_ENABLE_ACTIVATE), value = PHYSICAL_PRESENCE_ENABLE_ACTIVATE, flags = 0;
+ option text = STRING_TOKEN(STR_TPM_ENABLE_ACTIVATE_CLEAR), value = PHYSICAL_PRESENCE_ENABLE_ACTIVATE_CLEAR, flags = 0;
+ option text = STRING_TOKEN(STR_TPM_ENABLE_ACTIVATE_CLEAR_E_A), value = PHYSICAL_PRESENCE_ENABLE_ACTIVATE_CLEAR_ENABLE_ACTIVATE, flags = 0;
+ endoneof;
+
+ subtitle text = STRING_TOKEN(STR_NULL);
+
+ endform;
+
+endformset;
diff --git a/Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDriver.c b/Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDriver.c
new file mode 100644
index 0000000000..a9d3105456
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDriver.c
@@ -0,0 +1,156 @@
+/** @file
+ The module entry point for Tcg configuration module.
+
+Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "TcgConfigImpl.h"
+#include <Guid/TpmInstance.h>
+
+/**
+ 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;
+
+ if (!CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceTpm12Guid)){
+ DEBUG ((EFI_D_ERROR, "No TPM12 instance required!\n"));
+ return EFI_UNSUPPORTED;
+ }
+
+ Status = Tpm12RequestUseTpm ();
+ 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,
+ &gEfiCallerIdGuid,
+ 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->Configuration = AllocatePool (sizeof (TCG_CONFIGURATION));
+ if (PrivateData->Configuration == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ErrorExit;
+ }
+
+ PrivateData->TcgProtocol = TcgProtocol;
+
+ //
+ // Install TCG configuration form
+ //
+ Status = InstallTcgConfigForm (PrivateData);
+ if (EFI_ERROR (Status)) {
+ goto ErrorExit;
+ }
+
+ //
+ // Install private GUID.
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &ImageHandle,
+ &gEfiCallerIdGuid,
+ 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,
+ &gEfiCallerIdGuid,
+ (VOID **) &PrivateData
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ASSERT (PrivateData->Signature == TCG_CONFIG_PRIVATE_DATA_SIGNATURE);
+
+ gBS->UninstallMultipleProtocolInterfaces (
+ &ImageHandle,
+ &gEfiCallerIdGuid,
+ PrivateData,
+ NULL
+ );
+
+ UninstallTcgConfigForm (PrivateData);
+
+ return EFI_SUCCESS;
+}
diff --git a/Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDxe.inf b/Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDxe.inf
new file mode 100644
index 0000000000..82fc35eea0
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDxe.inf
@@ -0,0 +1,83 @@
+## @file
+# Provides the capability to update TPM state setup browser
+# By this module, user may enable/disable/activate/deactivate/clear TPM, etc.
+#
+# Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = TcgConfigDxe
+ MODULE_UNI_FILE = TcgConfigDxe.uni
+ 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
+ Tpm12DeviceLib
+
+[Guids]
+ ## SOMETIMES_PRODUCES ## Variable:L"PhysicalPresence"
+ ## SOMETIMES_CONSUMES ## Variable:L"PhysicalPresence"
+ gEfiPhysicalPresenceGuid
+
+ gEfiIfrTianoGuid ## SOMETIMES_PRODUCES ## GUID # HII opcode
+ ## PRODUCES ## HII
+ ## CONSUMES ## HII
+ gTcgConfigFormSetGuid
+ gEfiTpmDeviceInstanceTpm12Guid ## CONSUMES ## GUID # TPM device identifier
+
+[Protocols]
+ gEfiHiiConfigAccessProtocolGuid ## PRODUCES
+ gEfiDevicePathProtocolGuid ## PRODUCES
+ gEfiTcgProtocolGuid ## CONSUMES
+
+[Pcd]
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpmInstanceGuid ## CONSUMES
+
+[Depex]
+ gEfiHiiConfigRoutingProtocolGuid AND
+ gEfiHiiDatabaseProtocolGuid AND
+ gEfiVariableArchProtocolGuid AND
+ gEfiVariableWriteArchProtocolGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ TcgConfigDxeExtra.uni
diff --git a/Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDxe.uni b/Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDxe.uni
new file mode 100644
index 0000000000..c308271c0d
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDxe.uni
@@ -0,0 +1,21 @@
+// /** @file
+// Provides the capability to update TPM state setup browser
+//
+// By this module, user may enable/disable/activate/deactivate/clear TPM, etc.
+//
+// Copyright (c) 2011 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides the capability to update TPM state setup browser"
+
+#string STR_MODULE_DESCRIPTION #language en-US "By this module, user may enable/disable/activate/deactivate/clear TPM, etc."
+
diff --git a/Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDxeExtra.uni b/Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDxeExtra.uni
new file mode 100644
index 0000000000..2856bf1d40
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDxeExtra.uni
@@ -0,0 +1,19 @@
+// /** @file
+// TcgConfigDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"TCG (Trusted Computing Group) Config DXE"
+
+
diff --git a/Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigImpl.c b/Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigImpl.c
new file mode 100644
index 0000000000..7fa5611cfd
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigImpl.c
@@ -0,0 +1,509 @@
+/** @file
+ HII Config Access protocol implementation of TCG configuration module.
+
+Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "TcgConfigImpl.h"
+
+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_FORM_SET_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] = SwapBytes16 (TPM_TAG_RQU_COMMAND);
+ *(UINT32*)&CmdBuf[2] = SwapBytes32 (TpmSendSize);
+ *(UINT32*)&CmdBuf[6] = SwapBytes32 (TPM_ORD_GetCapability);
+
+ *(UINT32*)&CmdBuf[10] = SwapBytes32 (TPM_CAP_FLAG);
+ *(UINT32*)&CmdBuf[14] = SwapBytes32 (sizeof (TPM_CAP_FLAG_PERMANENT));
+ *(UINT32*)&CmdBuf[18] = SwapBytes32 (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 != SwapBytes16 (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
+ <ConfigRequest> format.
+ @param[out] Progress On return, points to a character in the Request
+ string. Points to the string's null terminator if
+ request was successful. Points to the most recent
+ '&' before the first failing name/value pair (or
+ the beginning of the string if the failure is in
+ the first name/value pair) if the request was not
+ successful.
+ @param[out] Results A null-terminated Unicode string in
+ <ConfigAltResp> format which has all values filled
+ in for the names in the Request string. String to
+ be allocated by the called function.
+
+ @retval EFI_SUCCESS The Results is filled with the requested values.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results.
+ @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name.
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in this
+ driver.
+
+**/
+EFI_STATUS
+EFIAPI
+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;
+ TCG_CONFIG_PRIVATE_DATA *PrivateData;
+ EFI_STRING ConfigRequestHdr;
+ EFI_STRING ConfigRequest;
+ BOOLEAN AllocatedRequest;
+ UINTN Size;
+ BOOLEAN TpmEnable;
+ BOOLEAN TpmActivate;
+
+ if (Progress == NULL || Results == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *Progress = Request;
+ if ((Request != NULL) && !HiiIsConfigHdrMatch (Request, &gTcgConfigFormSetGuid, 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 <ConfigResp> by helper function BlockToConfig()
+ //
+ PrivateData->Configuration->TpmOperation = PHYSICAL_PRESENCE_ENABLE;
+
+ //
+ // Get current TPM state.
+ //
+ if (PrivateData->TcgProtocol != NULL) {
+ Status = GetTpmState (PrivateData->TcgProtocol, &TpmEnable, &TpmActivate);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ PrivateData->Configuration->TpmEnable = TpmEnable;
+ PrivateData->Configuration->TpmActivate = TpmActivate;
+ }
+
+ ConfigRequest = Request;
+ if ((Request == NULL) || (StrStr (Request, L"OFFSET") == NULL)) {
+ //
+ // Request has no request element, construct full request string.
+ // Allocate and fill a buffer large enough to hold the <ConfigHdr> template
+ // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator
+ //
+ ConfigRequestHdr = HiiConstructConfigHdr (&gTcgConfigFormSetGuid, 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, sizeof (TCG_CONFIGURATION));
+ FreePool (ConfigRequestHdr);
+ }
+
+ Status = gHiiConfigRouting->BlockToConfig (
+ gHiiConfigRouting,
+ ConfigRequest,
+ (UINT8 *) PrivateData->Configuration,
+ sizeof (TCG_CONFIGURATION),
+ 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 <ConfigResp>
+ 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, &gTcgConfigFormSetGuid, mTcgStorageName)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Convert <ConfigResp> 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;
+ }
+
+ 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;
+ }
+
+ 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
+ )
+{
+ TCG_CONFIG_PRIVATE_DATA *PrivateData;
+ CHAR16 State[32];
+
+ if ((This == NULL) || (Value == NULL) || (ActionRequest == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Action == EFI_BROWSER_ACTION_FORM_OPEN) {
+ if (QuestionId == KEY_TPM_ACTION) {
+
+ PrivateData = TCG_CONFIG_PRIVATE_DATA_FROM_THIS (This);
+ UnicodeSPrint (
+ State,
+ sizeof (State),
+ L"%s, and %s",
+ PrivateData->Configuration->TpmEnable ? L"Enabled" : L"Disabled",
+ PrivateData->Configuration->TpmActivate ? L"Activated" : L"Deactivated"
+ );
+ HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_TPM_STATE_CONTENT), State, NULL);
+ }
+ return EFI_SUCCESS;
+ }
+
+ if ((Action != EFI_BROWSER_ACTION_CHANGED) || (QuestionId != KEY_TPM_ACTION)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ SavePpRequest (Value->u8);
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT;
+
+ 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;
+ 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 (
+ &gTcgConfigFormSetGuid,
+ DriverHandle,
+ TcgConfigDxeStrings,
+ TcgConfigBin,
+ NULL
+ );
+ if (HiiHandle == NULL) {
+ gBS->UninstallMultipleProtocolInterfaces (
+ DriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mTcgHiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ ConfigAccess,
+ NULL
+ );
+
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ PrivateData->HiiHandle = HiiHandle;
+
+ 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;
+ }
+
+ if (PrivateData->Configuration != NULL) {
+ FreePool(PrivateData->Configuration);
+ }
+ FreePool (PrivateData);
+}
diff --git a/Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigImpl.h b/Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigImpl.h
new file mode 100644
index 0000000000..a03abaa1dd
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigImpl.h
@@ -0,0 +1,194 @@
+/** @file
+ The header file of HII Config Access protocol implementation of TCG
+ configuration module.
+
+Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __TCG_CONFIG_IMPL_H__
+#define __TCG_CONFIG_IMPL_H__
+
+#include <Uefi.h>
+
+#include <Protocol/HiiConfigAccess.h>
+#include <Protocol/HiiConfigRouting.h>
+#include <Protocol/TcgService.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiHiiServicesLib.h>
+#include <Library/UefiLib.h>
+#include <Library/HiiLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PrintLib.h>
+#include <Library/Tpm12DeviceLib.h>
+
+#include <Guid/MdeModuleHii.h>
+
+#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;
+
+ TCG_CONFIGURATION *Configuration;
+ EFI_TCG_PROTOCOL *TcgProtocol;
+} 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
+ <ConfigRequest> format.
+ @param[out] Progress On return, points to a character in the Request
+ string. Points to the string's null terminator if
+ request was successful. Points to the most recent
+ '&' before the first failing name/value pair (or
+ the beginning of the string if the failure is in
+ the first name/value pair) if the request was not
+ successful.
+ @param[out] Results A null-terminated Unicode string in
+ <ConfigAltResp> format which has all values filled
+ in for the names in the Request string. String to
+ be allocated by the called function.
+
+ @retval EFI_SUCCESS The Results is filled with the requested values.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results.
+ @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name.
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in this
+ driver.
+
+**/
+EFI_STATUS
+EFIAPI
+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 <ConfigResp>
+ 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/Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigNvData.h b/Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigNvData.h
new file mode 100644
index 0000000000..eaa6fe8018
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigNvData.h
@@ -0,0 +1,39 @@
+/** @file
+ Header file for NV data structure definition.
+
+Copyright (c) 2011 - 2014, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __TCG_CONFIG_NV_DATA_H__
+#define __TCG_CONFIG_NV_DATA_H__
+
+#include <Guid/HiiPlatformSetupFormset.h>
+#include <Guid/PhysicalPresenceData.h>
+#include <Guid/TcgConfigHii.h>
+
+#define TCG_CONFIGURATION_VARSTORE_ID 0x0001
+#define TCG_CONFIGURATION_FORM_ID 0x0001
+
+#define KEY_TPM_ACTION 0x3000
+
+#define LABEL_TCG_CONFIGURATION_TPM_OPERATION 0x0001
+#define LABEL_END 0xffff
+
+//
+// Nv Data structure referenced by IFR
+//
+typedef struct {
+ UINT8 TpmOperation;
+ BOOLEAN TpmEnable;
+ BOOLEAN TpmActivate;
+} TCG_CONFIGURATION;
+
+#endif
diff --git a/Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigStrings.uni b/Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigStrings.uni
new file mode 100644
index 0000000000..fd8458dc00
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigStrings.uni
@@ -0,0 +1,40 @@
+/** @file
+ String definitions for TCG configuration form.
+
+Copyright (c) 2011 - 2012, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#langdef en-US "English"
+
+#string STR_TPM_TITLE #language en-US "TCG Configuration"
+#string STR_TPM_HELP #language en-US "Press <Enter> to select TCG Setup options."
+#string STR_TPM_STATE_PROMPT #language en-US "Current TPM State"
+#string STR_TPM_STATE_HELP #language en-US "Current TPM device state: enabled or disabled; activated or deactivated."
+#string STR_TPM_STATE_CONTENT #language en-US ""
+
+#string STR_TPM_OPERATION #language en-US "TPM Operation"
+#string STR_TPM_OPERATION_HELP #language en-US "Select one of the supported operation to change TPM state."
+
+#string STR_ENABLE #language en-US "Enable"
+#string STR_DISABLE #language en-US "Disable"
+#string STR_TPM_ACTIVATE #language en-US "Activate"
+#string STR_TPM_DEACTIVATE #language en-US "Deactivate"
+#string STR_TPM_CLEAR #language en-US "Force TPM Clear"
+#string STR_TPM_ENABLE_ACTIVATE #language en-US "Enable and Activate"
+#string STR_TPM_DEACTIVATE_DISABLE #language en-US "Deactivate and Disable"
+#string STR_TPM_ENABLE_ACTIVATE_CLEAR #language en-US "Enable, Activate, and Force TPM Clear"
+#string STR_TPM_CLEAR_ENABLE_ACTIVATE #language en-US "Force TPM Clear, Enable, and Activate"
+#string STR_TPM_ENABLE_ACTIVATE_CLEAR_E_A #language en-US "Enable, Activate, Force TPM Clear, Enable, and Activate"
+
+#string STR_NULL #language en-US ""
+
+#string STR_HIDE_TPM_PROMPT #language en-US "Hide TPM"
+#string STR_HIDE_TPM_HELP #language en-US "Check to hide TPM in OS" \ No newline at end of file
diff --git a/Core/SecurityPkg/Tcg/TcgDxe/TcgDxe.c b/Core/SecurityPkg/Tcg/TcgDxe/TcgDxe.c
new file mode 100644
index 0000000000..5b7c5c3e16
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TcgDxe/TcgDxe.c
@@ -0,0 +1,1467 @@
+/** @file
+ This module implements TCG EFI Protocol.
+
+Caution: This module requires additional review when modified.
+This driver will have external input - TcgDxePassThroughToTpm
+This external input must be validated carefully to avoid security issue like
+buffer overflow, integer overflow.
+
+TcgDxePassThroughToTpm() will receive untrusted input and do basic validation.
+
+Copyright (c) 2005 - 2017, Intel Corporation. All rights reserved.<BR>
+(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiDxe.h>
+#include <IndustryStandard/Tpm12.h>
+#include <IndustryStandard/Acpi.h>
+#include <IndustryStandard/PeImage.h>
+#include <IndustryStandard/TcpaAcpi.h>
+
+#include <Guid/GlobalVariable.h>
+#include <Guid/HobList.h>
+#include <Guid/TcgEventHob.h>
+#include <Guid/EventGroup.h>
+#include <Guid/EventExitBootServiceFailed.h>
+#include <Guid/TpmInstance.h>
+
+#include <Protocol/DevicePath.h>
+#include <Protocol/TcgService.h>
+#include <Protocol/AcpiTable.h>
+#include <Protocol/MpService.h>
+
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/HobLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/BaseLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PrintLib.h>
+#include <Library/Tpm12DeviceLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/Tpm12CommandLib.h>
+#include <Library/BaseCryptLib.h>
+
+#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;
+} 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
+ 0x0120, // TCG Specification revision 1.2
+ 0, // 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,
+ 0 // 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";
+
+/**
+ Get All processors EFI_CPU_LOCATION in system. LocationBuf is allocated inside the function
+ Caller is responsible to free LocationBuf.
+
+ @param[out] LocationBuf Returns Processor Location Buffer.
+ @param[out] Num Returns processor number.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_UNSUPPORTED MpService protocol not found.
+
+**/
+EFI_STATUS
+GetProcessorsCpuLocation (
+ OUT EFI_CPU_PHYSICAL_LOCATION **LocationBuf,
+ OUT UINTN *Num
+ )
+{
+ EFI_STATUS Status;
+ EFI_MP_SERVICES_PROTOCOL *MpProtocol;
+ UINTN ProcessorNum;
+ UINTN EnabledProcessorNum;
+ EFI_PROCESSOR_INFORMATION ProcessorInfo;
+ EFI_CPU_PHYSICAL_LOCATION *ProcessorLocBuf;
+ UINTN Index;
+
+ Status = gBS->LocateProtocol (&gEfiMpServiceProtocolGuid, NULL, (VOID **) &MpProtocol);
+ if (EFI_ERROR (Status)) {
+ //
+ // MP protocol is not installed
+ //
+ return EFI_UNSUPPORTED;
+ }
+
+ Status = MpProtocol->GetNumberOfProcessors(
+ MpProtocol,
+ &ProcessorNum,
+ &EnabledProcessorNum
+ );
+ if (EFI_ERROR(Status)){
+ return Status;
+ }
+
+ Status = gBS->AllocatePool(
+ EfiBootServicesData,
+ sizeof(EFI_CPU_PHYSICAL_LOCATION) * ProcessorNum,
+ (VOID **) &ProcessorLocBuf
+ );
+ if (EFI_ERROR(Status)){
+ return Status;
+ }
+
+ //
+ // Get each processor Location info
+ //
+ for (Index = 0; Index < ProcessorNum; Index++) {
+ Status = MpProtocol->GetProcessorInfo(
+ MpProtocol,
+ Index,
+ &ProcessorInfo
+ );
+ if (EFI_ERROR(Status)){
+ FreePool(ProcessorLocBuf);
+ return Status;
+ }
+
+ //
+ // Get all Processor Location info & measure
+ //
+ CopyMem(
+ &ProcessorLocBuf[Index],
+ &ProcessorInfo.Location,
+ sizeof(EFI_CPU_PHYSICAL_LOCATION)
+ );
+ }
+
+ *LocationBuf = ProcessorLocBuf;
+ *Num = ProcessorNum;
+
+ return Status;
+}
+
+/**
+ 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 || (!TcgData->BsCap.TPMPresentFlag)) {
+ *EventLogLastEntry = (EFI_PHYSICAL_ADDRESS)(UINTN)0;
+ } else {
+ *EventLogLastEntry = (EFI_PHYSICAL_ADDRESS)(UINTN)TcgData->LastEvent;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+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;
+}
+
+/**
+ 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);
+
+ if (*HashedDataResult == NULL) {
+ *HashedDataResult = AllocatePool ((UINTN) *HashedDataLen);
+ }
+
+ return TpmCommHashAll (
+ HashData,
+ (UINTN) HashDataLen,
+ (TPM_DIGEST*)*HashedDataResult
+ );
+ default:
+ return EFI_UNSUPPORTED;
+ }
+}
+
+/**
+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
+ )
+{
+ UINTN NewLogSize;
+
+ //
+ // Prevent Event Overflow
+ //
+ if ((UINTN) NewEventHdr->EventSize > MAX_UINTN - sizeof (*NewEventHdr)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NewLogSize = sizeof (*NewEventHdr) + NewEventHdr->EventSize;
+ if (NewLogSize > MaxSize - *LogSize) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ *EventLogPtr += *LogSize;
+ *LogSize += NewLogSize;
+ CopyMem (*EventLogPtr, NewEventHdr, sizeof (*NewEventHdr));
+ CopyMem (
+ *EventLogPtr + sizeof (*NewEventHdr),
+ NewEventData,
+ NewEventHdr->EventSize
+ );
+ return EFI_SUCCESS;
+}
+
+/**
+ 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;
+
+ if (TCGLogData == NULL){
+ return EFI_INVALID_PARAMETER;
+ }
+
+ TcgData = TCG_DXE_DATA_FROM_THIS (This);
+
+ if (TcgData->BsCap.TPMDeactivatedFlag || (!TcgData->BsCap.TPMPresentFlag)) {
+ 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
+ )
+{
+ if (TpmInputParameterBlock == NULL ||
+ TpmOutputParameterBlock == NULL ||
+ TpmInputParameterBlockSize == 0 ||
+ TpmOutputParameterBlockSize == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return Tpm12SubmitCommand (
+ TpmInputParameterBlockSize,
+ TpmInputParameterBlock,
+ &TpmOutputParameterBlockSize,
+ TpmOutputParameterBlock
+ );
+}
+
+/**
+ 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 (!TcgData->BsCap.TPMPresentFlag) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (HashDataLen > 0 || HashData != NULL) {
+ Status = TpmCommHashAll (
+ HashData,
+ (UINTN) HashDataLen,
+ &NewEventHdr->Digest
+ );
+ if (EFI_ERROR(Status)) {
+ DEBUG ((DEBUG_ERROR, "TpmCommHashAll Failed. %x\n", Status));
+ goto Done;
+ }
+ }
+
+ Status = Tpm12Extend (
+ &NewEventHdr->Digest,
+ NewEventHdr->PCRIndex,
+ NULL
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = TcgDxeLogEventI (TcgData, NewEventHdr, NewEventData);
+ }
+
+Done:
+ if ((Status == EFI_DEVICE_ERROR) || (Status == EFI_TIMEOUT)) {
+ DEBUG ((EFI_D_ERROR, "TcgDxeHashLogExtendEventI - %r. Disable TPM.\n", Status));
+ TcgData->BsCap.TPMPresentFlag = FALSE;
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ (PcdGet32 (PcdStatusCodeSubClassTpmDevice) | EFI_P_EC_INTERFACE_ERROR)
+ );
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ 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;
+ EFI_STATUS Status;
+
+ if (TCGLogData == NULL || EventLogLastEntry == NULL){
+ return EFI_INVALID_PARAMETER;
+ }
+
+ TcgData = TCG_DXE_DATA_FROM_THIS (This);
+
+ if (TcgData->BsCap.TPMDeactivatedFlag || (!TcgData->BsCap.TPMPresentFlag)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (AlgorithmId != TPM_ALG_SHA) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (HashData == 0 && HashDataLen > 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = TcgDxeHashLogExtendEventI (
+ TcgData,
+ (UINT8 *) (UINTN) HashData,
+ HashDataLen,
+ (TCG_PCR_EVENT_HDR*)TCGLogData,
+ TCGLogData->Event
+ );
+
+ if (!EFI_ERROR(Status)){
+ *EventLogLastEntry = (EFI_PHYSICAL_ADDRESS)(UINTN) TcgData->LastEvent;
+ }
+
+ return Status;
+}
+
+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
+};
+
+/**
+ 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 (PcdGet32 (PcdTcgLogAreaMinLen)),
+ &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, PcdGet32 (PcdTcgLogAreaMinLen), 0xFF);
+ mTcgClientAcpiTemplate.Laml = PcdGet32 (PcdTcgLogAreaMinLen);
+
+ } else {
+ Lasa = mTcgServerAcpiTemplate.Lasa;
+
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiACPIMemoryNVS,
+ EFI_SIZE_TO_PAGES (PcdGet32 (PcdTcgLogAreaMinLen)),
+ &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, PcdGet32 (PcdTcgLogAreaMinLen), 0xFF);
+ mTcgServerAcpiTemplate.Laml = PcdGet32 (PcdTcgLogAreaMinLen);
+ }
+
+ 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;
+ TCG_PCR_EVENT_HDR TcgEvent;
+ EFI_HANDOFF_TABLE_POINTERS HandoffTables;
+ UINTN ProcessorNum;
+ EFI_CPU_PHYSICAL_LOCATION *ProcessorLocBuf;
+
+ ProcessorLocBuf = NULL;
+ Status = EFI_SUCCESS;
+
+ if (PcdGet8 (PcdTpmPlatformClass) == TCG_PLATFORM_TYPE_SERVER) {
+ //
+ // Tcg Server spec.
+ // Measure each processor EFI_CPU_PHYSICAL_LOCATION with EV_TABLE_OF_DEVICES to PCR[1]
+ //
+ Status = GetProcessorsCpuLocation(&ProcessorLocBuf, &ProcessorNum);
+
+ if (!EFI_ERROR(Status)){
+ TcgEvent.PCRIndex = 1;
+ TcgEvent.EventType = EV_TABLE_OF_DEVICES;
+ TcgEvent.EventSize = sizeof (HandoffTables);
+
+ HandoffTables.NumberOfTables = 1;
+ HandoffTables.TableEntry[0].VendorGuid = gEfiMpServiceProtocolGuid;
+ HandoffTables.TableEntry[0].VendorTable = ProcessorLocBuf;
+
+ Status = TcgDxeHashLogExtendEventI (
+ &mTcgDxeData,
+ (UINT8*)(UINTN)ProcessorLocBuf,
+ sizeof(EFI_CPU_PHYSICAL_LOCATION) * ProcessorNum,
+ &TcgEvent,
+ (UINT8*)&HandoffTables
+ );
+
+ FreePool(ProcessorLocBuf);
+ }
+ }
+
+ 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*)VarLog,
+ TcgEvent.EventSize,
+ &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 || BootOrder == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ if (EFI_ERROR (Status)) {
+ //
+ // BootOrder can't be NULL if status is not EFI_NOT_FOUND
+ //
+ 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
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "%a not Measured. Error!\n", EFI_CALLING_EFI_APPLICATION));
+ }
+
+ //
+ // 2. Draw a line between pre-boot env and entering post-boot env.
+ //
+ for (PcrIndex = 0; PcrIndex < 8; PcrIndex++) {
+ Status = MeasureSeparatorEvent (PcrIndex);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Separator Event not Measured. Error!\n"));
+ }
+ }
+
+ //
+ // 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
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "%a not Measured. Error!\n", EFI_RETURNING_FROM_EFI_APPLICATOIN));
+ }
+ }
+
+ 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;
+ UINT64 OemTableId;
+
+ Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **)&AcpiTable);
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ if (PcdGet8 (PcdTpmPlatformClass) == TCG_PLATFORM_TYPE_CLIENT) {
+ CopyMem (mTcgClientAcpiTemplate.Header.OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (mTcgClientAcpiTemplate.Header.OemId));
+ OemTableId = PcdGet64 (PcdAcpiDefaultOemTableId);
+ CopyMem (&mTcgClientAcpiTemplate.Header.OemTableId, &OemTableId, sizeof (UINT64));
+ mTcgClientAcpiTemplate.Header.OemRevision = PcdGet32 (PcdAcpiDefaultOemRevision);
+ mTcgClientAcpiTemplate.Header.CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId);
+ mTcgClientAcpiTemplate.Header.CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision);
+ //
+ // 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 {
+ CopyMem (mTcgServerAcpiTemplate.Header.OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (mTcgServerAcpiTemplate.Header.OemId));
+ OemTableId = PcdGet64 (PcdAcpiDefaultOemTableId);
+ CopyMem (&mTcgServerAcpiTemplate.Header.OemTableId, &OemTableId, sizeof (UINT64));
+ mTcgServerAcpiTemplate.Header.OemRevision = PcdGet32 (PcdAcpiDefaultOemRevision);
+ mTcgServerAcpiTemplate.Header.CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId);
+ mTcgServerAcpiTemplate.Header.CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision);
+ //
+ // 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;
+
+ mTcgServerAcpiTemplate.BaseAddress.Address = PcdGet64 (PcdTpmBaseAddress);
+ Status = AcpiTable->InstallAcpiTable (
+ AcpiTable,
+ &mTcgServerAcpiTemplate,
+ sizeof (mTcgServerAcpiTemplate),
+ &TableKey
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+ DEBUG((EFI_D_ERROR, "Tcg Acpi Table installation failure"));
+ }
+}
+
+/**
+ 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
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "%a not Measured. Error!\n", EFI_EXIT_BOOT_SERVICES_INVOCATION));
+ }
+
+ //
+ // Measure success of ExitBootServices
+ //
+ Status = TcgMeasureAction (
+ EFI_EXIT_BOOT_SERVICES_SUCCEEDED
+ );
+ if (EFI_ERROR (Status)){
+ DEBUG ((EFI_D_ERROR, "%a not Measured. Error!\n", EFI_EXIT_BOOT_SERVICES_SUCCEEDED));
+ }
+}
+
+/**
+ Exit Boot Services Failed Event notification handler.
+
+ Measure Failure of ExitBootServices.
+
+ @param[in] Event Event whose notification function is being invoked
+ @param[in] Context Pointer to the notification function's context
+
+**/
+VOID
+EFIAPI
+OnExitBootServicesFailed (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Measure Failure of ExitBootServices,
+ //
+ Status = TcgMeasureAction (
+ EFI_EXIT_BOOT_SERVICES_FAILED
+ );
+ if (EFI_ERROR (Status)){
+ DEBUG ((EFI_D_ERROR, "%a not Measured. Error!\n", EFI_EXIT_BOOT_SERVICES_FAILED));
+ }
+}
+
+/**
+ 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 VolatileFlags;
+
+ Status = Tpm12GetCapabilityFlagVolatile (&VolatileFlags);
+ if (!EFI_ERROR (Status)) {
+ *TPMDeactivatedFlag = VolatileFlags.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;
+
+ if (!CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceTpm12Guid)){
+ DEBUG ((EFI_D_ERROR, "No TPM12 instance required!\n"));
+ return EFI_UNSUPPORTED;
+ }
+
+ if (GetFirstGuidHob (&gTpmErrorHobGuid) != NULL) {
+ DEBUG ((EFI_D_ERROR, "TPM error!\n"));
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = Tpm12RequestUseTpm ();
+ 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
+ );
+ if (!EFI_ERROR (Status) && (!mTcgDxeData.BsCap.TPMDeactivatedFlag) && mTcgDxeData.BsCap.TPMPresentFlag) {
+ //
+ // 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
+ );
+
+ //
+ // Measure Exit Boot Service failed
+ //
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ OnExitBootServicesFailed,
+ NULL,
+ &gEventExitBootServicesFailedGuid,
+ &Event
+ );
+ }
+
+ //
+ // Install ACPI Table
+ //
+ EfiCreateProtocolNotifyEvent (&gEfiAcpiTableProtocolGuid, TPL_CALLBACK, InstallAcpiTable, NULL, &Registration);
+
+ return Status;
+}
diff --git a/Core/SecurityPkg/Tcg/TcgDxe/TcgDxe.inf b/Core/SecurityPkg/Tcg/TcgDxe/TcgDxe.inf
new file mode 100644
index 0000000000..1b96ecbe2a
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TcgDxe/TcgDxe.inf
@@ -0,0 +1,86 @@
+## @file
+# Produces TCG protocol and measures boot environment
+# This module will produce TCG protocol and measure boot environment.
+#
+# Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = TcgDxe
+ MODULE_UNI_FILE = TcgDxe.uni
+ 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
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ CryptoPkg/CryptoPkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+ MemoryAllocationLib
+ BaseLib
+ UefiBootServicesTableLib
+ HobLib
+ UefiDriverEntryPoint
+ UefiRuntimeServicesTableLib
+ BaseMemoryLib
+ DebugLib
+ Tpm12DeviceLib
+ BaseCryptLib
+ PrintLib
+ UefiLib
+ PcdLib
+ ReportStatusCodeLib
+ Tpm12CommandLib
+
+[Guids]
+ gEfiGlobalVariableGuid ## SOMETIMES_CONSUMES ## Variable:L"BootXXXX"
+ gTcgEventEntryHobGuid ## SOMETIMES_CONSUMES ## HOB
+ gTpmErrorHobGuid ## SOMETIMES_CONSUMES ## HOB
+ gEfiEventExitBootServicesGuid ## CONSUMES ## Event
+ gEventExitBootServicesFailedGuid ## SOMETIMES_CONSUMES ## Event
+ gEfiTpmDeviceInstanceTpm12Guid ## PRODUCES ## GUID # TPM device identifier
+
+[Protocols]
+ gEfiTcgProtocolGuid ## PRODUCES
+ gEfiAcpiTableProtocolGuid ## NOTIFY
+ gEfiMpServiceProtocolGuid ## SOMETIMES_CONSUMES
+
+[Pcd]
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpmPlatformClass ## SOMETIMES_CONSUMES
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpmInstanceGuid ## CONSUMES
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpmBaseAddress ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemId ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemTableId ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemRevision ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorId ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorRevision ## SOMETIMES_CONSUMES
+ gEfiSecurityPkgTokenSpaceGuid.PcdStatusCodeSubClassTpmDevice ## SOMETIMES_CONSUMES
+ gEfiSecurityPkgTokenSpaceGuid.PcdTcgLogAreaMinLen ## CONSUMES
+
+[Depex]
+ TRUE
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ TcgDxeExtra.uni
+ \ No newline at end of file
diff --git a/Core/SecurityPkg/Tcg/TcgDxe/TcgDxe.uni b/Core/SecurityPkg/Tcg/TcgDxe/TcgDxe.uni
new file mode 100644
index 0000000000..d8e9b91edf
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TcgDxe/TcgDxe.uni
@@ -0,0 +1,21 @@
+// /** @file
+// Produces TCG protocol and measures boot environment
+//
+// This module will produce TCG protocol and measure boot environment.
+//
+// Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Produces TCG protocol and measures boot environment"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This module will produce TCG protocol and measure boot environment."
+
diff --git a/Core/SecurityPkg/Tcg/TcgDxe/TcgDxeExtra.uni b/Core/SecurityPkg/Tcg/TcgDxe/TcgDxeExtra.uni
new file mode 100644
index 0000000000..f6f8b634e0
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TcgDxe/TcgDxeExtra.uni
@@ -0,0 +1,19 @@
+// /** @file
+// TcgDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"TCG (Trusted Computing Group) DXE"
+
+
diff --git a/Core/SecurityPkg/Tcg/TcgPei/TcgPei.c b/Core/SecurityPkg/Tcg/TcgPei/TcgPei.c
new file mode 100644
index 0000000000..63807f44ff
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TcgPei/TcgPei.c
@@ -0,0 +1,841 @@
+/** @file
+ Initialize TPM device and measure FVs before handing off control to DXE.
+
+Copyright (c) 2005 - 2017, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiPei.h>
+
+#include <IndustryStandard/Tpm12.h>
+#include <IndustryStandard/UefiTcgPlatform.h>
+#include <Ppi/FirmwareVolumeInfo.h>
+#include <Ppi/FirmwareVolumeInfo2.h>
+#include <Ppi/LockPhysicalPresence.h>
+#include <Ppi/TpmInitialized.h>
+#include <Ppi/FirmwareVolume.h>
+#include <Ppi/EndOfPeiPhase.h>
+#include <Ppi/FirmwareVolumeInfoMeasurementExcluded.h>
+
+#include <Guid/TcgEventHob.h>
+#include <Guid/MeasuredFvHob.h>
+#include <Guid/TpmInstance.h>
+
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/PeimEntryPoint.h>
+#include <Library/HobLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PeiServicesTablePointerLib.h>
+#include <Library/BaseLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/Tpm12DeviceLib.h>
+#include <Library/Tpm12CommandLib.h>
+#include <Library/BaseCryptLib.h>
+
+BOOLEAN mImageInMemory = FALSE;
+
+EFI_PEI_PPI_DESCRIPTOR mTpmInitializedPpiList = {
+ EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
+ &gPeiTpmInitializedPpiGuid,
+ NULL
+};
+
+EFI_PEI_PPI_DESCRIPTOR mTpmInitializationDonePpiList = {
+ EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
+ &gPeiTpmInitializationDonePpiGuid,
+ NULL
+};
+
+EFI_PLATFORM_FIRMWARE_BLOB *mMeasuredBaseFvInfo;
+UINT32 mMeasuredBaseFvIndex = 0;
+
+EFI_PLATFORM_FIRMWARE_BLOB *mMeasuredChildFvInfo;
+UINT32 mMeasuredChildFvIndex = 0;
+
+EFI_PEI_FIRMWARE_VOLUME_INFO_MEASUREMENT_EXCLUDED_PPI *mMeasurementExcludedFvPpi;
+
+/**
+ 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
+ );
+
+/**
+ Record all measured Firmware Volum Information into a Guid Hob
+
+ @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
+EndofPeiSignalNotifyCallBack (
+ 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,
+ &gEfiPeiFirmwareVolumeInfoPpiGuid,
+ FirmwareVolmeInfoPpiNotifyCallback
+ },
+ {
+ EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,
+ &gEfiPeiFirmwareVolumeInfo2PpiGuid,
+ FirmwareVolmeInfoPpiNotifyCallback
+ },
+ {
+ (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEfiEndOfPeiSignalPpiGuid,
+ EndofPeiSignalNotifyCallBack
+ }
+};
+
+/**
+ Record all measured Firmware Volum Information into a Guid Hob
+ Guid Hob payload layout is
+
+ UINT32 *************************** FIRMWARE_BLOB number
+ EFI_PLATFORM_FIRMWARE_BLOB******** BLOB Array
+
+ @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
+EndofPeiSignalNotifyCallBack (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *Ppi
+ )
+{
+ MEASURED_HOB_DATA *MeasuredHobData;
+
+ MeasuredHobData = NULL;
+
+ //
+ // Create a Guid hob to save all measured Fv
+ //
+ MeasuredHobData = BuildGuidHob(
+ &gMeasuredFvHobGuid,
+ sizeof(UINTN) + sizeof(EFI_PLATFORM_FIRMWARE_BLOB) * (mMeasuredBaseFvIndex + mMeasuredChildFvIndex)
+ );
+
+ if (MeasuredHobData != NULL){
+ //
+ // Save measured FV info enty number
+ //
+ MeasuredHobData->Num = mMeasuredBaseFvIndex + mMeasuredChildFvIndex;
+
+ //
+ // Save measured base Fv info
+ //
+ CopyMem (MeasuredHobData->MeasuredFvBuf, mMeasuredBaseFvInfo, sizeof(EFI_PLATFORM_FIRMWARE_BLOB) * (mMeasuredBaseFvIndex));
+
+ //
+ // Save measured child Fv info
+ //
+ CopyMem (&MeasuredHobData->MeasuredFvBuf[mMeasuredBaseFvIndex] , mMeasuredChildFvInfo, sizeof(EFI_PLATFORM_FIRMWARE_BLOB) * (mMeasuredChildFvIndex));
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+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;
+}
+
+/**
+ 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] 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 TCG_PCR_EVENT_HDR *NewEventHdr,
+ IN UINT8 *NewEventData
+ )
+{
+ EFI_STATUS Status;
+ VOID *HobData;
+
+ if (GetFirstGuidHob (&gTpmErrorHobGuid) != NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ HobData = NULL;
+ if (HashDataLen != 0) {
+ Status = TpmCommHashAll (
+ HashData,
+ HashDataLen,
+ &NewEventHdr->Digest
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ }
+
+ Status = Tpm12Extend (
+ &NewEventHdr->Digest,
+ NewEventHdr->PCRIndex,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ HobData = BuildGuidHob (
+ &gTcgEventEntryHobGuid,
+ sizeof (*NewEventHdr) + NewEventHdr->EventSize
+ );
+ if (HobData == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ CopyMem (HobData, NewEventHdr, sizeof (*NewEventHdr));
+ HobData = (VOID *) ((UINT8*)HobData + sizeof (*NewEventHdr));
+ CopyMem (HobData, NewEventData, NewEventHdr->EventSize);
+
+Done:
+ if ((Status == EFI_DEVICE_ERROR) || (Status == EFI_TIMEOUT)) {
+ DEBUG ((EFI_D_ERROR, "HashLogExtendEvent - %r. Disable TPM.\n", Status));
+ BuildGuidHob (&gTpmErrorHobGuid,0);
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ (PcdGet32 (PcdStatusCodeSubClassTpmDevice) | EFI_P_EC_INTERFACE_ERROR)
+ );
+ Status = EFI_DEVICE_ERROR;
+ }
+ return Status;
+}
+
+/**
+ Measure CRTM version.
+
+ @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
+MeasureCRTMVersion (
+ IN EFI_PEI_SERVICES **PeiServices
+ )
+{
+ TCG_PCR_EVENT_HDR TcgEventHdr;
+
+ //
+ // Use FirmwareVersion string to represent CRTM version.
+ // OEMs should get real CRTM version string and measure it.
+ //
+
+ TcgEventHdr.PCRIndex = 0;
+ TcgEventHdr.EventType = EV_S_CRTM_VERSION;
+ TcgEventHdr.EventSize = (UINT32) StrSize((CHAR16*)PcdGetPtr (PcdFirmwareVersionString));
+
+ return HashLogExtendEvent (
+ PeiServices,
+ (UINT8*)PcdGetPtr (PcdFirmwareVersionString),
+ TcgEventHdr.EventSize,
+ &TcgEventHdr,
+ (UINT8*)PcdGetPtr (PcdFirmwareVersionString)
+ );
+}
+
+/**
+ 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;
+
+ //
+ // Check if it is in Excluded FV list
+ //
+ if (mMeasurementExcludedFvPpi != NULL) {
+ for (Index = 0; Index < mMeasurementExcludedFvPpi->Count; Index ++) {
+ if (mMeasurementExcludedFvPpi->Fv[Index].FvBase == FvBase) {
+ DEBUG ((DEBUG_INFO, "The FV which is excluded by TcgPei starts at: 0x%x\n", FvBase));
+ DEBUG ((DEBUG_INFO, "The FV which is excluded by TcgPei has the size: 0x%x\n", FvLength));
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ //
+ // Check whether FV is in the measured FV list.
+ //
+ for (Index = 0; Index < mMeasuredBaseFvIndex; Index ++) {
+ if (mMeasuredBaseFvInfo[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,
+ &TcgEventHdr,
+ (UINT8*) &FvBlob
+ );
+
+ //
+ // Add new FV into the measured FV list.
+ //
+ ASSERT (mMeasuredBaseFvIndex < PcdGet32 (PcdPeiCoreMaxFvSupported));
+ if (mMeasuredBaseFvIndex < PcdGet32 (PcdPeiCoreMaxFvSupported)) {
+ mMeasuredBaseFvInfo[mMeasuredBaseFvIndex].BlobBase = FvBase;
+ mMeasuredBaseFvInfo[mMeasuredBaseFvIndex].BlobLength = FvLength;
+ mMeasuredBaseFvIndex++;
+ }
+
+ return Status;
+}
+
+/**
+ Measure main BIOS.
+
+ @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
+MeasureMainBios (
+ IN EFI_PEI_SERVICES **PeiServices
+ )
+{
+ 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;
+ UINTN Index;
+
+ 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 record the FV and return
+ //
+ if (Fv->ParentFvName != NULL || Fv->ParentFileName != NULL ) {
+
+ ASSERT (mMeasuredChildFvIndex < PcdGet32 (PcdPeiCoreMaxFvSupported));
+ if (mMeasuredChildFvIndex < PcdGet32 (PcdPeiCoreMaxFvSupported)) {
+ //
+ // Check whether FV is in the measured child FV list.
+ //
+ for (Index = 0; Index < mMeasuredChildFvIndex; Index++) {
+ if (mMeasuredChildFvInfo[Index].BlobBase == (EFI_PHYSICAL_ADDRESS) (UINTN) Fv->FvInfo) {
+ return EFI_SUCCESS;
+ }
+ }
+ mMeasuredChildFvInfo[mMeasuredChildFvIndex].BlobBase = (EFI_PHYSICAL_ADDRESS) (UINTN) Fv->FvInfo;
+ mMeasuredChildFvInfo[mMeasuredChildFvIndex].BlobLength = Fv->FvInfoSize;
+ mMeasuredChildFvIndex++;
+ }
+ return EFI_SUCCESS;
+ }
+
+ return MeasureFvImage ((EFI_PHYSICAL_ADDRESS) (UINTN) Fv->FvInfo, Fv->FvInfoSize);
+}
+
+/**
+ Set physicalPresenceLifetimeLock, physicalPresenceHWEnable and physicalPresenceCMDEnable bit by corresponding PCDs.
+ And 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;
+ TPM_PERMANENT_FLAGS TpmPermanentFlags;
+ PEI_LOCK_PHYSICAL_PRESENCE_PPI *LockPhysicalPresencePpi;
+ TPM_PHYSICAL_PRESENCE PhysicalPresenceValue;
+
+ Status = Tpm12GetCapabilityFlagPermanent (&TpmPermanentFlags);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // 1. Set physicalPresenceLifetimeLock, physicalPresenceHWEnable and physicalPresenceCMDEnable bit by PCDs.
+ //
+ if (PcdGetBool (PcdPhysicalPresenceLifetimeLock) && !TpmPermanentFlags.physicalPresenceLifetimeLock) {
+ //
+ // Lock TPM LifetimeLock is required, and LifetimeLock is not locked yet.
+ //
+ PhysicalPresenceValue = TPM_PHYSICAL_PRESENCE_LIFETIME_LOCK;
+ TpmPermanentFlags.physicalPresenceLifetimeLock = TRUE;
+
+ if (PcdGetBool (PcdPhysicalPresenceCmdEnable)) {
+ PhysicalPresenceValue |= TPM_PHYSICAL_PRESENCE_CMD_ENABLE;
+ TpmPermanentFlags.physicalPresenceCMDEnable = TRUE;
+ } else {
+ PhysicalPresenceValue |= TPM_PHYSICAL_PRESENCE_CMD_DISABLE;
+ TpmPermanentFlags.physicalPresenceCMDEnable = FALSE;
+ }
+
+ if (PcdGetBool (PcdPhysicalPresenceHwEnable)) {
+ PhysicalPresenceValue |= TPM_PHYSICAL_PRESENCE_HW_ENABLE;
+ } else {
+ PhysicalPresenceValue |= TPM_PHYSICAL_PRESENCE_HW_DISABLE;
+ }
+
+ Status = Tpm12PhysicalPresence (
+ PhysicalPresenceValue
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // 2. Lock physical presence if it is required.
+ //
+ LockPhysicalPresencePpi = (PEI_LOCK_PHYSICAL_PRESENCE_PPI *) Ppi;
+ if (!LockPhysicalPresencePpi->LockPhysicalPresence ((CONST EFI_PEI_SERVICES**) PeiServices)) {
+ return EFI_SUCCESS;
+ }
+
+ if (!TpmPermanentFlags.physicalPresenceCMDEnable) {
+ if (TpmPermanentFlags.physicalPresenceLifetimeLock) {
+ //
+ // physicalPresenceCMDEnable is locked, can't change.
+ //
+ return EFI_ABORTED;
+ }
+
+ //
+ // Enable physical presence command
+ // It is necessary in order to lock physical presence
+ //
+ Status = Tpm12PhysicalPresence (
+ TPM_PHYSICAL_PRESENCE_CMD_ENABLE
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // Lock physical presence
+ //
+ Status = Tpm12PhysicalPresence (
+ TPM_PHYSICAL_PRESENCE_LOCK
+ );
+ return Status;
+}
+
+/**
+ Check if TPM chip is activeated or not.
+
+ @param[in] PeiServices Describes the list of possible PEI Services.
+
+ @retval TRUE TPM is activated.
+ @retval FALSE TPM is deactivated.
+
+**/
+BOOLEAN
+IsTpmUsable (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ TPM_PERMANENT_FLAGS TpmPermanentFlags;
+
+ Status = Tpm12GetCapabilityFlagPermanent (&TpmPermanentFlags);
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+ return (BOOLEAN)(!TpmPermanentFlags.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;
+
+ Status = PeiServicesLocatePpi (
+ &gEfiPeiFirmwareVolumeInfoMeasurementExcludedPpiGuid,
+ 0,
+ NULL,
+ (VOID**)&mMeasurementExcludedFvPpi
+ );
+ // Do not check status, because it is optional
+
+ mMeasuredBaseFvInfo = (EFI_PLATFORM_FIRMWARE_BLOB *) AllocateZeroPool (sizeof (EFI_PLATFORM_FIRMWARE_BLOB) * PcdGet32 (PcdPeiCoreMaxFvSupported));
+ ASSERT (mMeasuredBaseFvInfo != NULL);
+ mMeasuredChildFvInfo = (EFI_PLATFORM_FIRMWARE_BLOB *) AllocateZeroPool (sizeof (EFI_PLATFORM_FIRMWARE_BLOB) * PcdGet32 (PcdPeiCoreMaxFvSupported));
+ ASSERT (mMeasuredChildFvInfo != NULL);
+
+ Status = Tpm12RequestUseTpm ();
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (IsTpmUsable ()) {
+ if (PcdGet8 (PcdTpmScrtmPolicy) == 1) {
+ Status = MeasureCRTMVersion (PeiServices);
+ }
+
+ Status = MeasureMainBios (PeiServices);
+ }
+
+ //
+ // 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_STATUS Status2;
+ EFI_BOOT_MODE BootMode;
+
+ if (!CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceTpm12Guid)){
+ DEBUG ((EFI_D_ERROR, "No TPM12 instance required!\n"));
+ return EFI_UNSUPPORTED;
+ }
+
+ if (GetFirstGuidHob (&gTpmErrorHobGuid) != NULL) {
+ DEBUG ((EFI_D_ERROR, "TPM error!\n"));
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Initialize TPM device
+ //
+ Status = PeiServicesGetBootMode (&BootMode);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // In S3 path, skip shadow logic. no measurement is required
+ //
+ if (BootMode != BOOT_ON_S3_RESUME) {
+ Status = (**PeiServices).RegisterForShadow(FileHandle);
+ if (Status == EFI_ALREADY_STARTED) {
+ mImageInMemory = TRUE;
+ } else if (Status == EFI_NOT_FOUND) {
+ ASSERT_EFI_ERROR (Status);
+ }
+ }
+
+ if (!mImageInMemory) {
+ Status = Tpm12RequestUseTpm ();
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "TPM not detected!\n"));
+ goto Done;
+ }
+
+ if (PcdGet8 (PcdTpmInitializationPolicy) == 1) {
+ if (BootMode == BOOT_ON_S3_RESUME) {
+ Status = Tpm12Startup (TPM_ST_STATE);
+ } else {
+ Status = Tpm12Startup (TPM_ST_CLEAR);
+ }
+ if (EFI_ERROR (Status) ) {
+ goto Done;
+ }
+ }
+
+ //
+ // TpmSelfTest is optional on S3 path, skip it to save S3 time
+ //
+ if (BootMode != BOOT_ON_S3_RESUME) {
+ Status = Tpm12ContinueSelfTest ();
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ }
+
+ //
+ // Only intall TpmInitializedPpi on success
+ //
+ Status = PeiServicesInstallPpi (&mTpmInitializedPpiList);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ if (mImageInMemory) {
+ Status = PeimEntryMP ((EFI_PEI_SERVICES**)PeiServices);
+ return Status;
+ }
+
+Done:
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "TPM error! Build Hob\n"));
+ BuildGuidHob (&gTpmErrorHobGuid,0);
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ (PcdGet32 (PcdStatusCodeSubClassTpmDevice) | EFI_P_EC_INTERFACE_ERROR)
+ );
+ }
+ //
+ // Always intall TpmInitializationDonePpi no matter success or fail.
+ // Other driver can know TPM initialization state by TpmInitializedPpi.
+ //
+ Status2 = PeiServicesInstallPpi (&mTpmInitializationDonePpiList);
+ ASSERT_EFI_ERROR (Status2);
+
+ return Status;
+}
diff --git a/Core/SecurityPkg/Tcg/TcgPei/TcgPei.inf b/Core/SecurityPkg/Tcg/TcgPei/TcgPei.inf
new file mode 100644
index 0000000000..9a44d8fbda
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TcgPei/TcgPei.inf
@@ -0,0 +1,93 @@
+## @file
+# Initializes TPM device and measures FVs in PEI phase
+#
+# This module will initialize TPM device, measure reported FVs and BIOS version.
+# This module may also lock TPM physical presence and physicalPresenceLifetimeLock.
+#
+# Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = TcgPei
+ MODULE_UNI_FILE = TcgPei.uni
+ 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
+#
+# [BootMode]
+# S3_RESUME ## SOMETIMES_CONSUMES
+#
+
+[Sources]
+ TcgPei.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ CryptoPkg/CryptoPkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+ HobLib
+ PeimEntryPoint
+ PeiServicesLib
+ BaseMemoryLib
+ DebugLib
+ BaseCryptLib
+ Tpm12DeviceLib
+ TimerLib
+ PeiServicesTablePointerLib
+ BaseLib
+ PcdLib
+ MemoryAllocationLib
+ ReportStatusCodeLib
+ Tpm12CommandLib
+
+[Guids]
+ gTcgEventEntryHobGuid ## PRODUCES ## HOB
+ gTpmErrorHobGuid ## SOMETIMES_PRODUCES ## HOB
+ gMeasuredFvHobGuid ## PRODUCES ## HOB
+ gEfiTpmDeviceInstanceTpm12Guid ## PRODUCES ## GUID # TPM device identifier
+
+[Ppis]
+ gPeiLockPhysicalPresencePpiGuid ## SOMETIMES_CONSUMES ## NOTIFY
+ gEfiPeiFirmwareVolumeInfoPpiGuid ## SOMETIMES_CONSUMES ## NOTIFY
+ gEfiPeiFirmwareVolumeInfo2PpiGuid ## SOMETIMES_CONSUMES ## NOTIFY
+ gEfiPeiFirmwareVolumeInfoMeasurementExcludedPpiGuid ## SOMETIMES_CONSUMES
+ gPeiTpmInitializedPpiGuid ## SOMETIMES_PRODUCES
+ gPeiTpmInitializationDonePpiGuid ## PRODUCES
+ gEfiEndOfPeiSignalPpiGuid ## SOMETIMES_CONSUMES ## NOTIFY
+
+[Pcd]
+ gEfiSecurityPkgTokenSpaceGuid.PcdPhysicalPresenceLifetimeLock ## SOMETIMES_CONSUMES
+ gEfiSecurityPkgTokenSpaceGuid.PcdPhysicalPresenceCmdEnable ## SOMETIMES_CONSUMES
+ gEfiSecurityPkgTokenSpaceGuid.PcdPhysicalPresenceHwEnable ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFirmwareVersionString ## SOMETIMES_CONSUMES
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpmInstanceGuid ## CONSUMES
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpmInitializationPolicy ## CONSUMES
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpmScrtmPolicy ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdPeiCoreMaxFvSupported ## CONSUMES
+ gEfiSecurityPkgTokenSpaceGuid.PcdStatusCodeSubClassTpmDevice ## SOMETIMES_CONSUMES
+
+[Depex]
+ gEfiPeiMasterBootModePpiGuid AND
+ gEfiPeiReadOnlyVariable2PpiGuid AND
+ gEfiTpmDeviceSelectedGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ TcgPeiExtra.uni
+ \ No newline at end of file
diff --git a/Core/SecurityPkg/Tcg/TcgPei/TcgPei.uni b/Core/SecurityPkg/Tcg/TcgPei/TcgPei.uni
new file mode 100644
index 0000000000..b2d2d5c1c1
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TcgPei/TcgPei.uni
@@ -0,0 +1,22 @@
+// /** @file
+// Initializes TPM device and measures FVs in PEI phase
+//
+// This module will initialize TPM device, measure reported FVs and BIOS version.
+// This module may also lock TPM physical presence and physicalPresenceLifetimeLock.
+//
+// Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Initializes TPM device and measures FVs in PEI phase"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This module will initialize TPM device, measure reported FVs and BIOS version. This module may also lock TPM physical presence and physicalPresenceLifetimeLock."
+
diff --git a/Core/SecurityPkg/Tcg/TcgPei/TcgPeiExtra.uni b/Core/SecurityPkg/Tcg/TcgPei/TcgPeiExtra.uni
new file mode 100644
index 0000000000..e469d984c8
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TcgPei/TcgPeiExtra.uni
@@ -0,0 +1,19 @@
+// /** @file
+// TcgPei Localized Strings and Content
+//
+// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"TCG (Trusted Computing Group) PEI"
+
+
diff --git a/Core/SecurityPkg/Tcg/TcgSmm/TcgSmm.c b/Core/SecurityPkg/Tcg/TcgSmm/TcgSmm.c
new file mode 100644
index 0000000000..589bab694b
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TcgSmm/TcgSmm.c
@@ -0,0 +1,465 @@
+/** @file
+ It updates TPM items in ACPI table and registers SMI callback
+ functions for physical presence and ClearMemory.
+
+ Caution: This module requires additional review when modified.
+ This driver will have external input - variable and ACPINvs data in SMM mode.
+ This external input must be validated carefully to avoid security issue.
+
+ PhysicalPresenceCallback() and MemoryClearCallback() will receive untrusted input and do some check.
+
+Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "TcgSmm.h"
+
+EFI_SMM_VARIABLE_PROTOCOL *mSmmVariable;
+TCG_NVS *mTcgNvs;
+
+/**
+ Software SMI callback for TPM physical presence which is called from ACPI method.
+
+ Caution: This function may receive untrusted input.
+ Variable and ACPINvs are external input, so this function will validate
+ its data structure to be valid value.
+
+ @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;
+ EFI_PHYSICAL_PRESENCE_FLAGS Flags;
+ BOOLEAN RequestConfirmed;
+
+ //
+ // Get the Physical Presence variable
+ //
+ DataSize = sizeof (EFI_PHYSICAL_PRESENCE);
+ Status = mSmmVariable->SmmGetVariable (
+ PHYSICAL_PRESENCE_VARIABLE,
+ &gEfiPhysicalPresenceGuid,
+ NULL,
+ &DataSize,
+ &PpData
+ );
+
+ DEBUG ((EFI_D_INFO, "[TPM] PP callback, Parameter = %x\n", mTcgNvs->PhysicalPresence.Parameter));
+ if (mTcgNvs->PhysicalPresence.Parameter == ACPI_FUNCTION_RETURN_REQUEST_RESPONSE_TO_OS) {
+ if (EFI_ERROR (Status)) {
+ mTcgNvs->PhysicalPresence.ReturnCode = PP_RETURN_TPM_OPERATION_RESPONSE_FAILURE;
+ mTcgNvs->PhysicalPresence.LastRequest = 0;
+ mTcgNvs->PhysicalPresence.Response = 0;
+ DEBUG ((EFI_D_ERROR, "[TPM] Get PP variable failure! Status = %r\n", Status));
+ return EFI_SUCCESS;
+ }
+ mTcgNvs->PhysicalPresence.ReturnCode = PP_RETURN_TPM_OPERATION_RESPONSE_SUCCESS;
+ mTcgNvs->PhysicalPresence.LastRequest = PpData.LastPPRequest;
+ mTcgNvs->PhysicalPresence.Response = PpData.PPResponse;
+ } else if ((mTcgNvs->PhysicalPresence.Parameter == ACPI_FUNCTION_SUBMIT_REQUEST_TO_BIOS)
+ || (mTcgNvs->PhysicalPresence.Parameter == ACPI_FUNCTION_SUBMIT_REQUEST_TO_BIOS_2)) {
+ if (EFI_ERROR (Status)) {
+ mTcgNvs->PhysicalPresence.ReturnCode = TCG_PP_SUBMIT_REQUEST_TO_PREOS_GENERAL_FAILURE;
+ DEBUG ((EFI_D_ERROR, "[TPM] Get PP variable failure! Status = %r\n", Status));
+ return EFI_SUCCESS;
+ }
+ if (mTcgNvs->PhysicalPresence.Request == PHYSICAL_PRESENCE_SET_OPERATOR_AUTH) {
+ //
+ // This command requires UI to prompt user for Auth data.
+ //
+ mTcgNvs->PhysicalPresence.ReturnCode = TCG_PP_SUBMIT_REQUEST_TO_PREOS_NOT_IMPLEMENTED;
+ 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)) {
+ mTcgNvs->PhysicalPresence.ReturnCode = TCG_PP_SUBMIT_REQUEST_TO_PREOS_GENERAL_FAILURE;
+ return EFI_SUCCESS;
+ }
+ mTcgNvs->PhysicalPresence.ReturnCode = TCG_PP_SUBMIT_REQUEST_TO_PREOS_SUCCESS;
+
+ if (mTcgNvs->PhysicalPresence.Request >= TCG_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION) {
+ DataSize = sizeof (EFI_PHYSICAL_PRESENCE_FLAGS);
+ Status = mSmmVariable->SmmGetVariable (
+ PHYSICAL_PRESENCE_FLAGS_VARIABLE,
+ &gEfiPhysicalPresenceGuid,
+ NULL,
+ &DataSize,
+ &Flags
+ );
+ if (EFI_ERROR (Status)) {
+ Flags.PPFlags = TCG_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_PROVISION;
+ }
+ mTcgNvs->PhysicalPresence.ReturnCode = TcgPpVendorLibSubmitRequestToPreOSFunction (mTcgNvs->PhysicalPresence.Request, Flags.PPFlags);
+ }
+ } else if (mTcgNvs->PhysicalPresence.Parameter == ACPI_FUNCTION_GET_USER_CONFIRMATION_STATUS_FOR_REQUEST) {
+ if (EFI_ERROR (Status)) {
+ mTcgNvs->PhysicalPresence.ReturnCode = TCG_PP_GET_USER_CONFIRMATION_BLOCKED_BY_BIOS_CONFIGURATION;
+ DEBUG ((EFI_D_ERROR, "[TPM] Get PP variable failure! Status = %r\n", Status));
+ return EFI_SUCCESS;
+ }
+ //
+ // Get the Physical Presence flags
+ //
+ DataSize = sizeof (EFI_PHYSICAL_PRESENCE_FLAGS);
+ Status = mSmmVariable->SmmGetVariable (
+ PHYSICAL_PRESENCE_FLAGS_VARIABLE,
+ &gEfiPhysicalPresenceGuid,
+ NULL,
+ &DataSize,
+ &Flags
+ );
+ if (EFI_ERROR (Status)) {
+ mTcgNvs->PhysicalPresence.ReturnCode = TCG_PP_GET_USER_CONFIRMATION_BLOCKED_BY_BIOS_CONFIGURATION;
+ DEBUG ((EFI_D_ERROR, "[TPM] Get PP flags failure! Status = %r\n", Status));
+ return EFI_SUCCESS;
+ }
+
+ RequestConfirmed = FALSE;
+
+ switch (mTcgNvs->PPRequestUserConfirm) {
+ case PHYSICAL_PRESENCE_ENABLE:
+ case PHYSICAL_PRESENCE_DISABLE:
+ case PHYSICAL_PRESENCE_ACTIVATE:
+ case PHYSICAL_PRESENCE_DEACTIVATE:
+ case PHYSICAL_PRESENCE_ENABLE_ACTIVATE:
+ case PHYSICAL_PRESENCE_DEACTIVATE_DISABLE:
+ case PHYSICAL_PRESENCE_SET_OWNER_INSTALL_TRUE:
+ case PHYSICAL_PRESENCE_SET_OWNER_INSTALL_FALSE:
+ case PHYSICAL_PRESENCE_ENABLE_ACTIVATE_OWNER_TRUE:
+ case PHYSICAL_PRESENCE_DEACTIVATE_DISABLE_OWNER_FALSE:
+ if ((Flags.PPFlags & TCG_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_PROVISION) != 0) {
+ RequestConfirmed = TRUE;
+ }
+ break;
+
+ case PHYSICAL_PRESENCE_CLEAR:
+ case PHYSICAL_PRESENCE_ENABLE_ACTIVATE_CLEAR:
+ if ((Flags.PPFlags & TCG_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_CLEAR) != 0) {
+ RequestConfirmed = TRUE;
+ }
+ break;
+
+ case PHYSICAL_PRESENCE_DEFERRED_PP_UNOWNERED_FIELD_UPGRADE:
+ if ((Flags.PPFlags & TCG_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_MAINTENANCE) != 0) {
+ RequestConfirmed = TRUE;
+ }
+ break;
+
+ case PHYSICAL_PRESENCE_ENABLE_ACTIVATE_CLEAR_ENABLE_ACTIVATE:
+ case PHYSICAL_PRESENCE_CLEAR_ENABLE_ACTIVATE:
+ if ((Flags.PPFlags & TCG_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_CLEAR) != 0 && (Flags.PPFlags & TCG_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_PROVISION) != 0) {
+ RequestConfirmed = TRUE;
+ }
+ break;
+
+ case PHYSICAL_PRESENCE_SET_NO_PPI_PROVISION_FALSE:
+ case PHYSICAL_PRESENCE_SET_NO_PPI_CLEAR_FALSE:
+ case PHYSICAL_PRESENCE_SET_NO_PPI_MAINTENANCE_FALSE:
+ case PHYSICAL_PRESENCE_NO_ACTION:
+ RequestConfirmed = TRUE;
+ break;
+
+ case PHYSICAL_PRESENCE_SET_OPERATOR_AUTH:
+ //
+ // This command requires UI to prompt user for Auth data
+ //
+ mTcgNvs->PhysicalPresence.ReturnCode = TCG_PP_GET_USER_CONFIRMATION_NOT_IMPLEMENTED;
+ return EFI_SUCCESS;
+ default:
+ break;
+ }
+
+ if (RequestConfirmed) {
+ mTcgNvs->PhysicalPresence.ReturnCode = TCG_PP_GET_USER_CONFIRMATION_ALLOWED_AND_PPUSER_NOT_REQUIRED;
+ } else {
+ mTcgNvs->PhysicalPresence.ReturnCode = TCG_PP_GET_USER_CONFIRMATION_ALLOWED_AND_PPUSER_REQUIRED;
+ }
+ if (mTcgNvs->PhysicalPresence.Request >= TCG_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION) {
+ mTcgNvs->PhysicalPresence.ReturnCode = TcgPpVendorLibGetUserConfirmationStatusFunction (mTcgNvs->PhysicalPresence.Request, Flags.PPFlags);
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Software SMI callback for MemoryClear which is called from ACPI method.
+
+ Caution: This function may receive untrusted input.
+ Variable and ACPINvs are external input, so this function will validate
+ its data structure to be valid value.
+
+ @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;
+
+ mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_SUCCESS;
+ if (mTcgNvs->MemoryClear.Parameter == ACPI_FUNCTION_DSM_MEMORY_CLEAR_INTERFACE) {
+ MorControl = (UINT8) mTcgNvs->MemoryClear.Request;
+ } else if (mTcgNvs->MemoryClear.Parameter == ACPI_FUNCTION_PTS_CLEAR_MOR_BIT) {
+ DataSize = sizeof (UINT8);
+ Status = mSmmVariable->SmmGetVariable (
+ MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,
+ &gEfiMemoryOverwriteControlDataGuid,
+ NULL,
+ &DataSize,
+ &MorControl
+ );
+ if (EFI_ERROR (Status)) {
+ mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_GENERAL_FAILURE;
+ DEBUG ((EFI_D_ERROR, "[TPM] Get MOR variable failure! Status = %r\n", Status));
+ 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
+ );
+ if (EFI_ERROR (Status)) {
+ mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_GENERAL_FAILURE;
+ DEBUG ((EFI_D_ERROR, "[TPM] Set MOR variable failure! Status = %r\n", 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_EXT_REGION_OP) &&
+ (OpRegion->NameString == Name) &&
+ (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;
+ OpRegion->RegionLen = (UINT8) Size;
+ 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);
+
+
+ //
+ // Measure to PCR[0] with event EV_POST_CODE ACPI DATA
+ //
+ TpmMeasureAndLogData(
+ 0,
+ EV_POST_CODE,
+ EV_POSTCODE_INFO_ACPI_DATA,
+ ACPI_DATA_LEN,
+ Table,
+ TableSize
+ );
+
+
+ ASSERT (Table->OemTableId == SIGNATURE_64 ('T', 'c', 'g', 'T', 'a', 'b', 'l', 'e'));
+ CopyMem (Table->OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (Table->OemId) );
+ mTcgNvs = AssignOpRegion (Table, SIGNATURE_32 ('T', 'N', 'V', 'S'), (UINT16) 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;
+
+ if (!CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceTpm12Guid)){
+ DEBUG ((EFI_D_ERROR, "No TPM12 instance required!\n"));
+ return EFI_UNSUPPORTED;
+ }
+
+ 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/Core/SecurityPkg/Tcg/TcgSmm/TcgSmm.h b/Core/SecurityPkg/Tcg/TcgSmm/TcgSmm.h
new file mode 100644
index 0000000000..21e4ad96d2
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TcgSmm/TcgSmm.h
@@ -0,0 +1,105 @@
+/** @file
+ The header file for TCG SMM driver.
+
+Copyright (c) 2012 - 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __TCG_SMM_H__
+#define __TCG_SMM_H__
+
+#include <PiDxe.h>
+#include <IndustryStandard/Acpi.h>
+#include <IndustryStandard/UefiTcgPlatform.h>
+
+#include <Guid/PhysicalPresenceData.h>
+#include <Guid/MemoryOverwriteControl.h>
+#include <Guid/TpmInstance.h>
+
+#include <Protocol/SmmSwDispatch2.h>
+#include <Protocol/AcpiTable.h>
+#include <Protocol/SmmVariable.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/SmmServicesTableLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DxeServicesLib.h>
+#include <Library/TpmMeasurementLib.h>
+#include <Library/PcdLib.h>
+#include <Library/TcgPpVendorLib.h>
+
+#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;
+ UINT32 ReturnCode;
+} MEMORY_CLEAR_NVS;
+
+typedef struct {
+ PHYSICAL_PRESENCE_NVS PhysicalPresence;
+ MEMORY_CLEAR_NVS MemoryClear;
+ UINT32 PPRequestUserConfirm;
+} 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()
+
+//
+// The definition for TCG physical presence ACPI function
+//
+#define ACPI_FUNCTION_GET_PHYSICAL_PRESENCE_INTERFACE_VERSION 1
+#define ACPI_FUNCTION_SUBMIT_REQUEST_TO_BIOS 2
+#define ACPI_FUNCTION_GET_PENDING_REQUEST_BY_OS 3
+#define ACPI_FUNCTION_GET_PLATFORM_ACTION_TO_TRANSITION_TO_BIOS 4
+#define ACPI_FUNCTION_RETURN_REQUEST_RESPONSE_TO_OS 5
+#define ACPI_FUNCTION_SUBMIT_PREFERRED_USER_LANGUAGE 6
+#define ACPI_FUNCTION_SUBMIT_REQUEST_TO_BIOS_2 7
+#define ACPI_FUNCTION_GET_USER_CONFIRMATION_STATUS_FOR_REQUEST 8
+
+//
+// The return code for Return TPM Operation Response to OS Environment
+//
+#define PP_RETURN_TPM_OPERATION_RESPONSE_SUCCESS 0
+#define PP_RETURN_TPM_OPERATION_RESPONSE_FAILURE 1
+
+//
+// The definition for TCG MOR
+//
+#define ACPI_FUNCTION_DSM_MEMORY_CLEAR_INTERFACE 1
+#define ACPI_FUNCTION_PTS_CLEAR_MOR_BIT 2
+
+//
+// The return code for Memory Clear Interface Functions
+//
+#define MOR_REQUEST_SUCCESS 0
+#define MOR_REQUEST_GENERAL_FAILURE 1
+
+#endif // __TCG_SMM_H__
diff --git a/Core/SecurityPkg/Tcg/TcgSmm/TcgSmm.inf b/Core/SecurityPkg/Tcg/TcgSmm/TcgSmm.inf
new file mode 100644
index 0000000000..be7a96bc62
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TcgSmm/TcgSmm.inf
@@ -0,0 +1,83 @@
+## @file
+# Implements ACPI metholds for the TCG feature
+#
+# 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.
+#
+# Caution: This module requires additional review when modified.
+# This driver will have external input - variable and ACPINvs data in SMM mode.
+# This external input must be validated carefully to avoid security issue.
+#
+# Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = TcgSmm
+ MODULE_UNI_FILE = TcgSmm.uni
+ 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
+ TcgSmm.h
+ Tpm.asl
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ UefiDriverEntryPoint
+ SmmServicesTableLib
+ UefiBootServicesTableLib
+ DebugLib
+ DxeServicesLib
+ TpmMeasurementLib
+ PcdLib
+ TcgPpVendorLib
+
+[Guids]
+ ## SOMETIMES_PRODUCES ## Variable:L"PhysicalPresence"
+ ## SOMETIMES_CONSUMES ## Variable:L"PhysicalPresence"
+ ## SOMETIMES_CONSUMES ## Variable:L"PhysicalPresenceFlags"
+ gEfiPhysicalPresenceGuid
+
+ ## SOMETIMES_PRODUCES ## Variable:L"MemoryOverwriteRequestControl"
+ ## SOMETIMES_CONSUMES ## Variable:L"MemoryOverwriteRequestControl"
+ gEfiMemoryOverwriteControlDataGuid
+
+ gEfiTpmDeviceInstanceTpm12Guid ## PRODUCES ## GUID # TPM device identifier
+
+[Protocols]
+ gEfiSmmSwDispatch2ProtocolGuid ## CONSUMES
+ gEfiSmmVariableProtocolGuid ## CONSUMES
+ gEfiAcpiTableProtocolGuid ## CONSUMES
+
+[Pcd]
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpmInstanceGuid ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemId ## SOMETIMES_CONSUMES
+
+[Depex]
+ gEfiAcpiTableProtocolGuid AND
+ gEfiSmmSwDispatch2ProtocolGuid AND
+ gEfiSmmVariableProtocolGuid AND
+ gEfiTcgProtocolGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ TcgSmmExtra.uni
+ \ No newline at end of file
diff --git a/Core/SecurityPkg/Tcg/TcgSmm/TcgSmm.uni b/Core/SecurityPkg/Tcg/TcgSmm/TcgSmm.uni
new file mode 100644
index 0000000000..81f7f8d53a
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TcgSmm/TcgSmm.uni
@@ -0,0 +1,27 @@
+// /** @file
+// Implements ACPI metholds for the TCG feature
+//
+// 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.
+//
+// Caution: This module requires additional review when modified.
+// This driver will have external input - variable and ACPINvs data in SMM mode.
+// This external input must be validated carefully to avoid security issue.
+//
+// Copyright (c) 2011 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Implements ACPI methods for the TCG feature"
+
+#string STR_MODULE_DESCRIPTION #language en-US "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. Caution: This module requires additional review when modified. This driver will have external input - variable and ACPINvs data in SMM mode. This external input must be validated carefully to avoid security issues."
+
diff --git a/Core/SecurityPkg/Tcg/TcgSmm/TcgSmmExtra.uni b/Core/SecurityPkg/Tcg/TcgSmm/TcgSmmExtra.uni
new file mode 100644
index 0000000000..b9ca98bb6e
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TcgSmm/TcgSmmExtra.uni
@@ -0,0 +1,19 @@
+// /** @file
+// TcgSmm Localized Strings and Content
+//
+// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"TCG (Trusted Computing Group) SMM"
+
+
diff --git a/Core/SecurityPkg/Tcg/TcgSmm/Tpm.asl b/Core/SecurityPkg/Tcg/TcgSmm/Tpm.asl
new file mode 100644
index 0000000000..b5449d98b4
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TcgSmm/Tpm.asl
@@ -0,0 +1,356 @@
+/** @file
+ The TPM definition block in ACPI table for physical presence
+ and MemoryClear.
+
+Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+DefinitionBlock (
+ "Tpm.aml",
+ "SSDT",
+ 2,
+ "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 (ReadWrite, 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 0xFFFF0000 and Length 0xF0 will be fixed in C code.
+ //
+ OperationRegion (TNVS, SystemMemory, 0xFFFF0000, 0xF0)
+ 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
+ MRET, 32, // Memory Overwrite function return code
+ UCRQ, 32 // Phyical Presence request operation to Get User Confirmation Status
+ }
+
+ 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}, {UnknownObj, UnknownObj, UnknownObj}) // 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 () {0x1, 0x20}})
+ 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}, {UnknownObj, UnknownObj, UnknownObj}) // 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)), UCRQ)
+
+ //
+ // Triggle the SMI interrupt
+ //
+ Store (PPIN, IOB2)
+
+ Return (FRET)
+ }
+
+ Default {BreakPoint}
+ }
+ Return (1)
+ }
+
+ Method (TMCI, 3, Serialized, 0, IntObj, {UnknownObj, UnknownObj, UnknownObj}) // 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 (MRET)
+ }
+ 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/Core/SecurityPkg/Tcg/TrEEConfig/TpmDetection.c b/Core/SecurityPkg/Tcg/TrEEConfig/TpmDetection.c
new file mode 100644
index 0000000000..4e675d3602
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TrEEConfig/TpmDetection.c
@@ -0,0 +1,105 @@
+/** @file
+ TPM1.2/dTPM2.0 auto detection.
+
+Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+
+#include <PiPei.h>
+#include <Ppi/ReadOnlyVariable2.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/PcdLib.h>
+#include <Library/Tpm12DeviceLib.h>
+#include <Library/Tpm12CommandLib.h>
+#include <IndustryStandard/Tpm12.h>
+
+#include "TrEEConfigNvData.h"
+
+/**
+ This routine check both SetupVariable and real TPM device, and return final TpmDevice configuration.
+
+ @param SetupTpmDevice TpmDevice configuration in setup driver
+
+ @return TpmDevice configuration
+**/
+UINT8
+DetectTpmDevice (
+ IN UINT8 SetupTpmDevice
+ )
+{
+ EFI_STATUS Status;
+ EFI_BOOT_MODE BootMode;
+ TREE_DEVICE_DETECTION TrEEDeviceDetection;
+ EFI_PEI_READ_ONLY_VARIABLE2_PPI *VariablePpi;
+ UINTN Size;
+
+ Status = PeiServicesGetBootMode (&BootMode);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // In S3, we rely on normal boot Detection, because we save to ReadOnly Variable in normal boot.
+ //
+ if (BootMode == BOOT_ON_S3_RESUME) {
+ DEBUG ((EFI_D_INFO, "DetectTpmDevice: S3 mode\n"));
+
+ Status = PeiServicesLocatePpi (&gEfiPeiReadOnlyVariable2PpiGuid, 0, NULL, (VOID **) &VariablePpi);
+ ASSERT_EFI_ERROR (Status);
+
+ Size = sizeof(TREE_DEVICE_DETECTION);
+ ZeroMem (&TrEEDeviceDetection, sizeof(TrEEDeviceDetection));
+ Status = VariablePpi->GetVariable (
+ VariablePpi,
+ TREE_DEVICE_DETECTION_NAME,
+ &gTrEEConfigFormSetGuid,
+ NULL,
+ &Size,
+ &TrEEDeviceDetection
+ );
+ if (!EFI_ERROR (Status) &&
+ (TrEEDeviceDetection.TpmDeviceDetected >= TPM_DEVICE_MIN) &&
+ (TrEEDeviceDetection.TpmDeviceDetected <= TPM_DEVICE_MAX)) {
+ DEBUG ((EFI_D_ERROR, "TpmDevice from DeviceDetection: %x\n", TrEEDeviceDetection.TpmDeviceDetected));
+ return TrEEDeviceDetection.TpmDeviceDetected;
+ }
+ }
+
+ DEBUG ((EFI_D_INFO, "DetectTpmDevice:\n"));
+
+ // dTPM available and not disabled by setup
+ // We need check if it is TPM1.2 or TPM2.0
+ // So try TPM1.2 command at first
+
+ Status = Tpm12RequestUseTpm ();
+ if (EFI_ERROR (Status)) {
+ //
+ // dTPM not available
+ //
+ return TPM_DEVICE_NULL;
+ }
+
+ if (BootMode == BOOT_ON_S3_RESUME) {
+ Status = Tpm12Startup (TPM_ST_STATE);
+ } else {
+ Status = Tpm12Startup (TPM_ST_CLEAR);
+ }
+ if (EFI_ERROR (Status)) {
+ return TPM_DEVICE_2_0_DTPM;
+ }
+
+ // NO initialization needed again.
+ Status = PcdSet8S (PcdTpmInitializationPolicy, 0);
+ ASSERT_EFI_ERROR (Status);
+ return TPM_DEVICE_1_2;
+}
diff --git a/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfig.vfr b/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfig.vfr
new file mode 100644
index 0000000000..84b55a9f15
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfig.vfr
@@ -0,0 +1,68 @@
+/** @file
+ VFR file used by the TREE configuration component.
+
+Copyright (c) 2013, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "TrEEConfigNvData.h"
+
+formset
+ guid = TREE_CONFIG_FORM_SET_GUID,
+ title = STRING_TOKEN(STR_TREE_TITLE),
+ help = STRING_TOKEN(STR_TREE_HELP),
+ classguid = EFI_HII_PLATFORM_SETUP_FORMSET_GUID,
+
+ efivarstore TREE_CONFIGURATION,
+ varid = TREE_CONFIGURATION_VARSTORE_ID,
+ attribute = 0x03, // EFI variable attribures EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE
+ name = TREE_CONFIGURATION,
+ guid = TREE_CONFIG_FORM_SET_GUID;
+
+ form formid = TREE_CONFIGURATION_FORM_ID,
+ title = STRING_TOKEN(STR_TREE_TITLE);
+
+ subtitle text = STRING_TOKEN(STR_NULL);
+
+ text
+ help = STRING_TOKEN(STR_TREE_DEVICE_STATE_HELP),
+ text = STRING_TOKEN(STR_TREE_DEVICE_STATE_PROMPT),
+ text = STRING_TOKEN(STR_TREE_DEVICE_STATE_CONTENT);
+
+ oneof varid = TREE_CONFIGURATION.TpmDevice,
+ questionid = KEY_TPM_DEVICE,
+ prompt = STRING_TOKEN(STR_TREE_DEVICE_PROMPT),
+ help = STRING_TOKEN(STR_TREE_DEVICE_HELP),
+ flags = INTERACTIVE,
+ option text = STRING_TOKEN(STR_TREE_TPM_1_2), value = TPM_DEVICE_1_2, flags = DEFAULT | MANUFACTURING | RESET_REQUIRED;
+ option text = STRING_TOKEN(STR_TREE_TPM_2_0_DTPM), value = TPM_DEVICE_2_0_DTPM, flags = RESET_REQUIRED;
+ endoneof;
+
+ subtitle text = STRING_TOKEN(STR_NULL);
+
+ suppressif ideqvallist TREE_CONFIGURATION.TpmDevice == TPM_DEVICE_NULL TPM_DEVICE_1_2;
+
+ subtitle text = STRING_TOKEN(STR_NULL);
+ subtitle text = STRING_TOKEN(STR_TREE_PP_OPERATION);
+
+ oneof name = Tpm2Operation,
+ questionid = KEY_TPM2_OPERATION,
+ prompt = STRING_TOKEN(STR_TREE_OPERATION),
+ help = STRING_TOKEN(STR_TREE_OPERATION_HELP),
+ flags = INTERACTIVE | NUMERIC_SIZE_1,
+ option text = STRING_TOKEN(STR_TREE_NO_ACTION), value = TREE_PHYSICAL_PRESENCE_NO_ACTION, flags = DEFAULT | MANUFACTURING | RESET_REQUIRED;
+ option text = STRING_TOKEN(STR_TREE_CLEAR), value = TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR, flags = RESET_REQUIRED;
+ endoneof;
+
+ endif;
+
+ endform;
+
+endformset;
diff --git a/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigDriver.c b/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigDriver.c
new file mode 100644
index 0000000000..2ad02c05a6
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigDriver.c
@@ -0,0 +1,216 @@
+/** @file
+ The module entry point for TrEE configuration module.
+
+Copyright (c) 2013, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "TrEEConfigImpl.h"
+
+extern TPM_INSTANCE_ID mTpmInstanceId[TPM_DEVICE_MAX + 1];
+
+/**
+ The entry point for TrEE 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
+TrEEConfigDriverEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ TREE_CONFIG_PRIVATE_DATA *PrivateData;
+ TREE_CONFIGURATION TrEEConfiguration;
+ TREE_DEVICE_DETECTION TrEEDeviceDetection;
+ UINTN Index;
+ UINTN DataSize;
+ EDKII_VARIABLE_LOCK_PROTOCOL *VariableLockProtocol;
+
+ Status = gBS->OpenProtocol (
+ ImageHandle,
+ &gEfiCallerIdGuid,
+ NULL,
+ ImageHandle,
+ ImageHandle,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+ if (!EFI_ERROR (Status)) {
+ return EFI_ALREADY_STARTED;
+ }
+
+ //
+ // Create a private data structure.
+ //
+ PrivateData = AllocateCopyPool (sizeof (TREE_CONFIG_PRIVATE_DATA), &mTrEEConfigPrivateDateTemplate);
+ ASSERT (PrivateData != NULL);
+
+ //
+ // Install private GUID.
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &ImageHandle,
+ &gEfiCallerIdGuid,
+ PrivateData,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ DataSize = sizeof(TrEEConfiguration);
+ Status = gRT->GetVariable (
+ TREE_STORAGE_NAME,
+ &gTrEEConfigFormSetGuid,
+ NULL,
+ &DataSize,
+ &TrEEConfiguration
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Variable not ready, set default value
+ //
+ TrEEConfiguration.TpmDevice = TPM_DEVICE_DEFAULT;
+ }
+
+ //
+ // Validation
+ //
+ if ((TrEEConfiguration.TpmDevice > TPM_DEVICE_MAX) || (TrEEConfiguration.TpmDevice < TPM_DEVICE_MIN)) {
+ TrEEConfiguration.TpmDevice = TPM_DEVICE_DEFAULT;
+ }
+
+ //
+ // Save to variable so platform driver can get it.
+ //
+ Status = gRT->SetVariable (
+ TREE_STORAGE_NAME,
+ &gTrEEConfigFormSetGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ sizeof(TrEEConfiguration),
+ &TrEEConfiguration
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "TrEEConfigDriver: Fail to set TREE_STORAGE_NAME\n"));
+ }
+
+ //
+ // Sync data from PCD to variable, so that we do not need detect again in S3 phase.
+ //
+ TrEEDeviceDetection.TpmDeviceDetected = TPM_DEVICE_NULL;
+ for (Index = 0; Index < sizeof(mTpmInstanceId)/sizeof(mTpmInstanceId[0]); Index++) {
+ if (CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &mTpmInstanceId[Index].TpmInstanceGuid)) {
+ TrEEDeviceDetection.TpmDeviceDetected = mTpmInstanceId[Index].TpmDevice;
+ break;
+ }
+ }
+
+ PrivateData->TpmDeviceDetected = TrEEDeviceDetection.TpmDeviceDetected;
+
+ //
+ // Save to variable so platform driver can get it.
+ //
+ Status = gRT->SetVariable (
+ TREE_DEVICE_DETECTION_NAME,
+ &gTrEEConfigFormSetGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ sizeof(TrEEDeviceDetection),
+ &TrEEDeviceDetection
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "TrEEConfigDriver: Fail to set TREE_DEVICE_DETECTION_NAME\n"));
+ Status = gRT->SetVariable (
+ TREE_DEVICE_DETECTION_NAME,
+ &gTrEEConfigFormSetGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ 0,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ //
+ // We should lock TrEEDeviceDetection, because it contains information needed at S3.
+ //
+ Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **)&VariableLockProtocol);
+ if (!EFI_ERROR (Status)) {
+ Status = VariableLockProtocol->RequestToLock (
+ VariableLockProtocol,
+ TREE_DEVICE_DETECTION_NAME,
+ &gTrEEConfigFormSetGuid
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ //
+ // Install TrEE configuration form
+ //
+ Status = InstallTrEEConfigForm (PrivateData);
+ if (EFI_ERROR (Status)) {
+ goto ErrorExit;
+ }
+
+ return EFI_SUCCESS;
+
+ErrorExit:
+ if (PrivateData != NULL) {
+ UninstallTrEEConfigForm (PrivateData);
+ }
+
+ return Status;
+}
+
+/**
+ Unload the TrEE configuration form.
+
+ @param[in] ImageHandle The driver's image handle.
+
+ @retval EFI_SUCCESS The TrEE configuration form is unloaded.
+ @retval Others Failed to unload the form.
+
+**/
+EFI_STATUS
+EFIAPI
+TrEEConfigDriverUnload (
+ IN EFI_HANDLE ImageHandle
+ )
+{
+ EFI_STATUS Status;
+ TREE_CONFIG_PRIVATE_DATA *PrivateData;
+
+ Status = gBS->HandleProtocol (
+ ImageHandle,
+ &gEfiCallerIdGuid,
+ (VOID **) &PrivateData
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ASSERT (PrivateData->Signature == TREE_CONFIG_PRIVATE_DATA_SIGNATURE);
+
+ gBS->UninstallMultipleProtocolInterfaces (
+ &ImageHandle,
+ &gEfiCallerIdGuid,
+ PrivateData,
+ NULL
+ );
+
+ UninstallTrEEConfigForm (PrivateData);
+
+ return EFI_SUCCESS;
+}
diff --git a/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigDxe.inf b/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigDxe.inf
new file mode 100644
index 0000000000..368570aea0
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigDxe.inf
@@ -0,0 +1,88 @@
+## @file
+# TPM device configuration for TPM 2.0
+#
+# By this module, user may select TPM device, clear TPM state, etc.
+# NOTE: This module is only for reference only, each platform should have its own setup page.
+#
+# Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = TrEEConfigDxe
+ MODULE_UNI_FILE = TrEEConfigDxe.uni
+ FILE_GUID = 3141FD4D-EA02-4a70-9BCE-97EE837319AC
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = TrEEConfigDriverEntryPoint
+ UNLOAD_IMAGE = TrEEConfigDriverUnload
+
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ TrEEConfigDriver.c
+ TrEEConfigImpl.c
+ TrEEConfigImpl.h
+ TrEEConfig.vfr
+ TrEEConfigStrings.uni
+ TrEEConfigNvData.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ MemoryAllocationLib
+ UefiLib
+ UefiBootServicesTableLib
+ UefiRuntimeServicesTableLib
+ UefiDriverEntryPoint
+ UefiHiiServicesLib
+ DebugLib
+ HiiLib
+ PcdLib
+ PrintLib
+ Tpm2DeviceLib
+ Tpm2CommandLib
+
+[Guids]
+ ## SOMETIMES_PRODUCES ## Variable:L"TrEEPhysicalPresence"
+ ## SOMETIMES_CONSUMES ## Variable:L"TrEEPhysicalPresence"
+ gEfiTrEEPhysicalPresenceGuid
+
+ ## PRODUCES ## HII
+ ## SOMETIMES_PRODUCES ## Variable:L"TREE_CONFIGURATION"
+ ## SOMETIMES_CONSUMES ## Variable:L"TREE_CONFIGURATION"
+ ## PRODUCES ## Variable:L"TREE_DEVICE_DETECTION"
+ ## SOMETIMES_CONSUMES ## Variable:L"TREE_DEVICE_DETECTION"
+ gTrEEConfigFormSetGuid
+
+[Protocols]
+ gEfiHiiConfigAccessProtocolGuid ## PRODUCES
+ gEfiDevicePathProtocolGuid ## PRODUCES
+ gEdkiiVariableLockProtocolGuid ## SOMETIMES_CONSUMES
+
+[Pcd]
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpmInstanceGuid ## CONSUMES
+
+[Depex]
+ gEfiTrEEProtocolGuid AND
+ gEfiHiiConfigRoutingProtocolGuid AND
+ gEfiHiiDatabaseProtocolGuid AND
+ gEfiVariableArchProtocolGuid AND
+ gEfiVariableWriteArchProtocolGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ TrEEConfigDxeExtra.uni \ No newline at end of file
diff --git a/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigDxe.uni b/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigDxe.uni
new file mode 100644
index 0000000000..6b84586b2c
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigDxe.uni
@@ -0,0 +1,22 @@
+// /** @file
+// TPM device configuration for TPM 2.0
+//
+// By this module, user may select TPM device, clear TPM state, etc.
+// NOTE: This module is only for reference only, each platform should have its own setup page.
+//
+// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "TPM device configuration for TPM 2.0"
+
+#string STR_MODULE_DESCRIPTION #language en-US "By this module, user may select TPM device, clear TPM state, etc. NOTE: This module is only for reference only, each platform should have its own setup page."
+
diff --git a/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigDxeExtra.uni b/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigDxeExtra.uni
new file mode 100644
index 0000000000..c1b243e563
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigDxeExtra.uni
@@ -0,0 +1,19 @@
+// /** @file
+// TrEEConfigDxe Localized Strings and Content
+//
+// Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"TrEE (Trusted Execution Environment) Configuration DXE"
+
+
diff --git a/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigImpl.c b/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigImpl.c
new file mode 100644
index 0000000000..2f03adcc8c
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigImpl.c
@@ -0,0 +1,344 @@
+/** @file
+ HII Config Access protocol implementation of TREE configuration module.
+ NOTE: This module is only for reference only, each platform should have its own setup page.
+
+Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "TrEEConfigImpl.h"
+#include <Library/PcdLib.h>
+#include <Library/Tpm2CommandLib.h>
+#include <Guid/TpmInstance.h>
+
+TPM_INSTANCE_ID mTpmInstanceId[TPM_DEVICE_MAX + 1] = TPM_INSTANCE_ID_LIST;
+
+TREE_CONFIG_PRIVATE_DATA mTrEEConfigPrivateDateTemplate = {
+ TREE_CONFIG_PRIVATE_DATA_SIGNATURE,
+ {
+ TrEEExtractConfig,
+ TrEERouteConfig,
+ TrEECallback
+ }
+};
+
+HII_VENDOR_DEVICE_PATH mTrEEHiiVendorDevicePath = {
+ {
+ {
+ HARDWARE_DEVICE_PATH,
+ HW_VENDOR_DP,
+ {
+ (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
+ (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
+ }
+ },
+ TREE_CONFIG_FORM_SET_GUID
+ },
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ (UINT8) (END_DEVICE_PATH_LENGTH),
+ (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
+ }
+ }
+};
+
+/**
+ This function allows a caller to extract the current configuration for one
+ or more named elements from the target driver.
+
+ @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param[in] Request A null-terminated Unicode string in
+ <ConfigRequest> format.
+ @param[out] Progress On return, points to a character in the Request
+ string. Points to the string's null terminator if
+ request was successful. Points to the most recent
+ '&' before the first failing name/value pair (or
+ the beginning of the string if the failure is in
+ the first name/value pair) if the request was not
+ successful.
+ @param[out] Results A null-terminated Unicode string in
+ <ConfigAltResp> format which has all values filled
+ in for the names in the Request string. String to
+ be allocated by the called function.
+
+ @retval EFI_SUCCESS The Results is filled with the requested values.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results.
+ @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name.
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in this
+ driver.
+
+**/
+EFI_STATUS
+EFIAPI
+TrEEExtractConfig (
+ 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;
+}
+
+/**
+ 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
+SaveTrEEPpRequest (
+ IN UINT8 PpRequest
+ )
+{
+ EFI_STATUS Status;
+ UINTN DataSize;
+ EFI_TREE_PHYSICAL_PRESENCE PpData;
+
+ //
+ // Save TPM command to variable.
+ //
+ DataSize = sizeof (EFI_TREE_PHYSICAL_PRESENCE);
+ Status = gRT->GetVariable (
+ TREE_PHYSICAL_PRESENCE_VARIABLE,
+ &gEfiTrEEPhysicalPresenceGuid,
+ NULL,
+ &DataSize,
+ &PpData
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ PpData.PPRequest = PpRequest;
+ Status = gRT->SetVariable (
+ TREE_PHYSICAL_PRESENCE_VARIABLE,
+ &gEfiTrEEPhysicalPresenceGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ DataSize,
+ &PpData
+ );
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ 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] Configuration A null-terminated Unicode string in <ConfigResp>
+ 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
+TrEERouteConfig (
+ 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 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
+TrEECallback (
+ 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_CHANGED) {
+ if (QuestionId == KEY_TPM_DEVICE) {
+ return EFI_SUCCESS;
+ }
+ if (QuestionId == KEY_TPM2_OPERATION) {
+ return SaveTrEEPpRequest (Value->u8);
+ }
+ }
+
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ This function publish the TREE configuration Form for TPM device.
+
+ @param[in, out] PrivateData Points to TREE 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
+InstallTrEEConfigForm (
+ IN OUT TREE_CONFIG_PRIVATE_DATA *PrivateData
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_HANDLE HiiHandle;
+ EFI_HANDLE DriverHandle;
+ EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
+
+ DriverHandle = NULL;
+ ConfigAccess = &PrivateData->ConfigAccess;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &DriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mTrEEHiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ ConfigAccess,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ PrivateData->DriverHandle = DriverHandle;
+
+ //
+ // Publish the HII package list
+ //
+ HiiHandle = HiiAddPackages (
+ &gTrEEConfigFormSetGuid,
+ DriverHandle,
+ TrEEConfigDxeStrings,
+ TrEEConfigBin,
+ NULL
+ );
+ if (HiiHandle == NULL) {
+ gBS->UninstallMultipleProtocolInterfaces (
+ DriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mTrEEHiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ ConfigAccess,
+ NULL
+ );
+
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ PrivateData->HiiHandle = HiiHandle;
+
+ //
+ // Update static data
+ //
+ switch (PrivateData->TpmDeviceDetected) {
+ case TPM_DEVICE_NULL:
+ HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_TREE_DEVICE_STATE_CONTENT), L"Not Found", NULL);
+ break;
+ case TPM_DEVICE_1_2:
+ HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_TREE_DEVICE_STATE_CONTENT), L"TPM 1.2", NULL);
+ break;
+ case TPM_DEVICE_2_0_DTPM:
+ HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_TREE_DEVICE_STATE_CONTENT), L"TPM 2.0 (DTPM)", NULL);
+ break;
+ default:
+ HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_TREE_DEVICE_STATE_CONTENT), L"Unknown", NULL);
+ break;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function removes TREE configuration Form.
+
+ @param[in, out] PrivateData Points to TREE configuration private data.
+
+**/
+VOID
+UninstallTrEEConfigForm (
+ IN OUT TREE_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,
+ &mTrEEHiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ &PrivateData->ConfigAccess,
+ NULL
+ );
+ PrivateData->DriverHandle = NULL;
+ }
+
+ FreePool (PrivateData);
+}
diff --git a/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigImpl.h b/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigImpl.h
new file mode 100644
index 0000000000..720c698e7a
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigImpl.h
@@ -0,0 +1,193 @@
+/** @file
+ The header file of HII Config Access protocol implementation of TREE
+ configuration module.
+
+Copyright (c) 2013, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __TREE_CONFIG_IMPL_H__
+#define __TREE_CONFIG_IMPL_H__
+
+#include <Uefi.h>
+
+#include <Protocol/HiiConfigAccess.h>
+#include <Protocol/HiiConfigRouting.h>
+#include <Protocol/TrEEProtocol.h>
+#include <Protocol/VariableLock.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiHiiServicesLib.h>
+#include <Library/UefiLib.h>
+#include <Library/HiiLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PrintLib.h>
+
+#include <Guid/MdeModuleHii.h>
+
+#include "TrEEConfigNvData.h"
+
+//
+// Tool generated IFR binary data and String package data
+//
+extern UINT8 TrEEConfigBin[];
+extern UINT8 TrEEConfigDxeStrings[];
+
+///
+/// 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;
+
+ UINT8 TpmDeviceDetected;
+} TREE_CONFIG_PRIVATE_DATA;
+
+extern TREE_CONFIG_PRIVATE_DATA mTrEEConfigPrivateDateTemplate;
+
+#define TREE_CONFIG_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('T', 'r', 'E', 'D')
+#define TREE_CONFIG_PRIVATE_DATA_FROM_THIS(a) CR (a, TREE_CONFIG_PRIVATE_DATA, ConfigAccess, TREE_CONFIG_PRIVATE_DATA_SIGNATURE)
+
+
+/**
+ This function publish the TREE configuration Form for TPM device.
+
+ @param[in, out] PrivateData Points to TREE 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
+InstallTrEEConfigForm (
+ IN OUT TREE_CONFIG_PRIVATE_DATA *PrivateData
+ );
+
+/**
+ This function removes TREE configuration Form.
+
+ @param[in, out] PrivateData Points to TREE configuration private data.
+
+**/
+VOID
+UninstallTrEEConfigForm (
+ IN OUT TREE_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
+ <ConfigRequest> format.
+ @param[out] Progress On return, points to a character in the Request
+ string. Points to the string's null terminator if
+ request was successful. Points to the most recent
+ '&' before the first failing name/value pair (or
+ the beginning of the string if the failure is in
+ the first name/value pair) if the request was not
+ successful.
+ @param[out] Results A null-terminated Unicode string in
+ <ConfigAltResp> format which has all values filled
+ in for the names in the Request string. String to
+ be allocated by the called function.
+
+ @retval EFI_SUCCESS The Results is filled with the requested values.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results.
+ @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name.
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in this
+ driver.
+
+**/
+EFI_STATUS
+EFIAPI
+TrEEExtractConfig (
+ 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 <ConfigResp>
+ 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
+TrEERouteConfig (
+ 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
+TrEECallback (
+ 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/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigNvData.h b/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigNvData.h
new file mode 100644
index 0000000000..14e5d926a1
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigNvData.h
@@ -0,0 +1,76 @@
+/** @file
+ Header file for NV data structure definition.
+
+Copyright (c) 2013, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __TREE_CONFIG_NV_DATA_H__
+#define __TREE_CONFIG_NV_DATA_H__
+
+#include <Guid/HiiPlatformSetupFormset.h>
+#include <Guid/TrEEPhysicalPresenceData.h>
+#include <Guid/TrEEConfigHii.h>
+
+#define TREE_CONFIGURATION_VARSTORE_ID 0x0001
+#define TREE_CONFIGURATION_FORM_ID 0x0001
+
+#define KEY_TPM_DEVICE 0x2000
+#define KEY_TPM2_OPERATION 0x2001
+
+#define TPM_DEVICE_NULL 0
+#define TPM_DEVICE_1_2 1
+#define TPM_DEVICE_2_0_DTPM 2
+#define TPM_DEVICE_MIN TPM_DEVICE_1_2
+#define TPM_DEVICE_MAX TPM_DEVICE_2_0_DTPM
+#define TPM_DEVICE_DEFAULT TPM_DEVICE_1_2
+
+//
+// Nv Data structure referenced by IFR, TPM device user desired
+//
+typedef struct {
+ UINT8 TpmDevice;
+} TREE_CONFIGURATION;
+
+//
+// Variable saved for S3, TPM detected, only valid in S3 path.
+// This variable is ReadOnly.
+//
+typedef struct {
+ UINT8 TpmDeviceDetected;
+} TREE_DEVICE_DETECTION;
+
+#define TREE_STORAGE_NAME L"TREE_CONFIGURATION"
+#define TREE_DEVICE_DETECTION_NAME L"TREE_DEVICE_DETECTION"
+
+#define TPM_INSTANCE_ID_LIST { \
+ {TPM_DEVICE_INTERFACE_NONE, TPM_DEVICE_NULL}, \
+ {TPM_DEVICE_INTERFACE_TPM12, TPM_DEVICE_1_2}, \
+ {TPM_DEVICE_INTERFACE_TPM20_DTPM, TPM_DEVICE_2_0_DTPM}, \
+}
+
+//
+// BUGBUG: In order to pass VfrCompiler, we have to redefine GUID here.
+//
+#ifndef __BASE_H__
+typedef struct {
+ UINT32 Data1;
+ UINT16 Data2;
+ UINT16 Data3;
+ UINT8 Data4[8];
+} GUID;
+#endif
+
+typedef struct {
+ GUID TpmInstanceGuid;
+ UINT8 TpmDevice;
+} TPM_INSTANCE_ID;
+
+#endif
diff --git a/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigPei.inf b/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigPei.inf
new file mode 100644
index 0000000000..a4d6b58c6a
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigPei.inf
@@ -0,0 +1,77 @@
+## @file
+# Set TPM device type
+#
+# This module initializes TPM device type based on variable and detection.
+# NOTE: This module is only for reference only, each platform should have its own setup page.
+#
+# Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = TrEEConfigPei
+ MODULE_UNI_FILE = TrEEConfigPei.uni
+ FILE_GUID = A5C1EF72-9379-4370-B4C7-0F5126CAC38E
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ ENTRY_POINT = TrEEConfigPeimEntryPoint
+
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+# [BootMode]
+# S3_RESUME ## SOMETIMES_CONSUMES
+#
+
+[Sources]
+ TrEEConfigPeim.c
+ TrEEConfigNvData.h
+ TpmDetection.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ MemoryAllocationLib
+ PeiServicesLib
+ PeimEntryPoint
+ DebugLib
+ PcdLib
+ TimerLib
+ Tpm12CommandLib
+ Tpm12DeviceLib
+
+[Guids]
+ ## SOMETIMES_CONSUMES ## Variable:L"TREE_CONFIGURATION"
+ ## SOMETIMES_CONSUMES ## Variable:L"TREE_DEVICE_DETECTION"
+ gTrEEConfigFormSetGuid
+ gEfiTpmDeviceSelectedGuid ## PRODUCES ## GUID # Used as a PPI GUID
+ gEfiTpmDeviceInstanceNoneGuid ## SOMETIMES_CONSUMES ## GUID # TPM device identifier
+
+[Ppis]
+ gEfiPeiReadOnlyVariable2PpiGuid ## CONSUMES
+ gPeiTpmInitializationDonePpiGuid ## SOMETIMES_PRODUCES
+
+[Pcd]
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpmInstanceGuid ## PRODUCES
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpmInitializationPolicy ## PRODUCES
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpmAutoDetection ## CONSUMES
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpmBaseAddress ## SOMETIMES_CONSUMES
+
+[Depex]
+ gEfiPeiMasterBootModePpiGuid AND
+ gEfiPeiReadOnlyVariable2PpiGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ TrEEConfigPeiExtra.uni \ No newline at end of file
diff --git a/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigPei.uni b/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigPei.uni
new file mode 100644
index 0000000000..7050be29a4
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigPei.uni
@@ -0,0 +1,23 @@
+// /** @file
+// Set TPM device type
+//
+// This module initializes TPM device type based on variable and detection.
+// NOTE: This module is only for reference only, each platform should have its own setup page.
+//
+// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Set TPM device type"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This module initializes TPM device type based on variable and detection.\n"
+ "NOTE: This module is only for reference only, each platform should have its own setup page."
+
diff --git a/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigPeiExtra.uni b/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigPeiExtra.uni
new file mode 100644
index 0000000000..1ebef052c3
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigPeiExtra.uni
@@ -0,0 +1,19 @@
+// /** @file
+// TrEEConfigDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"TrEE (Trusted Execution Environment) Configuration DXE"
+
+
diff --git a/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigPeim.c b/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigPeim.c
new file mode 100644
index 0000000000..b4a3d52347
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigPeim.c
@@ -0,0 +1,159 @@
+/** @file
+ The module entry point for TrEE configuration module.
+
+Copyright (c) 2013 - 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+
+#include <PiPei.h>
+
+#include <Guid/TpmInstance.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/PcdLib.h>
+
+#include <Ppi/ReadOnlyVariable2.h>
+#include <Ppi/TpmInitialized.h>
+#include <Protocol/TrEEProtocol.h>
+
+#include "TrEEConfigNvData.h"
+
+TPM_INSTANCE_ID mTpmInstanceId[] = TPM_INSTANCE_ID_LIST;
+
+CONST EFI_PEI_PPI_DESCRIPTOR gTpmSelectedPpi = {
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEfiTpmDeviceSelectedGuid,
+ NULL
+};
+
+EFI_PEI_PPI_DESCRIPTOR mTpmInitializationDonePpiList = {
+ EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
+ &gPeiTpmInitializationDonePpiGuid,
+ NULL
+};
+
+/**
+ This routine check both SetupVariable and real TPM device, and return final TpmDevice configuration.
+
+ @param SetupTpmDevice TpmDevice configuration in setup driver
+
+ @return TpmDevice configuration
+**/
+UINT8
+DetectTpmDevice (
+ IN UINT8 SetupTpmDevice
+ );
+
+/**
+ The entry point for TrEE configuration driver.
+
+ @param FileHandle Handle of the file being invoked.
+ @param PeiServices Describes the list of possible PEI Services.
+
+ @retval EFI_SUCCES Convert variable to PCD successfully.
+ @retval Others Fail to convert variable to PCD.
+**/
+EFI_STATUS
+EFIAPI
+TrEEConfigPeimEntryPoint (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ UINTN Size;
+ EFI_STATUS Status;
+ EFI_STATUS Status2;
+ EFI_PEI_READ_ONLY_VARIABLE2_PPI *VariablePpi;
+ TREE_CONFIGURATION TrEEConfiguration;
+ UINTN Index;
+ UINT8 TpmDevice;
+
+ Status = PeiServicesLocatePpi (&gEfiPeiReadOnlyVariable2PpiGuid, 0, NULL, (VOID **) &VariablePpi);
+ ASSERT_EFI_ERROR (Status);
+
+ Size = sizeof(TrEEConfiguration);
+ Status = VariablePpi->GetVariable (
+ VariablePpi,
+ TREE_STORAGE_NAME,
+ &gTrEEConfigFormSetGuid,
+ NULL,
+ &Size,
+ &TrEEConfiguration
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Variable not ready, set default value
+ //
+ TrEEConfiguration.TpmDevice = TPM_DEVICE_DEFAULT;
+ }
+
+ //
+ // Validation
+ //
+ if ((TrEEConfiguration.TpmDevice > TPM_DEVICE_MAX) || (TrEEConfiguration.TpmDevice < TPM_DEVICE_MIN)) {
+ TrEEConfiguration.TpmDevice = TPM_DEVICE_DEFAULT;
+ }
+
+ //
+ // Although we have SetupVariable info, we still need detect TPM device manually.
+ //
+ DEBUG ((EFI_D_INFO, "TrEEConfiguration.TpmDevice from Setup: %x\n", TrEEConfiguration.TpmDevice));
+
+ if (PcdGetBool (PcdTpmAutoDetection)) {
+ TpmDevice = DetectTpmDevice (TrEEConfiguration.TpmDevice);
+ DEBUG ((EFI_D_INFO, "TpmDevice final: %x\n", TpmDevice));
+ if (TpmDevice != TPM_DEVICE_NULL) {
+ TrEEConfiguration.TpmDevice = TpmDevice;
+ }
+ } else {
+ TpmDevice = TrEEConfiguration.TpmDevice;
+ }
+
+ //
+ // Convert variable to PCD.
+ // This is work-around because there is no gurantee DynamicHiiPcd can return correct value in DXE phase.
+ // Using DynamicPcd instead.
+ //
+ // NOTE: TrEEConfiguration variable contains the desired TpmDevice type,
+ // while PcdTpmInstanceGuid PCD contains the real detected TpmDevice type
+ //
+ for (Index = 0; Index < sizeof(mTpmInstanceId)/sizeof(mTpmInstanceId[0]); Index++) {
+ if (TpmDevice == mTpmInstanceId[Index].TpmDevice) {
+ Size = sizeof(mTpmInstanceId[Index].TpmInstanceGuid);
+ Status = PcdSetPtrS (PcdTpmInstanceGuid, &Size, &mTpmInstanceId[Index].TpmInstanceGuid);
+ ASSERT_EFI_ERROR (Status);
+ DEBUG ((EFI_D_INFO, "TpmDevice PCD: %g\n", &mTpmInstanceId[Index].TpmInstanceGuid));
+ break;
+ }
+ }
+
+ //
+ // Selection done
+ //
+ Status = PeiServicesInstallPpi (&gTpmSelectedPpi);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Even if no TPM is selected or detected, we still need intall TpmInitializationDonePpi.
+ // Because TcgPei or TrEEPei will not run, but we still need a way to notify other driver.
+ // Other driver can know TPM initialization state by TpmInitializedPpi.
+ //
+ if (CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceNoneGuid)) {
+ Status2 = PeiServicesInstallPpi (&mTpmInitializationDonePpiList);
+ ASSERT_EFI_ERROR (Status2);
+ }
+
+ return Status;
+}
diff --git a/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigStrings.uni b/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigStrings.uni
new file mode 100644
index 0000000000..41d6c2412f
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigStrings.uni
@@ -0,0 +1,40 @@
+/** @file
+ String definitions for TCG configuration form.
+
+Copyright (c) 2013, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#langdef en-US "English"
+
+#string STR_TREE_TITLE #language en-US "TrEE Configuration"
+#string STR_TREE_HELP #language en-US "Press <Enter> to select TrEE Setup options."
+
+#string STR_TREE_DEVICE_STATE_PROMPT #language en-US "Current TPM Device"
+#string STR_TREE_DEVICE_STATE_HELP #language en-US "Current TPM Device: Disable, TPM1.2, or TPM2.0"
+#string STR_TREE_DEVICE_STATE_CONTENT #language en-US ""
+
+#string STR_TREE_DEVICE_PROMPT #language en-US "Attempt TPM Device"
+#string STR_TREE_DEVICE_HELP #language en-US "Attempt TPM Device: Disable, TPM1.2, or TPM2.0"
+#string STR_TREE_DEVICE_CONTENT #language en-US ""
+
+#string STR_TREE_PP_OPERATION #language en-US "TPM2 Physical Presence Operation"
+
+#string STR_TREE_OPERATION #language en-US "TPM2 Operation"
+#string STR_TREE_OPERATION_HELP #language en-US "Select one of the supported operation to change TPM2 state."
+
+#string STR_TREE_NO_ACTION #language en-US "No Action"
+#string STR_TREE_CLEAR #language en-US "TPM2 ClearControl(NO) + Clear"
+
+#string STR_TREE_TPM_DISABLE #language en-US "Disable"
+#string STR_TREE_TPM_1_2 #language en-US "TPM 1.2"
+#string STR_TREE_TPM_2_0_DTPM #language en-US "TPM 2.0 (DTPM)"
+
+#string STR_NULL #language en-US ""
diff --git a/Core/SecurityPkg/Tcg/TrEEDxe/MeasureBootPeCoff.c b/Core/SecurityPkg/Tcg/TrEEDxe/MeasureBootPeCoff.c
new file mode 100644
index 0000000000..a7de5883cc
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TrEEDxe/MeasureBootPeCoff.c
@@ -0,0 +1,427 @@
+/** @file
+ This module implements measuring PeCoff image for TrEE Protocol.
+
+ Caution: This file requires additional review when modified.
+ This driver will have external input - PE/COFF image.
+ This external input must be validated carefully to avoid security issue like
+ buffer overflow, integer overflow.
+
+Copyright (c) 2013 - 2017, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiDxe.h>
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/PeCoffLib.h>
+#include <Library/Tpm2CommandLib.h>
+#include <Library/HashLib.h>
+
+UINTN mTrEEDxeImageSize = 0;
+
+/**
+ Reads contents of a PE/COFF image in memory buffer.
+
+ Caution: This function may receive untrusted input.
+ PE/COFF image is external input, so this function will make sure the PE/COFF image content
+ read is within the image 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
+TrEEDxeImageRead (
+ IN VOID *FileHandle,
+ IN UINTN FileOffset,
+ IN OUT UINTN *ReadSize,
+ OUT VOID *Buffer
+ )
+{
+ UINTN EndPosition;
+
+ if (FileHandle == NULL || ReadSize == NULL || Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (MAX_ADDRESS - FileOffset < *ReadSize) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ EndPosition = FileOffset + *ReadSize;
+ if (EndPosition > mTrEEDxeImageSize) {
+ *ReadSize = (UINT32)(mTrEEDxeImageSize - FileOffset);
+ }
+
+ if (FileOffset >= mTrEEDxeImageSize) {
+ *ReadSize = 0;
+ }
+
+ CopyMem (Buffer, (UINT8 *)((UINTN) FileHandle + FileOffset), *ReadSize);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Measure PE image into TPM log based on the authenticode image hashing in
+ PE/COFF Specification 8.0 Appendix A.
+
+ Caution: This function may receive untrusted input.
+ PE/COFF image is external input, so this function will validate its data structure
+ within this image buffer before use.
+
+ Notes: PE/COFF image is checked by BasePeCoffLib PeCoffLoaderGetImageInfo().
+
+ @param[in] PCRIndex TPM PCR index
+ @param[in] ImageAddress Start address of image buffer.
+ @param[in] ImageSize Image size
+ @param[out] DigestList Digeest list of this image.
+
+ @retval EFI_SUCCESS Successfully measure image.
+ @retval EFI_OUT_OF_RESOURCES No enough resource to measure image.
+ @retval other error value
+**/
+EFI_STATUS
+MeasurePeImageAndExtend (
+ IN UINT32 PCRIndex,
+ IN EFI_PHYSICAL_ADDRESS ImageAddress,
+ IN UINTN ImageSize,
+ OUT TPML_DIGEST_VALUES *DigestList
+ )
+{
+ EFI_STATUS Status;
+ 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;
+ UINTN Pos;
+ UINT16 Magic;
+ EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
+ UINT32 NumberOfRvaAndSizes;
+ UINT32 CertSize;
+ HASH_HANDLE HashHandle;
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
+
+ HashHandle = 0xFFFFFFFF; // Know bad value
+
+ Status = EFI_UNSUPPORTED;
+ SectionHeader = NULL;
+
+ //
+ // Check PE/COFF image
+ //
+ ZeroMem (&ImageContext, sizeof (ImageContext));
+ ImageContext.Handle = (VOID *) (UINTN) ImageAddress;
+ mTrEEDxeImageSize = ImageSize;
+ ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) TrEEDxeImageRead;
+
+ //
+ // Get information about the image being loaded
+ //
+ Status = PeCoffLoaderGetImageInfo (&ImageContext);
+ if (EFI_ERROR (Status)) {
+ //
+ // The information can't be got from the invalid PeImage
+ //
+ DEBUG ((DEBUG_INFO, "TreeDxe: PeImage invalid. Cannot retrieve image information.\n"));
+ goto Finish;
+ }
+
+ DosHdr = (EFI_IMAGE_DOS_HEADER *) (UINTN) ImageAddress;
+ PeCoffHeaderOffset = 0;
+ if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
+ PeCoffHeaderOffset = DosHdr->e_lfanew;
+ }
+
+ Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINT8 *) (UINTN) ImageAddress + PeCoffHeaderOffset);
+ if (Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {
+ Status = EFI_UNSUPPORTED;
+ 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.
+
+ Status = HashStart (&HashHandle);
+ if (EFI_ERROR (Status)) {
+ goto Finish;
+ }
+
+ //
+ // Measuring PE/COFF Image Header;
+ // But CheckSum field and SECURITY data directory (certificate) are excluded
+ //
+ if (Hdr.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ //
+ // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value
+ // in the PE/COFF Header. If the MachineType is Itanium(IA64) and the
+ // Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
+ // then override the magic value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
+ //
+ Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;
+ } else {
+ //
+ // Get the magic value from the PE/COFF Optional Header
+ //
+ 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
+ //
+ NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
+ HashSize = (UINTN) (&Hdr.Pe32->OptionalHeader.CheckSum) - (UINTN) HashBase;
+ } else {
+ //
+ // Use PE32+ offset
+ //
+ NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
+ HashSize = (UINTN) (&Hdr.Pe32Plus->OptionalHeader.CheckSum) - (UINTN) HashBase;
+ }
+
+ Status = HashUpdate (HashHandle, HashBase, HashSize);
+ if (EFI_ERROR (Status)) {
+ goto Finish;
+ }
+
+ //
+ // 5. Skip over the image checksum (it occupies a single ULONG).
+ //
+ if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {
+ //
+ // 6. Since there is no Cert Directory in optional header, hash everything
+ // from the end of the checksum to the end of image header.
+ //
+ if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ //
+ // Use PE32 offset.
+ //
+ HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);
+ HashSize = Hdr.Pe32->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress);
+ } else {
+ //
+ // Use PE32+ offset.
+ //
+ HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);
+ HashSize = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress);
+ }
+
+ if (HashSize != 0) {
+ Status = HashUpdate (HashHandle, HashBase, HashSize);
+ if (EFI_ERROR (Status)) {
+ goto Finish;
+ }
+ }
+ } else {
+ //
+ // 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) (&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - (UINTN) HashBase;
+ } else {
+ //
+ // Use PE32+ offset
+ //
+ HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);
+ HashSize = (UINTN) (&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - (UINTN) HashBase;
+ }
+
+ if (HashSize != 0) {
+ Status = HashUpdate (HashHandle, HashBase, HashSize);
+ if (EFI_ERROR (Status)) {
+ goto Finish;
+ }
+ }
+
+ //
+ // 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) (HashBase - ImageAddress);
+ } else {
+ //
+ // Use PE32+ offset
+ //
+ HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];
+ HashSize = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress);
+ }
+
+ if (HashSize != 0) {
+ Status = HashUpdate (HashHandle, HashBase, HashSize);
+ if (EFI_ERROR (Status)) {
+ goto Finish;
+ }
+ }
+ }
+
+ //
+ // 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;
+
+ Status = HashUpdate (HashHandle, HashBase, HashSize);
+ if (EFI_ERROR (Status)) {
+ goto Finish;
+ }
+
+ 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 (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {
+ CertSize = 0;
+ } else {
+ if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ //
+ // Use PE32 offset.
+ //
+ CertSize = Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size;
+ } else {
+ //
+ // Use PE32+ offset.
+ //
+ CertSize = Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size;
+ }
+ }
+
+ if (ImageSize > CertSize + SumOfBytesHashed) {
+ HashSize = (UINTN) (ImageSize - CertSize - SumOfBytesHashed);
+
+ Status = HashUpdate (HashHandle, HashBase, HashSize);
+ if (EFI_ERROR (Status)) {
+ goto Finish;
+ }
+ } else if (ImageSize < CertSize + SumOfBytesHashed) {
+ Status = EFI_UNSUPPORTED;
+ goto Finish;
+ }
+ }
+
+ //
+ // 17. Finalize the SHA hash.
+ //
+ Status = HashCompleteAndExtend (HashHandle, PCRIndex, NULL, 0, DigestList);
+ if (EFI_ERROR (Status)) {
+ goto Finish;
+ }
+
+Finish:
+ if (SectionHeader != NULL) {
+ FreePool (SectionHeader);
+ }
+
+ return Status;
+}
diff --git a/Core/SecurityPkg/Tcg/TrEEDxe/TrEEDxe.c b/Core/SecurityPkg/Tcg/TrEEDxe/TrEEDxe.c
new file mode 100644
index 0000000000..95e9d745ad
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TrEEDxe/TrEEDxe.c
@@ -0,0 +1,1877 @@
+/** @file
+ This module implements TrEE Protocol.
+
+Copyright (c) 2013 - 2017, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiDxe.h>
+#include <IndustryStandard/Acpi.h>
+#include <IndustryStandard/PeImage.h>
+#include <IndustryStandard/TcpaAcpi.h>
+
+#include <Guid/GlobalVariable.h>
+#include <Guid/HobList.h>
+#include <Guid/TcgEventHob.h>
+#include <Guid/EventGroup.h>
+#include <Guid/EventExitBootServiceFailed.h>
+#include <Guid/ImageAuthentication.h>
+#include <Guid/TpmInstance.h>
+
+#include <Protocol/DevicePath.h>
+#include <Protocol/AcpiTable.h>
+#include <Protocol/MpService.h>
+#include <Protocol/VariableWrite.h>
+#include <Protocol/TrEEProtocol.h>
+
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/HobLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/BaseLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PrintLib.h>
+#include <Library/Tpm2CommandLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiLib.h>
+#include <Library/Tpm2DeviceLib.h>
+#include <Library/HashLib.h>
+#include <Library/PerformanceLib.h>
+#include <Library/ReportStatusCodeLib.h>
+
+#define PERF_ID_TREE_DXE 0x3120
+
+typedef struct {
+ CHAR16 *VariableName;
+ EFI_GUID *VendorGuid;
+} VARIABLE_TYPE;
+
+#define TREE_DEFAULT_MAX_COMMAND_SIZE 0x1000
+#define TREE_DEFAULT_MAX_RESPONSE_SIZE 0x1000
+
+typedef struct {
+ EFI_GUID *EventGuid;
+ TREE_EVENT_LOG_FORMAT LogFormat;
+} TREE_EVENT_INFO_STRUCT;
+
+TREE_EVENT_INFO_STRUCT mTreeEventInfo[] = {
+ {&gTcgEventEntryHobGuid, TREE_EVENT_LOG_FORMAT_TCG_1_2},
+};
+
+#define TCG_EVENT_LOG_AREA_COUNT_MAX 2
+
+typedef struct {
+ TREE_EVENT_LOG_FORMAT EventLogFormat;
+ EFI_PHYSICAL_ADDRESS Lasa;
+ UINT64 Laml;
+ UINTN EventLogSize;
+ UINT8 *LastEvent;
+ BOOLEAN EventLogStarted;
+ BOOLEAN EventLogTruncated;
+} TCG_EVENT_LOG_AREA_STRUCT;
+
+typedef struct _TCG_DXE_DATA {
+ TREE_BOOT_SERVICE_CAPABILITY BsCap;
+ EFI_TCG_CLIENT_ACPI_TABLE *TcgClientAcpiTable;
+ EFI_TCG_SERVER_ACPI_TABLE *TcgServerAcpiTable;
+ TCG_EVENT_LOG_AREA_STRUCT EventLogAreaStruct[TCG_EVENT_LOG_AREA_COUNT_MAX];
+} 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,
+ 0x0 // 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
+};
+
+TCG_DXE_DATA mTcgDxeData = {
+ {
+ sizeof (TREE_BOOT_SERVICE_CAPABILITY_1_0), // Size
+ { 1, 0 }, // StructureVersion
+ { 1, 0 }, // ProtocolVersion
+ TREE_BOOT_HASH_ALG_SHA1, // HashAlgorithmBitmap
+ TREE_EVENT_LOG_FORMAT_TCG_1_2, // SupportedEventLogs
+ TRUE, // TrEEPresentFlag
+ TREE_DEFAULT_MAX_COMMAND_SIZE, // MaxCommandSize
+ TREE_DEFAULT_MAX_RESPONSE_SIZE, // MaxResponseSize
+ 0 // ManufacturerID
+ },
+ &mTcgClientAcpiTemplate,
+ &mTcgServerAcpiTemplate,
+};
+
+UINTN mBootAttempts = 0;
+CHAR16 mBootVarName[] = L"BootOrder";
+
+VARIABLE_TYPE mVariableType[] = {
+ {EFI_SECURE_BOOT_MODE_NAME, &gEfiGlobalVariableGuid},
+ {EFI_PLATFORM_KEY_NAME, &gEfiGlobalVariableGuid},
+ {EFI_KEY_EXCHANGE_KEY_NAME, &gEfiGlobalVariableGuid},
+ {EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid},
+ {EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid},
+};
+
+EFI_HANDLE mImageHandle;
+
+/**
+ Measure PE image into TPM log based on the authenticode image hashing in
+ PE/COFF Specification 8.0 Appendix A.
+
+ Caution: This function may receive untrusted input.
+ PE/COFF image is external input, so this function will validate its data structure
+ within this image buffer before use.
+
+ Notes: PE/COFF image is checked by BasePeCoffLib PeCoffLoaderGetImageInfo().
+
+ @param[in] PCRIndex TPM PCR index
+ @param[in] ImageAddress Start address of image buffer.
+ @param[in] ImageSize Image size
+ @param[out] DigestList Digeest list of this image.
+
+ @retval EFI_SUCCESS Successfully measure image.
+ @retval EFI_OUT_OF_RESOURCES No enough resource to measure image.
+ @retval other error value
+**/
+EFI_STATUS
+MeasurePeImageAndExtend (
+ IN UINT32 PCRIndex,
+ IN EFI_PHYSICAL_ADDRESS ImageAddress,
+ IN UINTN ImageSize,
+ OUT TPML_DIGEST_VALUES *DigestList
+ );
+
+/**
+
+ This function dump raw data.
+
+ @param Data raw data
+ @param Size raw data size
+
+**/
+VOID
+InternalDumpData (
+ IN UINT8 *Data,
+ IN UINTN Size
+ )
+{
+ UINTN Index;
+ for (Index = 0; Index < Size; Index++) {
+ DEBUG ((EFI_D_INFO, "%02x", (UINTN)Data[Index]));
+ }
+}
+
+/**
+
+ This function dump raw data with colume format.
+
+ @param Data raw data
+ @param Size raw data size
+
+**/
+VOID
+InternalDumpHex (
+ IN UINT8 *Data,
+ IN UINTN Size
+ )
+{
+ UINTN Index;
+ UINTN Count;
+ UINTN Left;
+
+#define COLUME_SIZE (16 * 2)
+
+ Count = Size / COLUME_SIZE;
+ Left = Size % COLUME_SIZE;
+ for (Index = 0; Index < Count; Index++) {
+ DEBUG ((EFI_D_INFO, "%04x: ", Index * COLUME_SIZE));
+ InternalDumpData (Data + Index * COLUME_SIZE, COLUME_SIZE);
+ DEBUG ((EFI_D_INFO, "\n"));
+ }
+
+ if (Left != 0) {
+ DEBUG ((EFI_D_INFO, "%04x: ", Index * COLUME_SIZE));
+ InternalDumpData (Data + Index * COLUME_SIZE, Left);
+ DEBUG ((EFI_D_INFO, "\n"));
+ }
+}
+
+/**
+ Get All processors EFI_CPU_LOCATION in system. LocationBuf is allocated inside the function
+ Caller is responsible to free LocationBuf.
+
+ @param[out] LocationBuf Returns Processor Location Buffer.
+ @param[out] Num Returns processor number.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_UNSUPPORTED MpService protocol not found.
+
+**/
+EFI_STATUS
+GetProcessorsCpuLocation (
+ OUT EFI_CPU_PHYSICAL_LOCATION **LocationBuf,
+ OUT UINTN *Num
+ )
+{
+ EFI_STATUS Status;
+ EFI_MP_SERVICES_PROTOCOL *MpProtocol;
+ UINTN ProcessorNum;
+ UINTN EnabledProcessorNum;
+ EFI_PROCESSOR_INFORMATION ProcessorInfo;
+ EFI_CPU_PHYSICAL_LOCATION *ProcessorLocBuf;
+ UINTN Index;
+
+ Status = gBS->LocateProtocol (&gEfiMpServiceProtocolGuid, NULL, (VOID **) &MpProtocol);
+ if (EFI_ERROR (Status)) {
+ //
+ // MP protocol is not installed
+ //
+ return EFI_UNSUPPORTED;
+ }
+
+ Status = MpProtocol->GetNumberOfProcessors(
+ MpProtocol,
+ &ProcessorNum,
+ &EnabledProcessorNum
+ );
+ if (EFI_ERROR(Status)){
+ return Status;
+ }
+
+ Status = gBS->AllocatePool(
+ EfiBootServicesData,
+ sizeof(EFI_CPU_PHYSICAL_LOCATION) * ProcessorNum,
+ (VOID **) &ProcessorLocBuf
+ );
+ if (EFI_ERROR(Status)){
+ return Status;
+ }
+
+ //
+ // Get each processor Location info
+ //
+ for (Index = 0; Index < ProcessorNum; Index++) {
+ Status = MpProtocol->GetProcessorInfo(
+ MpProtocol,
+ Index,
+ &ProcessorInfo
+ );
+ if (EFI_ERROR(Status)){
+ FreePool(ProcessorLocBuf);
+ return Status;
+ }
+
+ //
+ // Get all Processor Location info & measure
+ //
+ CopyMem(
+ &ProcessorLocBuf[Index],
+ &ProcessorInfo.Location,
+ sizeof(EFI_CPU_PHYSICAL_LOCATION)
+ );
+ }
+
+ *LocationBuf = ProcessorLocBuf;
+ *Num = ProcessorNum;
+
+ return Status;
+}
+
+/**
+ The EFI_TREE_PROTOCOL GetCapability function call provides protocol
+ capability information and state information about the TrEE.
+
+ @param[in] This Indicates the calling context
+ @param[in, out] ProtocolCapability The caller allocates memory for a TREE_BOOT_SERVICE_CAPABILITY
+ structure and sets the size field to the size of the structure allocated.
+ The callee fills in the fields with the EFI protocol capability information
+ and the current TrEE state information up to the number of fields which
+ fit within the size of the structure passed in.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+ The ProtocolCapability variable will not be populated.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters are incorrect.
+ The ProtocolCapability variable will not be populated.
+ @retval EFI_BUFFER_TOO_SMALL The ProtocolCapability variable is too small to hold the full response.
+ It will be partially populated (required Size field will be set).
+**/
+EFI_STATUS
+EFIAPI
+TreeGetCapability (
+ IN EFI_TREE_PROTOCOL *This,
+ IN OUT TREE_BOOT_SERVICE_CAPABILITY *ProtocolCapability
+ )
+{
+ DEBUG ((EFI_D_INFO, "TreeGetCapability ...\n"));
+
+ if ((This == NULL) || (ProtocolCapability == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (ProtocolCapability->Size < mTcgDxeData.BsCap.Size) {
+ ProtocolCapability->Size = mTcgDxeData.BsCap.Size;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ CopyMem (ProtocolCapability, &mTcgDxeData.BsCap, mTcgDxeData.BsCap.Size);
+ DEBUG ((EFI_D_INFO, "TreeGetCapability - %r\n", EFI_SUCCESS));
+ return EFI_SUCCESS;
+}
+
+/**
+ This function dump event log.
+
+ @param[in] EventLogFormat The type of the event log for which the information is requested.
+ @param[in] EventLogLocation A pointer to the memory address of the event log.
+ @param[in] 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.
+**/
+VOID
+DumpEventLog (
+ IN TREE_EVENT_LOG_FORMAT EventLogFormat,
+ IN EFI_PHYSICAL_ADDRESS EventLogLocation,
+ IN EFI_PHYSICAL_ADDRESS EventLogLastEntry
+ )
+{
+ TCG_PCR_EVENT_HDR *EventHdr;
+ UINTN Index;
+
+ DEBUG ((EFI_D_INFO, "EventLogFormat: (0x%x)\n", EventLogFormat));
+
+ switch (EventLogFormat) {
+ case TREE_EVENT_LOG_FORMAT_TCG_1_2:
+ EventHdr = (TCG_PCR_EVENT_HDR *)(UINTN)EventLogLocation;
+ while ((UINTN)EventHdr <= EventLogLastEntry) {
+ DEBUG ((EFI_D_INFO, " Event:\n"));
+ DEBUG ((EFI_D_INFO, " PCRIndex - %d\n", EventHdr->PCRIndex));
+ DEBUG ((EFI_D_INFO, " EventType - 0x%08x\n", EventHdr->EventType));
+ DEBUG ((EFI_D_INFO, " Digest - "));
+ for (Index = 0; Index < sizeof(TCG_DIGEST); Index++) {
+ DEBUG ((EFI_D_INFO, "%02x ", EventHdr->Digest.digest[Index]));
+ }
+ DEBUG ((EFI_D_INFO, "\n"));
+ DEBUG ((EFI_D_INFO, " EventSize - 0x%08x\n", EventHdr->EventSize));
+ InternalDumpHex ((UINT8 *)(EventHdr + 1), EventHdr->EventSize);
+ EventHdr = (TCG_PCR_EVENT_HDR *)((UINTN)EventHdr + sizeof(TCG_PCR_EVENT_HDR) + EventHdr->EventSize);
+ }
+ break;
+ }
+
+ return ;
+}
+
+/**
+ The EFI_TREE_PROTOCOL Get Event Log function call allows a caller to
+ retrieve the address of a given event log and its last entry.
+
+ @param[in] This Indicates the calling context
+ @param[in] EventLogFormat The type of the event log for which the information is requested.
+ @param[out] EventLogLocation A pointer to the memory address of the event log.
+ @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.
+ @param[out] EventLogTruncated If the Event Log is missing at least one entry because an event would
+ have exceeded the area allocated for events, this value is set to TRUE.
+ Otherwise, the value will be FALSE and the Event Log will be complete.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters are incorrect
+ (e.g. asking for an event log whose format is not supported).
+**/
+EFI_STATUS
+EFIAPI
+TreeGetEventLog (
+ IN EFI_TREE_PROTOCOL *This,
+ IN TREE_EVENT_LOG_FORMAT EventLogFormat,
+ OUT EFI_PHYSICAL_ADDRESS *EventLogLocation,
+ OUT EFI_PHYSICAL_ADDRESS *EventLogLastEntry,
+ OUT BOOLEAN *EventLogTruncated
+ )
+{
+ UINTN Index;
+
+ DEBUG ((EFI_D_INFO, "TreeGetEventLog ...\n"));
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ for (Index = 0; Index < sizeof(mTreeEventInfo)/sizeof(mTreeEventInfo[0]); Index++) {
+ if (EventLogFormat == mTreeEventInfo[Index].LogFormat) {
+ break;
+ }
+ }
+
+ if (Index == sizeof(mTreeEventInfo)/sizeof(mTreeEventInfo[0])) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!mTcgDxeData.BsCap.TrEEPresentFlag) {
+ if (EventLogLocation != NULL) {
+ *EventLogLocation = 0;
+ }
+ if (EventLogLastEntry != NULL) {
+ *EventLogLastEntry = 0;
+ }
+ if (EventLogTruncated != NULL) {
+ *EventLogTruncated = FALSE;
+ }
+ return EFI_SUCCESS;
+ }
+
+ if (EventLogLocation != NULL) {
+ *EventLogLocation = mTcgDxeData.EventLogAreaStruct[Index].Lasa;
+ DEBUG ((EFI_D_INFO, "TreeGetEventLog (EventLogLocation - %x)\n", *EventLogLocation));
+ }
+
+ if (EventLogLastEntry != NULL) {
+ if (!mTcgDxeData.EventLogAreaStruct[Index].EventLogStarted) {
+ *EventLogLastEntry = (EFI_PHYSICAL_ADDRESS)(UINTN)0;
+ } else {
+ *EventLogLastEntry = (EFI_PHYSICAL_ADDRESS)(UINTN)mTcgDxeData.EventLogAreaStruct[Index].LastEvent;
+ }
+ DEBUG ((EFI_D_INFO, "TreeGetEventLog (EventLogLastEntry - %x)\n", *EventLogLastEntry));
+ }
+
+ if (EventLogTruncated != NULL) {
+ *EventLogTruncated = mTcgDxeData.EventLogAreaStruct[Index].EventLogTruncated;
+ DEBUG ((EFI_D_INFO, "TreeGetEventLog (EventLogTruncated - %x)\n", *EventLogTruncated));
+ }
+
+ DEBUG ((EFI_D_INFO, "TreeGetEventLog - %r\n", EFI_SUCCESS));
+
+ // Dump Event Log for debug purpose
+ if ((EventLogLocation != NULL) && (EventLogLastEntry != NULL)) {
+ DumpEventLog (EventLogFormat, *EventLogLocation, *EventLogLastEntry);
+ }
+
+ 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/TCG_PCR_EVENT_EX data structure.
+ @param[in] NewEventHdrSize New event header size.
+ @param[in] NewEventData Pointer to the new event data.
+ @param[in] NewEventSize New event data size.
+
+ @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
+TcgCommLogEvent (
+ IN OUT UINT8 **EventLogPtr,
+ IN OUT UINTN *LogSize,
+ IN UINTN MaxSize,
+ IN VOID *NewEventHdr,
+ IN UINT32 NewEventHdrSize,
+ IN UINT8 *NewEventData,
+ IN UINT32 NewEventSize
+ )
+{
+ UINTN NewLogSize;
+
+ if (NewEventSize > MAX_ADDRESS - NewEventHdrSize) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NewLogSize = NewEventHdrSize + NewEventSize;
+
+ if (NewLogSize > MAX_ADDRESS - *LogSize) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (NewLogSize + *LogSize > MaxSize) {
+ DEBUG ((EFI_D_INFO, " MaxSize - 0x%x\n", MaxSize));
+ DEBUG ((EFI_D_INFO, " NewLogSize - 0x%x\n", NewLogSize));
+ DEBUG ((EFI_D_INFO, " LogSize - 0x%x\n", *LogSize));
+ DEBUG ((EFI_D_INFO, "TcgCommLogEvent - %r\n", EFI_OUT_OF_RESOURCES));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ *EventLogPtr += *LogSize;
+ *LogSize += NewLogSize;
+ CopyMem (*EventLogPtr, NewEventHdr, NewEventHdrSize);
+ CopyMem (
+ *EventLogPtr + NewEventHdrSize,
+ NewEventData,
+ NewEventSize
+ );
+ return EFI_SUCCESS;
+}
+
+/**
+ Add a new entry to the Event Log.
+
+ @param[in] EventLogFormat The type of the event log for which the information is requested.
+ @param[in] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR/TCG_PCR_EVENT_EX data structure.
+ @param[in] NewEventHdrSize New event header size.
+ @param[in] NewEventData Pointer to the new event data.
+ @param[in] NewEventSize New event data size.
+
+ @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
+TcgDxeLogEvent (
+ IN TREE_EVENT_LOG_FORMAT EventLogFormat,
+ IN VOID *NewEventHdr,
+ IN UINT32 NewEventHdrSize,
+ IN UINT8 *NewEventData,
+ IN UINT32 NewEventSize
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+
+ for (Index = 0; Index < sizeof(mTreeEventInfo)/sizeof(mTreeEventInfo[0]); Index++) {
+ if (EventLogFormat == mTreeEventInfo[Index].LogFormat) {
+ break;
+ }
+ }
+
+ if (Index == sizeof(mTreeEventInfo)/sizeof(mTreeEventInfo[0])) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (mTcgDxeData.EventLogAreaStruct[Index].EventLogTruncated) {
+ return EFI_VOLUME_FULL;
+ }
+
+ mTcgDxeData.EventLogAreaStruct[Index].LastEvent = (UINT8*)(UINTN)mTcgDxeData.EventLogAreaStruct[Index].Lasa;
+ Status = TcgCommLogEvent (
+ &mTcgDxeData.EventLogAreaStruct[Index].LastEvent,
+ &mTcgDxeData.EventLogAreaStruct[Index].EventLogSize,
+ (UINTN)mTcgDxeData.EventLogAreaStruct[Index].Laml,
+ NewEventHdr,
+ NewEventHdrSize,
+ NewEventData,
+ NewEventSize
+ );
+
+ if (Status == EFI_DEVICE_ERROR) {
+ return EFI_DEVICE_ERROR;
+ } else if (Status == EFI_OUT_OF_RESOURCES) {
+ mTcgDxeData.EventLogAreaStruct[Index].EventLogTruncated = TRUE;
+ return EFI_VOLUME_FULL;
+ } else if (Status == EFI_SUCCESS) {
+ mTcgDxeData.EventLogAreaStruct[Index].EventLogStarted = TRUE;
+ }
+
+ return Status;
+}
+
+/**
+ Add a new entry to the Event Log.
+
+ @param[in] DigestList A list of digest.
+ @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 The new event log entry was added.
+ @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.
+**/
+EFI_STATUS
+TcgDxeLogHashEvent (
+ IN TPML_DIGEST_VALUES *DigestList,
+ IN OUT TCG_PCR_EVENT_HDR *NewEventHdr,
+ IN UINT8 *NewEventData
+ )
+{
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+ UINTN Index;
+ EFI_STATUS RetStatus;
+
+ RetStatus = EFI_SUCCESS;
+ for (Index = 0; Index < sizeof(mTreeEventInfo)/sizeof(mTreeEventInfo[0]); Index++) {
+ DEBUG ((EFI_D_INFO, " LogFormat - 0x%08x\n", mTreeEventInfo[Index].LogFormat));
+ switch (mTreeEventInfo[Index].LogFormat) {
+ case TREE_EVENT_LOG_FORMAT_TCG_1_2:
+ Status = GetDigestFromDigestList (TPM_ALG_SHA1, DigestList, &NewEventHdr->Digest);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Enter critical region
+ //
+ OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
+ Status = TcgDxeLogEvent (
+ mTreeEventInfo[Index].LogFormat,
+ NewEventHdr,
+ sizeof(TCG_PCR_EVENT_HDR),
+ NewEventData,
+ NewEventHdr->EventSize
+ );
+ if (Status != EFI_SUCCESS) {
+ RetStatus = Status;
+ }
+ gBS->RestoreTPL (OldTpl);
+ //
+ // Exit critical region
+ //
+ }
+ break;
+ }
+ }
+
+ return RetStatus;
+}
+
+/**
+ 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] Flags Bitmap providing additional information.
+ @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
+TcgDxeHashLogExtendEvent (
+ IN UINT64 Flags,
+ IN UINT8 *HashData,
+ IN UINT64 HashDataLen,
+ IN OUT TCG_PCR_EVENT_HDR *NewEventHdr,
+ IN UINT8 *NewEventData
+ )
+{
+ EFI_STATUS Status;
+ TPML_DIGEST_VALUES DigestList;
+
+ if (!mTcgDxeData.BsCap.TrEEPresentFlag) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = HashAndExtend (
+ NewEventHdr->PCRIndex,
+ HashData,
+ (UINTN)HashDataLen,
+ &DigestList
+ );
+ if (!EFI_ERROR (Status)) {
+ if ((Flags & TREE_EXTEND_ONLY) == 0) {
+ Status = TcgDxeLogHashEvent (&DigestList, NewEventHdr, NewEventData);
+ }
+ }
+
+ if (Status == EFI_DEVICE_ERROR) {
+ DEBUG ((EFI_D_ERROR, "TcgDxeHashLogExtendEvent - %r. Disable TPM.\n", Status));
+ mTcgDxeData.BsCap.TrEEPresentFlag = FALSE;
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ (PcdGet32 (PcdStatusCodeSubClassTpmDevice) | EFI_P_EC_INTERFACE_ERROR)
+ );
+ }
+
+ return Status;
+}
+
+/**
+ The EFI_TREE_PROTOCOL HashLogExtendEvent function call provides callers with
+ an opportunity to extend and optionally log events without requiring
+ knowledge of actual TPM commands.
+ The extend operation will occur even if this function cannot create an event
+ log entry (e.g. due to the event log being full).
+
+ @param[in] This Indicates the calling context
+ @param[in] Flags Bitmap providing additional information.
+ @param[in] DataToHash Physical address of the start of the data buffer to be hashed.
+ @param[in] DataToHashLen The length in bytes of the buffer referenced by DataToHash.
+ @param[in] Event Pointer to data buffer containing information about the event.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+ @retval EFI_VOLUME_FULL The extend operation occurred, but the event could not be written to one or more event logs.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters are incorrect.
+ @retval EFI_UNSUPPORTED The PE/COFF image type is not supported.
+**/
+EFI_STATUS
+EFIAPI
+TreeHashLogExtendEvent (
+ IN EFI_TREE_PROTOCOL *This,
+ IN UINT64 Flags,
+ IN EFI_PHYSICAL_ADDRESS DataToHash,
+ IN UINT64 DataToHashLen,
+ IN TrEE_EVENT *Event
+ )
+{
+ EFI_STATUS Status;
+ TCG_PCR_EVENT_HDR NewEventHdr;
+ TPML_DIGEST_VALUES DigestList;
+
+ DEBUG ((EFI_D_INFO, "TreeHashLogExtendEvent ...\n"));
+
+ if ((This == NULL) || (DataToHash == 0) || (Event == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!mTcgDxeData.BsCap.TrEEPresentFlag) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (Event->Size < Event->Header.HeaderSize + sizeof(UINT32)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Event->Header.PCRIndex > MAX_PCR_INDEX) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ NewEventHdr.PCRIndex = Event->Header.PCRIndex;
+ NewEventHdr.EventType = Event->Header.EventType;
+ NewEventHdr.EventSize = Event->Size - sizeof(UINT32) - Event->Header.HeaderSize;
+ if ((Flags & PE_COFF_IMAGE) != 0) {
+ Status = MeasurePeImageAndExtend (
+ NewEventHdr.PCRIndex,
+ DataToHash,
+ (UINTN)DataToHashLen,
+ &DigestList
+ );
+ if (!EFI_ERROR (Status)) {
+ if ((Flags & TREE_EXTEND_ONLY) == 0) {
+ Status = TcgDxeLogHashEvent (&DigestList, &NewEventHdr, Event->Event);
+ }
+ }
+ if (Status == EFI_DEVICE_ERROR) {
+ DEBUG ((EFI_D_ERROR, "MeasurePeImageAndExtend - %r. Disable TPM.\n", Status));
+ mTcgDxeData.BsCap.TrEEPresentFlag = FALSE;
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ (PcdGet32 (PcdStatusCodeSubClassTpmDevice) | EFI_P_EC_INTERFACE_ERROR)
+ );
+ }
+ } else {
+ Status = TcgDxeHashLogExtendEvent (
+ Flags,
+ (UINT8 *) (UINTN) DataToHash,
+ DataToHashLen,
+ &NewEventHdr,
+ Event->Event
+ );
+ }
+ DEBUG ((EFI_D_INFO, "TreeHashLogExtendEvent - %r\n", Status));
+ return Status;
+}
+
+/**
+ This service enables the sending of commands to the TrEE.
+
+ @param[in] This Indicates the calling context
+ @param[in] InputParameterBlockSize Size of the TrEE input parameter block.
+ @param[in] InputParameterBlock Pointer to the TrEE input parameter block.
+ @param[in] OutputParameterBlockSize Size of the TrEE output parameter block.
+ @param[in] OutputParameterBlock Pointer to the TrEE output parameter block.
+
+ @retval EFI_SUCCESS The command byte stream was successfully sent to the device and a response was successfully received.
+ @retval EFI_DEVICE_ERROR The command was not successfully sent to the device or a response was not successfully received from the device.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters are incorrect.
+ @retval EFI_BUFFER_TOO_SMALL The output parameter block is too small.
+**/
+EFI_STATUS
+EFIAPI
+TreeSubmitCommand (
+ IN EFI_TREE_PROTOCOL *This,
+ IN UINT32 InputParameterBlockSize,
+ IN UINT8 *InputParameterBlock,
+ IN UINT32 OutputParameterBlockSize,
+ IN UINT8 *OutputParameterBlock
+ )
+{
+ EFI_STATUS Status;
+
+ DEBUG ((EFI_D_INFO, "TreeSubmitCommand ...\n"));
+
+ if ((This == NULL) ||
+ (InputParameterBlockSize == 0) || (InputParameterBlock == NULL) ||
+ (OutputParameterBlockSize == 0) || (OutputParameterBlock == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!mTcgDxeData.BsCap.TrEEPresentFlag) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (InputParameterBlockSize > mTcgDxeData.BsCap.MaxCommandSize) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (OutputParameterBlockSize > mTcgDxeData.BsCap.MaxResponseSize) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = Tpm2SubmitCommand (
+ InputParameterBlockSize,
+ InputParameterBlock,
+ &OutputParameterBlockSize,
+ OutputParameterBlock
+ );
+ DEBUG ((EFI_D_INFO, "TreeSubmitCommand - %r\n", Status));
+ return Status;
+}
+
+
+EFI_TREE_PROTOCOL mTreeProtocol = {
+ TreeGetCapability,
+ TreeGetEventLog,
+ TreeHashLogExtendEvent,
+ TreeSubmitCommand
+};
+
+/**
+ 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
+SetupEventLog (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ VOID *TcgEvent;
+ EFI_PEI_HOB_POINTERS GuidHob;
+ EFI_PHYSICAL_ADDRESS Lasa;
+ UINTN Index;
+
+ DEBUG ((EFI_D_INFO, "SetupEventLog\n"));
+
+ //
+ // 1. Create Log Area
+ //
+ for (Index = 0; Index < sizeof(mTreeEventInfo)/sizeof(mTreeEventInfo[0]); Index++) {
+ mTcgDxeData.EventLogAreaStruct[Index].EventLogFormat = mTreeEventInfo[Index].LogFormat;
+ Lasa = (EFI_PHYSICAL_ADDRESS) (SIZE_4GB - 1);
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiACPIMemoryNVS,
+ EFI_SIZE_TO_PAGES (PcdGet32 (PcdTcgLogAreaMinLen)),
+ &Lasa
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ mTcgDxeData.EventLogAreaStruct[Index].Lasa = Lasa;
+ mTcgDxeData.EventLogAreaStruct[Index].Laml = PcdGet32 (PcdTcgLogAreaMinLen);
+ //
+ // To initialize them as 0xFF is recommended
+ // because the OS can know the last entry for that.
+ //
+ SetMem ((VOID *)(UINTN)Lasa, PcdGet32 (PcdTcgLogAreaMinLen), 0xFF);
+ }
+
+ //
+ // 2. Create ACPI table for TCG1.2 only
+ //
+ if (PcdGet8 (PcdTpmPlatformClass) == TCG_PLATFORM_TYPE_CLIENT) {
+ mTcgClientAcpiTemplate.Lasa = mTcgDxeData.EventLogAreaStruct[0].Lasa;
+ mTcgClientAcpiTemplate.Laml = PcdGet32 (PcdTcgLogAreaMinLen);
+ } else {
+ mTcgServerAcpiTemplate.Lasa = mTcgDxeData.EventLogAreaStruct[0].Lasa;
+ mTcgServerAcpiTemplate.Laml = PcdGet32 (PcdTcgLogAreaMinLen);
+ }
+
+ //
+ // 3. Sync data from PEI to DXE
+ //
+ Status = EFI_SUCCESS;
+ for (Index = 0; Index < sizeof(mTreeEventInfo)/sizeof(mTreeEventInfo[0]); Index++) {
+ GuidHob.Raw = GetHobList ();
+ Status = EFI_SUCCESS;
+ while (!EFI_ERROR (Status) &&
+ (GuidHob.Raw = GetNextGuidHob (mTreeEventInfo[Index].EventGuid, GuidHob.Raw)) != NULL) {
+ TcgEvent = GET_GUID_HOB_DATA (GuidHob.Guid);
+ GuidHob.Raw = GET_NEXT_HOB (GuidHob);
+ switch (mTreeEventInfo[Index].LogFormat) {
+ case TREE_EVENT_LOG_FORMAT_TCG_1_2:
+ Status = TcgDxeLogEvent (
+ mTreeEventInfo[Index].LogFormat,
+ TcgEvent,
+ sizeof(TCG_PCR_EVENT_HDR),
+ ((TCG_PCR_EVENT*)TcgEvent)->Event,
+ ((TCG_PCR_EVENT_HDR*)TcgEvent)->EventSize
+ );
+ break;
+ }
+ }
+ }
+
+ 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
+TcgMeasureAction (
+ IN CHAR8 *String
+ )
+{
+ TCG_PCR_EVENT_HDR TcgEvent;
+
+ TcgEvent.PCRIndex = 5;
+ TcgEvent.EventType = EV_EFI_ACTION;
+ TcgEvent.EventSize = (UINT32)AsciiStrLen (String);
+ return TcgDxeHashLogExtendEvent (
+ 0,
+ (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
+MeasureHandoffTables (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ TCG_PCR_EVENT_HDR TcgEvent;
+ EFI_HANDOFF_TABLE_POINTERS HandoffTables;
+ UINTN ProcessorNum;
+ EFI_CPU_PHYSICAL_LOCATION *ProcessorLocBuf;
+
+ ProcessorLocBuf = NULL;
+ Status = EFI_SUCCESS;
+
+ if (PcdGet8 (PcdTpmPlatformClass) == TCG_PLATFORM_TYPE_SERVER) {
+ //
+ // Tcg Server spec.
+ // Measure each processor EFI_CPU_PHYSICAL_LOCATION with EV_TABLE_OF_DEVICES to PCR[1]
+ //
+ Status = GetProcessorsCpuLocation(&ProcessorLocBuf, &ProcessorNum);
+
+ if (!EFI_ERROR(Status)){
+ TcgEvent.PCRIndex = 1;
+ TcgEvent.EventType = EV_TABLE_OF_DEVICES;
+ TcgEvent.EventSize = sizeof (HandoffTables);
+
+ HandoffTables.NumberOfTables = 1;
+ HandoffTables.TableEntry[0].VendorGuid = gEfiMpServiceProtocolGuid;
+ HandoffTables.TableEntry[0].VendorTable = ProcessorLocBuf;
+
+ Status = TcgDxeHashLogExtendEvent (
+ 0,
+ (UINT8*)(UINTN)ProcessorLocBuf,
+ sizeof(EFI_CPU_PHYSICAL_LOCATION) * ProcessorNum,
+ &TcgEvent,
+ (UINT8*)&HandoffTables
+ );
+
+ FreePool(ProcessorLocBuf);
+ }
+ }
+
+ 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
+MeasureSeparatorEvent (
+ IN TPM_PCRINDEX PCRIndex
+ )
+{
+ TCG_PCR_EVENT_HDR TcgEvent;
+ UINT32 EventData;
+
+ DEBUG ((EFI_D_INFO, "MeasureSeparatorEvent Pcr - %x\n", PCRIndex));
+
+ EventData = 0;
+ TcgEvent.PCRIndex = PCRIndex;
+ TcgEvent.EventType = EV_SEPARATOR;
+ TcgEvent.EventSize = (UINT32)sizeof (EventData);
+ return TcgDxeHashLogExtendEvent (
+ 0,
+ (UINT8 *)&EventData,
+ sizeof (EventData),
+ &TcgEvent,
+ (UINT8 *)&EventData
+ );
+}
+
+/**
+ 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
+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_TREE *VarLog;
+
+ DEBUG ((EFI_D_INFO, "TrEEDxe: MeasureVariable (Pcr - %x, EventType - %x, ", (UINTN)PCRIndex, (UINTN)EventType));
+ DEBUG ((EFI_D_INFO, "VariableName - %s, VendorGuid - %g)\n", VarName, VendorGuid));
+
+ 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_TREE*)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)
+ );
+ if (VarSize != 0 && VarData != NULL) {
+ CopyMem (
+ (CHAR16 *)VarLog->UnicodeName + VarNameLength,
+ VarData,
+ VarSize
+ );
+ }
+
+ Status = TcgDxeHashLogExtendEvent (
+ 0,
+ (UINT8*)VarLog,
+ TcgEvent.EventSize,
+ &TcgEvent,
+ (UINT8*)VarLog
+ );
+
+ FreePool (VarLog);
+ return Status;
+}
+
+/**
+ Read then 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[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
+ReadAndMeasureVariable (
+ IN TPM_PCRINDEX PCRIndex,
+ IN TCG_EVENTTYPE EventType,
+ IN CHAR16 *VarName,
+ IN EFI_GUID *VendorGuid,
+ OUT UINTN *VarSize,
+ OUT VOID **VarData
+ )
+{
+ EFI_STATUS Status;
+
+ Status = GetVariable2 (VarName, VendorGuid, VarData, VarSize);
+ if (EventType == EV_EFI_VARIABLE_DRIVER_CONFIG) {
+ if (EFI_ERROR (Status)) {
+ //
+ // It is valid case, so we need handle it.
+ //
+ *VarData = NULL;
+ *VarSize = 0;
+ }
+ } else {
+ //
+ // if status error, VarData is freed and set NULL by GetVariable2
+ //
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ Status = MeasureVariable (
+ PCRIndex,
+ EventType,
+ VarName,
+ VendorGuid,
+ *VarData,
+ *VarSize
+ );
+ 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
+ReadAndMeasureBootVariable (
+ IN CHAR16 *VarName,
+ IN EFI_GUID *VendorGuid,
+ OUT UINTN *VarSize,
+ OUT VOID **VarData
+ )
+{
+ return ReadAndMeasureVariable (
+ 5,
+ EV_EFI_VARIABLE_BOOT,
+ VarName,
+ VendorGuid,
+ VarSize,
+ VarData
+ );
+}
+
+/**
+ Read then Measure and log an EFI Secure variable, and extend the measurement result into PCR[7].
+
+ @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
+ReadAndMeasureSecureVariable (
+ IN CHAR16 *VarName,
+ IN EFI_GUID *VendorGuid,
+ OUT UINTN *VarSize,
+ OUT VOID **VarData
+ )
+{
+ return ReadAndMeasureVariable (
+ 7,
+ EV_EFI_VARIABLE_DRIVER_CONFIG,
+ VarName,
+ VendorGuid,
+ VarSize,
+ VarData
+ );
+}
+
+/**
+ 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
+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 || BootOrder == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ if (EFI_ERROR (Status)) {
+ //
+ // BootOrder can't be NULL if status is not EFI_NOT_FOUND
+ //
+ 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;
+}
+
+/**
+ Measure and log all EFI Secure 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
+MeasureAllSecureVariables (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ VOID *Data;
+ UINTN DataSize;
+ UINTN Index;
+
+ Status = EFI_NOT_FOUND;
+ for (Index = 0; Index < sizeof(mVariableType)/sizeof(mVariableType[0]); Index++) {
+ Status = ReadAndMeasureSecureVariable (
+ mVariableType[Index].VariableName,
+ mVariableType[Index].VendorGuid,
+ &DataSize,
+ &Data
+ );
+ if (!EFI_ERROR (Status)) {
+ if (Data != NULL) {
+ FreePool (Data);
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Measure and log launch of FirmwareDebugger, and extend the measurement result into a specific PCR.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_OUT_OF_RESOURCES Out of memory.
+ @retval EFI_DEVICE_ERROR The operation was unsuccessful.
+
+**/
+EFI_STATUS
+MeasureLaunchOfFirmwareDebugger (
+ VOID
+ )
+{
+ TCG_PCR_EVENT_HDR TcgEvent;
+
+ TcgEvent.PCRIndex = 7;
+ TcgEvent.EventType = EV_EFI_ACTION;
+ TcgEvent.EventSize = sizeof(FIRMWARE_DEBUGGER_EVENT_STRING) - 1;
+ return TcgDxeHashLogExtendEvent (
+ 0,
+ (UINT8 *)FIRMWARE_DEBUGGER_EVENT_STRING,
+ sizeof(FIRMWARE_DEBUGGER_EVENT_STRING) - 1,
+ &TcgEvent,
+ (UINT8 *)FIRMWARE_DEBUGGER_EVENT_STRING
+ );
+}
+
+/**
+ Measure and log all Secure Boot Policy, and extend the measurement result into a specific PCR.
+
+ Platform firmware adhering to the policy must therefore measure the following values into PCR[7]: (in order listed)
+ - The contents of the SecureBoot variable
+ - The contents of the PK variable
+ - The contents of the KEK variable
+ - The contents of the EFI_IMAGE_SECURITY_DATABASE variable
+ - The contents of the EFI_IMAGE_SECURITY_DATABASE1 variable
+ - Separator
+ - Entries in the EFI_IMAGE_SECURITY_DATABASE that are used to validate EFI Drivers or EFI Boot Applications in the boot path
+
+ NOTE: Because of the above, UEFI variables PK, KEK, EFI_IMAGE_SECURITY_DATABASE,
+ EFI_IMAGE_SECURITY_DATABASE1 and SecureBoot SHALL NOT be measured into PCR[3].
+
+ @param[in] Event Event whose notification function is being invoked
+ @param[in] Context Pointer to the notification function's context
+**/
+VOID
+EFIAPI
+MeasureSecureBootPolicy (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ VOID *Protocol;
+
+ Status = gBS->LocateProtocol (&gEfiVariableWriteArchProtocolGuid, NULL, (VOID **)&Protocol);
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ if (PcdGetBool (PcdFirmwareDebuggerInitialized)) {
+ Status = MeasureLaunchOfFirmwareDebugger ();
+ DEBUG ((EFI_D_INFO, "MeasureLaunchOfFirmwareDebugger - %r\n", Status));
+ }
+
+ Status = MeasureAllSecureVariables ();
+ DEBUG ((EFI_D_INFO, "MeasureAllSecureVariables - %r\n", Status));
+
+ //
+ // We need measure Separator(7) here, because this event must be between SecureBootPolicy (Configure)
+ // and ImageVerification (Authority)
+ // There might be a case that we need measure UEFI image from DriverOrder, besides BootOrder. So
+ // the Authority measurement happen before ReadToBoot event.
+ //
+ Status = MeasureSeparatorEvent (7);
+ DEBUG ((EFI_D_INFO, "MeasureSeparatorEvent - %r\n", Status));
+ return ;
+}
+
+/**
+ 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;
+
+ PERF_START_EX (mImageHandle, "EventRec", "TrEEDxe", 0, PERF_ID_TREE_DXE);
+ 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
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "%a not Measured. Error!\n", EFI_CALLING_EFI_APPLICATION));
+ }
+
+ //
+ // 2. Draw a line between pre-boot env and entering post-boot env.
+ // PCR[7] is already done.
+ //
+ for (PcrIndex = 0; PcrIndex < 7; PcrIndex++) {
+ Status = MeasureSeparatorEvent (PcrIndex);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Seperator Event not Measured. Error!\n"));
+ }
+ }
+
+ //
+ // 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
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "%a not Measured. Error!\n", EFI_RETURNING_FROM_EFI_APPLICATOIN));
+ }
+ }
+
+ DEBUG ((EFI_D_INFO, "TPM2 TrEEDxe Measure Data when ReadyToBoot\n"));
+ //
+ // Increase boot attempt counter.
+ //
+ mBootAttempts++;
+ PERF_END_EX (mImageHandle, "EventRec", "TrEEDxe", 0, PERF_ID_TREE_DXE + 1);
+}
+
+/**
+ 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;
+ UINT64 OemTableId;
+
+ Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **)&AcpiTable);
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ if (PcdGet8 (PcdTpmPlatformClass) == TCG_PLATFORM_TYPE_CLIENT) {
+ CopyMem (mTcgClientAcpiTemplate.Header.OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (mTcgClientAcpiTemplate.Header.OemId));
+ OemTableId = PcdGet64 (PcdAcpiDefaultOemTableId);
+ CopyMem (&mTcgClientAcpiTemplate.Header.OemTableId, &OemTableId, sizeof (UINT64));
+ mTcgClientAcpiTemplate.Header.OemRevision = PcdGet32 (PcdAcpiDefaultOemRevision);
+ mTcgClientAcpiTemplate.Header.CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId);
+ mTcgClientAcpiTemplate.Header.CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision);
+ //
+ // 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 {
+ CopyMem (mTcgServerAcpiTemplate.Header.OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (mTcgServerAcpiTemplate.Header.OemId));
+ OemTableId = PcdGet64 (PcdAcpiDefaultOemTableId);
+ CopyMem (&mTcgServerAcpiTemplate.Header.OemTableId, &OemTableId, sizeof (UINT64));
+ mTcgServerAcpiTemplate.Header.OemRevision = PcdGet32 (PcdAcpiDefaultOemRevision);
+ mTcgServerAcpiTemplate.Header.CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId);
+ mTcgServerAcpiTemplate.Header.CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision);
+ //
+ // 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;
+
+ mTcgServerAcpiTemplate.BaseAddress.Address = PcdGet64 (PcdTpmBaseAddress);
+ Status = AcpiTable->InstallAcpiTable (
+ AcpiTable,
+ &mTcgServerAcpiTemplate,
+ sizeof (mTcgServerAcpiTemplate),
+ &TableKey
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+ DEBUG((EFI_D_ERROR, "Tcg Acpi Table installation failure"));
+ }
+}
+
+/**
+ 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
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "%a not Measured. Error!\n", EFI_EXIT_BOOT_SERVICES_INVOCATION));
+ }
+
+ //
+ // Measure success of ExitBootServices
+ //
+ Status = TcgMeasureAction (
+ EFI_EXIT_BOOT_SERVICES_SUCCEEDED
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "%a not Measured. Error!\n", EFI_EXIT_BOOT_SERVICES_SUCCEEDED));
+ }
+}
+
+/**
+ Exit Boot Services Failed Event notification handler.
+
+ Measure Failure of ExitBootServices.
+
+ @param[in] Event Event whose notification function is being invoked
+ @param[in] Context Pointer to the notification function's context
+
+**/
+VOID
+EFIAPI
+OnExitBootServicesFailed (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Measure Failure of ExitBootServices,
+ //
+ Status = TcgMeasureAction (
+ EFI_EXIT_BOOT_SERVICES_FAILED
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "%a not Measured. Error!\n", EFI_EXIT_BOOT_SERVICES_FAILED));
+ }
+
+}
+
+/**
+ The function install TrEE protocol.
+
+ @retval EFI_SUCCESS TrEE protocol is installed.
+ @retval other Some error occurs.
+**/
+EFI_STATUS
+InstallTrEE (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE Handle;
+
+ Handle = NULL;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Handle,
+ &gEfiTrEEProtocolGuid,
+ &mTreeProtocol,
+ NULL
+ );
+ return Status;
+}
+
+/**
+ The driver's entry point. It publishes EFI TrEE 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;
+ UINT32 MaxCommandSize;
+ UINT32 MaxResponseSize;
+ TPML_PCR_SELECTION Pcrs;
+ UINTN Index;
+ UINT32 TpmHashAlgorithmBitmap;
+
+ mImageHandle = ImageHandle;
+
+ if (CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceNoneGuid) ||
+ CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceTpm12Guid)){
+ DEBUG ((DEBUG_INFO, "No TPM2 instance required!\n"));
+ return EFI_UNSUPPORTED;
+ }
+
+ if (GetFirstGuidHob (&gTpmErrorHobGuid) != NULL) {
+ DEBUG ((EFI_D_ERROR, "TPM2 error!\n"));
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = Tpm2RequestUseTpm ();
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "TPM2 not detected!\n"));
+ return Status;
+ }
+
+ //
+ // Fill information
+ //
+ DEBUG ((EFI_D_INFO, "TrEE.ProtocolVersion - %02x.%02x\n", mTcgDxeData.BsCap.ProtocolVersion.Major, mTcgDxeData.BsCap.ProtocolVersion.Minor));
+ DEBUG ((EFI_D_INFO, "TrEE.StructureVersion - %02x.%02x\n", mTcgDxeData.BsCap.StructureVersion.Major, mTcgDxeData.BsCap.StructureVersion.Minor));
+
+ Status = Tpm2GetCapabilityManufactureID (&mTcgDxeData.BsCap.ManufacturerID);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Tpm2GetCapabilityManufactureID fail!\n"));
+ } else {
+ DEBUG ((EFI_D_INFO, "Tpm2GetCapabilityManufactureID - %08x\n", mTcgDxeData.BsCap.ManufacturerID));
+ }
+
+ DEBUG_CODE (
+ UINT32 FirmwareVersion1;
+ UINT32 FirmwareVersion2;
+
+ Status = Tpm2GetCapabilityFirmwareVersion (&FirmwareVersion1, &FirmwareVersion2);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Tpm2GetCapabilityFirmwareVersion fail!\n"));
+ } else {
+ DEBUG ((EFI_D_INFO, "Tpm2GetCapabilityFirmwareVersion - %08x %08x\n", FirmwareVersion1, FirmwareVersion2));
+ }
+ );
+
+ Status = Tpm2GetCapabilityMaxCommandResponseSize (&MaxCommandSize, &MaxResponseSize);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Tpm2GetCapabilityMaxCommandResponseSize fail!\n"));
+ } else {
+ mTcgDxeData.BsCap.MaxCommandSize = (UINT16)MaxCommandSize;
+ mTcgDxeData.BsCap.MaxResponseSize = (UINT16)MaxResponseSize;
+ DEBUG ((EFI_D_INFO, "Tpm2GetCapabilityMaxCommandResponseSize - %08x, %08x\n", MaxCommandSize, MaxResponseSize));
+ }
+
+ Status = Tpm2GetCapabilityPcrs (&Pcrs);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Tpm2GetCapabilityPcrs fail!\n"));
+ TpmHashAlgorithmBitmap = TREE_BOOT_HASH_ALG_SHA1;
+ } else {
+ DEBUG ((EFI_D_INFO, "Tpm2GetCapabilityPcrs Count - %08x\n", Pcrs.count));
+ TpmHashAlgorithmBitmap = 0;
+ for (Index = 0; Index < Pcrs.count; Index++) {
+ DEBUG ((EFI_D_INFO, "hash - %x\n", Pcrs.pcrSelections[Index].hash));
+ switch (Pcrs.pcrSelections[Index].hash) {
+ case TPM_ALG_SHA1:
+ TpmHashAlgorithmBitmap |= TREE_BOOT_HASH_ALG_SHA1;
+ break;
+ case TPM_ALG_SHA256:
+ TpmHashAlgorithmBitmap |= TREE_BOOT_HASH_ALG_SHA256;
+ break;
+ case TPM_ALG_SHA384:
+ TpmHashAlgorithmBitmap |= TREE_BOOT_HASH_ALG_SHA384;
+ break;
+ case TPM_ALG_SHA512:
+ TpmHashAlgorithmBitmap |= TREE_BOOT_HASH_ALG_SHA512;
+ break;
+ case TPM_ALG_SM3_256:
+ // TBD: Spec not define TREE_BOOT_HASH_ALG_SM3_256 yet
+ break;
+ }
+ }
+ }
+ DEBUG ((EFI_D_INFO, "TPM.HashAlgorithmBitmap - 0x%08x\n", TpmHashAlgorithmBitmap));
+
+ DEBUG ((EFI_D_INFO, "TrEE.SupportedEventLogs - 0x%08x\n", mTcgDxeData.BsCap.SupportedEventLogs));
+ mTcgDxeData.BsCap.HashAlgorithmBitmap = TpmHashAlgorithmBitmap;
+ DEBUG ((EFI_D_INFO, "TrEE.HashAlgorithmBitmap - 0x%08x\n", mTcgDxeData.BsCap.HashAlgorithmBitmap));
+
+ if (mTcgDxeData.BsCap.TrEEPresentFlag) {
+ //
+ // 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
+ );
+
+ //
+ // Measure Exit Boot Service failed
+ //
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ OnExitBootServicesFailed,
+ NULL,
+ &gEventExitBootServicesFailedGuid,
+ &Event
+ );
+
+ //
+ // Create event callback, because we need access variable on SecureBootPolicyVariable
+ // We should use VariableWriteArch instead of VariableArch, because Variable driver
+ // may update SecureBoot value based on last setting.
+ //
+ EfiCreateProtocolNotifyEvent (&gEfiVariableWriteArchProtocolGuid, TPL_CALLBACK, MeasureSecureBootPolicy, NULL, &Registration);
+ }
+
+ //
+ // Install ACPI Table
+ //
+ EfiCreateProtocolNotifyEvent (&gEfiAcpiTableProtocolGuid, TPL_CALLBACK, InstallAcpiTable, NULL, &Registration);
+
+ //
+ // Install TrEEProtocol
+ //
+ Status = InstallTrEE ();
+ DEBUG ((EFI_D_INFO, "InstallTrEE - %r\n", Status));
+
+ return Status;
+}
diff --git a/Core/SecurityPkg/Tcg/TrEEDxe/TrEEDxe.inf b/Core/SecurityPkg/Tcg/TrEEDxe/TrEEDxe.inf
new file mode 100644
index 0000000000..2dd038aba3
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TrEEDxe/TrEEDxe.inf
@@ -0,0 +1,104 @@
+## @file
+# Produces TrEE protocol and measure boot environment
+# This module will produce TrEE protocol and measure boot environment.
+#
+# Caution: This module requires additional review when modified.
+# This driver will have external input - PE/COFF image.
+# This external input must be validated carefully to avoid security issue like
+# buffer overflow, integer overflow.
+#
+# Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = TrEEDxe
+ MODULE_UNI_FILE = TrEEDxe.uni
+ FILE_GUID = 2A7946E3-1AB2-49a9-ACCB-C6275139C1A5
+ 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]
+ TrEEDxe.c
+ MeasureBootPeCoff.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ SecurityPkg/SecurityPkg.dec
+ CryptoPkg/CryptoPkg.dec
+
+[LibraryClasses]
+ MemoryAllocationLib
+ BaseLib
+ UefiBootServicesTableLib
+ HobLib
+ UefiDriverEntryPoint
+ UefiRuntimeServicesTableLib
+ BaseMemoryLib
+ DebugLib
+ Tpm2CommandLib
+ PrintLib
+ UefiLib
+ Tpm2DeviceLib
+ HashLib
+ PerformanceLib
+ ReportStatusCodeLib
+ PeCoffLib
+
+[Guids]
+ ## SOMETIMES_CONSUMES ## Variable:L"SecureBoot"
+ ## SOMETIMES_CONSUMES ## Variable:L"PK"
+ ## SOMETIMES_CONSUMES ## Variable:L"KEK"
+ ## SOMETIMES_CONSUMES ## Variable:L"BootXXXX"
+ gEfiGlobalVariableGuid
+
+ ## SOMETIMES_CONSUMES ## Variable:L"db"
+ ## SOMETIMES_CONSUMES ## Variable:L"dbx"
+ gEfiImageSecurityDatabaseGuid
+
+ gTcgEventEntryHobGuid ## SOMETIMES_CONSUMES ## HOB
+ gTpmErrorHobGuid ## SOMETIMES_CONSUMES ## HOB
+ gEfiEventExitBootServicesGuid ## CONSUMES ## Event
+ gEventExitBootServicesFailedGuid ## SOMETIMES_CONSUMES ## Event
+ gEfiTpmDeviceInstanceNoneGuid ## SOMETIMES_CONSUMES ## GUID # TPM device identifier
+ gEfiTpmDeviceInstanceTpm12Guid ## SOMETIMES_CONSUMES ## GUID # TPM device identifier
+
+[Protocols]
+ gEfiTrEEProtocolGuid ## PRODUCES
+ gEfiAcpiTableProtocolGuid ## NOTIFY
+ gEfiMpServiceProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiVariableWriteArchProtocolGuid ## NOTIFY
+
+[Pcd]
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpmPlatformClass ## SOMETIMES_CONSUMES
+ gEfiSecurityPkgTokenSpaceGuid.PcdFirmwareDebuggerInitialized ## SOMETIMES_CONSUMES
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpmInstanceGuid ## CONSUMES
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpmBaseAddress ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemId ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemTableId ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemRevision ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorId ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorRevision ## SOMETIMES_CONSUMES
+ gEfiSecurityPkgTokenSpaceGuid.PcdStatusCodeSubClassTpmDevice ## SOMETIMES_CONSUMES
+ gEfiSecurityPkgTokenSpaceGuid.PcdTcgLogAreaMinLen ## CONSUMES
+
+[Depex]
+ TRUE
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ TrEEDxeExtra.uni
diff --git a/Core/SecurityPkg/Tcg/TrEEDxe/TrEEDxe.uni b/Core/SecurityPkg/Tcg/TrEEDxe/TrEEDxe.uni
new file mode 100644
index 0000000000..fd7292d3a8
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TrEEDxe/TrEEDxe.uni
@@ -0,0 +1,26 @@
+// /** @file
+// Produces TrEE protocol and measure boot environment
+//
+// This module will produce TrEE protocol and measure boot environment.
+//
+// Caution: This module requires additional review when modified.
+// This driver will have external input - PE/COFF image.
+// This external input must be validated carefully to avoid security issue like
+// buffer overflow, integer overflow.
+//
+// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Produces TrEE protocol and measure boot environment"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This module will produce TrEE protocol and measure boot environment."
+
diff --git a/Core/SecurityPkg/Tcg/TrEEDxe/TrEEDxeExtra.uni b/Core/SecurityPkg/Tcg/TrEEDxe/TrEEDxeExtra.uni
new file mode 100644
index 0000000000..2ca23ebab7
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TrEEDxe/TrEEDxeExtra.uni
@@ -0,0 +1,17 @@
+// /** @file
+// TrEEDxe Localized Strings and Content
+//
+// Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"TrEE (Trusted Execution Environment) DXE" \ No newline at end of file
diff --git a/Core/SecurityPkg/Tcg/TrEEPei/TrEEPei.c b/Core/SecurityPkg/Tcg/TrEEPei/TrEEPei.c
new file mode 100644
index 0000000000..b561245790
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TrEEPei/TrEEPei.c
@@ -0,0 +1,690 @@
+/** @file
+ Initialize TPM2 device and measure FVs before handing off control to DXE.
+
+Copyright (c) 2013 - 2017, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiPei.h>
+
+#include <IndustryStandard/UefiTcgPlatform.h>
+#include <Ppi/FirmwareVolumeInfo.h>
+#include <Ppi/FirmwareVolumeInfo2.h>
+#include <Ppi/LockPhysicalPresence.h>
+#include <Ppi/TpmInitialized.h>
+#include <Ppi/FirmwareVolume.h>
+#include <Ppi/EndOfPeiPhase.h>
+#include <Ppi/FirmwareVolumeInfoMeasurementExcluded.h>
+
+#include <Guid/TcgEventHob.h>
+#include <Guid/MeasuredFvHob.h>
+#include <Guid/TpmInstance.h>
+
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/PeimEntryPoint.h>
+#include <Library/Tpm2CommandLib.h>
+#include <Library/Tpm2DeviceLib.h>
+#include <Library/HashLib.h>
+#include <Library/HobLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PeiServicesTablePointerLib.h>
+#include <Protocol/TrEEProtocol.h>
+#include <Library/PerformanceLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/ReportStatusCodeLib.h>
+
+#define PERF_ID_TREE_PEI 0x3080
+
+typedef struct {
+ EFI_GUID *EventGuid;
+ TREE_EVENT_LOG_FORMAT LogFormat;
+} TREE_EVENT_INFO_STRUCT;
+
+TREE_EVENT_INFO_STRUCT mTreeEventInfo[] = {
+ {&gTcgEventEntryHobGuid, TREE_EVENT_LOG_FORMAT_TCG_1_2},
+};
+
+BOOLEAN mImageInMemory = FALSE;
+EFI_PEI_FILE_HANDLE mFileHandle;
+
+EFI_PEI_PPI_DESCRIPTOR mTpmInitializedPpiList = {
+ EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
+ &gPeiTpmInitializedPpiGuid,
+ NULL
+};
+
+EFI_PEI_PPI_DESCRIPTOR mTpmInitializationDonePpiList = {
+ EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
+ &gPeiTpmInitializationDonePpiGuid,
+ NULL
+};
+
+EFI_PLATFORM_FIRMWARE_BLOB *mMeasuredBaseFvInfo;
+UINT32 mMeasuredBaseFvIndex = 0;
+
+EFI_PLATFORM_FIRMWARE_BLOB *mMeasuredChildFvInfo;
+UINT32 mMeasuredChildFvIndex = 0;
+
+/**
+ 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
+ );
+
+/**
+ Record all measured Firmware Volum Information into a Guid Hob
+
+ @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
+EndofPeiSignalNotifyCallBack (
+ 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,
+ &gEfiPeiFirmwareVolumeInfoPpiGuid,
+ FirmwareVolmeInfoPpiNotifyCallback
+ },
+ {
+ EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK,
+ &gEfiPeiFirmwareVolumeInfo2PpiGuid,
+ FirmwareVolmeInfoPpiNotifyCallback
+ },
+ {
+ (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEfiEndOfPeiSignalPpiGuid,
+ EndofPeiSignalNotifyCallBack
+ }
+};
+
+EFI_PEI_FIRMWARE_VOLUME_INFO_MEASUREMENT_EXCLUDED_PPI *mMeasurementExcludedFvPpi;
+
+/**
+ Record all measured Firmware Volum Information into a Guid Hob
+ Guid Hob payload layout is
+
+ UINT32 *************************** FIRMWARE_BLOB number
+ EFI_PLATFORM_FIRMWARE_BLOB******** BLOB Array
+
+ @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
+EndofPeiSignalNotifyCallBack (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *Ppi
+ )
+{
+ MEASURED_HOB_DATA *MeasuredHobData;
+
+ MeasuredHobData = NULL;
+
+ //
+ // Create a Guid hob to save all measured Fv
+ //
+ MeasuredHobData = BuildGuidHob(
+ &gMeasuredFvHobGuid,
+ sizeof(UINTN) + sizeof(EFI_PLATFORM_FIRMWARE_BLOB) * (mMeasuredBaseFvIndex + mMeasuredChildFvIndex)
+ );
+
+ if (MeasuredHobData != NULL){
+ //
+ // Save measured FV info enty number
+ //
+ MeasuredHobData->Num = mMeasuredBaseFvIndex + mMeasuredChildFvIndex;
+
+ //
+ // Save measured base Fv info
+ //
+ CopyMem (MeasuredHobData->MeasuredFvBuf, mMeasuredBaseFvInfo, sizeof(EFI_PLATFORM_FIRMWARE_BLOB) * (mMeasuredBaseFvIndex));
+
+ //
+ // Save measured child Fv info
+ //
+ CopyMem (&MeasuredHobData->MeasuredFvBuf[mMeasuredBaseFvIndex] , mMeasuredChildFvInfo, sizeof(EFI_PLATFORM_FIRMWARE_BLOB) * (mMeasuredChildFvIndex));
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Add a new entry to the Event Log.
+
+ @param[in] DigestList A list of digest.
+ @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 The new event log entry was added.
+ @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.
+**/
+EFI_STATUS
+LogHashEvent (
+ IN TPML_DIGEST_VALUES *DigestList,
+ IN OUT TCG_PCR_EVENT_HDR *NewEventHdr,
+ IN UINT8 *NewEventData
+ )
+{
+ VOID *HobData;
+ EFI_STATUS Status;
+ UINTN Index;
+ EFI_STATUS RetStatus;
+
+ RetStatus = EFI_SUCCESS;
+ for (Index = 0; Index < sizeof(mTreeEventInfo)/sizeof(mTreeEventInfo[0]); Index++) {
+ DEBUG ((EFI_D_INFO, " LogFormat - 0x%08x\n", mTreeEventInfo[Index].LogFormat));
+ switch (mTreeEventInfo[Index].LogFormat) {
+ case TREE_EVENT_LOG_FORMAT_TCG_1_2:
+ Status = GetDigestFromDigestList (TPM_ALG_SHA1, DigestList, &NewEventHdr->Digest);
+ if (!EFI_ERROR (Status)) {
+ HobData = BuildGuidHob (
+ &gTcgEventEntryHobGuid,
+ sizeof (*NewEventHdr) + NewEventHdr->EventSize
+ );
+ if (HobData == NULL) {
+ RetStatus = EFI_OUT_OF_RESOURCES;
+ break;
+ }
+
+ CopyMem (HobData, NewEventHdr, sizeof (*NewEventHdr));
+ HobData = (VOID *) ((UINT8*)HobData + sizeof (*NewEventHdr));
+ CopyMem (HobData, NewEventData, NewEventHdr->EventSize);
+ }
+ break;
+ }
+ }
+
+ return RetStatus;
+}
+
+/**
+ 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] Flags Bitmap providing additional information.
+ @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] 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 UINT64 Flags,
+ IN UINT8 *HashData,
+ IN UINTN HashDataLen,
+ IN TCG_PCR_EVENT_HDR *NewEventHdr,
+ IN UINT8 *NewEventData
+ )
+{
+ EFI_STATUS Status;
+ TPML_DIGEST_VALUES DigestList;
+
+ if (GetFirstGuidHob (&gTpmErrorHobGuid) != NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = HashAndExtend (
+ NewEventHdr->PCRIndex,
+ HashData,
+ HashDataLen,
+ &DigestList
+ );
+ if (!EFI_ERROR (Status)) {
+ if ((Flags & TREE_EXTEND_ONLY) == 0) {
+ Status = LogHashEvent (&DigestList, NewEventHdr, NewEventData);
+ }
+ }
+
+ if (Status == EFI_DEVICE_ERROR) {
+ DEBUG ((EFI_D_ERROR, "HashLogExtendEvent - %r. Disable TPM.\n", Status));
+ BuildGuidHob (&gTpmErrorHobGuid,0);
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ (PcdGet32 (PcdStatusCodeSubClassTpmDevice) | EFI_P_EC_INTERFACE_ERROR)
+ );
+ }
+
+ return Status;
+}
+
+/**
+ Measure CRTM version.
+
+ @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
+MeasureCRTMVersion (
+ VOID
+ )
+{
+ TCG_PCR_EVENT_HDR TcgEventHdr;
+
+ //
+ // Use FirmwareVersion string to represent CRTM version.
+ // OEMs should get real CRTM version string and measure it.
+ //
+
+ TcgEventHdr.PCRIndex = 0;
+ TcgEventHdr.EventType = EV_S_CRTM_VERSION;
+ TcgEventHdr.EventSize = (UINT32) StrSize((CHAR16*)PcdGetPtr (PcdFirmwareVersionString));
+
+ return HashLogExtendEvent (
+ 0,
+ (UINT8*)PcdGetPtr (PcdFirmwareVersionString),
+ TcgEventHdr.EventSize,
+ &TcgEventHdr,
+ (UINT8*)PcdGetPtr (PcdFirmwareVersionString)
+ );
+}
+
+/**
+ 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
+MeasureFvImage (
+ IN EFI_PHYSICAL_ADDRESS FvBase,
+ IN UINT64 FvLength
+ )
+{
+ UINT32 Index;
+ EFI_STATUS Status;
+ EFI_PLATFORM_FIRMWARE_BLOB FvBlob;
+ TCG_PCR_EVENT_HDR TcgEventHdr;
+
+ //
+ // Check if it is in Excluded FV list
+ //
+ if (mMeasurementExcludedFvPpi != NULL) {
+ for (Index = 0; Index < mMeasurementExcludedFvPpi->Count; Index ++) {
+ if (mMeasurementExcludedFvPpi->Fv[Index].FvBase == FvBase) {
+ DEBUG ((DEBUG_INFO, "The FV which is excluded by TrEEPei starts at: 0x%x\n", FvBase));
+ DEBUG ((DEBUG_INFO, "The FV which is excluded by TrEEPei has the size: 0x%x\n", FvLength));
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ //
+ // Check whether FV is in the measured FV list.
+ //
+ for (Index = 0; Index < mMeasuredBaseFvIndex; Index ++) {
+ if (mMeasuredBaseFvInfo[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 TrEEPei starts at: 0x%x\n", FvBlob.BlobBase));
+ DEBUG ((DEBUG_INFO, "The FV which is measured by TrEEPei has the size: 0x%x\n", FvBlob.BlobLength));
+
+ TcgEventHdr.PCRIndex = 0;
+ TcgEventHdr.EventType = EV_EFI_PLATFORM_FIRMWARE_BLOB;
+ TcgEventHdr.EventSize = sizeof (FvBlob);
+
+ Status = HashLogExtendEvent (
+ 0,
+ (UINT8*) (UINTN) FvBlob.BlobBase,
+ (UINTN) FvBlob.BlobLength,
+ &TcgEventHdr,
+ (UINT8*) &FvBlob
+ );
+
+ //
+ // Add new FV into the measured FV list.
+ //
+ ASSERT (mMeasuredBaseFvIndex < PcdGet32 (PcdPeiCoreMaxFvSupported));
+ if (mMeasuredBaseFvIndex < PcdGet32 (PcdPeiCoreMaxFvSupported)) {
+ mMeasuredBaseFvInfo[mMeasuredBaseFvIndex].BlobBase = FvBase;
+ mMeasuredBaseFvInfo[mMeasuredBaseFvIndex].BlobLength = FvLength;
+ mMeasuredBaseFvIndex++;
+ }
+
+ return Status;
+}
+
+/**
+ Measure main BIOS.
+
+ @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
+MeasureMainBios (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINT32 FvInstances;
+ EFI_PEI_FV_HANDLE VolumeHandle;
+ EFI_FV_INFO VolumeInfo;
+ EFI_PEI_FIRMWARE_VOLUME_PPI *FvPpi;
+
+ PERF_START_EX (mFileHandle, "EventRec", "TrEEPei", 0, PERF_ID_TREE_PEI);
+ 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++;
+ }
+ PERF_END_EX (mFileHandle, "EventRec", "TrEEPei", 0, PERF_ID_TREE_PEI + 1);
+
+ 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;
+ UINTN Index;
+
+ 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 record the FV and return
+ //
+ if (Fv->ParentFvName != NULL || Fv->ParentFileName != NULL ) {
+
+ ASSERT (mMeasuredChildFvIndex < PcdGet32 (PcdPeiCoreMaxFvSupported));
+ if (mMeasuredChildFvIndex < PcdGet32 (PcdPeiCoreMaxFvSupported)) {
+ //
+ // Check whether FV is in the measured child FV list.
+ //
+ for (Index = 0; Index < mMeasuredChildFvIndex; Index++) {
+ if (mMeasuredChildFvInfo[Index].BlobBase == (EFI_PHYSICAL_ADDRESS) (UINTN) Fv->FvInfo) {
+ return EFI_SUCCESS;
+ }
+ }
+ mMeasuredChildFvInfo[mMeasuredChildFvIndex].BlobBase = (EFI_PHYSICAL_ADDRESS) (UINTN) Fv->FvInfo;
+ mMeasuredChildFvInfo[mMeasuredChildFvIndex].BlobLength = Fv->FvInfoSize;
+ mMeasuredChildFvIndex++;
+ }
+ return EFI_SUCCESS;
+ }
+
+ return MeasureFvImage ((EFI_PHYSICAL_ADDRESS) (UINTN) Fv->FvInfo, Fv->FvInfoSize);
+}
+
+/**
+ 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
+PeimEntryMP (
+ IN EFI_PEI_SERVICES **PeiServices
+ )
+{
+ EFI_STATUS Status;
+
+ Status = PeiServicesLocatePpi (
+ &gEfiPeiFirmwareVolumeInfoMeasurementExcludedPpiGuid,
+ 0,
+ NULL,
+ (VOID**)&mMeasurementExcludedFvPpi
+ );
+ // Do not check status, because it is optional
+
+ mMeasuredBaseFvInfo = (EFI_PLATFORM_FIRMWARE_BLOB *) AllocateZeroPool (sizeof (EFI_PLATFORM_FIRMWARE_BLOB) * PcdGet32 (PcdPeiCoreMaxFvSupported));
+ ASSERT (mMeasuredBaseFvInfo != NULL);
+ mMeasuredChildFvInfo = (EFI_PLATFORM_FIRMWARE_BLOB *) AllocateZeroPool (sizeof (EFI_PLATFORM_FIRMWARE_BLOB) * PcdGet32 (PcdPeiCoreMaxFvSupported));
+ ASSERT (mMeasuredChildFvInfo != NULL);
+
+ if (PcdGet8 (PcdTpm2ScrtmPolicy) == 1) {
+ Status = MeasureCRTMVersion ();
+ }
+
+ Status = MeasureMainBios ();
+
+ //
+ // Post callbacks:
+ // for the FvInfoPpi services to measure and record
+ // the additional Fvs to 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_STATUS Status2;
+ EFI_BOOT_MODE BootMode;
+
+ if (CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceNoneGuid) ||
+ CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceTpm12Guid)){
+ DEBUG ((DEBUG_INFO, "No TPM2 instance required!\n"));
+ return EFI_UNSUPPORTED;
+ }
+
+ if (GetFirstGuidHob (&gTpmErrorHobGuid) != NULL) {
+ DEBUG ((EFI_D_ERROR, "TPM2 error!\n"));
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = PeiServicesGetBootMode (&BootMode);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // In S3 path, skip shadow logic. no measurement is required
+ //
+ if (BootMode != BOOT_ON_S3_RESUME) {
+ Status = (**PeiServices).RegisterForShadow(FileHandle);
+ if (Status == EFI_ALREADY_STARTED) {
+ mImageInMemory = TRUE;
+ mFileHandle = FileHandle;
+ } else if (Status == EFI_NOT_FOUND) {
+ ASSERT_EFI_ERROR (Status);
+ }
+ }
+
+ if (!mImageInMemory) {
+ //
+ // Initialize TPM device
+ //
+ Status = Tpm2RequestUseTpm ();
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "TPM2 not detected!\n"));
+ goto Done;
+ }
+
+ if (PcdGet8 (PcdTpm2InitializationPolicy) == 1) {
+ if (BootMode == BOOT_ON_S3_RESUME) {
+ Status = Tpm2Startup (TPM_SU_STATE);
+ if (EFI_ERROR (Status) ) {
+ Status = Tpm2Startup (TPM_SU_CLEAR);
+ }
+ } else {
+ Status = Tpm2Startup (TPM_SU_CLEAR);
+ }
+ if (EFI_ERROR (Status) ) {
+ goto Done;
+ }
+ }
+
+ //
+ // TpmSelfTest is optional on S3 path, skip it to save S3 time
+ //
+ if (BootMode != BOOT_ON_S3_RESUME) {
+ if (PcdGet8 (PcdTpm2SelfTestPolicy) == 1) {
+ Status = Tpm2SelfTest (NO);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ }
+ }
+
+ //
+ // Only intall TpmInitializedPpi on success
+ //
+ Status = PeiServicesInstallPpi (&mTpmInitializedPpiList);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ if (mImageInMemory) {
+ Status = PeimEntryMP ((EFI_PEI_SERVICES**)PeiServices);
+ return Status;
+ }
+
+Done:
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "TPM2 error! Build Hob\n"));
+ BuildGuidHob (&gTpmErrorHobGuid,0);
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ (PcdGet32 (PcdStatusCodeSubClassTpmDevice) | EFI_P_EC_INTERFACE_ERROR)
+ );
+ }
+ //
+ // Always intall TpmInitializationDonePpi no matter success or fail.
+ // Other driver can know TPM initialization state by TpmInitializedPpi.
+ //
+ Status2 = PeiServicesInstallPpi (&mTpmInitializationDonePpiList);
+ ASSERT_EFI_ERROR (Status2);
+
+ return Status;
+}
diff --git a/Core/SecurityPkg/Tcg/TrEEPei/TrEEPei.inf b/Core/SecurityPkg/Tcg/TrEEPei/TrEEPei.inf
new file mode 100644
index 0000000000..61a8cd0824
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TrEEPei/TrEEPei.inf
@@ -0,0 +1,86 @@
+## @file
+# Initializes TPM 2.0 device and measure FVs in PEI phase
+#
+# This module will initialize TPM device, measure reported FVs and BIOS version.
+#
+# Copyright (c) 2013 - 2015, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = TrEEPei
+ MODULE_UNI_FILE = TrEEPei.uni
+ FILE_GUID = CA5A1928-6523-409d-A9FE-5DCC87387222
+ 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
+#
+# [BootMode]
+# S3_RESUME ## SOMETIMES_CONSUMES
+#
+
+[Sources]
+ TrEEPei.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+ HobLib
+ PeimEntryPoint
+ PeiServicesLib
+ BaseMemoryLib
+ DebugLib
+ Tpm2CommandLib
+ PeiServicesTablePointerLib
+ Tpm2DeviceLib
+ HashLib
+ PerformanceLib
+ MemoryAllocationLib
+ ReportStatusCodeLib
+
+[Guids]
+ gTcgEventEntryHobGuid ## PRODUCES ## HOB
+ gTpmErrorHobGuid ## SOMETIMES_PRODUCES ## HOB
+ gMeasuredFvHobGuid ## PRODUCES ## HOB
+ gEfiTpmDeviceInstanceNoneGuid ## SOMETIMES_PRODUCES ## GUID # TPM device identifier
+ gEfiTpmDeviceInstanceTpm12Guid ## SOMETIMES_PRODUCES ## GUID # TPM device identifier
+
+[Ppis]
+ gEfiPeiFirmwareVolumeInfoPpiGuid ## SOMETIMES_CONSUMES ## NOTIFY
+ gEfiPeiFirmwareVolumeInfo2PpiGuid ## SOMETIMES_CONSUMES ## NOTIFY
+ gEfiPeiFirmwareVolumeInfoMeasurementExcludedPpiGuid ## SOMETIMES_CONSUMES
+ gPeiTpmInitializedPpiGuid ## SOMETIMES_PRODUCES
+ gPeiTpmInitializationDonePpiGuid ## PRODUCES
+ gEfiEndOfPeiSignalPpiGuid ## SOMETIMES_CONSUMES ## NOTIFY
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFirmwareVersionString ## SOMETIMES_CONSUMES
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpmInstanceGuid ## CONSUMES
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpm2InitializationPolicy ## CONSUMES
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpm2SelfTestPolicy ## SOMETIMES_CONSUMES
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpm2ScrtmPolicy ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdPeiCoreMaxFvSupported ## CONSUMES
+ gEfiSecurityPkgTokenSpaceGuid.PcdStatusCodeSubClassTpmDevice ## SOMETIMES_CONSUMES
+
+[Depex]
+ gEfiPeiMasterBootModePpiGuid AND
+ gEfiPeiReadOnlyVariable2PpiGuid AND
+ gEfiTpmDeviceSelectedGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ TrEEPeiExtra.uni \ No newline at end of file
diff --git a/Core/SecurityPkg/Tcg/TrEEPei/TrEEPei.uni b/Core/SecurityPkg/Tcg/TrEEPei/TrEEPei.uni
new file mode 100644
index 0000000000..619484abfc
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TrEEPei/TrEEPei.uni
@@ -0,0 +1,21 @@
+// /** @file
+// Initializes TPM 2.0 device and measure FVs in PEI phase
+//
+// This module will initialize TPM device, measure reported FVs and BIOS version.
+//
+// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Initializes TPM 2.0 device and measure FVs in PEI phase"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This module will initialize TPM device, measure reported FVs and BIOS version."
+
diff --git a/Core/SecurityPkg/Tcg/TrEEPei/TrEEPeiExtra.uni b/Core/SecurityPkg/Tcg/TrEEPei/TrEEPeiExtra.uni
new file mode 100644
index 0000000000..b6743ab953
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TrEEPei/TrEEPeiExtra.uni
@@ -0,0 +1,19 @@
+// /** @file
+// TrEEPei Localized Strings and Content
+//
+// Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"TrEE (Trusted Execution Environment) PEI"
+
+
diff --git a/Core/SecurityPkg/Tcg/TrEESmm/Tpm.asl b/Core/SecurityPkg/Tcg/TrEESmm/Tpm.asl
new file mode 100644
index 0000000000..0f6b94a23d
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TrEESmm/Tpm.asl
@@ -0,0 +1,354 @@
+/** @file
+ The TPM2 definition block in ACPI table for TrEE physical presence
+ and MemoryClear.
+
+Copyright (c) 2013 - 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+DefinitionBlock (
+ "Tpm.aml",
+ "SSDT",
+ 2,
+ "INTEL ",
+ "Tpm2Tabl",
+ 0x1000
+ )
+{
+ Scope (\_SB)
+ {
+ Device (TPM)
+ {
+ //
+ // TREE
+ //
+ Name (_HID, "MSFT0101")
+
+ //
+ // Readable name of this device, don't know if this way is correct yet
+ //
+ Name (_STR, Unicode ("TPM 2.0 Device"))
+
+ //
+ // Return the resource consumed by TPM device
+ //
+ Name (_CRS, ResourceTemplate () {
+ Memory32Fixed (ReadWrite, 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 0xFFFF0000 and Length 0xF0 will be fixed in C code.
+ //
+ OperationRegion (TNVS, SystemMemory, 0xFFFF0000, 0xF0)
+ 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
+ MRET, 32 // Memory Overwrite function return code
+ }
+
+ 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}, {UnknownObj, UnknownObj, UnknownObj}) // 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 () {0x2, 0x0}})
+ 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}, {UnknownObj, UnknownObj, UnknownObj}) // 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, {UnknownObj, UnknownObj, UnknownObj}) // 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 (MRET)
+ }
+ 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/Core/SecurityPkg/Tcg/TrEESmm/TrEESmm.c b/Core/SecurityPkg/Tcg/TrEESmm/TrEESmm.c
new file mode 100644
index 0000000000..1683dedc8a
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TrEESmm/TrEESmm.c
@@ -0,0 +1,521 @@
+/** @file
+ It updates TPM2 items in ACPI table and registers SMI2 callback
+ functions for TrEE physical presence, ClearMemory, and sample
+ for dTPM StartMethod.
+
+ Caution: This module requires additional review when modified.
+ This driver will have external input - variable and ACPINvs data in SMM mode.
+ This external input must be validated carefully to avoid security issue.
+
+ PhysicalPresenceCallback() and MemoryClearCallback() will receive untrusted input and do some check.
+
+Copyright (c) 2013 - 2017, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "TrEESmm.h"
+
+EFI_TPM2_ACPI_TABLE mTpm2AcpiTemplate = {
+ {
+ EFI_ACPI_5_0_TRUSTED_COMPUTING_PLATFORM_2_TABLE_SIGNATURE,
+ sizeof (mTpm2AcpiTemplate),
+ EFI_TPM2_ACPI_TABLE_REVISION_3,
+ //
+ // Compiler initializes the remaining bytes to 0
+ // These fields should be filled in in production
+ //
+ },
+ 0, // Flags
+ 0, // Control Area
+ EFI_TPM2_ACPI_TABLE_START_METHOD_TIS, // StartMethod
+};
+
+EFI_SMM_VARIABLE_PROTOCOL *mSmmVariable;
+TCG_NVS *mTcgNvs;
+
+/**
+ Software SMI callback for TPM physical presence which is called from ACPI method.
+
+ Caution: This function may receive untrusted input.
+ Variable and ACPINvs are external input, so this function will validate
+ its data structure to be valid value.
+
+ @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_TREE_PHYSICAL_PRESENCE PpData;
+ EFI_TREE_PHYSICAL_PRESENCE_FLAGS Flags;
+ BOOLEAN RequestConfirmed;
+
+ //
+ // Get the Physical Presence variable
+ //
+ DataSize = sizeof (EFI_TREE_PHYSICAL_PRESENCE);
+ Status = mSmmVariable->SmmGetVariable (
+ TREE_PHYSICAL_PRESENCE_VARIABLE,
+ &gEfiTrEEPhysicalPresenceGuid,
+ NULL,
+ &DataSize,
+ &PpData
+ );
+
+ DEBUG ((EFI_D_INFO, "[TPM2] PP callback, Parameter = %x, Request = %x\n", mTcgNvs->PhysicalPresence.Parameter, mTcgNvs->PhysicalPresence.Request));
+
+ if (mTcgNvs->PhysicalPresence.Parameter == ACPI_FUNCTION_RETURN_REQUEST_RESPONSE_TO_OS) {
+ if (EFI_ERROR (Status)) {
+ mTcgNvs->PhysicalPresence.ReturnCode = PP_RETURN_TPM_OPERATION_RESPONSE_FAILURE;
+ mTcgNvs->PhysicalPresence.LastRequest = 0;
+ mTcgNvs->PhysicalPresence.Response = 0;
+ DEBUG ((EFI_D_ERROR, "[TPM2] Get PP variable failure! Status = %r\n", Status));
+ return EFI_SUCCESS;
+ }
+ mTcgNvs->PhysicalPresence.ReturnCode = PP_RETURN_TPM_OPERATION_RESPONSE_SUCCESS;
+ mTcgNvs->PhysicalPresence.LastRequest = PpData.LastPPRequest;
+ mTcgNvs->PhysicalPresence.Response = PpData.PPResponse;
+ } else if ((mTcgNvs->PhysicalPresence.Parameter == ACPI_FUNCTION_SUBMIT_REQUEST_TO_BIOS)
+ || (mTcgNvs->PhysicalPresence.Parameter == ACPI_FUNCTION_SUBMIT_REQUEST_TO_BIOS_2)) {
+ if (EFI_ERROR (Status)) {
+ mTcgNvs->PhysicalPresence.ReturnCode = TREE_PP_SUBMIT_REQUEST_TO_PREOS_GENERAL_FAILURE;
+ DEBUG ((EFI_D_ERROR, "[TPM2] Get PP variable failure! Status = %r\n", Status));
+ return EFI_SUCCESS;
+ }
+ if ((mTcgNvs->PhysicalPresence.Request > TREE_PHYSICAL_PRESENCE_NO_ACTION_MAX) &&
+ (mTcgNvs->PhysicalPresence.Request < TREE_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION) ) {
+ //
+ // This command requires UI to prompt user for Auth data.
+ //
+ mTcgNvs->PhysicalPresence.ReturnCode = TREE_PP_SUBMIT_REQUEST_TO_PREOS_NOT_IMPLEMENTED;
+ return EFI_SUCCESS;
+ }
+
+ if (PpData.PPRequest != mTcgNvs->PhysicalPresence.Request) {
+ PpData.PPRequest = (UINT8) mTcgNvs->PhysicalPresence.Request;
+ DataSize = sizeof (EFI_TREE_PHYSICAL_PRESENCE);
+ Status = mSmmVariable->SmmSetVariable (
+ TREE_PHYSICAL_PRESENCE_VARIABLE,
+ &gEfiTrEEPhysicalPresenceGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ DataSize,
+ &PpData
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+ mTcgNvs->PhysicalPresence.ReturnCode = TREE_PP_SUBMIT_REQUEST_TO_PREOS_GENERAL_FAILURE;
+ DEBUG ((EFI_D_ERROR, "[TPM2] Set PP variable failure! Status = %r\n", Status));
+ return EFI_SUCCESS;
+ }
+ mTcgNvs->PhysicalPresence.ReturnCode = TREE_PP_SUBMIT_REQUEST_TO_PREOS_SUCCESS;
+
+ if (mTcgNvs->PhysicalPresence.Request >= TREE_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION) {
+ DataSize = sizeof (EFI_TREE_PHYSICAL_PRESENCE_FLAGS);
+ Status = mSmmVariable->SmmGetVariable (
+ TREE_PHYSICAL_PRESENCE_FLAGS_VARIABLE,
+ &gEfiTrEEPhysicalPresenceGuid,
+ NULL,
+ &DataSize,
+ &Flags
+ );
+ if (EFI_ERROR (Status)) {
+ Flags.PPFlags = 0;
+ }
+ mTcgNvs->PhysicalPresence.ReturnCode = TrEEPpVendorLibSubmitRequestToPreOSFunction (mTcgNvs->PhysicalPresence.Request, Flags.PPFlags);
+ }
+ } else if (mTcgNvs->PhysicalPresence.Parameter == ACPI_FUNCTION_GET_USER_CONFIRMATION_STATUS_FOR_REQUEST) {
+ if (EFI_ERROR (Status)) {
+ mTcgNvs->PhysicalPresence.ReturnCode = TREE_PP_GET_USER_CONFIRMATION_BLOCKED_BY_BIOS_CONFIGURATION;
+ DEBUG ((EFI_D_ERROR, "[TPM2] Get PP variable failure! Status = %r\n", Status));
+ return EFI_SUCCESS;
+ }
+ //
+ // Get the Physical Presence flags
+ //
+ DataSize = sizeof (EFI_TREE_PHYSICAL_PRESENCE_FLAGS);
+ Status = mSmmVariable->SmmGetVariable (
+ TREE_PHYSICAL_PRESENCE_FLAGS_VARIABLE,
+ &gEfiTrEEPhysicalPresenceGuid,
+ NULL,
+ &DataSize,
+ &Flags
+ );
+ if (EFI_ERROR (Status)) {
+ mTcgNvs->PhysicalPresence.ReturnCode = TREE_PP_GET_USER_CONFIRMATION_BLOCKED_BY_BIOS_CONFIGURATION;
+ DEBUG ((EFI_D_ERROR, "[TPM2] Get PP flags failure! Status = %r\n", Status));
+ return EFI_SUCCESS;
+ }
+
+ RequestConfirmed = FALSE;
+
+ switch (mTcgNvs->PhysicalPresence.Request) {
+
+ case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR:
+ case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_2:
+ case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_3:
+ case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_4:
+ if ((Flags.PPFlags & TREE_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_CLEAR) != 0) {
+ RequestConfirmed = TRUE;
+ }
+ break;
+
+ case TREE_PHYSICAL_PRESENCE_SET_NO_PPI_CLEAR_FALSE:
+ RequestConfirmed = TRUE;
+ break;
+
+ case TREE_PHYSICAL_PRESENCE_SET_NO_PPI_CLEAR_TRUE:
+ break;
+
+ default:
+ if (mTcgNvs->PhysicalPresence.Request <= TREE_PHYSICAL_PRESENCE_NO_ACTION_MAX) {
+ RequestConfirmed = TRUE;
+ } else {
+ if (mTcgNvs->PhysicalPresence.Request < TREE_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION) {
+ mTcgNvs->PhysicalPresence.ReturnCode = TREE_PP_GET_USER_CONFIRMATION_NOT_IMPLEMENTED;
+ return EFI_SUCCESS;
+ }
+ }
+ break;
+ }
+
+ if (RequestConfirmed) {
+ mTcgNvs->PhysicalPresence.ReturnCode = TREE_PP_GET_USER_CONFIRMATION_ALLOWED_AND_PPUSER_NOT_REQUIRED;
+ } else {
+ mTcgNvs->PhysicalPresence.ReturnCode = TREE_PP_GET_USER_CONFIRMATION_ALLOWED_AND_PPUSER_REQUIRED;
+ }
+ if (mTcgNvs->PhysicalPresence.Request >= TREE_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION) {
+ mTcgNvs->PhysicalPresence.ReturnCode = TrEEPpVendorLibGetUserConfirmationStatusFunction (mTcgNvs->PhysicalPresence.Request, Flags.PPFlags);
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Software SMI callback for MemoryClear which is called from ACPI method.
+
+ Caution: This function may receive untrusted input.
+ Variable and ACPINvs are external input, so this function will validate
+ its data structure to be valid value.
+
+ @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;
+
+ mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_SUCCESS;
+ if (mTcgNvs->MemoryClear.Parameter == ACPI_FUNCTION_DSM_MEMORY_CLEAR_INTERFACE) {
+ MorControl = (UINT8) mTcgNvs->MemoryClear.Request;
+ } else if (mTcgNvs->MemoryClear.Parameter == ACPI_FUNCTION_PTS_CLEAR_MOR_BIT) {
+ DataSize = sizeof (UINT8);
+ Status = mSmmVariable->SmmGetVariable (
+ MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,
+ &gEfiMemoryOverwriteControlDataGuid,
+ NULL,
+ &DataSize,
+ &MorControl
+ );
+ if (EFI_ERROR (Status)) {
+ mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_GENERAL_FAILURE;
+ DEBUG ((EFI_D_ERROR, "[TPM] Get MOR variable failure! Status = %r\n", Status));
+ 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
+ );
+ if (EFI_ERROR (Status)) {
+ mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_GENERAL_FAILURE;
+ DEBUG ((EFI_D_ERROR, "[TPM] Set MOR variable failure! Status = %r\n", 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_EXT_REGION_OP) &&
+ (OpRegion->NameString == Name) &&
+ (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;
+ OpRegion->RegionLen = (UINT8) Size;
+ 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);
+
+
+ //
+ // Measure to PCR[0] with event EV_POST_CODE ACPI DATA
+ //
+ TpmMeasureAndLogData(
+ 0,
+ EV_POST_CODE,
+ EV_POSTCODE_INFO_ACPI_DATA,
+ ACPI_DATA_LEN,
+ Table,
+ TableSize
+ );
+
+
+ ASSERT (Table->OemTableId == SIGNATURE_64 ('T', 'p', 'm', '2', 'T', 'a', 'b', 'l'));
+ CopyMem (Table->OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (Table->OemId) );
+ mTcgNvs = AssignOpRegion (Table, SIGNATURE_32 ('T', 'N', 'V', 'S'), (UINT16) 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;
+}
+
+/**
+ Publish TPM2 ACPI table
+
+ @retval EFI_SUCCESS The TPM2 ACPI table is published successfully.
+ @retval Others The TPM2 ACPI table is not published.
+
+**/
+EFI_STATUS
+PublishTpm2 (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_ACPI_TABLE_PROTOCOL *AcpiTable;
+ UINTN TableKey;
+ UINT64 OemTableId;
+
+ //
+ // Measure to PCR[0] with event EV_POST_CODE ACPI DATA
+ //
+ TpmMeasureAndLogData(
+ 0,
+ EV_POST_CODE,
+ EV_POSTCODE_INFO_ACPI_DATA,
+ ACPI_DATA_LEN,
+ &mTpm2AcpiTemplate,
+ sizeof(mTpm2AcpiTemplate)
+ );
+
+ CopyMem (mTpm2AcpiTemplate.Header.OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (mTpm2AcpiTemplate.Header.OemId));
+ OemTableId = PcdGet64 (PcdAcpiDefaultOemTableId);
+ CopyMem (&mTpm2AcpiTemplate.Header.OemTableId, &OemTableId, sizeof (UINT64));
+ mTpm2AcpiTemplate.Header.OemRevision = PcdGet32 (PcdAcpiDefaultOemRevision);
+ mTpm2AcpiTemplate.Header.CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId);
+ mTpm2AcpiTemplate.Header.CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision);
+
+ //
+ // Construct ACPI table
+ //
+ Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTable);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = AcpiTable->InstallAcpiTable (
+ AcpiTable,
+ &mTpm2AcpiTemplate,
+ sizeof(mTpm2AcpiTemplate),
+ &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;
+
+ if (!CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceTpm20DtpmGuid)){
+ DEBUG ((EFI_D_ERROR, "No TPM2 DTPM instance required!\n"));
+ return EFI_UNSUPPORTED;
+ }
+
+ 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);
+
+ //
+ // Set TPM2 ACPI table
+ //
+ Status = PublishTpm2 ();
+ ASSERT_EFI_ERROR (Status);
+
+
+ return EFI_SUCCESS;
+}
+
diff --git a/Core/SecurityPkg/Tcg/TrEESmm/TrEESmm.h b/Core/SecurityPkg/Tcg/TrEESmm/TrEESmm.h
new file mode 100644
index 0000000000..a0e1182248
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TrEESmm/TrEESmm.h
@@ -0,0 +1,105 @@
+/** @file
+ The header file for TrEE SMM driver.
+
+Copyright (c) 2013 - 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __TREE_SMM_H__
+#define __TREE_SMM_H__
+
+#include <PiDxe.h>
+#include <IndustryStandard/Acpi.h>
+#include <IndustryStandard/Tpm2Acpi.h>
+
+#include <Guid/TrEEPhysicalPresenceData.h>
+#include <Guid/MemoryOverwriteControl.h>
+#include <Guid/TpmInstance.h>
+
+#include <Protocol/SmmSwDispatch2.h>
+#include <Protocol/AcpiTable.h>
+#include <Protocol/SmmVariable.h>
+#include <Protocol/TrEEProtocol.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/SmmServicesTableLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DxeServicesLib.h>
+#include <Library/TpmMeasurementLib.h>
+#include <Library/Tpm2DeviceLib.h>
+#include <Library/TrEEPpVendorLib.h>
+
+#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;
+ UINT32 ReturnCode;
+} 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()
+
+//
+// The definition for TCG physical presence ACPI function
+//
+#define ACPI_FUNCTION_GET_PHYSICAL_PRESENCE_INTERFACE_VERSION 1
+#define ACPI_FUNCTION_SUBMIT_REQUEST_TO_BIOS 2
+#define ACPI_FUNCTION_GET_PENDING_REQUEST_BY_OS 3
+#define ACPI_FUNCTION_GET_PLATFORM_ACTION_TO_TRANSITION_TO_BIOS 4
+#define ACPI_FUNCTION_RETURN_REQUEST_RESPONSE_TO_OS 5
+#define ACPI_FUNCTION_SUBMIT_PREFERRED_USER_LANGUAGE 6
+#define ACPI_FUNCTION_SUBMIT_REQUEST_TO_BIOS_2 7
+#define ACPI_FUNCTION_GET_USER_CONFIRMATION_STATUS_FOR_REQUEST 8
+
+//
+// The return code for Return TPM Operation Response to OS Environment
+//
+#define PP_RETURN_TPM_OPERATION_RESPONSE_SUCCESS 0
+#define PP_RETURN_TPM_OPERATION_RESPONSE_FAILURE 1
+
+//
+// The definition for TCG MOR
+//
+#define ACPI_FUNCTION_DSM_MEMORY_CLEAR_INTERFACE 1
+#define ACPI_FUNCTION_PTS_CLEAR_MOR_BIT 2
+
+//
+// The return code for Memory Clear Interface Functions
+//
+#define MOR_REQUEST_SUCCESS 0
+#define MOR_REQUEST_GENERAL_FAILURE 1
+
+#endif // __TCG_SMM_H__
diff --git a/Core/SecurityPkg/Tcg/TrEESmm/TrEESmm.inf b/Core/SecurityPkg/Tcg/TrEESmm/TrEESmm.inf
new file mode 100644
index 0000000000..de71ffdc1b
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TrEESmm/TrEESmm.inf
@@ -0,0 +1,85 @@
+## @file
+# Provides ACPI metholds for TPM 2.0 support
+#
+# This driver implements TPM 2.0 definition block in ACPI table and
+# registers SMI callback functions for TrEE physical presence and
+# MemoryClear to handle the requests from ACPI method.
+#
+# Caution: This module requires additional review when modified.
+# This driver will have external input - variable and ACPINvs data in SMM mode.
+# This external input must be validated carefully to avoid security issue.
+#
+# Copyright (c) 2013 - 2015, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = TrEESmm
+ MODULE_UNI_FILE = TrEESmm.uni
+ FILE_GUID = 114B7105-6CC9-453c-BADC-16DF227BB4EF
+ MODULE_TYPE = DXE_SMM_DRIVER
+ PI_SPECIFICATION_VERSION = 0x0001000A
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializeTcgSmm
+
+[Sources]
+ TrEESmm.h
+ TrEESmm.c
+ Tpm.asl
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ UefiDriverEntryPoint
+ SmmServicesTableLib
+ UefiBootServicesTableLib
+ DebugLib
+ DxeServicesLib
+ TpmMeasurementLib
+ Tpm2DeviceLib
+ TrEEPpVendorLib
+
+[Guids]
+ ## SOMETIMES_PRODUCES ## Variable:L"PhysicalPresence"
+ ## SOMETIMES_CONSUMES ## Variable:L"PhysicalPresence"
+ ## SOMETIMES_CONSUMES ## Variable:L"PhysicalPresenceFlags"
+ gEfiTrEEPhysicalPresenceGuid
+
+ ## SOMETIMES_PRODUCES ## Variable:L"MemoryOverwriteRequestControl"
+ ## SOMETIMES_CONSUMES ## Variable:L"MemoryOverwriteRequestControl"
+ gEfiMemoryOverwriteControlDataGuid
+
+ gEfiTpmDeviceInstanceTpm20DtpmGuid ## PRODUCES ## GUID # TPM device identifier
+
+[Protocols]
+ gEfiSmmSwDispatch2ProtocolGuid ## CONSUMES
+ gEfiSmmVariableProtocolGuid ## CONSUMES
+ gEfiAcpiTableProtocolGuid ## CONSUMES
+
+[Pcd]
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpmInstanceGuid ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemId ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemTableId ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemRevision ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorId ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorRevision ## SOMETIMES_CONSUMES
+
+[Depex]
+ gEfiAcpiTableProtocolGuid AND
+ gEfiSmmSwDispatch2ProtocolGuid AND
+ gEfiSmmVariableProtocolGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ TrEESmmExtra.uni \ No newline at end of file
diff --git a/Core/SecurityPkg/Tcg/TrEESmm/TrEESmm.uni b/Core/SecurityPkg/Tcg/TrEESmm/TrEESmm.uni
new file mode 100644
index 0000000000..3123918c3e
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TrEESmm/TrEESmm.uni
@@ -0,0 +1,28 @@
+// /** @file
+// Provides ACPI metholds for TPM 2.0 support
+//
+// This driver implements TPM 2.0 definition block in ACPI table and
+// registers SMI callback functions for TrEE physical presence and
+// MemoryClear to handle the requests from ACPI method.
+//
+// Caution: This module requires additional review when modified.
+// This driver will have external input - variable and ACPINvs data in SMM mode.
+// This external input must be validated carefully to avoid security issue.
+//
+// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides ACPI metholds for TPM 2.0 support"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This driver implements TPM 2.0 definition block in ACPI table and registers SMI callback functions for TrEE physical presence and MemoryClear to handle the requests from ACPI method.\n"
+ "Caution: This module requires additional review when modified. This driver will have external input - variable and ACPINvs data in SMM mode. This external input must be validated carefully to avoid security issues."
+
diff --git a/Core/SecurityPkg/Tcg/TrEESmm/TrEESmmExtra.uni b/Core/SecurityPkg/Tcg/TrEESmm/TrEESmmExtra.uni
new file mode 100644
index 0000000000..c7e4da28c8
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TrEESmm/TrEESmmExtra.uni
@@ -0,0 +1,19 @@
+// /** @file
+// TrEESmm Localized Strings and Content
+//
+// Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"TrEE (Trusted Execution Environment) SMM"
+
+
diff --git a/Core/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProvider.c b/Core/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProvider.c
new file mode 100644
index 0000000000..b9e89cbfe7
--- /dev/null
+++ b/Core/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProvider.c
@@ -0,0 +1,1461 @@
+/** @file
+ Password Credential Provider driver implementation.
+
+Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "PwdCredentialProvider.h"
+
+CREDENTIAL_TABLE *mPwdTable = NULL;
+PWD_PROVIDER_CALLBACK_INFO *mCallbackInfo = NULL;
+PASSWORD_CREDENTIAL_INFO *mPwdInfoHandle = NULL;
+
+HII_VENDOR_DEVICE_PATH mHiiVendorDevicePath = {
+ {
+ {
+ HARDWARE_DEVICE_PATH,
+ HW_VENDOR_DP,
+ {
+ (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
+ (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
+ }
+ },
+ PWD_CREDENTIAL_PROVIDER_GUID
+ },
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ (UINT8) (END_DEVICE_PATH_LENGTH),
+ (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
+ }
+ }
+};
+
+EFI_USER_CREDENTIAL2_PROTOCOL gPwdCredentialProviderDriver = {
+ PWD_CREDENTIAL_PROVIDER_GUID,
+ EFI_USER_CREDENTIAL_CLASS_PASSWORD,
+ CredentialEnroll,
+ CredentialForm,
+ CredentialTile,
+ CredentialTitle,
+ CredentialUser,
+ CredentialSelect,
+ CredentialDeselect,
+ CredentialDefault,
+ CredentialGetInfo,
+ CredentialGetNextInfo,
+ EFI_CREDENTIAL_CAPABILITIES_ENROLL,
+ CredentialDelete
+};
+
+
+/**
+ 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, update or delete info in table, and sync with NV variable.
+
+ @param[in] Index The index of the password in table. If index is found in
+ table, update the info, else add the into to table.
+ @param[in] Info The new password info to add into table.If Info is NULL,
+ delete the info by Index.
+
+ @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;
+ PASSWORD_INFO *NewPasswordInfo;
+
+ NewPasswordInfo = NULL;
+
+ if (Index < mPwdTable->Count) {
+ if (Info == NULL) {
+ //
+ // Delete the specified entry.
+ //
+ mPwdTable->Count--;
+ if (Index != mPwdTable->Count) {
+ NewPasswordInfo = &mPwdTable->UserInfo[mPwdTable->Count];
+ }
+ } else {
+ //
+ // Update the specified entry.
+ //
+ NewPasswordInfo = Info;
+ }
+ } else {
+ //
+ // Add a new password info.
+ //
+ if (Info == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (mPwdTable->Count >= mPwdTable->MaxCount) {
+ ExpandTableSize ();
+ }
+
+ NewPasswordInfo = Info;
+ mPwdTable->Count++;
+ }
+
+ if (NewPasswordInfo != NULL) {
+ CopyMem (&mPwdTable->UserInfo[Index], NewPasswordInfo, sizeof (PASSWORD_INFO));
+ }
+
+ //
+ // Save the credential table.
+ //
+ Status = gRT->SetVariable (
+ L"PwdCredential",
+ &gPwdCredentialProviderGuid,
+ 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",
+ &gPwdCredentialProviderGuid,
+ 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",
+ &gPwdCredentialProviderGuid,
+ 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_CHANGED) {
+ 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 <ConfigRequest> 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 <ConfigAltResp> format which
+ has all values filled in for the names in the Request string.
+ String to be allocated by the called function.
+
+ @retval EFI_SUCCESS The Results is filled with the requested values.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results.
+ @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name.
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in this driver.
+
+**/
+EFI_STATUS
+EFIAPI
+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 <ConfigResp> 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 (
+ &gPwdCredentialProviderGuid,
+ 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 a user on this credential provider. If the user exists on
+ this credential provider, update the user information on this credential provider;
+ otherwise add the user information on credential provider.
+
+ @param[in] This Points to this instance of EFI_USER_CREDENTIAL2_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_CREDENTIAL2_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;
+ UINT8 *UserId;
+ CHAR16 *QuestionStr;
+ CHAR16 *PromptStr;
+
+ if ((This == NULL) || (User == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Get User Identifier.
+ //
+ UserInfo = NULL;
+ Status = FindUserInfoByType (
+ User,
+ EFI_USER_INFO_IDENTIFIER_RECORD,
+ &UserInfo
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CopyMem (PwdInfo.UserId, (UINT8 *) (UserInfo + 1), sizeof (EFI_USER_INFO_IDENTIFIER));
+ FreePool (UserInfo);
+
+ //
+ // Get password from 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);
+ }
+
+ //
+ // Check whether User is ever enrolled in the provider.
+ //
+ for (Index = 0; Index < mPwdTable->Count; Index++) {
+ UserId = (UINT8 *) &mPwdTable->UserInfo[Index].UserId;
+ if (CompareMem (UserId, (UINT8 *) &PwdInfo.UserId, sizeof (EFI_USER_INFO_IDENTIFIER)) == 0) {
+ //
+ // User already exists, update the password.
+ //
+ break;
+ }
+ }
+
+ //
+ // Enroll the User to the provider.
+ //
+ Status = ModifyTable (Index, &PwdInfo);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ 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_CREDENTIAL2_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_CREDENTIAL2_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, &gPwdCredentialProviderGuid);
+
+ 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_CREDENTIAL2_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_CREDENTIAL2_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_CREDENTIAL2_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_CREDENTIAL2_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_CREDENTIAL2_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_CREDENTIAL2_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;
+ }
+ }
+ }
+
+ FreePool (UserInfo);
+ return EFI_NOT_READY;
+}
+
+
+/**
+ 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_CREDENTIAL2_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_CREDENTIAL2_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_CREDENTIAL2_PROTOCOL.
+
+ @retval EFI_SUCCESS Credential provider successfully deselected.
+
+**/
+EFI_STATUS
+EFIAPI
+CredentialDeselect (
+ IN CONST EFI_USER_CREDENTIAL2_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_CREDENTIAL2_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_CREDENTIAL2_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_CREDENTIAL2_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_CREDENTIAL2_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_CREDENTIAL2_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_CREDENTIAL2_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, &gPwdCredentialProviderGuid);
+ CopyGuid ((EFI_GUID *)(Info + 1), &gPwdCredentialProviderGuid);
+
+ 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, &gPwdCredentialProviderGuid);
+ 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, &gPwdCredentialProviderGuid);
+ 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, &gPwdCredentialProviderGuid);
+ 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;
+}
+
+/**
+ Delete a user on this credential provider.
+
+ This function deletes a user on this credential provider.
+
+ @param[in] This Points to this instance of the EFI_USER_CREDENTIAL2_PROTOCOL.
+ @param[in] User The user profile handle to delete.
+
+ @retval EFI_SUCCESS User profile was successfully deleted.
+ @retval EFI_ACCESS_DENIED Current user profile does not permit deletion on the user profile handle.
+ Either the user profile cannot delete on any user profile or cannot delete
+ on a user profile other than the current user profile.
+ @retval EFI_UNSUPPORTED This credential provider does not support deletion in the pre-OS.
+ @retval EFI_DEVICE_ERROR The new credential could not be deleted because of a device error.
+ @retval EFI_INVALID_PARAMETER User does not refer to a valid user profile handle.
+**/
+EFI_STATUS
+EFIAPI
+CredentialDelete (
+ IN CONST EFI_USER_CREDENTIAL2_PROTOCOL *This,
+ IN EFI_USER_PROFILE_HANDLE User
+ )
+{
+ EFI_STATUS Status;
+ EFI_USER_INFO *UserInfo;
+ UINT8 *UserId;
+ UINT8 *NewUserId;
+ UINTN Index;
+
+ if ((This == NULL) || (User == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Get User Identifier.
+ //
+ UserInfo = NULL;
+ Status = FindUserInfoByType (
+ User,
+ EFI_USER_INFO_IDENTIFIER_RECORD,
+ &UserInfo
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Find the user by user identifier in mPwdTable.
+ //
+ 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) {
+ //
+ // Found the user, delete it.
+ //
+ ModifyTable (Index, NULL);
+ break;
+ }
+ }
+
+ FreePool (UserInfo);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ 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;
+
+ //
+ // It is NOT robust enough to be included in production.
+ //
+ #error "This implementation is just a sample, please comment this line if you really want to use this driver."
+
+ //
+ // 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,
+ &gEfiUserCredential2ProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &gPwdCredentialProviderDriver
+ );
+ return Status;
+}
diff --git a/Core/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProvider.h b/Core/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProvider.h
new file mode 100644
index 0000000000..7a51e7d078
--- /dev/null
+++ b/Core/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProvider.h
@@ -0,0 +1,374 @@
+/** @file
+ Password Credential Provider driver header file.
+
+Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _PASSWORD_CREDENTIAL_PROVIDER_H_
+#define _PASSWORD_CREDENTIAL_PROVIDER_H_
+
+#include <Uefi.h>
+
+#include <Guid/GlobalVariable.h>
+
+#include <Protocol/HiiConfigAccess.h>
+#include <Protocol/UserCredential2.h>
+#include <Protocol/UserManager.h>
+
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+#include <Library/PrintLib.h>
+#include <Library/HiiLib.h>
+#include <Library/BaseCryptLib.h>
+
+#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 a user on this credential provider. If the user exists on
+ this credential provider, update the user information on this credential provider;
+ otherwise delete the user information on credential provider.
+
+ @param[in] This Points to this instance of EFI_USER_CREDENTIAL2_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_CREDENTIAL2_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_CREDENTIAL2_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_CREDENTIAL2_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_CREDENTIAL2_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_CREDENTIAL2_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_CREDENTIAL2_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_CREDENTIAL2_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_CREDENTIAL2_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_CREDENTIAL2_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_CREDENTIAL2_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_CREDENTIAL2_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_CREDENTIAL2_PROTOCOL.
+
+ @retval EFI_SUCCESS Credential provider successfully deselected.
+
+**/
+EFI_STATUS
+EFIAPI
+CredentialDeselect (
+ IN CONST EFI_USER_CREDENTIAL2_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_CREDENTIAL2_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_CREDENTIAL2_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_CREDENTIAL2_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_CREDENTIAL2_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_CREDENTIAL2_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_CREDENTIAL2_PROTOCOL *This,
+ IN OUT EFI_USER_INFO_HANDLE *UserInfo
+ );
+
+/**
+ Delete a user on this credential provider.
+
+ This function deletes a user on this credential provider.
+
+ @param[in] This Points to this instance of the EFI_USER_CREDENTIAL2_PROTOCOL.
+ @param[in] User The user profile handle to delete.
+
+ @retval EFI_SUCCESS User profile was successfully deleted.
+ @retval EFI_ACCESS_DENIED Current user profile does not permit deletion on the user profile handle.
+ Either the user profile cannot delete on any user profile or cannot delete
+ on a user profile other than the current user profile.
+ @retval EFI_UNSUPPORTED This credential provider does not support deletion in the pre-OS.
+ @retval EFI_DEVICE_ERROR The new credential could not be deleted because of a device error.
+ @retval EFI_INVALID_PARAMETER User does not refer to a valid user profile handle.
+**/
+EFI_STATUS
+EFIAPI
+CredentialDelete (
+ IN CONST EFI_USER_CREDENTIAL2_PROTOCOL *This,
+ IN EFI_USER_PROFILE_HANDLE User
+ );
+
+#endif
diff --git a/Core/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProvider.uni b/Core/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProvider.uni
new file mode 100644
index 0000000000..749e9a8f17
--- /dev/null
+++ b/Core/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProvider.uni
@@ -0,0 +1,21 @@
+// /** @file
+// Provides a password credential provider implementation
+//
+// This module provides a password credential provider implementation.
+//
+// Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides a password credential provider implementation"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This module provides a password credential provider implementation."
+
diff --git a/Core/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderData.h b/Core/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderData.h
new file mode 100644
index 0000000000..feeffcc6df
--- /dev/null
+++ b/Core/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderData.h
@@ -0,0 +1,30 @@
+/** @file
+ Data structure used by the Password Credential Provider driver.
+
+Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _PWD_CREDENTIAL_PROVIDER_DATA_H_
+#define _PWD_CREDENTIAL_PROVIDER_DATA_H_
+
+#include <Guid/PwdCredentialProviderHii.h>
+
+//
+// Forms definition
+//
+#define FORMID_GET_PASSWORD_FORM 1
+
+//
+// Key defination
+//
+#define KEY_GET_PASSWORD 0x1000
+
+#endif
diff --git a/Core/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderDxe.inf b/Core/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderDxe.inf
new file mode 100644
index 0000000000..07e6163e8b
--- /dev/null
+++ b/Core/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderDxe.inf
@@ -0,0 +1,65 @@
+## @file
+# Provides a password credential provider implementation
+# This module provides a password credential provider implementation.
+#
+# Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PwdCredentialProvider
+ MODULE_UNI_FILE = PwdCredentialProvider.uni
+ 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
+ SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+ UefiRuntimeServicesTableLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ MemoryAllocationLib
+ BaseMemoryLib
+ DebugLib
+ HiiLib
+ UefiLib
+ BaseCryptLib
+
+[Guids]
+ gEfiUserCredentialClassPasswordGuid ## SOMETIMES_CONSUMES ## GUID
+
+ ## PRODUCES ## Variable:L"PwdCredential"
+ ## CONSUMES ## Variable:L"PwdCredential"
+ ## CONSUMES ## HII
+ ## SOMETIMES_CONSUMES ## GUID # The credential provider identifier
+ gPwdCredentialProviderGuid
+
+[Protocols]
+ gEfiDevicePathProtocolGuid ## PRODUCES
+ gEfiHiiConfigAccessProtocolGuid ## PRODUCES
+ gEfiUserCredential2ProtocolGuid ## PRODUCES
+ gEfiUserManagerProtocolGuid ## SOMETIMES_CONSUMES
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ PwdCredentialProviderExtra.uni
+ \ No newline at end of file
diff --git a/Core/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderExtra.uni b/Core/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderExtra.uni
new file mode 100644
index 0000000000..be332aa681
--- /dev/null
+++ b/Core/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderExtra.uni
@@ -0,0 +1,19 @@
+// /** @file
+// PwdCredentialProvider Localized Strings and Content
+//
+// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Password Credential Provider"
+
+
diff --git a/Core/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderStrings.uni b/Core/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderStrings.uni
new file mode 100644
index 0000000000..ca0e5669c0
--- /dev/null
+++ b/Core/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderStrings.uni
@@ -0,0 +1,38 @@
+/** @file
+ String definitions for the Password Credential Provider.
+
+Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#langdef en-US "English"
+#langdef fr-FR "Francais"
+
+#string STR_CREDENTIAL_TITLE #language en-US "Password Credential Provider"
+ #language fr-FR "Password Credential Provider (French)"
+#string STR_FORM_TITLE #language en-US "Get Password"
+ #language fr-FR "Get Password(French)"
+#string STR_NULL_STRING #language en-US ""
+ #language fr-FR ""
+#string STR_INPUT_PASSWORD #language en-US "Please Input Password"
+ #language fr-FR "Please Input Password(French)"
+#string STR_PROVIDER_NAME #language en-US "INTEL Password Credential Provider"
+ #language fr-FR "INTEL Password Credential Provider(French)"
+#string STR_PROVIDER_TYPE_NAME #language en-US "Password Credential Provider"
+ #language fr-FR "Password Credential Provider(French)"
+#string STR_INPUT_PASSWORD_AGAIN #language en-US "Input Password Again"
+ #language fr-FR "Input Password Again (French)"
+#string STR_DRAW_A_LINE #language en-US "-----------------------------"
+ #language fr-FR "------------------------------------"
+#string STR_PASSWORD_INCORRECT #language en-US " Incorrect Password! "
+ #language fr-FR " Incorrect Password! (French) "
+#string STR_PASSWORD_MISMATCH #language en-US " The Password Mismatch! "
+ #language fr-FR " The Password Mismatch! (French) "
+
diff --git a/Core/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderVfr.Vfr b/Core/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderVfr.Vfr
new file mode 100644
index 0000000000..60972203b0
--- /dev/null
+++ b/Core/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderVfr.Vfr
@@ -0,0 +1,34 @@
+/** @file
+ Password Credential Provider formset.
+
+Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "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),
+ flags = INTERACTIVE,
+ key = KEY_GET_PASSWORD;
+
+ endform;
+
+endformset; \ No newline at end of file
diff --git a/Core/SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProvider.c b/Core/SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProvider.c
new file mode 100644
index 0000000000..f623f48304
--- /dev/null
+++ b/Core/SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProvider.c
@@ -0,0 +1,1410 @@
+/** @file
+ Usb Credential Provider driver implemenetation.
+
+Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "UsbCredentialProvider.h"
+
+CREDENTIAL_TABLE *mUsbTable = NULL;
+USB_PROVIDER_CALLBACK_INFO *mCallbackInfo = NULL;
+USB_CREDENTIAL_INFO *mUsbInfoHandle = NULL;
+
+EFI_USER_CREDENTIAL2_PROTOCOL gUsbCredentialProviderDriver = {
+ USB_CREDENTIAL_PROVIDER_GUID,
+ EFI_USER_CREDENTIAL_CLASS_SECURE_CARD,
+ CredentialEnroll,
+ CredentialForm,
+ CredentialTile,
+ CredentialTitle,
+ CredentialUser,
+ CredentialSelect,
+ CredentialDeselect,
+ CredentialDefault,
+ CredentialGetInfo,
+ CredentialGetNextInfo,
+ EFI_CREDENTIAL_CAPABILITIES_ENROLL,
+ CredentialDelete
+};
+
+
+/**
+ 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, update or delete info in table, and sync with NV variable.
+
+ @param[in] Index The index of the password in table. If index is found in
+ table, update the info, else add the into to table.
+ @param[in] Info The new credential info to add into table. If Info is NULL,
+ delete the info by Index.
+
+ @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;
+ USB_INFO *NewUsbInfo;
+
+ NewUsbInfo = NULL;
+ if (Index < mUsbTable->Count) {
+ if (Info == NULL) {
+ //
+ // Delete the specified entry.
+ //
+ mUsbTable->Count--;
+ if (Index != mUsbTable->Count) {
+ NewUsbInfo = &mUsbTable->UserInfo[mUsbTable->Count];
+ }
+ } else {
+ //
+ // Update the specified entry.
+ //
+ NewUsbInfo = Info;
+ }
+ } else {
+ //
+ // Add a new entry
+ //
+ if (Info == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (mUsbTable->Count >= mUsbTable->MaxCount) {
+ ExpandTableSize ();
+ }
+
+ NewUsbInfo = Info;
+ mUsbTable->Count++;
+ }
+
+ if (NewUsbInfo != NULL) {
+ CopyMem (&mUsbTable->UserInfo[Index], NewUsbInfo, sizeof (USB_INFO));
+ }
+
+ //
+ // Save the credential table.
+ //
+ Status = gRT->SetVariable (
+ L"UsbCredential",
+ &gUsbCredentialProviderGuid,
+ 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",
+ &gUsbCredentialProviderGuid,
+ 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",
+ &gUsbCredentialProviderGuid,
+ 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 = PcdGetPtr (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 (
+ &gUsbCredentialProviderGuid,
+ 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 a user on this credential provider. If the user exists on
+ this credential provider, update the user information on this credential provider;
+ otherwise add the user information on credential provider.
+
+ @param[in] This Points to this instance of EFI_USER_CREDENTIAL2_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_CREDENTIAL2_PROTOCOL *This,
+ IN EFI_USER_PROFILE_HANDLE User
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ USB_INFO UsbInfo;
+ EFI_USER_INFO *UserInfo;
+ EFI_INPUT_KEY Key;
+ UINT8 *UserId;
+ CHAR16 *QuestionStr;
+ CHAR16 *PromptStr;
+
+ if ((This == NULL) || (User == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Get User Identifier
+ //
+ UserInfo = NULL;
+ Status = FindUserInfoByType (
+ User,
+ EFI_USER_INFO_IDENTIFIER_RECORD,
+ &UserInfo
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CopyMem (UsbInfo.UserId, (UINT8 *) (UserInfo + 1), sizeof (EFI_USER_INFO_IDENTIFIER));
+ FreePool (UserInfo);
+
+ //
+ // 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));
+ CreatePopUp (
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
+ &Key,
+ QuestionStr,
+ L"",
+ PromptStr,
+ NULL
+ );
+ FreePool (QuestionStr);
+ FreePool (PromptStr);
+ return Status;
+ }
+
+ //
+ // Check whether User is ever enrolled in the provider.
+ //
+ for (Index = 0; Index < mUsbTable->Count; Index++) {
+ UserId = (UINT8 *) &mUsbTable->UserInfo[Index].UserId;
+ if (CompareMem (UserId, (UINT8 *) &UsbInfo.UserId, sizeof (EFI_USER_INFO_IDENTIFIER)) == 0) {
+ //
+ // User already exists, update the password.
+ //
+ break;
+ }
+ }
+
+ //
+ // Enroll the User to the provider.
+ //
+ Status = ModifyTable (Index, &UsbInfo);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ 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_CREDENTIAL2_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_CREDENTIAL2_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_CREDENTIAL2_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_CREDENTIAL2_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_CREDENTIAL2_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_CREDENTIAL2_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_CREDENTIAL2_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_CREDENTIAL2_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;
+ 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));
+ CreatePopUp (
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
+ &Key,
+ QuestionStr,
+ L"",
+ PromptStr,
+ NULL
+ );
+ 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);
+
+ return EFI_NOT_READY;
+}
+
+
+/**
+ 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_CREDENTIAL2_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_CREDENTIAL2_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_CREDENTIAL2_PROTOCOL.
+
+ @retval EFI_SUCCESS Credential provider successfully deselected.
+
+**/
+EFI_STATUS
+EFIAPI
+CredentialDeselect (
+ IN CONST EFI_USER_CREDENTIAL2_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_CREDENTIAL2_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_CREDENTIAL2_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_CREDENTIAL2_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_CREDENTIAL2_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_CREDENTIAL2_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_CREDENTIAL2_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, &gUsbCredentialProviderGuid);
+ CopyGuid ((EFI_GUID *)(Info + 1), &gUsbCredentialProviderGuid);
+
+ 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, &gUsbCredentialProviderGuid);
+ 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, &gUsbCredentialProviderGuid);
+ 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, &gUsbCredentialProviderGuid);
+ 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;
+}
+
+
+/**
+ Delete a user on this credential provider.
+
+ This function deletes a user on this credential provider.
+
+ @param[in] This Points to this instance of the EFI_USER_CREDENTIAL2_PROTOCOL.
+ @param[in] User The user profile handle to delete.
+
+ @retval EFI_SUCCESS User profile was successfully deleted.
+ @retval EFI_ACCESS_DENIED Current user profile does not permit deletion on the user profile handle.
+ Either the user profile cannot delete on any user profile or cannot delete
+ on a user profile other than the current user profile.
+ @retval EFI_UNSUPPORTED This credential provider does not support deletion in the pre-OS.
+ @retval EFI_DEVICE_ERROR The new credential could not be deleted because of a device error.
+ @retval EFI_INVALID_PARAMETER User does not refer to a valid user profile handle.
+**/
+EFI_STATUS
+EFIAPI
+CredentialDelete (
+ IN CONST EFI_USER_CREDENTIAL2_PROTOCOL *This,
+ IN EFI_USER_PROFILE_HANDLE User
+ )
+{
+ EFI_STATUS Status;
+ EFI_USER_INFO *UserInfo;
+ UINT8 *UserId;
+ UINT8 *NewUserId;
+ UINTN Index;
+
+ if ((This == NULL) || (User == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Get User Identifier.
+ //
+ UserInfo = NULL;
+ Status = FindUserInfoByType (
+ User,
+ EFI_USER_INFO_IDENTIFIER_RECORD,
+ &UserInfo
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Find the user by user identifier in mPwdTable.
+ //
+ 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) {
+ //
+ // Found the user, delete it.
+ //
+ ModifyTable (Index, NULL);
+ break;
+ }
+ }
+
+ FreePool (UserInfo);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ 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;
+
+ //
+ // It is NOT robust enough to be included in production.
+ //
+ #error "This implementation is just a sample, please comment this line if you really want to use this driver."
+
+ //
+ // 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,
+ &gEfiUserCredential2ProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &gUsbCredentialProviderDriver
+ );
+ return Status;
+}
diff --git a/Core/SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProvider.h b/Core/SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProvider.h
new file mode 100644
index 0000000000..83f7f9e2ca
--- /dev/null
+++ b/Core/SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProvider.h
@@ -0,0 +1,361 @@
+/** @file
+ Usb Credential Provider driver header file.
+
+Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _USB_CREDENTIAL_PROVIDER_H_
+#define _USB_CREDENTIAL_PROVIDER_H_
+
+#include <Uefi.h>
+
+#include <Guid/GlobalVariable.h>
+#include <Guid/FileInfo.h>
+#include <Guid/SecurityPkgTokenSpace.h>
+#include <Guid/UsbCredentialProviderHii.h>
+
+#include <Protocol/SimpleFileSystem.h>
+#include <Protocol/BlockIo.h>
+#include <Protocol/UserCredential2.h>
+#include <Protocol/UserManager.h>
+
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/BaseCryptLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+#include <Library/PrintLib.h>
+#include <Library/HiiLib.h>
+#include <Library/PcdLib.h>
+
+extern UINT8 UsbCredentialProviderStrings[];
+
+#define USB_TABLE_INC 16
+#define HASHED_CREDENTIAL_LEN 20
+
+//
+// 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;
+
+#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_CREDENTIAL2_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_CREDENTIAL2_PROTOCOL *This,
+ IN EFI_USER_PROFILE_HANDLE User
+ );
+
+/**
+ Returns the user interface information used during user identification.
+
+ This function enrolls a user on this credential provider. If the user exists on
+ this credential provider, update the user information on this credential provider;
+ otherwise delete the user information on credential provider.
+
+ @param[in] This Points to this instance of the EFI_USER_CREDENTIAL2_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_CREDENTIAL2_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_CREDENTIAL2_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_CREDENTIAL2_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_CREDENTIAL2_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_CREDENTIAL2_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_CREDENTIAL2_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_CREDENTIAL2_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_CREDENTIAL2_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_CREDENTIAL2_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_CREDENTIAL2_PROTOCOL.
+
+ @retval EFI_SUCCESS Credential provider successfully deselected.
+
+**/
+EFI_STATUS
+EFIAPI
+CredentialDeselect (
+ IN CONST EFI_USER_CREDENTIAL2_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_CREDENTIAL2_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_CREDENTIAL2_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_CREDENTIAL2_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_CREDENTIAL2_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_CREDENTIAL2_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_CREDENTIAL2_PROTOCOL *This,
+ IN OUT EFI_USER_INFO_HANDLE *UserInfo
+ );
+
+/**
+ Delete a user on this credential provider.
+
+ This function deletes a user on this credential provider.
+
+ @param[in] This Points to this instance of the EFI_USER_CREDENTIAL2_PROTOCOL.
+ @param[in] User The user profile handle to delete.
+
+ @retval EFI_SUCCESS User profile was successfully deleted.
+ @retval EFI_ACCESS_DENIED Current user profile does not permit deletion on the user profile handle.
+ Either the user profile cannot delete on any user profile or cannot delete
+ on a user profile other than the current user profile.
+ @retval EFI_UNSUPPORTED This credential provider does not support deletion in the pre-OS.
+ @retval EFI_DEVICE_ERROR The new credential could not be deleted because of a device error.
+ @retval EFI_INVALID_PARAMETER User does not refer to a valid user profile handle.
+**/
+EFI_STATUS
+EFIAPI
+CredentialDelete (
+ IN CONST EFI_USER_CREDENTIAL2_PROTOCOL *This,
+ IN EFI_USER_PROFILE_HANDLE User
+ );
+
+#endif
diff --git a/Core/SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProvider.uni b/Core/SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProvider.uni
new file mode 100644
index 0000000000..961e09f360
--- /dev/null
+++ b/Core/SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProvider.uni
@@ -0,0 +1,23 @@
+// /** @file
+// Provides a USB credential provider implementation
+//
+// This module reads a token from a token file that is saved in the root
+// folder of a USB stick. The token file name can be specified by the PCD
+// PcdFixedUsbCredentialProviderTokenFileName.
+//
+// Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides a USB credential provider implementation"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This module reads a token from a token file that is saved in the root folder of a USB stick. The token file name can be specified by the PCD PcdFixedUsbCredentialProviderTokenFileName."
+
diff --git a/Core/SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProviderDxe.inf b/Core/SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProviderDxe.inf
new file mode 100644
index 0000000000..87a66fbea0
--- /dev/null
+++ b/Core/SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProviderDxe.inf
@@ -0,0 +1,70 @@
+## @file
+# Provides a USB credential provider implementation
+#
+# This module reads a token from a token file that is saved in the root
+# folder of a USB stick. The token file name can be specified by the PCD
+# PcdFixedUsbCredentialProviderTokenFileName.
+#
+# Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = UsbCredentialProvider
+ MODULE_UNI_FILE = UsbCredentialProvider.uni
+ 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]
+ ## PRODUCES ## Variable:L"UsbCredential"
+ ## CONSUMES ## Variable:L"UsbCredential"
+ ## CONSUMES ## HII
+ ## SOMETIMES_CONSUMES ## GUID # The credential provider identifier
+ gUsbCredentialProviderGuid
+
+ gEfiFileInfoGuid ## SOMETIMES_CONSUMES ## GUID
+ gEfiUserCredentialClassSecureCardGuid ## SOMETIMES_CONSUMES ## GUID
+
+[Pcd]
+ gEfiSecurityPkgTokenSpaceGuid.PcdFixedUsbCredentialProviderTokenFileName ## SOMETIMES_CONSUMES
+
+[Protocols]
+ gEfiUserCredential2ProtocolGuid ## PRODUCES
+ gEfiUserManagerProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiBlockIoProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiSimpleFileSystemProtocolGuid ## SOMETIMES_CONSUMES
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ UsbCredentialProviderExtra.uni
+ \ No newline at end of file
diff --git a/Core/SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProviderExtra.uni b/Core/SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProviderExtra.uni
new file mode 100644
index 0000000000..0fc955e477
--- /dev/null
+++ b/Core/SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProviderExtra.uni
@@ -0,0 +1,19 @@
+// /** @file
+// UsbCredentialProvider Localized Strings and Content
+//
+// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"USB Credential Provider"
+
+
diff --git a/Core/SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProviderStrings.uni b/Core/SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProviderStrings.uni
new file mode 100644
index 0000000000..b91fe9ca06
--- /dev/null
+++ b/Core/SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProviderStrings.uni
@@ -0,0 +1,29 @@
+/** @file
+ String definitions for the USB Credential Provider.
+
+Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#langdef en-US "English"
+#langdef fr-FR "Francais"
+
+#string STR_CREDENTIAL_TITLE #language en-US "USB Credential Provider"
+ #language fr-FR "USB Credential Provider (French)"
+#string STR_NULL_STRING #language en-US ""
+ #language fr-FR ""
+#string STR_PROVIDER_NAME #language en-US "INTEL USB Credential Provider"
+ #language fr-FR "INTEL USB Credential Provider (French)"
+#string STR_PROVIDER_TYPE_NAME #language en-US "Secure Card Credential Provider"
+ #language fr-FR "Secure Card Credential Provider (French)"
+#string STR_READ_USB_TOKEN_ERROR #language en-US "Read USB Token File Error!"
+ #language fr-FR "Read USB Token File Error! (French)"
+#string STR_INSERT_USB_TOKEN #language en-US "Please insert USB key with Token"
+ #language fr-FR "Please insert USB key with Token (French)"
diff --git a/Core/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/LoadDeferredImage.c b/Core/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/LoadDeferredImage.c
new file mode 100644
index 0000000000..da1201a5f9
--- /dev/null
+++ b/Core/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.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "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/Core/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManager.c b/Core/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManager.c
new file mode 100644
index 0000000000..a7467b3662
--- /dev/null
+++ b/Core/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManager.c
@@ -0,0 +1,3763 @@
+/** @file
+ This driver manages user information and produces user manager protocol.
+
+Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "UserIdentifyManager.h"
+
+//
+// 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)
+ }
+ },
+ USER_IDENTIFY_MANAGER_GUID
+ },
+ {
+ 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;
+}
+
+
+/**
+ 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;
+}
+
+
+/**
+ 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,
+ &gUserIdentifyManagerGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ Delete ? 0 : User->UserProfileSize,
+ User->ProfileInfo
+ );
+ return Status;
+}
+
+/**
+ 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 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;
+ }
+
+ //
+ // 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;
+
+ 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);
+ }
+
+ 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;
+
+ //
+ // 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 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 identifier 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_CREDENTIAL2_PROTOCOL *UserCredential;
+
+ 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;
+ }
+
+ 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_CREDENTIAL2_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
+ &gUserIdentifyManagerGuid,// 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
+ &gUserIdentifyManagerGuid,// 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_CHANGED:
+ 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;
+ }
+ break;
+
+ case EFI_BROWSER_ACTION_CHANGING:
+ //
+ // QuestionId comes from the first Form (Select a user to identify).
+ //
+ if (QuestionId >= LABEL_PROVIDER_NAME) {
+ return EFI_SUCCESS;
+ }
+
+ 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;
+ if (Type == EFI_IFR_TYPE_REF) {
+ Value->ref.FormId = FORMID_INVALID_FORM;
+ }
+ }
+ 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, &gUserIdentifyManagerGuid, &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, &gUserIdentifyManagerGuid, &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, &gUserIdentifyManagerGuid, 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, &gUserIdentifyManagerGuid, 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, &gUserIdentifyManagerGuid, 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,
+ &gEfiUserCredential2ProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuf
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Get provider infomation.
+ //
+ mProviderDb = AllocateZeroPool (
+ sizeof (CREDENTIAL_PROVIDER_INFO) -
+ sizeof (EFI_USER_CREDENTIAL2_PROTOCOL *) +
+ HandleCount * sizeof (EFI_USER_CREDENTIAL2_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],
+ &gEfiUserCredential2ProtocolGuid,
+ (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 <ConfigRequest> 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 <ConfigAltResp> format which
+ has all values filled in for the names in the Request string.
+ String to be allocated by the called function.
+
+ @retval EFI_SUCCESS The Results is filled with the requested values.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results.
+ @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name.
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in this driver.
+
+**/
+EFI_STATUS
+EFIAPI
+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 <ConfigResp> 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 (
+ &gUserIdentifyManagerGuid,
+ 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_CREDENTIAL2_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,
+ &gUserIdentifyManagerGuid,
+ 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_IDENITTY_POLICY_RECORD is changed, it is the caller's responsibility to keep
+ it to be synced with the information on credential providers.
+ 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.
+ If the User Identity Manager doesn't support asynchronous changes in credentials, then this function
+ should return EFI_UNSUPPORTED.
+ If current user does not exist, and the credential provider can identify a user, then make the user
+ to be current user and signal the EFI_EVENT_GROUP_USER_PROFILE_CHANGED event.
+ If current user already exists, and the credential provider can identify another user, then switch
+ current user to the newly identified user, and signal the EFI_EVENT_GROUP_USER_PROFILE_CHANGED event.
+ If current user was identified by this credential provider and now the credential provider cannot identify
+ current user, then logout current user and signal the EFI_EVENT_GROUP_USER_PROFILE_CHANGED event.
+
+ @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_CREDENTIAL2_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
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+
+/**
+ 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;
+
+ //
+ // It is NOT robust enough to be included in production.
+ //
+ #error "This implementation is just a sample, please comment this line if you really want to use this driver."
+
+ //
+ // 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/Core/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManager.h b/Core/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManager.h
new file mode 100644
index 0000000000..fab0605728
--- /dev/null
+++ b/Core/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManager.h
@@ -0,0 +1,413 @@
+/** @file
+ The header file for User identify Manager driver.
+
+Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _USER_IDENTIFY_MANAGER_H_
+#define _USER_IDENTIFY_MANAGER_H_
+
+#include <Uefi.h>
+
+#include <Guid/GlobalVariable.h>
+#include <Guid/MdeModuleHii.h>
+
+#include <Protocol/FormBrowser2.h>
+#include <Protocol/HiiDatabase.h>
+#include <Protocol/HiiConfigAccess.h>
+#include <Protocol/HiiString.h>
+#include <Protocol/HiiConfigRouting.h>
+#include <Protocol/UserCredential2.h>
+#include <Protocol/UserManager.h>
+#include <Protocol/DeferredImageLoad.h>
+#include <Protocol/SimpleTextOut.h>
+#include <Protocol/SimpleTextIn.h>
+#include <Protocol/SimpleTextInEx.h>
+
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+#include <Library/PrintLib.h>
+#include <Library/HiiLib.h>
+
+#include "UserIdentifyManagerData.h"
+
+//
+// This is the generated IFR binary data for each formset defined in VFR.
+// This data array is ready to be used as input of HiiAddPackages() to
+// create a packagelist.
+//
+extern UINT8 UserIdentifyManagerVfrBin[];
+
+//
+// This is the generated String package data for all .UNI files.
+// This data array is ready to be used as input of HiiAddPackages() to
+// create a packagelist.
+//
+extern UINT8 UserIdentifyManagerStrings[];
+
+#define USER_NUMBER_INC 32
+#define DEFAULT_PROFILE_SIZE 512
+#define INFO_PAYLOAD_SIZE 64
+
+//
+// Credential Provider Information.
+//
+typedef struct {
+ UINTN Count;
+ EFI_USER_CREDENTIAL2_PROTOCOL *Provider[1];
+} CREDENTIAL_PROVIDER_INFO;
+
+//
+// Internal user profile entry.
+//
+typedef struct {
+ UINTN MaxProfileSize;
+ UINTN UserProfileSize;
+ CHAR16 UserVarName[9];
+ UINT8 *ProfileInfo;
+} USER_PROFILE_ENTRY;
+
+//
+// Internal user profile database.
+//
+typedef struct {
+ UINTN UserProfileNum;
+ UINTN MaxProfileNum;
+ EFI_USER_PROFILE_HANDLE UserProfile[1];
+} USER_PROFILE_DB;
+
+#define USER_MANAGER_SIGNATURE SIGNATURE_32 ('U', 'I', 'M', 'S')
+
+typedef struct {
+ UINTN Signature;
+ EFI_HANDLE DriverHandle;
+ EFI_HII_HANDLE HiiHandle;
+
+ //
+ // Consumed protocol.
+ //
+ EFI_HII_DATABASE_PROTOCOL *HiiDatabase;
+ EFI_HII_STRING_PROTOCOL *HiiString;
+ EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
+ EFI_FORM_BROWSER2_PROTOCOL *FormBrowser2;
+
+ //
+ // Produced protocol.
+ //
+ EFI_HII_CONFIG_ACCESS_PROTOCOL ConfigAccess;
+} USER_MANAGER_CALLBACK_INFO;
+
+///
+/// HII specific Vendor Device Path definition.
+///
+typedef struct {
+ VENDOR_DEVICE_PATH VendorDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} HII_VENDOR_DEVICE_PATH;
+
+/**
+ Register an event notification function for the user profile changed.
+
+ @param[in] ImageHandle Image handle this driver.
+
+**/
+VOID
+LoadDeferredImageInit (
+ IN EFI_HANDLE ImageHandle
+ );
+
+
+/**
+ 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 Protocol EFI_USER_MANAGER_PROTOCOL instance
+ pointer.
+ @param[out] User Handle of a new user profile.
+
+ @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 User is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+UserProfileCreate (
+ IN CONST EFI_USER_MANAGER_PROTOCOL *This,
+ OUT EFI_USER_PROFILE_HANDLE *User
+ );
+
+
+/**
+ Delete an existing user profile.
+
+ @param This Protocol EFI_USER_MANAGER_PROTOCOL instance
+ pointer.
+ @param 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
+ );
+
+
+/**
+ Get next user profile from the user profile database.
+
+ @param[in] This Protocol EFI_USER_MANAGER_PROTOCOL instance
+ pointer.
+ @param[in, out] User User profile handle.
+
+ @retval EFI_SUCCESS Next enrolled user profile successfully returned.
+ @retval EFI_INVALID_PARAMETER User is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+UserProfileGetNext (
+ IN CONST EFI_USER_MANAGER_PROTOCOL *This,
+ IN OUT EFI_USER_PROFILE_HANDLE *User
+ );
+
+
+/**
+ This function returns the current user profile handle.
+
+ @param[in] This Protocol EFI_USER_MANAGER_PROTOCOL instance pointer.
+ @param[out] CurrentUser User profile handle.
+
+ @retval EFI_SUCCESS Current user profile handle returned successfully.
+ @retval EFI_INVALID_PARAMETER CurrentUser is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+UserProfileCurrent (
+ IN CONST EFI_USER_MANAGER_PROTOCOL *This,
+ OUT EFI_USER_PROFILE_HANDLE *CurrentUser
+ );
+
+
+/**
+ Identify the user and, if authenticated, returns the user handle and changes
+ the current user profile.
+
+ @param This Protocol EFI_USER_MANAGER_PROTOCOL instance pointer.
+ @param CurrentUser User profile handle.
+
+ @retval EFI_SUCCESS User was successfully identified.
+ @retval EFI_INVALID_PARAMETER User is NULL.
+ @retval EFI_ACCESS_DENIED User was not successfully identified.
+
+**/
+EFI_STATUS
+EFIAPI
+UserProfileIdentify (
+ IN CONST EFI_USER_MANAGER_PROTOCOL *This,
+ OUT EFI_USER_PROFILE_HANDLE *User
+ );
+
+
+/**
+ 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] 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 NULL, 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.
+
+**/
+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
+ );
+
+
+/**
+ This function returns user information.
+
+ @param This Protocol EFI_USER_MANAGER_PROTOCOL instance
+ pointer.
+ @param User Handle of the user whose profile will be
+ retrieved.
+ @param UserInfo Handle of the user information data record.
+ @param Info On entry, points to a buffer of at least
+ *InfoSize bytes. On exit, holds the user
+ information.
+ @param 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.
+ EFI_BUFFER_TOO_SMALL- The number of bytes
+ specified by *InfoSize is too small to hold the
+ returned data.
+
+**/
+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
+ );
+
+
+/**
+ This function changes user information.
+
+ @param This Protocol EFI_USER_MANAGER_PROTOCOL instance
+ pointer.
+ @param User Handle of the user whose profile will be
+ retrieved.
+ @param UserInfo Handle of the user information data record.
+ @param Info Points to the user information.
+ @param InfoSize The size of Info, in bytes.
+
+ @retval EFI_SUCCESS User profile information was successfully
+ changed/added.
+ @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.
+
+**/
+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
+ );
+
+
+/**
+ This function allows the credential provider to notify the User Identity Manager
+ when user status has changed while deselected.
+
+ @param This Protocol EFI_USER_MANAGER_PROTOCOL instance
+ pointer.
+ @param Changed Points to the 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
+ );
+
+
+/**
+ Delete the user information attached to the user profile specified by the UserInfo.
+
+ @param This Protocol EFI_USER_MANAGER_PROTOCOL instance pointer.
+ @param User Handle of the user whose profile will be retrieved.
+ @param UserInfo Handle of the user information data record.
+
+ @retval EFI_SUCCESS User information deleted successfully.
+ @retval EFI_ACCESS_DENIED The current user does not have permission to
+ delete this user in-formation.
+ @retval EFI_NOT_FOUND User information record UserInfo does not exist
+ in the user pro-file.
+
+**/
+EFI_STATUS
+EFIAPI
+UserProfileDeleteInfo (
+ IN CONST EFI_USER_MANAGER_PROTOCOL *This,
+ IN EFI_USER_PROFILE_HANDLE User,
+ IN EFI_USER_INFO_HANDLE UserInfo
+ );
+
+
+/**
+ This function returns the next user information record.
+
+ @param This Protocol EFI_USER_MANAGER_PROTOCOL instance pointer.
+ @param User Handle of the user whose profile will be retrieved.
+ @param UserInfo Handle of the user information data record.
+
+ @retval EFI_SUCCESS User information returned.
+ @retval EFI_NOT_FOUND No more user information found.
+
+**/
+EFI_STATUS
+EFIAPI
+UserProfileGetNextInfo (
+ IN CONST EFI_USER_MANAGER_PROTOCOL *This,
+ IN EFI_USER_PROFILE_HANDLE User,
+ IN OUT EFI_USER_INFO_HANDLE *UserInfo
+ );
+
+#endif
diff --git a/Core/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManager.uni b/Core/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManager.uni
new file mode 100644
index 0000000000..82c72baeeb
--- /dev/null
+++ b/Core/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManager.uni
@@ -0,0 +1,21 @@
+// /** @file
+// Produces user manager protocol
+//
+// This module manages user information and produces user manager protocol.
+//
+// Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Produces user manager protocol"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This module manages user information and produces user manager protocol."
+
diff --git a/Core/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManagerData.h b/Core/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManagerData.h
new file mode 100644
index 0000000000..b08ac46437
--- /dev/null
+++ b/Core/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManagerData.h
@@ -0,0 +1,35 @@
+/** @file
+ Data structure used by the user identify manager driver.
+
+Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _USER_IDENTIFY_MANAGER_DATA_H_
+#define _USER_IDENTIFY_MANAGER_DATA_H_
+
+#include <Guid/UserIdentifyManagerHii.h>
+
+//
+// Forms definition.
+//
+#define FORMID_USER_FORM 1
+#define FORMID_PROVIDER_FORM 2
+#define FORMID_INVALID_FORM 0x0FFF
+
+//
+// Labels definition.
+//
+#define LABEL_USER_NAME 0x1000
+#define LABEL_PROVIDER_NAME 0x3000
+#define LABEL_END 0xffff
+#define FORM_OPEN_QUESTION_ID 0xfffe
+
+#endif
diff --git a/Core/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManagerDxe.inf b/Core/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManagerDxe.inf
new file mode 100644
index 0000000000..ac23818660
--- /dev/null
+++ b/Core/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManagerDxe.inf
@@ -0,0 +1,79 @@
+## @file
+# Produces user manager protocol
+#
+# This module manages user information and produces user manager protocol.
+#
+# Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = UserIdentifyManager
+ MODULE_UNI_FILE = UserIdentifyManager.uni
+ FILE_GUID = C5D3191B-27D5-4873-8DF2-628136991A21
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = UserIdentifyManagerInit
+
+[sources]
+ UserIdentifyManager.c
+ LoadDeferredImage.c
+ UserIdentifyManager.h
+ UserIdentifyManagerData.h
+ UserIdentifyManagerStrings.uni
+ UserIdentifyManagerVfr.Vfr
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+ UefiRuntimeServicesTableLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ MemoryAllocationLib
+ BaseMemoryLib
+ DebugLib
+ HiiLib
+ UefiLib
+
+[Guids]
+ gEfiIfrTianoGuid ## SOMETIMES_CONSUMES ## GUID
+ gEfiEventUserProfileChangedGuid ## SOMETIMES_PRODUCES ## Event
+
+ ## SOMETIMES_PRODUCES ## Variable:L"Userxxxx"
+ ## SOMETIMES_CONSUMES ## Variable:L"Userxxxx"
+ ## CONSUMES ## HII
+ gUserIdentifyManagerGuid
+
+[Protocols]
+ gEfiFormBrowser2ProtocolGuid ## CONSUMES
+ gEfiHiiDatabaseProtocolGuid ## CONSUMES
+ gEfiUserCredential2ProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiDeferredImageLoadProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiSimpleTextOutProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiSimpleTextInProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiSimpleTextInputExProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiHiiConfigAccessProtocolGuid ## PRODUCES
+ gEfiDevicePathProtocolGuid ## PRODUCES
+
+ ## PRODUCES
+ ## SOMETIMES_PRODUCES ## SystemTable
+ gEfiUserManagerProtocolGuid
+
+[Depex]
+ gEfiHiiDatabaseProtocolGuid AND
+ gEfiHiiStringProtocolGuid AND
+ gEfiFormBrowser2ProtocolGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ UserIdentifyManagerExtra.uni
+ \ No newline at end of file
diff --git a/Core/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManagerExtra.uni b/Core/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManagerExtra.uni
new file mode 100644
index 0000000000..b0418b6e30
--- /dev/null
+++ b/Core/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManagerExtra.uni
@@ -0,0 +1,19 @@
+// /** @file
+// UserIdentifyManager Localized Strings and Content
+//
+// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"User Identify Manager"
+
+
diff --git a/Core/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManagerStrings.uni b/Core/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManagerStrings.uni
new file mode 100644
index 0000000000..8ac0cdfbec
--- /dev/null
+++ b/Core/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManagerStrings.uni
@@ -0,0 +1,27 @@
+/** @file
+ String definitions for the User Identify Manager driver.
+
+Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#langdef en-US "English"
+#langdef fr-FR "Francais"
+
+#string STR_TITLE #language en-US "User Identity Manager"
+ #language fr-FR "User Identity Manager(French)"
+#string STR_USER_SELECT #language en-US "User Selection"
+ #language fr-FR "User Selection(French)"
+#string STR_PROVIDER_SELECT #language en-US "Provider Selection"
+ #language fr-FR "User Selection(French)"
+#string STR_NULL_STRING #language en-US ""
+ #language fr-FR ""
+
+
diff --git a/Core/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManagerVfr.Vfr b/Core/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManagerVfr.Vfr
new file mode 100644
index 0000000000..306679776d
--- /dev/null
+++ b/Core/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManagerVfr.Vfr
@@ -0,0 +1,43 @@
+/** @file
+ User identify manager formset.
+
+Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "UserIdentifyManagerData.h"
+
+formset
+ guid = USER_IDENTIFY_MANAGER_GUID,
+ title = STRING_TOKEN(STR_TITLE),
+ help = STRING_TOKEN(STR_NULL_STRING),
+ classguid = USER_IDENTIFY_MANAGER_GUID,
+
+ form formid = FORMID_USER_FORM,
+ title = STRING_TOKEN(STR_USER_SELECT);
+
+ suppressif TRUE;
+ text
+ help = STRING_TOKEN(STR_NULL_STRING),
+ text = STRING_TOKEN(STR_NULL_STRING),
+ flags = INTERACTIVE,
+ key = FORM_OPEN_QUESTION_ID;
+ endif;
+
+ label LABEL_USER_NAME;
+ label LABEL_END;
+ endform;
+
+ form formid = FORMID_PROVIDER_FORM,
+ title = STRING_TOKEN(STR_PROVIDER_SELECT);
+ label LABEL_PROVIDER_NAME;
+ label LABEL_END;
+ endform;
+endformset; \ No newline at end of file
diff --git a/Core/SecurityPkg/UserIdentification/UserProfileManagerDxe/ModifyAccessPolicy.c b/Core/SecurityPkg/UserIdentification/UserProfileManagerDxe/ModifyAccessPolicy.c
new file mode 100644
index 0000000000..5b4171ddec
--- /dev/null
+++ b/Core/SecurityPkg/UserIdentification/UserProfileManagerDxe/ModifyAccessPolicy.c
@@ -0,0 +1,688 @@
+/** @file
+ The functions for access policy modification.
+
+Copyright (c) 2009 - 2013, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "UserProfileManager.h"
+
+/**
+ Collect all the access policy data to mUserInfo.AccessPolicy,
+ and save it to user profile.
+
+**/
+VOID
+SaveAccessPolicy (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN OffSet;
+ UINTN Size;
+ EFI_USER_INFO_ACCESS_CONTROL Control;
+ EFI_USER_INFO_HANDLE UserInfo;
+ EFI_USER_INFO *Info;
+
+ if (mUserInfo.AccessPolicy != NULL) {
+ FreePool (mUserInfo.AccessPolicy);
+ }
+ mUserInfo.AccessPolicy = NULL;
+ mUserInfo.AccessPolicyLen = 0;
+ mUserInfo.AccessPolicyModified = TRUE;
+ OffSet = 0;
+
+ //
+ // Save access right.
+ //
+ Size = sizeof (EFI_USER_INFO_ACCESS_CONTROL);
+ if (mUserInfo.AccessPolicyLen - OffSet < Size) {
+ ExpandMemory (OffSet, Size);
+ }
+
+ Control.Type = mAccessInfo.AccessRight;
+ Control.Size = (UINT32) Size;
+ CopyMem (mUserInfo.AccessPolicy + OffSet, &Control, sizeof (Control));
+ OffSet += sizeof (Control);
+
+ //
+ // Save access setup.
+ //
+ Size = sizeof (EFI_USER_INFO_ACCESS_CONTROL) + sizeof (EFI_GUID);
+ if (mUserInfo.AccessPolicyLen - OffSet < Size) {
+ ExpandMemory (OffSet, Size);
+ }
+
+ Control.Type = EFI_USER_INFO_ACCESS_SETUP;
+ Control.Size = (UINT32) Size;
+ CopyMem (mUserInfo.AccessPolicy + OffSet, &Control, sizeof (Control));
+ OffSet += sizeof (Control);
+
+ if (mAccessInfo.AccessSetup == ACCESS_SETUP_NORMAL) {
+ CopyGuid ((EFI_GUID *) (mUserInfo.AccessPolicy + OffSet), &gEfiUserInfoAccessSetupNormalGuid);
+ } else if (mAccessInfo.AccessSetup == ACCESS_SETUP_RESTRICTED) {
+ CopyGuid ((EFI_GUID *) (mUserInfo.AccessPolicy + OffSet), &gEfiUserInfoAccessSetupRestrictedGuid);
+ } else if (mAccessInfo.AccessSetup == ACCESS_SETUP_ADMIN) {
+ CopyGuid ((EFI_GUID *) (mUserInfo.AccessPolicy + OffSet), &gEfiUserInfoAccessSetupAdminGuid);
+ }
+ OffSet += sizeof (EFI_GUID);
+
+ //
+ // Save access of boot order.
+ //
+ Size = sizeof (EFI_USER_INFO_ACCESS_CONTROL) + sizeof (UINT32);
+ if (mUserInfo.AccessPolicyLen - OffSet < Size) {
+ ExpandMemory (OffSet, Size);
+ }
+
+ Control.Type = EFI_USER_INFO_ACCESS_BOOT_ORDER;
+ Control.Size = (UINT32) Size;
+ CopyMem (mUserInfo.AccessPolicy + OffSet, &Control, sizeof (Control));
+ OffSet += sizeof (Control);
+
+ CopyMem ((UINT8 *) (mUserInfo.AccessPolicy + OffSet), &mAccessInfo.AccessBootOrder, sizeof (UINT32));
+ OffSet += sizeof (UINT32);
+
+ //
+ // Save permit load.
+ //
+ if (mAccessInfo.LoadPermitLen > 0) {
+ Size = sizeof (EFI_USER_INFO_ACCESS_CONTROL) + mAccessInfo.LoadPermitLen;
+ if (mUserInfo.AccessPolicyLen - OffSet < Size) {
+ ExpandMemory (OffSet, Size);
+ }
+
+ Control.Type = EFI_USER_INFO_ACCESS_PERMIT_LOAD;
+ Control.Size = (UINT32) Size;
+ CopyMem (mUserInfo.AccessPolicy + OffSet, &Control, sizeof (Control));
+ OffSet += sizeof (Control);
+
+ CopyMem (mUserInfo.AccessPolicy + OffSet, mAccessInfo.LoadPermit, mAccessInfo.LoadPermitLen);
+ OffSet += mAccessInfo.LoadPermitLen;
+ }
+
+ //
+ // Save forbid load.
+ //
+ if (mAccessInfo.LoadForbidLen > 0) {
+ Size = sizeof (EFI_USER_INFO_ACCESS_CONTROL) + mAccessInfo.LoadForbidLen;
+ if (mUserInfo.AccessPolicyLen - OffSet < Size) {
+ ExpandMemory (OffSet, Size);
+ }
+
+ Control.Type = EFI_USER_INFO_ACCESS_FORBID_LOAD;
+ Control.Size = (UINT32) Size;
+ CopyMem (mUserInfo.AccessPolicy + OffSet, &Control, sizeof (Control));
+ OffSet += sizeof (Control);
+
+ CopyMem (mUserInfo.AccessPolicy + OffSet, mAccessInfo.LoadForbid, mAccessInfo.LoadForbidLen);
+ OffSet += mAccessInfo.LoadForbidLen;
+ }
+
+ //
+ // Save permit connect.
+ //
+ if (mAccessInfo.ConnectPermitLen > 0) {
+ Size = sizeof (EFI_USER_INFO_ACCESS_CONTROL) + mAccessInfo.ConnectPermitLen;
+ if (mUserInfo.AccessPolicyLen - OffSet < Size) {
+ ExpandMemory (OffSet, Size);
+ }
+
+ Control.Type = EFI_USER_INFO_ACCESS_PERMIT_CONNECT;
+ Control.Size = (UINT32) Size;
+ CopyMem (mUserInfo.AccessPolicy + OffSet, &Control, sizeof (Control));
+ OffSet += sizeof (Control);
+
+ CopyMem (mUserInfo.AccessPolicy + OffSet, mAccessInfo.ConnectPermit, mAccessInfo.ConnectPermitLen);
+ OffSet += mAccessInfo.ConnectPermitLen;
+ }
+
+ //
+ // Save forbid connect.
+ //
+ if (mAccessInfo.ConnectForbidLen > 0) {
+ Size = sizeof (EFI_USER_INFO_ACCESS_CONTROL) + mAccessInfo.ConnectForbidLen;
+ if (mUserInfo.AccessPolicyLen - OffSet < Size) {
+ ExpandMemory (OffSet, Size);
+ }
+
+ Control.Type = EFI_USER_INFO_ACCESS_FORBID_CONNECT;
+ Control.Size = (UINT32) Size;
+ CopyMem (mUserInfo.AccessPolicy + OffSet, &Control, sizeof (Control));
+ OffSet += sizeof (Control);
+
+ CopyMem (mUserInfo.AccessPolicy + OffSet, mAccessInfo.ConnectForbid, mAccessInfo.ConnectForbidLen);
+ OffSet += mAccessInfo.ConnectForbidLen;
+ }
+
+ mUserInfo.AccessPolicyLen = OffSet;
+
+ //
+ // Save access policy.
+ //
+ if (mUserInfo.AccessPolicyModified && (mUserInfo.AccessPolicyLen > 0) && (mUserInfo.AccessPolicy != NULL)) {
+ Info = AllocateZeroPool (sizeof (EFI_USER_INFO) + mUserInfo.AccessPolicyLen);
+ if (Info == NULL) {
+ return ;
+ }
+
+ Status = FindInfoByType (mModifyUser, EFI_USER_INFO_ACCESS_POLICY_RECORD, &UserInfo);
+ if (!EFI_ERROR (Status)) {
+ Info->InfoType = EFI_USER_INFO_ACCESS_POLICY_RECORD;
+ Info->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV |
+ EFI_USER_INFO_PUBLIC |
+ EFI_USER_INFO_EXCLUSIVE;
+ Info->InfoSize = (UINT32) (sizeof (EFI_USER_INFO) + mUserInfo.AccessPolicyLen);
+ CopyMem ((UINT8 *) (Info + 1), mUserInfo.AccessPolicy, mUserInfo.AccessPolicyLen);
+ Status = mUserManager->SetInfo (
+ mUserManager,
+ mModifyUser,
+ &UserInfo,
+ Info,
+ Info->InfoSize
+ );
+ mUserInfo.AccessPolicyModified = FALSE;
+ }
+ FreePool (Info);
+ }
+
+ if (mAccessInfo.ConnectForbid != NULL) {
+ FreePool (mAccessInfo.ConnectForbid);
+ mAccessInfo.ConnectForbid = NULL;
+ }
+
+ if (mAccessInfo.ConnectPermit != NULL) {
+ FreePool (mAccessInfo.ConnectPermit);
+ mAccessInfo.ConnectPermit = NULL;
+ }
+
+ if (mAccessInfo.LoadForbid != NULL) {
+ FreePool (mAccessInfo.LoadForbid);
+ mAccessInfo.LoadForbid = NULL;
+ }
+
+ if (mAccessInfo.LoadPermit != NULL) {
+ FreePool (mAccessInfo.LoadPermit);
+ mAccessInfo.LoadPermit = NULL;
+ }
+}
+
+/**
+ Create an action OpCode with QuestionID and DevicePath on a given OpCodeHandle.
+
+ @param[in] QuestionID The question ID.
+ @param[in] DevicePath Points to device path.
+ @param[in] OpCodeHandle Points to container for dynamic created opcodes.
+
+**/
+VOID
+AddDevicePath (
+ IN UINTN QuestionID,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ IN VOID *OpCodeHandle
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *Next;
+ EFI_STRING_ID NameID;
+ EFI_STRING DriverName;
+
+ //
+ // Get driver file name node.
+ //
+ Next = DevicePath;
+ while (!IsDevicePathEnd (Next)) {
+ DevicePath = Next;
+ Next = NextDevicePathNode (Next);
+ }
+
+ //
+ // Display the device path in form.
+ //
+ DriverName = ConvertDevicePathToText (DevicePath, FALSE, FALSE);
+ NameID = HiiSetString (mCallbackInfo->HiiHandle, 0, DriverName, NULL);
+ FreePool (DriverName);
+ if (NameID == 0) {
+ return ;
+ }
+
+ HiiCreateActionOpCode (
+ OpCodeHandle, // Container for dynamic created opcodes
+ (UINT16) QuestionID, // Question ID
+ NameID, // Prompt text
+ STRING_TOKEN (STR_NULL_STRING), // Help text
+ EFI_IFR_FLAG_CALLBACK, // Question flag
+ 0 // Action String ID
+ );
+}
+
+
+/**
+ Check whether the DevicePath is in the device path forbid list
+ (mAccessInfo.LoadForbid).
+
+ @param[in] DevicePath Points to device path.
+
+ @retval TRUE The DevicePath is in the device path forbid list.
+ @retval FALSE The DevicePath is not in the device path forbid list.
+
+**/
+BOOLEAN
+IsLoadForbidden (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ UINTN OffSet;
+ UINTN DPSize;
+ UINTN Size;
+ EFI_DEVICE_PATH_PROTOCOL *Dp;
+
+ OffSet = 0;
+ Size = GetDevicePathSize (DevicePath);
+ //
+ // Check each device path.
+ //
+ while (OffSet < mAccessInfo.LoadForbidLen) {
+ Dp = (EFI_DEVICE_PATH_PROTOCOL *) (mAccessInfo.LoadForbid + OffSet);
+ DPSize = GetDevicePathSize (Dp);
+ //
+ // Compare device path.
+ //
+ if ((DPSize == Size) && (CompareMem (DevicePath, Dp, Size) == 0)) {
+ return TRUE;
+ }
+ OffSet += DPSize;
+ }
+ return FALSE;
+}
+
+
+/**
+ Display the permit load device path in the loadable device path list.
+
+**/
+VOID
+DisplayLoadPermit(
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ CHAR16 *Order;
+ UINTN OrderSize;
+ UINTN ListCount;
+ UINTN Index;
+ UINT8 *Var;
+ UINT8 *VarPtr;
+ CHAR16 VarName[12];
+ VOID *StartOpCodeHandle;
+ VOID *EndOpCodeHandle;
+ EFI_IFR_GUID_LABEL *StartLabel;
+ EFI_IFR_GUID_LABEL *EndLabel;
+
+ //
+ // Get DriverOrder.
+ //
+ OrderSize = 0;
+ Status = gRT->GetVariable (
+ L"DriverOrder",
+ &gEfiGlobalVariableGuid,
+ NULL,
+ &OrderSize,
+ NULL
+ );
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ return ;
+ }
+
+ Order = AllocateZeroPool (OrderSize);
+ if (Order == NULL) {
+ return ;
+ }
+
+ Status = gRT->GetVariable (
+ L"DriverOrder",
+ &gEfiGlobalVariableGuid,
+ NULL,
+ &OrderSize,
+ Order
+ );
+ if (EFI_ERROR (Status)) {
+ return ;
+ }
+
+ //
+ // 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_PERMIT_LOAD_FUNC;
+
+ 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 each driver option.
+ //
+ Var = NULL;
+ ListCount = OrderSize / sizeof (UINT16);
+ for (Index = 0; Index < ListCount; Index++) {
+ //
+ // Get driver device path.
+ //
+ UnicodeSPrint (VarName, sizeof (VarName), L"Driver%04x", Order[Index]);
+ GetEfiGlobalVariable2 (VarName, (VOID**)&Var, NULL);
+ if (Var == NULL) {
+ continue;
+ }
+
+ //
+ // Check whether the driver is already forbidden.
+ //
+
+ VarPtr = Var;
+ //
+ // Skip attribute.
+ //
+ VarPtr += sizeof (UINT32);
+
+ //
+ // Skip device path lenth.
+ //
+ VarPtr += sizeof (UINT16);
+
+ //
+ // Skip descript string.
+ //
+ VarPtr += StrSize ((UINT16 *) VarPtr);
+
+ if (IsLoadForbidden ((EFI_DEVICE_PATH_PROTOCOL *) VarPtr)) {
+ FreePool (Var);
+ Var = NULL;
+ continue;
+ }
+
+ AddDevicePath (
+ KEY_MODIFY_USER | KEY_MODIFY_AP_DP | KEY_LOAD_PERMIT_MODIFY | Order[Index],
+ (EFI_DEVICE_PATH_PROTOCOL *) VarPtr,
+ StartOpCodeHandle
+ );
+ FreePool (Var);
+ Var = NULL;
+ }
+
+ HiiUpdateForm (
+ mCallbackInfo->HiiHandle, // HII handle
+ &gUserProfileManagerGuid, // Formset GUID
+ FORMID_PERMIT_LOAD_DP, // Form ID
+ StartOpCodeHandle, // Label for where to insert opcodes
+ EndOpCodeHandle // Replace data
+ );
+
+ HiiFreeOpCodeHandle (StartOpCodeHandle);
+ HiiFreeOpCodeHandle (EndOpCodeHandle);
+
+ //
+ // Clear Environment.
+ //
+ if (Var != NULL) {
+ FreePool (Var);
+ }
+ FreePool (Order);
+}
+
+
+/**
+ Display the forbid load device path list (mAccessInfo.LoadForbid).
+
+**/
+VOID
+DisplayLoadForbid (
+ VOID
+ )
+{
+ UINTN Offset;
+ UINTN DPSize;
+ UINTN Index;
+ EFI_DEVICE_PATH_PROTOCOL *Dp;
+ VOID *StartOpCodeHandle;
+ VOID *EndOpCodeHandle;
+ EFI_IFR_GUID_LABEL *StartLabel;
+ EFI_IFR_GUID_LABEL *EndLabel;
+
+ //
+ // 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 = LABLE_FORBID_LOAD_FUNC;
+
+ 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 each forbid load drivers.
+ //
+ Offset = 0;
+ Index = 0;
+ while (Offset < mAccessInfo.LoadForbidLen) {
+ Dp = (EFI_DEVICE_PATH_PROTOCOL *) (mAccessInfo.LoadForbid + Offset);
+ DPSize = GetDevicePathSize (Dp);
+ AddDevicePath (
+ KEY_MODIFY_USER | KEY_MODIFY_AP_DP | KEY_LOAD_FORBID_MODIFY | Index,
+ Dp,
+ StartOpCodeHandle
+ );
+ Index++;
+ Offset += DPSize;
+ }
+
+ HiiUpdateForm (
+ mCallbackInfo->HiiHandle, // HII handle
+ &gUserProfileManagerGuid, // Formset GUID
+ FORMID_FORBID_LOAD_DP, // Form ID
+ StartOpCodeHandle, // Label for where to insert opcodes
+ EndOpCodeHandle // Replace data
+ );
+
+ HiiFreeOpCodeHandle (StartOpCodeHandle);
+ HiiFreeOpCodeHandle (EndOpCodeHandle);
+}
+
+
+/**
+ Display the permit connect device path.
+
+**/
+VOID
+DisplayConnectPermit (
+ VOID
+ )
+{
+ //
+ // Note:
+ // As no architect protocol/interface to be called in ConnectController()
+ // to verify the device path, just add a place holder for permitted connect
+ // device path.
+ //
+}
+
+
+/**
+ Display the forbid connect device path list.
+
+**/
+VOID
+DisplayConnectForbid (
+ VOID
+ )
+{
+ //
+ // Note:
+ // As no architect protocol/interface to be called in ConnectController()
+ // to verify the device path, just add a place holder for forbidden connect
+ // device path.
+ //
+}
+
+
+/**
+ Delete the specified device path by DriverIndex from the forbid device path
+ list (mAccessInfo.LoadForbid).
+
+ @param[in] DriverIndex The index of driver in forbidden device path list.
+
+**/
+VOID
+DeleteFromForbidLoad (
+ IN UINT16 DriverIndex
+ )
+{
+ UINTN OffSet;
+ UINTN DPSize;
+ UINTN OffLen;
+ EFI_DEVICE_PATH_PROTOCOL *Dp;
+
+ OffSet = 0;
+ //
+ // Find the specified device path.
+ //
+ while ((OffSet < mAccessInfo.LoadForbidLen) && (DriverIndex > 0)) {
+ Dp = (EFI_DEVICE_PATH_PROTOCOL *) (mAccessInfo.LoadForbid + OffSet);
+ DPSize = GetDevicePathSize (Dp);
+ OffSet += DPSize;
+ DriverIndex--;
+ }
+
+ //
+ // Specified device path found.
+ //
+ if (DriverIndex == 0) {
+ Dp = (EFI_DEVICE_PATH_PROTOCOL *) (mAccessInfo.LoadForbid + OffSet);
+ DPSize = GetDevicePathSize (Dp);
+ OffLen = mAccessInfo.LoadForbidLen - OffSet - DPSize;
+ if (OffLen > 0) {
+ CopyMem (
+ mAccessInfo.LoadForbid + OffSet,
+ mAccessInfo.LoadForbid + OffSet + DPSize,
+ OffLen
+ );
+ }
+ mAccessInfo.LoadForbidLen -= DPSize;
+ }
+}
+
+
+/**
+ Add the specified device path by DriverIndex to the forbid device path
+ list (mAccessInfo.LoadForbid).
+
+ @param[in] DriverIndex The index of driver saved in driver options.
+
+**/
+VOID
+AddToForbidLoad (
+ IN UINT16 DriverIndex
+ )
+{
+ UINTN DevicePathLen;
+ UINT8 *Var;
+ UINT8 *VarPtr;
+ UINTN NewLen;
+ UINT8 *NewFL;
+ CHAR16 VarName[13];
+
+ //
+ // Get loadable driver device path.
+ //
+ UnicodeSPrint (VarName, sizeof (VarName), L"Driver%04x", DriverIndex);
+ GetEfiGlobalVariable2 (VarName, (VOID**)&Var, NULL);
+ if (Var == NULL) {
+ return;
+ }
+
+ //
+ // Save forbid load driver.
+ //
+
+ VarPtr = Var;
+ //
+ // Skip attribute.
+ //
+ VarPtr += sizeof (UINT32);
+
+ DevicePathLen = *(UINT16 *) VarPtr;
+ //
+ // Skip device path length.
+ //
+ VarPtr += sizeof (UINT16);
+
+ //
+ // Skip description string.
+ //
+ VarPtr += StrSize ((UINT16 *) VarPtr);
+
+ NewLen = mAccessInfo.LoadForbidLen + DevicePathLen;
+ NewFL = AllocateZeroPool (NewLen);
+ if (NewFL == NULL) {
+ FreePool (Var);
+ return ;
+ }
+
+ if (mAccessInfo.LoadForbidLen > 0) {
+ CopyMem (NewFL, mAccessInfo.LoadForbid, mAccessInfo.LoadForbidLen);
+ FreePool (mAccessInfo.LoadForbid);
+ }
+
+ CopyMem (NewFL + mAccessInfo.LoadForbidLen, VarPtr, DevicePathLen);
+ mAccessInfo.LoadForbidLen = NewLen;
+ mAccessInfo.LoadForbid = NewFL;
+ FreePool (Var);
+}
+
+
diff --git a/Core/SecurityPkg/UserIdentification/UserProfileManagerDxe/ModifyIdentityPolicy.c b/Core/SecurityPkg/UserIdentification/UserProfileManagerDxe/ModifyIdentityPolicy.c
new file mode 100644
index 0000000000..7c58329591
--- /dev/null
+++ b/Core/SecurityPkg/UserIdentification/UserProfileManagerDxe/ModifyIdentityPolicy.c
@@ -0,0 +1,516 @@
+/** @file
+ The functions for identification policy modification.
+
+Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "UserProfileManager.h"
+
+
+/**
+ Verify the new identity policy in the current implementation. The same credential
+ provider can't appear twice in one identity policy.
+
+ @param[in] NewGuid Points to the credential provider guid.
+
+ @retval TRUE The NewGuid was found in the identity policy.
+ @retval FALSE The NewGuid was not found.
+
+**/
+BOOLEAN
+ProviderAlreadyInPolicy (
+ IN EFI_GUID *NewGuid
+ )
+{
+ UINTN Offset;
+ EFI_USER_INFO_IDENTITY_POLICY *Identity;
+ EFI_INPUT_KEY Key;
+
+ Offset = 0;
+ while (Offset < mUserInfo.NewIdentityPolicyLen) {
+ Identity = (EFI_USER_INFO_IDENTITY_POLICY *) (mUserInfo.NewIdentityPolicy + Offset);
+ if (Identity->Type == EFI_USER_INFO_IDENTITY_CREDENTIAL_PROVIDER) {
+ if (CompareGuid (NewGuid, (EFI_GUID *) (Identity + 1))) {
+ CreatePopUp (
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
+ &Key,
+ L"This Credential Provider Are Already Used!",
+ L"",
+ L"Press Any Key to Continue ...",
+ NULL
+ );
+ return TRUE;
+ }
+ }
+ Offset += Identity->Length;
+ }
+
+ return FALSE;
+}
+
+
+/**
+ Add the user's credential record in the provider.
+
+ @param[in] Identity Identity policy item including credential provider.
+ @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
+EnrollUserOnProvider (
+ IN EFI_USER_INFO_IDENTITY_POLICY *Identity,
+ IN EFI_USER_PROFILE_HANDLE User
+ )
+{
+ UINTN Index;
+ EFI_USER_CREDENTIAL2_PROTOCOL *UserCredential;
+
+ //
+ // Find the specified credential provider.
+ //
+ for (Index = 0; Index < mProviderInfo->Count; Index++) {
+ UserCredential = mProviderInfo->Provider[Index];
+ if (CompareGuid ((EFI_GUID *)(Identity + 1), &UserCredential->Identifier)) {
+ return UserCredential->Enroll (UserCredential, User);
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ Delete the User's credential record on the provider.
+
+ @param[in] Identity Point to EFI_USER_INFO_IDENTITY_CREDENTIAL_PROVIDER user info.
+ @param[in] User Points to user profile.
+
+ @retval EFI_SUCCESS Delete User's credential record successfully.
+ @retval Others Fail to add or delete record.
+
+**/
+EFI_STATUS
+DeleteUserOnProvider (
+ IN EFI_USER_INFO_IDENTITY_POLICY *Identity,
+ IN EFI_USER_PROFILE_HANDLE User
+ )
+{
+ UINTN Index;
+ EFI_USER_CREDENTIAL2_PROTOCOL *UserCredential;
+
+ //
+ // Find the specified credential provider.
+ //
+ for (Index = 0; Index < mProviderInfo->Count; Index++) {
+ UserCredential = mProviderInfo->Provider[Index];
+ if (CompareGuid ((EFI_GUID *)(Identity + 1), &UserCredential->Identifier)) {
+ return UserCredential->Delete (UserCredential, User);
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ Delete User's credental from all the providers that exist in User's identity policy.
+
+ @param[in] IdentityPolicy Point to User's identity policy.
+ @param[in] IdentityPolicyLen The length of the identity policy.
+ @param[in] User Points to user profile.
+
+**/
+VOID
+DeleteCredentialFromProviders (
+ IN UINT8 *IdentityPolicy,
+ IN UINTN IdentityPolicyLen,
+ IN EFI_USER_PROFILE_HANDLE User
+ )
+{
+ EFI_USER_INFO_IDENTITY_POLICY *Identity;
+ UINTN Offset;
+
+ Offset = 0;
+ while (Offset < IdentityPolicyLen) {
+ Identity = (EFI_USER_INFO_IDENTITY_POLICY *) (IdentityPolicy + Offset);
+ if (Identity->Type == EFI_USER_INFO_IDENTITY_CREDENTIAL_PROVIDER) {
+ //
+ // Delete the user on this provider.
+ //
+ DeleteUserOnProvider (Identity, User);
+ }
+ Offset += Identity->Length;
+ }
+
+}
+
+
+/**
+ Remove the provider specified by Offset from the new user identification record.
+
+ @param[in] IdentityPolicy Point to user identity item in new identification policy.
+ @param[in] Offset The item offset in the new identification policy.
+
+**/
+VOID
+DeleteProviderFromPolicy (
+ IN EFI_USER_INFO_IDENTITY_POLICY *IdentityPolicy,
+ IN UINTN Offset
+ )
+{
+ UINTN RemainingLen;
+ UINTN DeleteLen;
+
+ if (IdentityPolicy->Length == mUserInfo.NewIdentityPolicyLen) {
+ //
+ // Only one credential provider in the identification policy.
+ // Set the new policy to be TRUE after removed the provider.
+ //
+ IdentityPolicy->Type = EFI_USER_INFO_IDENTITY_TRUE;
+ IdentityPolicy->Length = sizeof (EFI_USER_INFO_IDENTITY_POLICY);
+ mUserInfo.NewIdentityPolicyLen = IdentityPolicy->Length;
+ return ;
+ }
+
+ DeleteLen = IdentityPolicy->Length + sizeof(EFI_USER_INFO_IDENTITY_POLICY);
+ if ((Offset + IdentityPolicy->Length) != mUserInfo.NewIdentityPolicyLen) {
+ //
+ // This provider is not the last item in the identification policy, delete it and the connector.
+ //
+ RemainingLen = mUserInfo.NewIdentityPolicyLen - Offset - DeleteLen;
+ CopyMem ((UINT8 *) IdentityPolicy, (UINT8 *) IdentityPolicy + DeleteLen, RemainingLen);
+ }
+ mUserInfo.NewIdentityPolicyLen -= DeleteLen;
+}
+
+
+/**
+ Add a new provider to the mUserInfo.NewIdentityPolicy.
+
+ It is invoked when 'add option' in UI is pressed.
+
+ @param[in] NewGuid Points to the credential provider guid.
+
+**/
+VOID
+AddProviderToPolicy (
+ IN EFI_GUID *NewGuid
+ )
+{
+ UINT8 *NewPolicyInfo;
+ UINTN NewPolicyInfoLen;
+ EFI_USER_INFO_IDENTITY_POLICY *Policy;
+
+ //
+ // Allocate memory for the new identity policy.
+ //
+ NewPolicyInfoLen = mUserInfo.NewIdentityPolicyLen + sizeof (EFI_USER_INFO_IDENTITY_POLICY) + sizeof (EFI_GUID);
+ if (mUserInfo.NewIdentityPolicyLen > 0) {
+ //
+ // It is not the first provider in the policy. Add a connector before provider.
+ //
+ NewPolicyInfoLen += sizeof (EFI_USER_INFO_IDENTITY_POLICY);
+ }
+ NewPolicyInfo = AllocateZeroPool (NewPolicyInfoLen);
+ if (NewPolicyInfo == NULL) {
+ return ;
+ }
+
+ NewPolicyInfoLen = 0;
+ if (mUserInfo.NewIdentityPolicyLen > 0) {
+ //
+ // Save orginal policy.
+ //
+ CopyMem (NewPolicyInfo, mUserInfo.NewIdentityPolicy, mUserInfo.NewIdentityPolicyLen);
+
+ //
+ // Save logical connector.
+ //
+ Policy = (EFI_USER_INFO_IDENTITY_POLICY *) (NewPolicyInfo + mUserInfo.NewIdentityPolicyLen);
+ if (mConncetLogical == 0) {
+ Policy->Type = EFI_USER_INFO_IDENTITY_AND;
+ } else {
+ Policy->Type = EFI_USER_INFO_IDENTITY_OR;
+ }
+
+ Policy->Length = sizeof (EFI_USER_INFO_IDENTITY_POLICY);
+ NewPolicyInfoLen = mUserInfo.NewIdentityPolicyLen + Policy->Length;
+ FreePool (mUserInfo.NewIdentityPolicy);
+ }
+
+ //
+ // Save credential provider.
+ //
+ Policy = (EFI_USER_INFO_IDENTITY_POLICY *) (NewPolicyInfo + NewPolicyInfoLen);
+ Policy->Length = sizeof (EFI_USER_INFO_IDENTITY_POLICY) + sizeof (EFI_GUID);
+ Policy->Type = EFI_USER_INFO_IDENTITY_CREDENTIAL_PROVIDER;
+ CopyGuid ((EFI_GUID *) (Policy + 1), NewGuid);
+ NewPolicyInfoLen += Policy->Length;
+
+ //
+ // Update identity policy choice.
+ //
+ mUserInfo.NewIdentityPolicy = NewPolicyInfo;
+ mUserInfo.NewIdentityPolicyLen = NewPolicyInfoLen;
+ mUserInfo.NewIdentityPolicyModified = TRUE;
+}
+
+
+/**
+ This function replaces the old identity policy with a new identity policy.
+
+ This function delete the user identity policy information.
+ If enroll new credential failed, recover the old identity policy.
+
+ @retval EFI_SUCCESS Modify user identity policy successfully.
+ @retval Others Fail to modify user identity policy.
+
+**/
+EFI_STATUS
+UpdateCredentialProvider (
+ )
+{
+ EFI_STATUS Status;
+ EFI_USER_INFO_IDENTITY_POLICY *Identity;
+ UINTN Offset;
+
+ //
+ // Delete the old identification policy.
+ //
+ DeleteCredentialFromProviders (mUserInfo.IdentityPolicy, mUserInfo.IdentityPolicyLen, mModifyUser);
+
+ //
+ // Add the new identification policy.
+ //
+ Offset = 0;
+ while (Offset < mUserInfo.NewIdentityPolicyLen) {
+ Identity = (EFI_USER_INFO_IDENTITY_POLICY *) (mUserInfo.NewIdentityPolicy + Offset);
+ if (Identity->Type == EFI_USER_INFO_IDENTITY_CREDENTIAL_PROVIDER) {
+ //
+ // Enroll the user on this provider
+ //
+ Status = EnrollUserOnProvider (Identity, mModifyUser);
+ if (EFI_ERROR (Status)) {
+ //
+ // Failed to enroll the user by new identification policy.
+ // So removed the credential provider from the identification policy
+ //
+ DeleteProviderFromPolicy (Identity, Offset);
+ continue;
+ }
+ }
+ Offset += Identity->Length;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Check whether the identity policy is valid.
+
+ @param[in] PolicyInfo Point to the identity policy.
+ @param[in] PolicyInfoLen The policy length.
+
+ @retval TRUE The policy is a valid identity policy.
+ @retval FALSE The policy is not a valid identity policy.
+
+**/
+BOOLEAN
+CheckNewIdentityPolicy (
+ IN UINT8 *PolicyInfo,
+ IN UINTN PolicyInfoLen
+ )
+{
+ EFI_USER_INFO_IDENTITY_POLICY *Identity;
+ EFI_INPUT_KEY Key;
+ UINTN Offset;
+ UINT32 OpCode;
+
+ //
+ // Check policy expression.
+ //
+ OpCode = EFI_USER_INFO_IDENTITY_FALSE;
+ Offset = 0;
+ while (Offset < PolicyInfoLen) {
+ //
+ // Check identification policy according to type
+ //
+ Identity = (EFI_USER_INFO_IDENTITY_POLICY *) (PolicyInfo + Offset);
+ switch (Identity->Type) {
+
+ case EFI_USER_INFO_IDENTITY_TRUE:
+ break;
+
+ case EFI_USER_INFO_IDENTITY_OR:
+ if (OpCode == EFI_USER_INFO_IDENTITY_AND) {
+ CreatePopUp (
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
+ &Key,
+ L"Invalid Identity Policy, Mixed Connector Unsupport!",
+ L"",
+ L"Press Any Key to Continue ...",
+ NULL
+ );
+ return FALSE;
+ }
+
+ OpCode = EFI_USER_INFO_IDENTITY_OR;
+ break;
+
+ case EFI_USER_INFO_IDENTITY_AND:
+ if (OpCode == EFI_USER_INFO_IDENTITY_OR) {
+ CreatePopUp (
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
+ &Key,
+ L"Invalid Identity Policy, Mixed Connector Unsupport!",
+ L"",
+ L"Press Any Key to Continue ...",
+ NULL
+ );
+ return FALSE;
+ }
+
+ OpCode = EFI_USER_INFO_IDENTITY_AND;
+ break;
+
+ case EFI_USER_INFO_IDENTITY_CREDENTIAL_PROVIDER:
+ break;
+
+ default:
+ CreatePopUp (
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
+ &Key,
+ L"Unsupport parameter",
+ L"",
+ L"Press Any Key to Continue ...",
+ NULL
+ );
+ return FALSE;
+ }
+ Offset += Identity->Length;
+ }
+
+ return TRUE;
+}
+
+
+/**
+ Save the identity policy and update UI with it.
+
+ This function will verify the new identity policy, in current implementation,
+ the identity policy can be: T, P & P & P & ..., P | P | P | ...
+ Here, "T" means "True", "P" means "Credential Provider", "&" means "and", "|" means "or".
+ Other identity policies are not supported.
+
+**/
+VOID
+SaveIdentityPolicy (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_USER_INFO_HANDLE UserInfo;
+ EFI_USER_INFO *Info;
+
+ if (!mUserInfo.NewIdentityPolicyModified || (mUserInfo.NewIdentityPolicyLen == 0)) {
+ return;
+ }
+
+ //
+ // Check policy expression.
+ //
+ if (!CheckNewIdentityPolicy (mUserInfo.NewIdentityPolicy, mUserInfo.NewIdentityPolicyLen)) {
+ return;
+ }
+
+ Status = FindInfoByType (mModifyUser, EFI_USER_INFO_IDENTITY_POLICY_RECORD, &UserInfo);
+ if (EFI_ERROR (Status)) {
+ return ;
+ }
+
+ //
+ // Update the informantion on credential provider.
+ //
+ Status = UpdateCredentialProvider ();
+ if (EFI_ERROR (Status)) {
+ return ;
+ }
+
+ //
+ // Save new identification policy.
+ //
+ Info = AllocateZeroPool (sizeof (EFI_USER_INFO) + mUserInfo.NewIdentityPolicyLen);
+ ASSERT (Info != NULL);
+
+ Info->InfoType = EFI_USER_INFO_IDENTITY_POLICY_RECORD;
+ Info->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV | EFI_USER_INFO_PUBLIC | EFI_USER_INFO_EXCLUSIVE;
+ Info->InfoSize = (UINT32) (sizeof (EFI_USER_INFO) + mUserInfo.NewIdentityPolicyLen);
+ CopyMem ((UINT8 *) (Info + 1), mUserInfo.NewIdentityPolicy, mUserInfo.NewIdentityPolicyLen);
+
+ Status = mUserManager->SetInfo (mUserManager, mModifyUser, &UserInfo, Info, Info->InfoSize);
+ FreePool (Info);
+
+ //
+ // Update the mUserInfo.IdentityPolicy by mUserInfo.NewIdentityPolicy
+ //
+ if (mUserInfo.IdentityPolicy != NULL) {
+ FreePool (mUserInfo.IdentityPolicy);
+ }
+ mUserInfo.IdentityPolicy = mUserInfo.NewIdentityPolicy;
+ mUserInfo.IdentityPolicyLen = mUserInfo.NewIdentityPolicyLen;
+
+ mUserInfo.NewIdentityPolicy = NULL;
+ mUserInfo.NewIdentityPolicyLen = 0;
+ mUserInfo.NewIdentityPolicyModified = FALSE;
+
+ //
+ // Update identity policy choice.
+ //
+ ResolveIdentityPolicy (mUserInfo.IdentityPolicy, mUserInfo.IdentityPolicyLen, STRING_TOKEN (STR_IDENTIFY_POLICY_VAL));
+}
+
+
+/**
+ Update the mUserInfo.NewIdentityPolicy, and UI when 'add option' is pressed.
+
+**/
+VOID
+AddIdentityPolicyItem (
+ VOID
+ )
+{
+ if (mProviderInfo->Count == 0) {
+ return ;
+ }
+
+ //
+ // Check the identity policy.
+ //
+ if (ProviderAlreadyInPolicy (&mProviderInfo->Provider[mProviderChoice]->Identifier)) {
+ return;
+ }
+
+ //
+ // Add it to identification policy
+ //
+ AddProviderToPolicy (&mProviderInfo->Provider[mProviderChoice]->Identifier);
+
+ //
+ // Update identity policy choice.
+ //
+ ResolveIdentityPolicy (mUserInfo.NewIdentityPolicy, mUserInfo.NewIdentityPolicyLen, STRING_TOKEN (STR_IDENTIFY_POLICY_VALUE));
+}
+
+
diff --git a/Core/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileAdd.c b/Core/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileAdd.c
new file mode 100644
index 0000000000..11233a1509
--- /dev/null
+++ b/Core/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileAdd.c
@@ -0,0 +1,372 @@
+/** @file
+ The functions to add a user profile.
+
+Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "UserProfileManager.h"
+
+
+/**
+ Get user name from the popup windows.
+
+ @param[in, out] UserNameLen On entry, point to UserName buffer lengh, in bytes.
+ On exit, point to input user name length, in bytes.
+ @param[out] UserName The buffer to hold the input user name.
+
+ @retval EFI_ABORTED It is given up by pressing 'ESC' key.
+ @retval EFI_NOT_READY Not a valid input at all.
+ @retval EFI_SUCCESS Get a user name successfully.
+
+**/
+EFI_STATUS
+GetUserNameInput (
+ IN OUT UINTN *UserNameLen,
+ OUT CHAR16 *UserName
+ )
+{
+ EFI_INPUT_KEY Key;
+ UINTN NameLen;
+ CHAR16 Name[USER_NAME_LENGTH];
+
+ NameLen = 0;
+ while (TRUE) {
+ Name[NameLen] = L'_';
+ Name[NameLen + 1] = L'\0';
+ CreatePopUp (
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
+ &Key,
+ L"Input User Name",
+ L"---------------------",
+ Name,
+ NULL
+ );
+ //
+ // Check key.
+ //
+ if (Key.ScanCode == SCAN_NULL) {
+ if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {
+ //
+ // Add the null terminator.
+ //
+ Name[NameLen] = 0;
+ NameLen++;
+ break;
+ } else if ((Key.UnicodeChar == CHAR_NULL) ||
+ (Key.UnicodeChar == CHAR_TAB) ||
+ (Key.UnicodeChar == CHAR_LINEFEED)
+ ) {
+ continue;
+ } else {
+ if (Key.UnicodeChar == CHAR_BACKSPACE) {
+ if (NameLen > 0) {
+ NameLen--;
+ }
+ } else {
+ Name[NameLen] = Key.UnicodeChar;
+ NameLen++;
+ if (NameLen + 1 == USER_NAME_LENGTH) {
+ //
+ // Add the null terminator.
+ //
+ Name[NameLen] = 0;
+ NameLen++;
+ break;
+ }
+ }
+ }
+ }
+
+ if (Key.ScanCode == SCAN_ESC) {
+ return EFI_ABORTED;
+ }
+ }
+
+ if (NameLen <= 1) {
+ return EFI_NOT_READY;
+ }
+
+ if (*UserNameLen < NameLen * sizeof (CHAR16)) {
+ return EFI_NOT_READY;
+ }
+
+ *UserNameLen = NameLen * sizeof (CHAR16);
+ CopyMem (UserName, Name, *UserNameLen);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Set a user's username.
+
+ @param[in] User Handle of a user profile .
+ @param[in] UserNameLen The lengh of UserName.
+ @param[in] UserName Point to the buffer of user name.
+
+ @retval EFI_NOT_READY The usernme in mAddUserName had been used.
+ @retval EFI_SUCCESS Change the user's username successfully with
+ username in mAddUserName.
+
+**/
+EFI_STATUS
+SetUserName (
+ IN EFI_USER_PROFILE_HANDLE User,
+ IN UINTN UserNameLen,
+ IN CHAR16 *UserName
+ )
+{
+ EFI_STATUS Status;
+ EFI_USER_INFO_HANDLE UserInfo;
+ EFI_USER_PROFILE_HANDLE TempUser;
+ EFI_USER_INFO *NewUserInfo;
+
+ NewUserInfo = AllocateZeroPool (sizeof (EFI_USER_INFO) + UserNameLen);
+ ASSERT (NewUserInfo != NULL);
+
+ NewUserInfo->InfoType = EFI_USER_INFO_NAME_RECORD;
+ NewUserInfo->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV |
+ EFI_USER_INFO_PUBLIC |
+ EFI_USER_INFO_EXCLUSIVE;
+ NewUserInfo->InfoSize = (UINT32) (sizeof (EFI_USER_INFO) + UserNameLen);
+ CopyMem ((UINT8 *) (NewUserInfo + 1), UserName, UserNameLen);
+ TempUser = NULL;
+ Status = mUserManager->Find (
+ mUserManager,
+ &TempUser,
+ NULL,
+ NewUserInfo,
+ NewUserInfo->InfoSize
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // The user name had been used, return error.
+ //
+ FreePool (NewUserInfo);
+ return EFI_NOT_READY;
+ }
+
+ UserInfo = NULL;
+ mUserManager->SetInfo (
+ mUserManager,
+ User,
+ &UserInfo,
+ NewUserInfo,
+ NewUserInfo->InfoSize
+ );
+ FreePool (NewUserInfo);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Set create date of the specified user.
+
+ @param[in] User Handle of a user profile.
+
+**/
+VOID
+SetCreateDate (
+ IN EFI_USER_PROFILE_HANDLE User
+ )
+{
+ EFI_STATUS Status;
+ EFI_USER_INFO_HANDLE UserInfo;
+ EFI_USER_INFO_CREATE_DATE Date;
+ EFI_USER_INFO *NewUserInfo;
+
+ NewUserInfo = AllocateZeroPool (
+ sizeof (EFI_USER_INFO) +
+ sizeof (EFI_USER_INFO_CREATE_DATE)
+ );
+ ASSERT (NewUserInfo != NULL);
+
+ NewUserInfo->InfoType = EFI_USER_INFO_CREATE_DATE_RECORD;
+ NewUserInfo->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV |
+ EFI_USER_INFO_PUBLIC |
+ EFI_USER_INFO_EXCLUSIVE;
+ NewUserInfo->InfoSize = sizeof (EFI_USER_INFO) + sizeof (EFI_USER_INFO_CREATE_DATE);
+ Status = gRT->GetTime (&Date, NULL);
+ if (EFI_ERROR (Status)) {
+ FreePool (NewUserInfo);
+ return ;
+ }
+
+ CopyMem ((UINT8 *) (NewUserInfo + 1), &Date, sizeof (EFI_USER_INFO_CREATE_DATE));
+ UserInfo = NULL;
+ mUserManager->SetInfo (
+ mUserManager,
+ User,
+ &UserInfo,
+ NewUserInfo,
+ NewUserInfo->InfoSize
+ );
+ FreePool (NewUserInfo);
+}
+
+
+/**
+ Set the default identity policy of the specified user.
+
+ @param[in] User Handle of a user profile.
+
+**/
+VOID
+SetIdentityPolicy (
+ IN EFI_USER_PROFILE_HANDLE User
+ )
+{
+ EFI_USER_INFO_IDENTITY_POLICY *Policy;
+ EFI_USER_INFO_HANDLE UserInfo;
+ EFI_USER_INFO *NewUserInfo;
+
+ NewUserInfo = AllocateZeroPool (
+ sizeof (EFI_USER_INFO) +
+ sizeof (EFI_USER_INFO_IDENTITY_POLICY)
+ );
+ ASSERT (NewUserInfo != NULL);
+
+ Policy = (EFI_USER_INFO_IDENTITY_POLICY *) (NewUserInfo + 1);
+ Policy->Type = EFI_USER_INFO_IDENTITY_TRUE;
+ Policy->Length = sizeof (EFI_USER_INFO_IDENTITY_POLICY);
+
+ NewUserInfo->InfoType = EFI_USER_INFO_IDENTITY_POLICY_RECORD;
+ NewUserInfo->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV |
+ EFI_USER_INFO_PUBLIC |
+ EFI_USER_INFO_EXCLUSIVE;
+ NewUserInfo->InfoSize = sizeof (EFI_USER_INFO) + Policy->Length;
+ UserInfo = NULL;
+ mUserManager->SetInfo (
+ mUserManager,
+ User,
+ &UserInfo,
+ NewUserInfo,
+ NewUserInfo->InfoSize
+ );
+ FreePool (NewUserInfo);
+}
+
+
+/**
+ Set the default access policy of the specified user.
+
+ @param[in] User Handle of a user profile.
+
+**/
+VOID
+SetAccessPolicy (
+ IN EFI_USER_PROFILE_HANDLE User
+ )
+{
+ EFI_USER_INFO_ACCESS_CONTROL *Control;
+ EFI_USER_INFO_HANDLE UserInfo;
+ EFI_USER_INFO *NewUserInfo;
+
+ NewUserInfo = AllocateZeroPool (
+ sizeof (EFI_USER_INFO) +
+ sizeof (EFI_USER_INFO_ACCESS_CONTROL)
+ );
+ ASSERT (NewUserInfo != NULL);
+
+ Control = (EFI_USER_INFO_ACCESS_CONTROL *) (NewUserInfo + 1);
+ Control->Type = EFI_USER_INFO_ACCESS_ENROLL_SELF;
+ Control->Size = sizeof (EFI_USER_INFO_ACCESS_CONTROL);
+
+ NewUserInfo->InfoType = EFI_USER_INFO_ACCESS_POLICY_RECORD;
+ NewUserInfo->InfoAttribs = EFI_USER_INFO_STORAGE_PLATFORM_NV |
+ EFI_USER_INFO_PUBLIC |
+ EFI_USER_INFO_EXCLUSIVE;
+ NewUserInfo->InfoSize = sizeof (EFI_USER_INFO) + Control->Size;
+ UserInfo = NULL;
+ mUserManager->SetInfo (
+ mUserManager,
+ User,
+ &UserInfo,
+ NewUserInfo,
+ NewUserInfo->InfoSize
+ );
+ FreePool (NewUserInfo);
+}
+
+
+/**
+ Add a new user profile into the user profile database.
+
+**/
+VOID
+CallAddUser (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_INPUT_KEY Key;
+ EFI_USER_PROFILE_HANDLE User;
+ UINTN UserNameLen;
+ CHAR16 UserName[USER_NAME_LENGTH];
+ CHAR16 *QuestionStr;
+ CHAR16 *PromptStr;
+
+ QuestionStr = NULL;
+ PromptStr = NULL;
+
+ //
+ // Get user name to add.
+ //
+ UserNameLen = sizeof (UserName);
+ Status = GetUserNameInput (&UserNameLen, UserName);
+ if (EFI_ERROR (Status)) {
+ if (Status != EFI_ABORTED) {
+ QuestionStr = GetStringById (STRING_TOKEN (STR_GET_USERNAME_FAILED));
+ PromptStr = GetStringById (STRING_TOKEN (STR_STROKE_KEY_CONTINUE));
+ goto Done;
+ }
+ return ;
+ }
+
+ //
+ // Create a new user profile.
+ //
+ User = NULL;
+ Status = mUserManager->Create (mUserManager, &User);
+ if (EFI_ERROR (Status)) {
+ QuestionStr = GetStringById (STRING_TOKEN (STR_CREATE_PROFILE_FAILED));
+ PromptStr = GetStringById (STRING_TOKEN (STR_STROKE_KEY_CONTINUE));
+ } else {
+ //
+ // Add default user information.
+ //
+ Status = SetUserName (User, UserNameLen, UserName);
+ if (EFI_ERROR (Status)) {
+ QuestionStr = GetStringById (STRING_TOKEN (STR_USER_ALREADY_EXISTED));
+ PromptStr = GetStringById (STRING_TOKEN (STR_STROKE_KEY_CONTINUE));
+ goto Done;
+ }
+
+ SetCreateDate (User);
+ SetIdentityPolicy (User);
+ SetAccessPolicy (User);
+
+ QuestionStr = GetStringById (STRING_TOKEN (STR_CREATE_PROFILE_SUCCESS));
+ PromptStr = GetStringById (STRING_TOKEN (STR_STROKE_KEY_CONTINUE));
+ }
+
+Done:
+ CreatePopUp (
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
+ &Key,
+ QuestionStr,
+ L"",
+ PromptStr,
+ NULL
+ );
+ FreePool (QuestionStr);
+ FreePool (PromptStr);
+}
+
diff --git a/Core/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileDelete.c b/Core/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileDelete.c
new file mode 100644
index 0000000000..8be302e1cc
--- /dev/null
+++ b/Core/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileDelete.c
@@ -0,0 +1,343 @@
+/** @file
+ The functions to delete a user profile.
+
+Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "UserProfileManager.h"
+
+/**
+ Get the username from the specified user.
+
+ @param[in] User Handle of a user profile.
+
+ @retval EFI_STRING_ID The String Id of the user's username.
+
+**/
+EFI_STRING_ID
+GetUserName (
+ IN EFI_USER_PROFILE_HANDLE User
+ )
+{
+ EFI_STATUS Status;
+ EFI_USER_INFO_HANDLE UserInfo;
+ EFI_USER_INFO *Info;
+ UINTN InfoSize;
+ UINTN MemSize;
+ UINTN NameLen;
+ CHAR16 UserName[USER_NAME_LENGTH];
+ EFI_STRING_ID UserId;
+
+ //
+ // Allocate user information memory.
+ //
+ MemSize = sizeof (EFI_USER_INFO) + 63;
+ Info = AllocateZeroPool (MemSize);
+ ASSERT (Info != NULL);
+
+ //
+ // Get user name information.
+ //
+ UserInfo = NULL;
+ while (TRUE) {
+ InfoSize = MemSize;
+ //
+ // Get next user information.
+ //
+ Status = mUserManager->GetNextInfo (
+ mUserManager,
+ User,
+ &UserInfo
+ );
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ Status = mUserManager->GetInfo (
+ mUserManager,
+ User,
+ UserInfo,
+ Info,
+ &InfoSize
+ );
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ MemSize = InfoSize;
+ FreePool (Info);
+ Info = AllocateZeroPool (MemSize);
+ ASSERT (Info != NULL);
+
+ Status = mUserManager->GetInfo (
+ mUserManager,
+ User,
+ UserInfo,
+ Info,
+ &InfoSize
+ );
+ }
+ //
+ // Check user information.
+ //
+ if (Status == EFI_SUCCESS) {
+ if (Info->InfoType == EFI_USER_INFO_NAME_RECORD) {
+ NameLen = Info->InfoSize - sizeof (EFI_USER_INFO);
+ if (NameLen > USER_NAME_LENGTH * sizeof (CHAR16)) {
+ NameLen = USER_NAME_LENGTH * sizeof (CHAR16);
+ }
+ ASSERT (NameLen >= sizeof (CHAR16));
+ CopyMem (UserName, (UINT8 *) (Info + 1), NameLen);
+ UserName[NameLen / sizeof (CHAR16) - 1] = 0;
+ UserId = HiiSetString (
+ mCallbackInfo->HiiHandle,
+ 0,
+ UserName,
+ NULL
+ );
+ if (UserId != 0) {
+ FreePool (Info);
+ return UserId;
+ }
+ }
+ }
+ }
+
+ FreePool (Info);
+ return 0;
+}
+
+
+/**
+ Add a username item in form.
+
+ @param[in] User Points to the user profile whose username is added.
+ @param[in] Index The index of the user in the user name list
+ @param[in] OpCodeHandle Points to container for dynamic created opcodes.
+
+**/
+VOID
+AddUserToForm (
+ IN EFI_USER_PROFILE_HANDLE User,
+ IN UINT16 Index,
+ IN VOID *OpCodeHandle
+ )
+{
+ EFI_STRING_ID NameId;
+
+ //
+ // Get user name
+ //
+ NameId = GetUserName (User);
+ if (NameId == 0) {
+ return ;
+ }
+
+ //
+ // Create user name option.
+ //
+ switch (Index & KEY_FIRST_FORM_MASK) {
+ case KEY_MODIFY_USER:
+ HiiCreateGotoOpCode (
+ OpCodeHandle, // Container for dynamic created opcodes
+ FORMID_USER_INFO, // Target Form ID
+ NameId, // Prompt text
+ STRING_TOKEN (STR_NULL_STRING), // Help text
+ EFI_IFR_FLAG_CALLBACK, // Question flag
+ Index // Question ID
+ );
+ break;
+
+ case KEY_DEL_USER:
+ HiiCreateActionOpCode (
+ OpCodeHandle, // Container for dynamic created opcodes
+ Index, // Question ID
+ NameId, // Prompt text
+ STRING_TOKEN (STR_NULL_STRING), // Help text
+ EFI_IFR_FLAG_CALLBACK, // Question flag
+ 0 // Action String ID
+ );
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+/**
+ Delete the user specified by UserIndex in user profile database.
+
+ @param[in] UserIndex The index of user in the user name list
+ to be deleted.
+
+**/
+VOID
+DeleteUser (
+ IN UINT8 UserIndex
+ )
+{
+ EFI_STATUS Status;
+ EFI_USER_PROFILE_HANDLE User;
+ EFI_INPUT_KEY Key;
+ EFI_USER_INFO_HANDLE UserInfo;
+ EFI_USER_INFO *Info;
+ UINTN InfoSize;
+
+ //
+ // Find specified user profile and delete it.
+ //
+ User = NULL;
+ Status = mUserManager->GetNext (mUserManager, &User);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ while (UserIndex > 1) {
+ Status = mUserManager->GetNext (mUserManager, &User);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ UserIndex--;
+ }
+
+ if (UserIndex == 1) {
+ //
+ // Get the identification policy.
+ //
+ Status = FindInfoByType (User, EFI_USER_INFO_IDENTITY_POLICY_RECORD, &UserInfo);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ InfoSize = 0;
+ Info = NULL;
+ Status = mUserManager->GetInfo (mUserManager, User, UserInfo, Info, &InfoSize);
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ Info = AllocateZeroPool (InfoSize);
+ if (Info == NULL) {
+ goto Done;
+ }
+ Status = mUserManager->GetInfo (mUserManager, User, UserInfo, Info, &InfoSize);
+ }
+
+ //
+ // Delete the user on the credential providers by its identification policy.
+ //
+ ASSERT (Info != NULL);
+ DeleteCredentialFromProviders ((UINT8 *)(Info + 1), Info->InfoSize - sizeof (EFI_USER_INFO), User);
+ FreePool (Info);
+
+ Status = mUserManager->Delete (mUserManager, User);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ CreatePopUp (
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
+ &Key,
+ L"Delete User Succeed!",
+ L"",
+ L"Please Press Any Key to Continue ...",
+ NULL
+ );
+ return ;
+ }
+
+Done:
+ CreatePopUp (
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
+ &Key,
+ L"Delete User Failed!",
+ L"",
+ L"Please Press Any Key to Continue ...",
+ NULL
+ );
+}
+
+
+/**
+ Display user select form, cab select a user to delete.
+
+**/
+VOID
+SelectUserToDelete (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Index;
+ EFI_USER_PROFILE_HANDLE User;
+ EFI_USER_PROFILE_HANDLE CurrentUser;
+ VOID *StartOpCodeHandle;
+ VOID *EndOpCodeHandle;
+ EFI_IFR_GUID_LABEL *StartLabel;
+ EFI_IFR_GUID_LABEL *EndLabel;
+
+ //
+ // 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_DEL_FUNC;
+
+ 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 each user can be deleted.
+ //
+ User = NULL;
+ Index = 1;
+ mUserManager->Current (mUserManager, &CurrentUser);
+ while (TRUE) {
+ Status = mUserManager->GetNext (mUserManager, &User);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ if (User != CurrentUser) {
+ AddUserToForm (
+ User,
+ (UINT16)(KEY_DEL_USER | KEY_SELECT_USER | Index),
+ StartOpCodeHandle
+ );
+ }
+ Index++;
+ }
+
+ HiiUpdateForm (
+ mCallbackInfo->HiiHandle, // HII handle
+ &gUserProfileManagerGuid, // Formset GUID
+ FORMID_DEL_USER, // Form ID
+ StartOpCodeHandle, // Label for where to insert opcodes
+ EndOpCodeHandle // Replace data
+ );
+
+ HiiFreeOpCodeHandle (StartOpCodeHandle);
+ HiiFreeOpCodeHandle (EndOpCodeHandle);
+}
diff --git a/Core/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManager.c b/Core/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManager.c
new file mode 100644
index 0000000000..4bba0824c7
--- /dev/null
+++ b/Core/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManager.c
@@ -0,0 +1,884 @@
+/** @file
+ This driver is a configuration tool for adding, deleting or modifying user
+ profiles, including gathering the necessary information to ascertain their
+ identity in the future, updating user access policy and identification
+ policy, etc.
+
+Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "UserProfileManager.h"
+
+EFI_USER_MANAGER_PROTOCOL *mUserManager = NULL;
+CREDENTIAL_PROVIDER_INFO *mProviderInfo = NULL;
+UINT8 mProviderChoice;
+UINT8 mConncetLogical;
+USER_INFO_ACCESS mAccessInfo;
+USER_INFO mUserInfo;
+USER_PROFILE_MANAGER_CALLBACK_INFO *mCallbackInfo;
+HII_VENDOR_DEVICE_PATH mHiiVendorDevicePath = {
+ {
+ {
+ HARDWARE_DEVICE_PATH,
+ HW_VENDOR_DP,
+ {
+ (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
+ (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
+ }
+ },
+ USER_PROFILE_MANAGER_GUID
+ },
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ (UINT8) (END_DEVICE_PATH_LENGTH),
+ (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
+ }
+ }
+};
+
+
+/**
+ 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);
+}
+
+
+/**
+ This function gets all the credential providers in the system and saved them
+ to mProviderInfo.
+
+ @retval EFI_SUCESS Init credential provider database successfully.
+ @retval Others Fail to init credential provider database.
+
+**/
+EFI_STATUS
+InitProviderInfo (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuf;
+ UINTN Index;
+
+ //
+ // Try to find all the user credential provider driver.
+ //
+ HandleCount = 0;
+ HandleBuf = NULL;
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiUserCredential2ProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuf
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Get provider infomation.
+ //
+ if (mProviderInfo != NULL) {
+ FreePool (mProviderInfo);
+ }
+ mProviderInfo = AllocateZeroPool (
+ sizeof (CREDENTIAL_PROVIDER_INFO) -
+ sizeof (EFI_USER_CREDENTIAL2_PROTOCOL *) +
+ HandleCount * sizeof (EFI_USER_CREDENTIAL2_PROTOCOL *)
+ );
+ if (mProviderInfo == NULL) {
+ FreePool (HandleBuf);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ mProviderInfo->Count = HandleCount;
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->HandleProtocol (
+ HandleBuf[Index],
+ &gEfiUserCredential2ProtocolGuid,
+ (VOID **) &mProviderInfo->Provider[Index]
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (HandleBuf);
+ FreePool (mProviderInfo);
+ mProviderInfo = NULL;
+ return Status;
+ }
+ }
+
+ FreePool (HandleBuf);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function processes changes in user profile 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
+UserProfileManagerCallback (
+ 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;
+ UINT32 CurrentAccessRight;
+ CHAR16 *QuestionStr;
+ CHAR16 *PromptStr;
+ VOID *StartOpCodeHandle;
+ VOID *EndOpCodeHandle;
+ EFI_IFR_GUID_LABEL *StartLabel;
+ EFI_IFR_GUID_LABEL *EndLabel;
+ EFI_USER_PROFILE_HANDLE CurrentUser;
+
+ Status = EFI_SUCCESS;
+
+ switch (Action) {
+ case EFI_BROWSER_ACTION_FORM_OPEN:
+ {
+ //
+ // Update user manage Form when user manage Form is opened.
+ // This will be done only in FORM_OPEN CallBack of question with QUESTIONID_USER_MANAGE from user manage Form.
+ //
+ if (QuestionId != QUESTIONID_USER_MANAGE) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Get current user
+ //
+ CurrentUser = NULL;
+ mUserManager->Current (mUserManager, &CurrentUser);
+ if (CurrentUser == NULL) {
+ DEBUG ((DEBUG_ERROR, "Error: current user does not exist!\n"));
+ return EFI_NOT_READY;
+ }
+
+ //
+ // Get current user's right information.
+ //
+ Status = GetAccessRight (&CurrentAccessRight);
+ if (EFI_ERROR (Status)) {
+ CurrentAccessRight = EFI_USER_INFO_ACCESS_ENROLL_SELF;
+ }
+
+ //
+ // Init credential provider information.
+ //
+ Status = InitProviderInfo ();
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // 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_MANAGE_FUNC;
+
+ 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 user profile option.
+ //
+ if ((CurrentAccessRight == EFI_USER_INFO_ACCESS_MANAGE) ||
+ (CurrentAccessRight == EFI_USER_INFO_ACCESS_ENROLL_OTHERS)
+ ) {
+ HiiCreateActionOpCode (
+ StartOpCodeHandle, // Container for dynamic created opcodes
+ KEY_ADD_USER, // Question ID
+ STRING_TOKEN (STR_ADD_USER_TITLE), // Prompt text
+ STRING_TOKEN (STR_ADD_USER_HELP), // Help text
+ EFI_IFR_FLAG_CALLBACK, // Question flag
+ 0 // Action String ID
+ );
+ }
+
+ //
+ // Add modify user profile option.
+ //
+ HiiCreateGotoOpCode (
+ StartOpCodeHandle, // Container for dynamic created opcodes
+ FORMID_MODIFY_USER, // Target Form ID
+ STRING_TOKEN (STR_MODIFY_USER_TITLE), // Prompt text
+ STRING_TOKEN (STR_MODIFY_USER_HELP), // Help text
+ EFI_IFR_FLAG_CALLBACK, // Question flag
+ KEY_MODIFY_USER // Question ID
+ );
+
+ //
+ // Add delete user profile option
+ //
+ if (CurrentAccessRight == EFI_USER_INFO_ACCESS_MANAGE) {
+ HiiCreateGotoOpCode (
+ StartOpCodeHandle, // Container for dynamic created opcodes
+ FORMID_DEL_USER, // Target Form ID
+ STRING_TOKEN (STR_DELETE_USER_TITLE), // Prompt text
+ STRING_TOKEN (STR_DELETE_USER_HELP), // Help text
+ EFI_IFR_FLAG_CALLBACK, // Question flag
+ KEY_DEL_USER // Question ID
+ );
+ }
+
+ HiiUpdateForm (
+ mCallbackInfo->HiiHandle, // HII handle
+ &gUserProfileManagerGuid, // Formset GUID
+ FORMID_USER_MANAGE, // 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_CHANGED:
+ {
+ //
+ // Handle the request from form.
+ //
+ if ((Value == NULL) || (ActionRequest == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Judge first 2 bits.
+ //
+ switch (QuestionId & KEY_FIRST_FORM_MASK) {
+ //
+ // Add user profile operation.
+ //
+ case KEY_ADD_USER:
+ CallAddUser ();
+ break;
+
+ //
+ // Delete user profile operation.
+ //
+ case KEY_DEL_USER:
+ //
+ // Judge next 2 bits.
+ //
+ switch (QuestionId & KEY_SECOND_FORM_MASK) {
+ //
+ // Delete specified user profile.
+ //
+ case KEY_SELECT_USER:
+ DeleteUser ((UINT8) QuestionId);
+ //
+ // Update select user form after delete a user.
+ //
+ SelectUserToDelete ();
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ //
+ // Modify user profile operation.
+ //
+ case KEY_MODIFY_USER:
+ //
+ // Judge next 2 bits.
+ //
+ switch (QuestionId & KEY_SECOND_FORM_MASK) {
+ //
+ // Enter user profile information form.
+ //
+ case KEY_SELECT_USER:
+ //
+ // Judge next 3 bits.
+ //
+ switch (QuestionId & KEY_MODIFY_INFO_MASK) {
+ //
+ // Modify user name.
+ //
+ case KEY_MODIFY_NAME:
+ ModifyUserName ();
+ //
+ // Update username in parent form.
+ //
+ SelectUserToModify ();
+ break;
+
+ //
+ // Modify identity policy.
+ //
+ case KEY_MODIFY_IP:
+ //
+ // Judge next 3 bits
+ //
+ switch (QuestionId & KEY_MODIFY_IP_MASK) {
+ //
+ // Change credential provider option.
+ //
+ case KEY_MODIFY_PROV:
+ mProviderChoice = Value->u8;
+ break;
+
+ //
+ // Change logical connector.
+ //
+ case KEY_MODIFY_CONN:
+ mConncetLogical = Value->u8;
+ break;
+
+ //
+ // Save option.
+ //
+ case KEY_ADD_IP_OP:
+ AddIdentityPolicyItem ();
+ break;
+
+ //
+ // Return to user profile information form.
+ //
+ case KEY_IP_RETURN_UIF:
+ SaveIdentityPolicy ();
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ //
+ // Modify access policy.
+ //
+ case KEY_MODIFY_AP:
+ //
+ // Judge next 3 bits.
+ //
+ switch (QuestionId & KEY_MODIFY_AP_MASK) {
+ //
+ // Change access right choice.
+ //
+ case KEY_MODIFY_RIGHT:
+ mAccessInfo.AccessRight = Value->u8;
+ break;
+
+ //
+ // Change setup choice.
+ //
+ case KEY_MODIFY_SETUP:
+ mAccessInfo.AccessSetup= Value->u8;
+ break;
+
+ //
+ // Change boot order choice.
+ //
+ case KEY_MODIFY_BOOT:
+ mAccessInfo.AccessBootOrder = Value->u32;
+ break;
+
+ //
+ // Return to user profile information form.
+ //
+ case KEY_AP_RETURN_UIF:
+ SaveAccessPolicy ();
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ //
+ // Access policy device path modified.
+ //
+ case KEY_MODIFY_AP_DP:
+ //
+ // Judge next 2 bits.
+ //
+ switch (QuestionId & KEY_MODIFY_DP_MASK) {
+ //
+ // Load permit device path modified.
+ //
+ case KEY_LOAD_PERMIT_MODIFY:
+ QuestionStr = GetStringById (STRING_TOKEN (STR_MOVE_TO_FORBID_LIST));
+ PromptStr = GetStringById (STRING_TOKEN (STR_PRESS_KEY_CONTINUE));
+ CreatePopUp (
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
+ &Key,
+ QuestionStr,
+ L"",
+ PromptStr,
+ NULL
+ );
+ FreePool (QuestionStr);
+ FreePool (PromptStr);
+ if (Key.UnicodeChar != CHAR_CARRIAGE_RETURN) {
+ break;
+ }
+
+ AddToForbidLoad ((UINT16)(QuestionId & (KEY_MODIFY_DP_MASK - 1)));
+ DisplayLoadPermit ();
+ break;
+
+ //
+ // Load forbid device path modified.
+ //
+ case KEY_LOAD_FORBID_MODIFY:
+ QuestionStr = GetStringById (STRING_TOKEN (STR_MOVE_TO_PERMIT_LIST));
+ PromptStr = GetStringById (STRING_TOKEN (STR_PRESS_KEY_CONTINUE));
+ CreatePopUp (
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
+ &Key,
+ QuestionStr,
+ L"",
+ PromptStr,
+ NULL
+ );
+ FreePool (QuestionStr);
+ FreePool (PromptStr);
+ if (Key.UnicodeChar != CHAR_CARRIAGE_RETURN) {
+ break;
+ }
+
+ DeleteFromForbidLoad ((UINT16)(QuestionId & (KEY_MODIFY_DP_MASK - 1)));
+ DisplayLoadForbid ();
+ break;
+
+ //
+ // Connect permit device path modified.
+ //
+ case KEY_CONNECT_PERMIT_MODIFY:
+ break;
+
+ //
+ // Connect forbid device path modified.
+ //
+ case KEY_CONNECT_FORBID_MODIFY:
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ break;
+
+
+ case EFI_BROWSER_ACTION_CHANGING:
+ {
+ //
+ // Handle the request from form.
+ //
+ if (Value == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Judge first 2 bits.
+ //
+ switch (QuestionId & KEY_FIRST_FORM_MASK) {
+ //
+ // Delete user profile operation.
+ //
+ case KEY_DEL_USER:
+ //
+ // Judge next 2 bits.
+ //
+ switch (QuestionId & KEY_SECOND_FORM_MASK) {
+ //
+ // Enter delete user profile form.
+ //
+ case KEY_ENTER_NEXT_FORM:
+ SelectUserToDelete ();
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ //
+ // Modify user profile operation.
+ //
+ case KEY_MODIFY_USER:
+ //
+ // Judge next 2 bits.
+ //
+ switch (QuestionId & KEY_SECOND_FORM_MASK) {
+ //
+ // Enter modify user profile form.
+ //
+ case KEY_ENTER_NEXT_FORM:
+ SelectUserToModify ();
+ break;
+
+ //
+ // Enter user profile information form.
+ //
+ case KEY_SELECT_USER:
+ //
+ // Judge next 3 bits.
+ //
+ switch (QuestionId & KEY_MODIFY_INFO_MASK) {
+ //
+ // Display user information form.
+ //
+ case KEY_ENTER_NEXT_FORM:
+ ModifyUserInfo ((UINT8) QuestionId);
+ break;
+
+ //
+ // Modify identity policy.
+ //
+ case KEY_MODIFY_IP:
+ //
+ // Judge next 3 bits
+ //
+ switch (QuestionId & KEY_MODIFY_IP_MASK) {
+ //
+ // Display identity policy modify form.
+ //
+ case KEY_ENTER_NEXT_FORM:
+ ModifyIdentityPolicy ();
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ //
+ // Modify access policy.
+ //
+ case KEY_MODIFY_AP:
+ //
+ // Judge next 3 bits.
+ //
+ switch (QuestionId & KEY_MODIFY_AP_MASK) {
+ //
+ // Display access policy modify form.
+ //
+ case KEY_ENTER_NEXT_FORM:
+ ModidyAccessPolicy ();
+ break;
+ //
+ // Load device path form.
+ //
+ case KEY_MODIFY_LOAD:
+ //
+ // Judge next 2 bits.
+ //
+ switch (QuestionId & KEY_DISPLAY_DP_MASK) {
+ //
+ // Permit load device path.
+ //
+ case KEY_PERMIT_MODIFY:
+ DisplayLoadPermit ();
+ break;
+
+ //
+ // Forbid load device path.
+ //
+ case KEY_FORBID_MODIFY:
+ DisplayLoadForbid ();
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ //
+ // Connect device path form.
+ //
+ case KEY_MODIFY_CONNECT:
+ //
+ // Judge next 2 bits.
+ //
+ switch (QuestionId & KEY_DISPLAY_DP_MASK) {
+ //
+ // Permit connect device path.
+ //
+ case KEY_PERMIT_MODIFY:
+ DisplayConnectPermit ();
+ break;
+
+ //
+ // Forbid connect device path.
+ //
+ case KEY_FORBID_MODIFY:
+ DisplayConnectForbid ();
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ break;
+
+ default:
+ //
+ // All other action return unsupported.
+ //
+ Status = EFI_UNSUPPORTED;
+ break;
+ }
+
+
+ return Status;
+}
+
+
+/**
+ 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 <ConfigRequest> 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 <ConfigAltResp> format which
+ has all values filled in for the names in the Request string.
+ String to be allocated by the called function.
+
+ @retval EFI_SUCCESS The Results is filled with the requested values.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results.
+ @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name.
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in this driver.
+
+**/
+EFI_STATUS
+EFIAPI
+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 <ConfigResp> 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;
+}
+
+
+/**
+ 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
+UserProfileManagerInit (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ USER_PROFILE_MANAGER_CALLBACK_INFO *CallbackInfo;
+
+ Status = gBS->LocateProtocol (
+ &gEfiUserManagerProtocolGuid,
+ NULL,
+ (VOID **) &mUserManager
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Initialize driver private data.
+ //
+ ZeroMem (&mUserInfo, sizeof (mUserInfo));
+ ZeroMem (&mAccessInfo, sizeof (mAccessInfo));
+
+ CallbackInfo = AllocateZeroPool (sizeof (USER_PROFILE_MANAGER_CALLBACK_INFO));
+ ASSERT (CallbackInfo != NULL);
+
+ CallbackInfo->Signature = USER_PROFILE_MANAGER_SIGNATURE;
+ CallbackInfo->ConfigAccess.ExtractConfig = FakeExtractConfig;
+ CallbackInfo->ConfigAccess.RouteConfig = FakeRouteConfig;
+ CallbackInfo->ConfigAccess.Callback = UserProfileManagerCallback;
+ 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 (
+ &gUserProfileManagerGuid,
+ CallbackInfo->DriverHandle,
+ UserProfileManagerStrings,
+ UserProfileManagerVfrBin,
+ NULL
+ );
+ ASSERT (CallbackInfo->HiiHandle != NULL);
+ mCallbackInfo = CallbackInfo;
+
+ return Status;
+}
+
+
diff --git a/Core/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManager.h b/Core/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManager.h
new file mode 100644
index 0000000000..5ab5457a8f
--- /dev/null
+++ b/Core/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManager.h
@@ -0,0 +1,444 @@
+/** @file
+ The header file for user profile manager driver.
+
+Copyright (c) 2009 - 2013, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __EFI_USER_PROFILE_MANAGER_H__
+#define __EFI_USER_PROFILE_MANAGER_H__
+
+#include <Uefi.h>
+
+#include <Guid/GlobalVariable.h>
+#include <Guid/MdeModuleHii.h>
+
+#include <Protocol/HiiConfigAccess.h>
+#include <Protocol/UserCredential2.h>
+#include <Protocol/UserManager.h>
+
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+#include <Library/PrintLib.h>
+#include <Library/HiiLib.h>
+
+#include "UserProfileManagerData.h"
+
+#define USER_NAME_LENGTH 17
+
+//
+// Credential Provider Information.
+//
+typedef struct {
+ UINTN Count;
+ EFI_USER_CREDENTIAL2_PROTOCOL *Provider[1];
+} CREDENTIAL_PROVIDER_INFO;
+
+//
+// User profile information structure.
+//
+typedef struct {
+ UINT64 UsageCount;
+ EFI_TIME CreateDate;
+ EFI_TIME UsageDate;
+ UINTN AccessPolicyLen;
+ UINTN IdentityPolicyLen;
+ UINTN NewIdentityPolicyLen;
+ UINT8 *AccessPolicy;
+ UINT8 *IdentityPolicy;
+ UINT8 *NewIdentityPolicy;
+ CHAR16 UserName[USER_NAME_LENGTH];
+ BOOLEAN CreateDateExist;
+ BOOLEAN UsageDateExist;
+ BOOLEAN AccessPolicyModified;
+ BOOLEAN IdentityPolicyModified;
+ BOOLEAN NewIdentityPolicyModified;
+} USER_INFO;
+
+//
+// User access information structure.
+//
+typedef struct {
+ UINTN LoadPermitLen;
+ UINTN LoadForbidLen;
+ UINTN ConnectPermitLen;
+ UINTN ConnectForbidLen;
+ UINT8 *LoadPermit;
+ UINT8 *LoadForbid;
+ UINT8 *ConnectPermit;
+ UINT8 *ConnectForbid;
+ UINT32 AccessBootOrder;
+ UINT8 AccessRight;
+ UINT8 AccessSetup;
+} USER_INFO_ACCESS;
+
+#define USER_PROFILE_MANAGER_SIGNATURE SIGNATURE_32 ('U', 'P', 'M', 'S')
+
+typedef struct {
+ UINTN Signature;
+ EFI_HANDLE DriverHandle;
+ EFI_HII_HANDLE HiiHandle;
+ EFI_HII_CONFIG_ACCESS_PROTOCOL ConfigAccess;
+} USER_PROFILE_MANAGER_CALLBACK_INFO;
+
+//
+// HII specific Vendor Device Path definition.
+//
+typedef struct {
+ VENDOR_DEVICE_PATH VendorDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} HII_VENDOR_DEVICE_PATH;
+
+//
+// This is the generated IFR binary data for each formset defined in VFR.
+//
+extern UINT8 UserProfileManagerVfrBin[];
+
+//
+// This is the generated String package data for .UNI file.
+//
+extern UINT8 UserProfileManagerStrings[];
+
+//
+// The user manager protocol, used in several function.
+//
+extern EFI_USER_MANAGER_PROTOCOL *mUserManager;
+
+//
+// The credential providers database in system.
+//
+extern CREDENTIAL_PROVIDER_INFO *mProviderInfo;
+
+//
+// The variables used to update identity policy.
+//
+extern UINT8 mProviderChoice;
+extern UINT8 mConncetLogical;
+
+//
+// The variables used to update access policy.
+//
+extern USER_INFO_ACCESS mAccessInfo;
+
+//
+// The user information used to record all data in UI.
+//
+extern USER_INFO mUserInfo;
+
+extern USER_PROFILE_MANAGER_CALLBACK_INFO *mCallbackInfo;
+
+extern EFI_USER_PROFILE_HANDLE mModifyUser;
+
+/**
+ 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
+ );
+
+/**
+ Add a new user profile into the user profile database.
+
+**/
+VOID
+CallAddUser (
+ VOID
+ );
+
+/**
+ Display user select form; can select a user to modify.
+
+**/
+VOID
+SelectUserToModify (
+ VOID
+ );
+
+/**
+ Display user select form, cab select a user to delete.
+
+**/
+VOID
+SelectUserToDelete (
+ VOID
+ );
+
+/**
+ Delete the user specified by UserIndex in user profile database.
+
+ @param[in] UserIndex The index of user in the user name list to be deleted.
+
+**/
+VOID
+DeleteUser (
+ IN UINT8 UserIndex
+ );
+
+/**
+ Add a username item in form.
+
+ @param[in] User Points to the user profile whose username is added.
+ @param[in] Index The index of the user in the user name list.
+ @param[in] OpCodeHandle Points to container for dynamic created opcodes.
+
+**/
+VOID
+AddUserToForm (
+ IN EFI_USER_PROFILE_HANDLE User,
+ IN UINT16 Index,
+ IN VOID *OpCodeHandle
+ );
+
+/**
+ Display modify user information form
+
+ In this form, username, create Date, usage date, usage count, identity policy,
+ and access policy are displayed.
+
+ @param[in] UserIndex The index of the user in display list to modify.
+
+**/
+VOID
+ModifyUserInfo (
+ IN UINT8 UserIndex
+ );
+
+/**
+ Get the username from user input and update username string in Hii
+ database with it.
+
+**/
+VOID
+ModifyUserName (
+ VOID
+ );
+
+/**
+ Display the form of modifying user identity policy.
+
+**/
+VOID
+ModifyIdentityPolicy (
+ VOID
+ );
+
+/**
+ Update the mUserInfo.NewIdentityPolicy and UI when 'add option' is pressed.
+
+**/
+VOID
+AddIdentityPolicyItem (
+ VOID
+ );
+
+/**
+ Save the identity policy and update UI with it.
+
+ This function will verify the new identity policy, in current implementation,
+ the identity policy can be: T, P & P & P & ..., P | P | P | ...
+ Here, "T" means "True", "P" means "Credential Provider", "&" means "and", "|" means "or".
+ Other identity policies are not supported.
+
+**/
+VOID
+SaveIdentityPolicy (
+ VOID
+ );
+
+/**
+ Display modify user access policy form
+
+ In this form, access right, access setu,p and access boot order are dynamically
+ added. Load devicepath and connect devicepath are displayed too.
+
+**/
+VOID
+ModidyAccessPolicy (
+ VOID
+ );
+
+/**
+ Collect all the access policy data to mUserInfo.AccessPolicy,
+ and save it to user profile.
+
+**/
+VOID
+SaveAccessPolicy (
+ VOID
+ );
+
+/**
+ Get current user's access rights.
+
+ @param[out] AccessRight Points to the buffer used for user's access rights.
+
+ @retval EFI_SUCCESS Get current user access rights successfully.
+ @retval others Fail to get current user access rights.
+
+**/
+EFI_STATUS
+GetAccessRight (
+ OUT UINT32 *AccessRight
+ );
+
+/**
+ Display the permit load device path in the loadable device path list.
+
+**/
+VOID
+DisplayLoadPermit(
+ VOID
+ );
+
+/**
+ Display the forbid load device path list (mAccessInfo.LoadForbid).
+
+**/
+VOID
+DisplayLoadForbid (
+ VOID
+ );
+
+/**
+ Display the permit connect device path.
+
+**/
+VOID
+DisplayConnectPermit (
+ VOID
+ );
+
+/**
+ Display the forbid connect device path list.
+
+**/
+VOID
+DisplayConnectForbid (
+ VOID
+ );
+
+/**
+ Delete the specified device path by DriverIndex from the forbid device path
+ list (mAccessInfo.LoadForbid).
+
+ @param[in] DriverIndex The index of driver in a forbidden device path list.
+
+**/
+VOID
+DeleteFromForbidLoad (
+ IN UINT16 DriverIndex
+ );
+
+/**
+ Add the specified device path by DriverIndex to the forbid device path
+ list (mAccessInfo.LoadForbid).
+
+ @param[in] DriverIndex The index of driver saved in driver options.
+
+**/
+VOID
+AddToForbidLoad (
+ IN UINT16 DriverIndex
+ );
+
+/**
+ Get user name from the popup windows.
+
+ @param[in, out] UserNameLen On entry, point to the buffer lengh of UserName.
+ On exit, point to the input user name length.
+ @param[out] UserName The buffer to hold the input user name.
+
+ @retval EFI_ABORTED It is given up by pressing 'ESC' key.
+ @retval EFI_NOT_READY Not a valid input at all.
+ @retval EFI_SUCCESS Get a user name successfully.
+
+**/
+EFI_STATUS
+GetUserNameInput (
+ IN OUT UINTN *UserNameLen,
+ OUT CHAR16 *UserName
+ );
+
+/**
+ Find the specified info in User profile by the InfoType.
+
+ @param[in] User Handle of the user whose information will be searched.
+ @param[in] InfoType The user information type to find.
+ @param[out] UserInfo Points to user information handle found.
+
+ @retval EFI_SUCCESS Find the user information successfully.
+ @retval Others Fail to find the user information.
+
+**/
+EFI_STATUS
+FindInfoByType (
+ IN EFI_USER_PROFILE_HANDLE User,
+ IN UINT8 InfoType,
+ OUT EFI_USER_INFO_HANDLE *UserInfo
+ );
+
+/**
+ Convert the identity policy to a unicode string and update the Hii database
+ IpStringId string with it.
+
+ @param[in] Ip Points to identity policy.
+ @param[in] IpLen The identity policy length.
+ @param[in] IpStringId String ID in the HII database to be replaced.
+
+**/
+VOID
+ResolveIdentityPolicy (
+ IN UINT8 *Ip,
+ IN UINTN IpLen,
+ IN EFI_STRING_ID IpStringId
+ );
+
+/**
+ Expand access policy memory size.
+
+ @param[in] ValidLen The valid access policy length.
+ @param[in] ExpandLen The length that is needed to expand.
+
+**/
+VOID
+ExpandMemory (
+ IN UINTN ValidLen,
+ IN UINTN ExpandLen
+ );
+
+/**
+ Delete User's credental from all the providers that exist in User's identity policy.
+
+ @param[in] IdentityPolicy Point to User's identity policy.
+ @param[in] IdentityPolicyLen The length of the identity policy.
+ @param[in] User Points to user profile.
+
+**/
+VOID
+DeleteCredentialFromProviders (
+ IN UINT8 *IdentityPolicy,
+ IN UINTN IdentityPolicyLen,
+ IN EFI_USER_PROFILE_HANDLE User
+ );
+
+#endif
diff --git a/Core/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManager.uni b/Core/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManager.uni
new file mode 100644
index 0000000000..e4a768e00a
--- /dev/null
+++ b/Core/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManager.uni
@@ -0,0 +1,22 @@
+// /** @file
+// A UI tool to manage user profiles
+//
+// By this module, user can add/update/delete user profiles, and can also
+// modify the user access policy and the user identification policy.
+//
+// Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "A UI tool to manage user profiles"
+
+#string STR_MODULE_DESCRIPTION #language en-US "By this module, user can add/update/delete user profiles, and can also modify the user access policy and the user identification policy."
+
diff --git a/Core/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManagerData.h b/Core/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManagerData.h
new file mode 100644
index 0000000000..4548c758b5
--- /dev/null
+++ b/Core/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManagerData.h
@@ -0,0 +1,158 @@
+/** @file
+ The form data for user profile manager driver.
+
+Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __USER_PROFILE_MANAGER_DATA_H__
+#define __USER_PROFILE_MANAGER_DATA_H__
+
+#include <Guid/UserProfileManagerHii.h>
+
+//
+// Form ID
+//
+#define FORMID_USER_MANAGE 0x0001
+#define FORMID_MODIFY_USER 0x0002
+#define FORMID_DEL_USER 0x0003
+#define FORMID_USER_INFO 0x0004
+#define FORMID_MODIFY_IP 0x0005
+#define FORMID_MODIFY_AP 0x0006
+#define FORMID_LOAD_DP 0x0007
+#define FORMID_CONNECT_DP 0x0008
+#define FORMID_PERMIT_LOAD_DP 0x0009
+#define FORMID_FORBID_LOAD_DP 0x000A
+#define FORMID_PERMIT_CONNECT_DP 0x000B
+#define FORMID_FORBID_CONNECT_DP 0x000C
+
+//
+// Label ID
+//
+#define LABEL_USER_MANAGE_FUNC 0x0010
+#define LABEL_USER_DEL_FUNC 0x0020
+#define LABEL_USER_MOD_FUNC 0x0030
+#define LABEL_USER_INFO_FUNC 0x0040
+#define LABEL_IP_MOD_FUNC 0x0050
+#define LABEL_AP_MOD_FUNC 0x0060
+#define LABEL_PERMIT_LOAD_FUNC 0x0070
+#define LABLE_FORBID_LOAD_FUNC 0x0080
+#define LABEL_END 0x00F0
+
+//
+// First form key (Add/modify/del user profile).
+// First 2 bits (bit 16~15).
+//
+#define KEY_MODIFY_USER 0x4000
+#define KEY_DEL_USER 0x8000
+#define KEY_ADD_USER 0xC000
+#define KEY_FIRST_FORM_MASK 0xC000
+
+//
+// Second form key (Display new form /Select user / modify device path in access policy).
+// Next 2 bits (bit 14~13).
+//
+#define KEY_ENTER_NEXT_FORM 0x0000
+#define KEY_SELECT_USER 0x1000
+#define KEY_MODIFY_AP_DP 0x2000
+#define KEY_OPEN_CLOSE_FORM_ACTION 0x3000
+#define KEY_SECOND_FORM_MASK 0x3000
+
+//
+// User profile information form key.
+// Next 3 bits (bit 12~10).
+//
+#define KEY_MODIFY_NAME 0x0200
+#define KEY_MODIFY_IP 0x0400
+#define KEY_MODIFY_AP 0x0600
+#define KEY_MODIFY_INFO_MASK 0x0E00
+
+//
+// Specified key, used in VFR (KEY_MODIFY_USER | KEY_SELECT_USER | KEY_MODIFY_NAME).
+//
+#define KEY_MODIFY_USER_NAME 0x5200
+
+//
+// Modify identity policy form key.
+// Next 3 bits (bit 9~7).
+//
+#define KEY_MODIFY_PROV 0x0040
+#define KEY_MODIFY_MTYPE 0x0080
+#define KEY_MODIFY_CONN 0x00C0
+#define KEY_ADD_IP_OP 0x0100
+#define KEY_IP_RETURN_UIF 0x0140
+#define KEY_MODIFY_IP_MASK 0x01C0
+
+//
+// Specified key.
+//
+#define KEY_ADD_LOGICAL_OP 0x5500
+#define KEY_IP_RETURN 0x5540
+
+//
+// Modify access policy form key.
+// Next 3 bits (bit 9~7).
+//
+#define KEY_MODIFY_RIGHT 0x0040
+#define KEY_MODIFY_SETUP 0x0080
+#define KEY_MODIFY_BOOT 0x00C0
+#define KEY_MODIFY_LOAD 0x0100
+#define KEY_MODIFY_CONNECT 0x0140
+#define KEY_AP_RETURN_UIF 0x0180
+#define KEY_MODIFY_AP_MASK 0x01C0
+
+//
+// Specified key.
+//
+#define KEY_LOAD_DP 0x5700
+#define KEY_CONN_DP 0x5740
+#define KEY_AP_RETURN 0x5780
+
+//
+// Device path form key.
+// Next 2 bits (bit 6~5).
+//
+#define KEY_PERMIT_MODIFY 0x0010
+#define KEY_FORBID_MODIFY 0x0020
+#define KEY_DISPLAY_DP_MASK 0x0030
+
+//
+// Specified key.
+//
+#define KEY_LOAD_PERMIT 0x5710
+#define KEY_LOAD_FORBID 0x5720
+#define KEY_CONNECT_PERMIT 0x5750
+#define KEY_CONNECT_FORBID 0x5760
+
+//
+// Device path modify key.
+// 2 bits (bit 12~11).
+//
+#define KEY_LOAD_PERMIT_MODIFY 0x0000
+#define KEY_LOAD_FORBID_MODIFY 0x0400
+#define KEY_CONNECT_PERMIT_MODIFY 0x0800
+#define KEY_CONNECT_FORBID_MODIFY 0x0C00
+#define KEY_MODIFY_DP_MASK 0x0C00
+
+
+//
+// The permissions usable when configuring the platform.
+//
+#define ACCESS_SETUP_RESTRICTED 1
+#define ACCESS_SETUP_NORMAL 2
+#define ACCESS_SETUP_ADMIN 3
+
+//
+// Question ID for the question used in each form (KEY_OPEN_CLOSE_FORM_ACTION | FORMID_FORM_USER_MANAGE)
+// This ID is used in FORM OPEN/CLOSE CallBack action.
+//
+#define QUESTIONID_USER_MANAGE 0x3001
+
+#endif
diff --git a/Core/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManagerDxe.inf b/Core/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManagerDxe.inf
new file mode 100644
index 0000000000..619b2dd9f0
--- /dev/null
+++ b/Core/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManagerDxe.inf
@@ -0,0 +1,72 @@
+## @file
+# A UI tool to manage user profiles
+#
+# By this module, user can add/update/delete user profiles, and can also
+# modify the user access policy and the user identification policy.
+#
+# Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = UserProfileManager
+ MODULE_UNI_FILE = UserProfileManager.uni
+ FILE_GUID = E38CB52D-A74D-45db-A8D0-290C9B21BBF2
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = UserProfileManagerInit
+
+[Sources]
+ UserProfileManager.c
+ UserProfileManager.h
+ UserProfileAdd.c
+ UserProfileDelete.c
+ UserProfileModify.c
+ ModifyIdentityPolicy.c
+ ModifyAccessPolicy.c
+ UserProfileManagerData.h
+ UserProfileManagerStrings.uni
+ UserProfileManagerVfr.Vfr
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+ UefiRuntimeServicesTableLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ MemoryAllocationLib
+ BaseMemoryLib
+ DebugLib
+ HiiLib
+ UefiLib
+ DevicePathLib
+
+[Guids]
+ gEfiIfrTianoGuid ## SOMETIMES_CONSUMES ## GUID
+ gEfiUserInfoAccessSetupAdminGuid ## SOMETIMES_CONSUMES ## GUID
+ gEfiUserInfoAccessSetupNormalGuid ## SOMETIMES_CONSUMES ## GUID
+ gEfiUserInfoAccessSetupRestrictedGuid ## SOMETIMES_CONSUMES ## GUID
+ gUserProfileManagerGuid ## CONSUMES ## HII
+
+[Protocols]
+ gEfiDevicePathProtocolGuid ## PRODUCES
+ gEfiHiiConfigAccessProtocolGuid ## PRODUCES
+ gEfiUserCredential2ProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiUserManagerProtocolGuid ## CONSUMES
+
+[Depex]
+ gEfiUserManagerProtocolGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ UserProfileManagerExtra.uni
+ \ No newline at end of file
diff --git a/Core/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManagerExtra.uni b/Core/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManagerExtra.uni
new file mode 100644
index 0000000000..c96bbeca6a
--- /dev/null
+++ b/Core/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManagerExtra.uni
@@ -0,0 +1,19 @@
+// /** @file
+// UserProfileManager Localized Strings and Content
+//
+// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"User Profile Manager"
+
+
diff --git a/Core/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManagerStrings.uni b/Core/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManagerStrings.uni
new file mode 100644
index 0000000000..65f714a5c8
--- /dev/null
+++ b/Core/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManagerStrings.uni
@@ -0,0 +1,158 @@
+/** @file
+ String definitions for User Profile Manager driver.
+
+Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#langdef en-US "English"
+#langdef fr-FR "Français"
+
+#string STR_NULL_STRING #language en-US ""
+ #language fr-FR ""
+#string STR_FORMSET_TITLE #language en-US "User Manager"
+ #language fr-FR "User Manager(French)"
+#string STR_TITLE_HELP #language en-US "This selection will take you to the User Manager"
+ #language fr-FR "This selection will take you to the User Manager(French)"
+#string STR_USERMAN_TITLE #language en-US "User Manager"
+ #language fr-FR "User Manager(French)"
+#string STR_ADD_USER_TITLE #language en-US "Add User Profile"
+ #language fr-FR "Add User Profile(French)"
+#string STR_ADD_USER_HELP #language en-US "Add User Profile to User Database"
+ #language fr-FR "Add User Profile to User Database(French)"
+#string STR_MODIFY_USER_TITLE #language en-US "Modify User Profile"
+ #language fr-FR "Modify User Profile(French)"
+#string STR_MODIFY_USER_HELP #language en-US "Modify User Profile Information"
+ #language fr-FR "Modify User Profile Information(French)"
+#string STR_DELETE_USER_TITLE #language en-US "Delete User Profile"
+ #language fr-FR "Delete User Profile(French)"
+#string STR_DELETE_USER_HELP #language en-US "Delete User Profile from User Database"
+ #language fr-FR "Delete User Profile from User Database(French)"
+#string STR_USER_INFO #language en-US "User Profile Information"
+ #language fr-FR "User Profile Information(French)"
+#string STR_USER_NAME #language en-US "User Name"
+ #language fr-FR "User Name(French)"
+#string STR_USER_NAME_VAL #language en-US ""
+ #language fr-FR ""
+#string STR_CREATE_DATE #language en-US "Create Date"
+ #language fr-FR "Create Date(French)"
+#string STR_CREATE_DATE_VAL #language en-US ""
+ #language fr-FR ""
+#string STR_USAGE_DATE #language en-US "Usage Date"
+ #language fr-FR "Usage Date(French)"
+#string STR_USAGE_DATE_VAL #language en-US ""
+ #language fr-FR ""
+#string STR_USAGE_COUNT #language en-US "Usage Count"
+ #language fr-FR "Usage Count(French)"
+#string STR_USAGE_COUNT_VAL #language en-US ""
+ #language fr-FR ""
+#string STR_IDENTIFY_POLICY #language en-US "Identify Policy"
+ #language fr-FR "Identify Policy(French)"
+#string STR_IDENTIFY_POLICY_VAL #language en-US ""
+ #language fr-FR ""
+#string STR_ACCESS_POLICY #language en-US "Access Policy"
+ #language fr-FR "Access Policy(French)"
+#string STR_SAVE #language en-US "Save & Exit"
+ #language fr-FR "Save & Exit(French)"
+#string STR_IDENTIFY_SAVE_HELP #language en-US "Save Identify Policy and Exit"
+ #language fr-FR "Save Identify Policy and Exit(French)"
+#string STR_PROVIDER #language en-US "Credential Provider"
+ #language fr-FR "Credential Provider(French)"
+#string STR_PROVIDER_HELP #language en-US "Select Credential Provider Option"
+ #language fr-FR "Select Credential Provider Option(French)"
+#string STR_OR_CON #language en-US "Or"
+ #language fr-FR "Or(French)"
+#string STR_AND_CON #language en-US "And"
+ #language fr-FR "And(French)"
+#string STR_CONNECTOR #language en-US "Logical Connector"
+ #language fr-FR "Logical Connector(French)"
+#string STR_CONNECTOR_HELP #language en-US "Select Logical Connector Option"
+ #language fr-FR "Select Logical Connector Option(French)"
+#string STR_IDENTIFY_POLICY_VALUE #language en-US ""
+ #language fr-FR ""
+#string STR_IDENTIFY_POLICY_HELP #language en-US "Current Identify Policy"
+ #language fr-FR "Current Identify Policy(French)"
+#string STR_ADD_OPTION #language en-US "Add Option"
+ #language fr-FR "Add Option(French)"
+#string STR_ADD_OPTION_HELP #language en-US "Add This Option to Identify Policy"
+ #language fr-FR "Add This Option to Identify Policy(French)"
+#string STR_ACCESS_SAVE_HELP #language en-US "Save Access Policy and Exit"
+ #language fr-FR "Save Access Policy and Exit(French)"
+#string STR_ACCESS_RIGHT #language en-US "Access Right"
+ #language fr-FR "Access Right(French)"
+#string STR_ACCESS_RIGHT_HELP #language en-US "Select Access Right Option"
+ #language fr-FR "Select Access Right Option(French)"
+#string STR_NORMAL #language en-US "Normal"
+ #language fr-FR "Normal(French)"
+#string STR_ENROLL #language en-US "Enroll"
+ #language fr-FR "Enroll(French)"
+#string STR_MANAGE #language en-US "Manage"
+ #language fr-FR "Manage(French)"
+#string STR_ACCESS_SETUP #language en-US "Access Setup"
+ #language fr-FR "Access Setup(French)"
+#string STR_ACCESS_SETUP_HELP #language en-US "Select Access Setup Option"
+ #language fr-FR "Selelct Access Setup Option(French)"
+#string STR_RESTRICTED #language en-US "Restricted"
+ #language fr-FR "Restricted(French)"
+#string STR_ADMIN #language en-US "Admin"
+ #language fr-FR "Admin(French)"
+#string STR_BOOR_ORDER #language en-US "Access Boot Order"
+ #language fr-FR "Access Boot Order(French)"
+#string STR_BOOT_ORDER_HELP #language en-US "Select Access Boot Order Option"
+ #language fr-FR "Select Access Boot Order Option(French)"
+#string STR_INSERT #language en-US "Insert"
+ #language fr-FR "Insert(French)"
+#string STR_APPEND #language en-US "Append"
+ #language fr-FR "Append(French)"
+#string STR_REPLACE #language en-US "Replace"
+ #language fr-FR "Replace(French)"
+#string STR_NODEFAULT #language en-US "Nodefault"
+ #language fr-FR "Nodefault(French)"
+#string STR_LOAD #language en-US "Load Device Path"
+ #language fr-FR "Load Device Path(French)"
+#string STR_LOAD_HELP #language en-US "Select Permit/Forbid Load Device Path"
+ #language fr-FR "Select Permit/Forbid Load Device Path(French)"
+#string STR_CONNECT #language en-US "Connect Device Path"
+ #language fr-FR "Connect Device Path(French)"
+#string STR_CONNECT_HELP #language en-US "Select Permit/Forbid Connect Device Path"
+ #language fr-FR "Select Permit/Forbid Connect Device Path(French)"
+#string STR_LOAD_PERMIT #language en-US "Permit Load Device Path"
+ #language fr-FR "Permit Load Device Path(French)"
+#string STR_LOAD_PERMIT_HELP #language en-US "Change Permit Load Device Path to Forbid"
+ #language fr-FR "Change Permit Load Device Path to Forbid(French)"
+#string STR_LOAD_FORBID #language en-US "Forbid Load Device Path"
+ #language fr-FR "Forbid Load Device Path(French)"
+#string STR_LOAD_FORBID_HELP #language en-US "Change Forbid Load Device Path to Permit"
+ #language fr-FR "Change Forbid Load Device Path to Permit(French)"
+#string STR_CONNECT_PERMIT #language en-US "Permit Connect Device Path"
+ #language fr-FR "Permit Connect Device Path(French)"
+#string STR_CONNECT_PERMIT_HELP #language en-US "Change Permit Connect Device Path to Forbid"
+ #language fr-FR "Change Permit Connect Device Path to Forbid(French)"
+#string STR_CONNECT_FORBID #language en-US "Forbid Connect Device Path"
+ #language fr-FR "Forbid Connect Device Path(French)"
+#string STR_CONNECT_FORBID_HELP #language en-US "Change Forbid Connect Device Path to Permit"
+ #language fr-FR "Change Forbid Connect Device Path to Permit(French)"
+#string STR_PRESS_KEY_CONTINUE #language en-US "Press ENTER to Continue, Other Key to Cancel ..."
+ #language fr-FR "Press ENTER to Continue, Other Key to Cancel ...(French)"
+#string STR_MOVE_TO_FORBID_LIST #language en-US "Are You Sure to Move It to Forbid List?"
+ #language fr-FR "Are You Sure to Move It to Forbid List?(French)"
+#string STR_MOVE_TO_PERMIT_LIST #language en-US "Are You Sure to Move It to Permit List?"
+ #language fr-FR "Are You Sure to Move It to Permit List?(French)"
+#string STR_STROKE_KEY_CONTINUE #language en-US "Please Press Any Key to Continue ..."
+ #language fr-FR "Please Press Any Key to Continue ... (French)"
+#string STR_CREATE_PROFILE_FAILED #language en-US "Create New User Profile Failed!"
+ #language fr-FR "Create New User Profile Failed! (French)"
+#string STR_CREATE_PROFILE_SUCCESS #language en-US "Create New User Profile Succeed!"
+ #language fr-FR "Create New User Profile Succeed! (French)"
+#string STR_USER_ALREADY_EXISTED #language en-US "User Name Had Already Existed."
+ #language fr-FR "User Name Had Already Existed. (French)"
+#string STR_GET_USERNAME_FAILED #language en-US "Failed To Get User Name."
+ #language fr-FR "Failed To Get User Name. (French)"
+
diff --git a/Core/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManagerVfr.Vfr b/Core/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManagerVfr.Vfr
new file mode 100644
index 0000000000..2cf3359f2a
--- /dev/null
+++ b/Core/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManagerVfr.Vfr
@@ -0,0 +1,244 @@
+/** @file
+ User Profile Manager formset.
+
+Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "UserProfileManagerData.h"
+
+#define USER_MANAGER_CLASS 0x00
+#define USER_MANAGER_SUBCLASS 0x04
+
+formset
+ guid = USER_PROFILE_MANAGER_GUID,
+ title = STRING_TOKEN(STR_FORMSET_TITLE),
+ help = STRING_TOKEN(STR_TITLE_HELP),
+
+ // User manager form
+ form formid = FORMID_USER_MANAGE,
+ title = STRING_TOKEN(STR_USERMAN_TITLE);
+
+ label LABEL_USER_MANAGE_FUNC;
+ label LABEL_END;
+
+ suppressif TRUE;
+ text
+ help = STRING_TOKEN(STR_NULL_STRING),
+ text = STRING_TOKEN(STR_NULL_STRING),
+ flags = INTERACTIVE,
+ key = QUESTIONID_USER_MANAGE;
+ endif;
+
+ endform;
+
+ // Modify user profile form
+ form formid = FORMID_MODIFY_USER,
+ title = STRING_TOKEN(STR_MODIFY_USER_TITLE);
+
+ label LABEL_USER_MOD_FUNC;
+ label LABEL_END;
+
+ endform;
+
+ // Delete user profile form
+ form formid = FORMID_DEL_USER,
+ title = STRING_TOKEN(STR_DELETE_USER_TITLE);
+
+ label LABEL_USER_DEL_FUNC;
+ label LABEL_END;
+
+ subtitle
+ text = STRING_TOKEN(STR_NULL_STRING);
+ endform;
+
+ //
+ // User profile information form
+ //
+ form formid = FORMID_USER_INFO,
+ title = STRING_TOKEN(STR_USER_INFO);
+
+ text
+ help = STRING_TOKEN(STR_USER_NAME_VAL),
+ text = STRING_TOKEN(STR_USER_NAME),
+ flags = INTERACTIVE,
+ key = KEY_MODIFY_USER_NAME;
+
+ text
+ help = STRING_TOKEN(STR_CREATE_DATE_VAL),
+ text = STRING_TOKEN(STR_CREATE_DATE);
+
+ text
+ help = STRING_TOKEN(STR_USAGE_DATE_VAL),
+ text = STRING_TOKEN(STR_USAGE_DATE);
+
+ text
+ help = STRING_TOKEN(STR_USAGE_COUNT_VAL),
+ text = STRING_TOKEN(STR_USAGE_COUNT);
+
+ label LABEL_USER_INFO_FUNC;
+ label LABEL_END;
+
+ endform;
+
+ //
+ // Identify policy modify form
+ //
+ form formid = FORMID_MODIFY_IP,
+ title = STRING_TOKEN(STR_IDENTIFY_POLICY);
+
+ text
+ help = STRING_TOKEN(STR_IDENTIFY_POLICY_HELP),
+ text = STRING_TOKEN(STR_IDENTIFY_POLICY),
+ text = STRING_TOKEN(STR_IDENTIFY_POLICY_VALUE);
+
+ label LABEL_IP_MOD_FUNC;
+ label LABEL_END;
+
+ text
+ help = STRING_TOKEN(STR_ADD_OPTION_HELP),
+ text = STRING_TOKEN(STR_ADD_OPTION),
+ flags = INTERACTIVE,
+ key = KEY_ADD_LOGICAL_OP;
+
+ subtitle
+ text = STRING_TOKEN(STR_NULL_STRING);
+
+ text
+ help = STRING_TOKEN(STR_IDENTIFY_SAVE_HELP),
+ text = STRING_TOKEN(STR_SAVE),
+ flags = INTERACTIVE,
+ key = KEY_IP_RETURN;
+
+ endform;
+
+ //
+ // Access policy modify form
+ //
+ form formid = FORMID_MODIFY_AP,
+ title = STRING_TOKEN(STR_ACCESS_POLICY);
+
+ label LABEL_AP_MOD_FUNC;
+ label LABEL_END;
+
+ goto FORMID_LOAD_DP,
+ prompt = STRING_TOKEN(STR_LOAD),
+ help = STRING_TOKEN(STR_LOAD_HELP),
+ flags = INTERACTIVE,
+ key = KEY_LOAD_DP;
+
+ goto FORMID_CONNECT_DP,
+ prompt = STRING_TOKEN(STR_CONNECT),
+ help = STRING_TOKEN(STR_CONNECT_HELP),
+ flags = INTERACTIVE,
+ key = KEY_CONN_DP;
+
+ subtitle
+ text = STRING_TOKEN(STR_NULL_STRING);
+
+ text
+ help = STRING_TOKEN(STR_ACCESS_SAVE_HELP),
+ text = STRING_TOKEN(STR_SAVE),
+ flags = INTERACTIVE,
+ key = KEY_AP_RETURN;
+
+ endform;
+
+ //
+ // Load device path form
+ //
+ form formid = FORMID_LOAD_DP,
+ title = STRING_TOKEN(STR_LOAD);
+
+ goto FORMID_PERMIT_LOAD_DP,
+ prompt = STRING_TOKEN(STR_LOAD_PERMIT),
+ help = STRING_TOKEN(STR_LOAD_PERMIT_HELP),
+ flags = INTERACTIVE,
+ key = KEY_LOAD_PERMIT;
+
+ goto FORMID_FORBID_LOAD_DP,
+ prompt = STRING_TOKEN(STR_LOAD_FORBID),
+ help = STRING_TOKEN(STR_LOAD_FORBID_HELP),
+ flags = INTERACTIVE,
+ key = KEY_LOAD_FORBID;
+
+ endform;
+
+ //
+ // Permit load device path form
+ //
+ form formid = FORMID_PERMIT_LOAD_DP,
+ title = STRING_TOKEN(STR_LOAD_PERMIT);
+
+ label LABEL_PERMIT_LOAD_FUNC;
+ label LABEL_END;
+
+ subtitle
+ text = STRING_TOKEN(STR_NULL_STRING);
+
+ endform;
+
+ //
+ // Forbid load device path form
+ //
+ form formid = FORMID_FORBID_LOAD_DP,
+ title = STRING_TOKEN(STR_LOAD_FORBID);
+
+ label LABLE_FORBID_LOAD_FUNC;
+ label LABEL_END;
+
+ subtitle
+ text = STRING_TOKEN(STR_NULL_STRING);
+
+ endform;
+
+ //
+ // Connect device path form
+ //
+ form formid = FORMID_CONNECT_DP,
+ title = STRING_TOKEN(STR_CONNECT);
+
+ goto FORMID_PERMIT_CONNECT_DP,
+ prompt = STRING_TOKEN(STR_CONNECT_PERMIT),
+ help = STRING_TOKEN(STR_CONNECT_PERMIT_HELP),
+ flags = INTERACTIVE,
+ key = KEY_CONNECT_PERMIT;
+
+ goto FORMID_FORBID_CONNECT_DP,
+ prompt = STRING_TOKEN(STR_CONNECT_FORBID),
+ help = STRING_TOKEN(STR_CONNECT_FORBID_HELP),
+ flags = INTERACTIVE,
+ key = KEY_CONNECT_FORBID;
+
+ endform;
+
+ //
+ // Permit connect device path form
+ //
+ form formid = FORMID_PERMIT_CONNECT_DP,
+ title = STRING_TOKEN(STR_CONNECT_PERMIT);
+
+ subtitle
+ text = STRING_TOKEN(STR_NULL_STRING);
+
+ endform;
+
+ //
+ // Forbid connect device path form
+ //
+ form formid = FORMID_FORBID_CONNECT_DP,
+ title = STRING_TOKEN(STR_CONNECT_FORBID);
+
+ subtitle
+ text = STRING_TOKEN(STR_NULL_STRING);
+
+ endform;
+
+endformset;
diff --git a/Core/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileModify.c b/Core/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileModify.c
new file mode 100644
index 0000000000..833307189a
--- /dev/null
+++ b/Core/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileModify.c
@@ -0,0 +1,1475 @@
+/** @file
+ The functions to modify a user profile.
+
+Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "UserProfileManager.h"
+
+EFI_USER_PROFILE_HANDLE mModifyUser = NULL;
+
+/**
+ Display user select form, cab select a user to modify.
+
+**/
+VOID
+SelectUserToModify (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Index;
+ EFI_USER_PROFILE_HANDLE User;
+ EFI_USER_PROFILE_HANDLE CurrentUser;
+ UINT32 CurrentAccessRight;
+ VOID *StartOpCodeHandle;
+ VOID *EndOpCodeHandle;
+ EFI_IFR_GUID_LABEL *StartLabel;
+ EFI_IFR_GUID_LABEL *EndLabel;
+
+ //
+ // 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_MOD_FUNC;
+
+ 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 each user can be modified.
+ //
+ User = NULL;
+ Index = 1;
+ mUserManager->Current (mUserManager, &CurrentUser);
+ while (TRUE) {
+ Status = mUserManager->GetNext (mUserManager, &User);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ Status = GetAccessRight (&CurrentAccessRight);
+ if (EFI_ERROR (Status)) {
+ CurrentAccessRight = EFI_USER_INFO_ACCESS_ENROLL_SELF;
+ }
+
+ if ((CurrentAccessRight == EFI_USER_INFO_ACCESS_MANAGE) || (User == CurrentUser)) {
+ AddUserToForm (User, (UINT16)(KEY_MODIFY_USER | KEY_SELECT_USER | Index), StartOpCodeHandle);
+ }
+ Index++;
+ }
+
+ HiiUpdateForm (
+ mCallbackInfo->HiiHandle, // HII handle
+ &gUserProfileManagerGuid, // Formset GUID
+ FORMID_MODIFY_USER, // Form ID
+ StartOpCodeHandle, // Label for where to insert opcodes
+ EndOpCodeHandle // Replace data
+ );
+
+ HiiFreeOpCodeHandle (StartOpCodeHandle);
+ HiiFreeOpCodeHandle (EndOpCodeHandle);
+}
+
+
+/**
+ Get all the user info from mModifyUser in the user manager, and save on the
+ global variable.
+
+**/
+VOID
+GetAllUserInfo (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_USER_INFO_HANDLE UserInfo;
+ EFI_USER_INFO *Info;
+ UINTN InfoSize;
+ UINTN MemSize;
+ UINTN DataLen;
+
+ //
+ // Init variable to default value.
+ //
+ mProviderChoice = 0;
+ mConncetLogical = 0;
+
+ mUserInfo.CreateDateExist = FALSE;
+ mUserInfo.UsageDateExist = FALSE;
+ mUserInfo.UsageCount = 0;
+
+ mUserInfo.AccessPolicyLen = 0;
+ mUserInfo.AccessPolicyModified = FALSE;
+ if (mUserInfo.AccessPolicy != NULL) {
+ FreePool (mUserInfo.AccessPolicy);
+ mUserInfo.AccessPolicy = NULL;
+ }
+ mUserInfo.IdentityPolicyLen = 0;
+ mUserInfo.IdentityPolicyModified = FALSE;
+ if (mUserInfo.IdentityPolicy != NULL) {
+ FreePool (mUserInfo.IdentityPolicy);
+ mUserInfo.IdentityPolicy = NULL;
+ }
+
+ //
+ // Allocate user information memory.
+ //
+ MemSize = sizeof (EFI_USER_INFO) + 63;
+ Info = AllocateZeroPool (MemSize);
+ if (Info == NULL) {
+ return ;
+ }
+
+ //
+ // Get each user information.
+ //
+ UserInfo = NULL;
+ while (TRUE) {
+ Status = mUserManager->GetNextInfo (mUserManager, mModifyUser, &UserInfo);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ //
+ // Get information.
+ //
+ InfoSize = MemSize;
+ Status = mUserManager->GetInfo (
+ mUserManager,
+ mModifyUser,
+ UserInfo,
+ Info,
+ &InfoSize
+ );
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ MemSize = InfoSize;
+ FreePool (Info);
+ Info = AllocateZeroPool (MemSize);
+ if (Info == NULL) {
+ return ;
+ }
+
+ Status = mUserManager->GetInfo (
+ mUserManager,
+ mModifyUser,
+ UserInfo,
+ Info,
+ &InfoSize
+ );
+ }
+
+ if (Status == EFI_SUCCESS) {
+ //
+ // Deal with each information according to informaiton type.
+ //
+ DataLen = Info->InfoSize - sizeof (EFI_USER_INFO);
+ switch (Info->InfoType) {
+ case EFI_USER_INFO_NAME_RECORD:
+ CopyMem (&mUserInfo.UserName, (UINT8 *) (Info + 1), DataLen);
+ break;
+
+ case EFI_USER_INFO_CREATE_DATE_RECORD:
+ CopyMem (&mUserInfo.CreateDate, (UINT8 *) (Info + 1), DataLen);
+ mUserInfo.CreateDateExist = TRUE;
+ break;
+
+ case EFI_USER_INFO_USAGE_DATE_RECORD:
+ CopyMem (&mUserInfo.UsageDate, (UINT8 *) (Info + 1), DataLen);
+ mUserInfo.UsageDateExist = TRUE;
+ break;
+
+ case EFI_USER_INFO_USAGE_COUNT_RECORD:
+ CopyMem (&mUserInfo.UsageCount, (UINT8 *) (Info + 1), DataLen);
+ break;
+
+ case EFI_USER_INFO_ACCESS_POLICY_RECORD:
+ mUserInfo.AccessPolicy = AllocateZeroPool (DataLen);
+ if (mUserInfo.AccessPolicy == NULL) {
+ break;
+ }
+
+ CopyMem (mUserInfo.AccessPolicy, (UINT8 *) (Info + 1), DataLen);
+ mUserInfo.AccessPolicyLen = DataLen;
+ break;
+
+ case EFI_USER_INFO_IDENTITY_POLICY_RECORD:
+ mUserInfo.IdentityPolicy = AllocateZeroPool (DataLen);
+ if (mUserInfo.IdentityPolicy == NULL) {
+ break;
+ }
+
+ CopyMem (mUserInfo.IdentityPolicy, (UINT8 *) (Info + 1), DataLen);
+ mUserInfo.IdentityPolicyLen = DataLen;
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ FreePool (Info);
+}
+
+
+/**
+ Convert the Date to a string, and update the Hii database DateID string with it.
+
+ @param[in] Date Points to the date to be converted.
+ @param[in] DateId String ID in the HII database to be replaced.
+
+**/
+VOID
+ResolveDate (
+ IN EFI_TIME *Date,
+ IN EFI_STRING_ID DateId
+ )
+{
+ CHAR16 *Str;
+ UINTN DateBufLen;
+
+ //
+ // Convert date to string.
+ //
+ DateBufLen = 64;
+ Str = AllocateZeroPool (DateBufLen);
+ if (Str == NULL) {
+ return ;
+ }
+
+ UnicodeSPrint (
+ Str,
+ DateBufLen,
+ L"%4d-%2d-%2d ",
+ Date->Year,
+ Date->Month,
+ Date->Day
+ );
+
+ //
+ // Convert time to string.
+ //
+ DateBufLen -= StrLen (Str);
+ UnicodeSPrint (
+ Str + StrLen (Str),
+ DateBufLen,
+ L"%2d:%2d:%2d",
+ Date->Hour,
+ Date->Minute,
+ Date->Second
+ );
+
+ HiiSetString (mCallbackInfo->HiiHandle, DateId, Str, NULL);
+ FreePool (Str);
+}
+
+
+/**
+ Convert the CountVal to a string, and update the Hii database CountId string
+ with it.
+
+ @param[in] CountVal The hex value to convert.
+ @param[in] CountId String ID in the HII database to be replaced.
+
+**/
+VOID
+ResolveCount (
+ IN UINT32 CountVal,
+ IN EFI_STRING_ID CountId
+ )
+{
+ CHAR16 Count[10];
+
+ UnicodeSPrint (Count, 20, L"%d", CountVal);
+ HiiSetString (mCallbackInfo->HiiHandle, CountId, Count, NULL);
+}
+
+
+/**
+ Concatenates one Null-terminated Unicode string to another Null-terminated
+ Unicode string.
+
+ @param[in, out] Source1 On entry, point to a Null-terminated Unicode string.
+ On exit, point to a new concatenated Unicode string
+ @param[in] Source2 Pointer to a Null-terminated Unicode string.
+
+**/
+VOID
+AddStr (
+ IN OUT CHAR16 **Source1,
+ IN CONST CHAR16 *Source2
+ )
+{
+ CHAR16 *TmpStr;
+ UINTN StrLength;
+
+ ASSERT (Source1 != NULL);
+ ASSERT (Source2 != NULL);
+
+ if (*Source1 == NULL) {
+ StrLength = StrSize (Source2);
+ } else {
+ StrLength = StrSize (*Source1);
+ StrLength += StrSize (Source2) - 2;
+ }
+
+ TmpStr = AllocateZeroPool (StrLength);
+ ASSERT (TmpStr != NULL);
+
+ if (*Source1 == NULL) {
+ StrCpyS (TmpStr, StrLength / sizeof (CHAR16), Source2);
+ } else {
+ StrCpyS (TmpStr, StrLength / sizeof (CHAR16), *Source1);
+ FreePool (*Source1);
+ StrCatS (TmpStr, StrLength / sizeof (CHAR16),Source2);
+ }
+
+ *Source1 = TmpStr;
+}
+
+
+/**
+ Convert the identity policy to a unicode string and update the Hii database
+ IpStringId string with it.
+
+ @param[in] Ip Points to identity policy.
+ @param[in] IpLen The identity policy length.
+ @param[in] IpStringId String ID in the HII database to be replaced.
+
+**/
+VOID
+ResolveIdentityPolicy (
+ IN UINT8 *Ip,
+ IN UINTN IpLen,
+ IN EFI_STRING_ID IpStringId
+ )
+{
+ CHAR16 *TmpStr;
+ UINTN ChkLen;
+ EFI_USER_INFO_IDENTITY_POLICY *Identity;
+ UINT16 Index;
+ CHAR16 *ProvStr;
+ EFI_STRING_ID ProvId;
+ EFI_HII_HANDLE HiiHandle;
+ EFI_USER_CREDENTIAL2_PROTOCOL *UserCredential;
+
+ TmpStr = NULL;
+
+ //
+ // Resolve each policy.
+ //
+ ChkLen = 0;
+ while (ChkLen < IpLen) {
+ Identity = (EFI_USER_INFO_IDENTITY_POLICY *) (Ip + ChkLen);
+ switch (Identity->Type) {
+ case EFI_USER_INFO_IDENTITY_FALSE:
+ AddStr (&TmpStr, L"False");
+ break;
+
+ case EFI_USER_INFO_IDENTITY_TRUE:
+ AddStr (&TmpStr, L"None");
+ break;
+
+ case EFI_USER_INFO_IDENTITY_NOT:
+ AddStr (&TmpStr, L"! ");
+ break;
+
+ case EFI_USER_INFO_IDENTITY_AND:
+ AddStr (&TmpStr, L" && ");
+ break;
+
+ case EFI_USER_INFO_IDENTITY_OR:
+ AddStr (&TmpStr, L" || ");
+ break;
+
+ case EFI_USER_INFO_IDENTITY_CREDENTIAL_TYPE:
+ for (Index = 0; Index < mProviderInfo->Count; Index++) {
+ UserCredential = mProviderInfo->Provider[Index];
+ if (CompareGuid ((EFI_GUID *) (Identity + 1), &UserCredential->Type)) {
+ UserCredential->Title (
+ UserCredential,
+ &HiiHandle,
+ &ProvId
+ );
+ ProvStr = HiiGetString (HiiHandle, ProvId, NULL);
+ if (ProvStr != NULL) {
+ AddStr (&TmpStr, ProvStr);
+ FreePool (ProvStr);
+ }
+ break;
+ }
+ }
+ break;
+
+ case EFI_USER_INFO_IDENTITY_CREDENTIAL_PROVIDER:
+ for (Index = 0; Index < mProviderInfo->Count; Index++) {
+ UserCredential = mProviderInfo->Provider[Index];
+ if (CompareGuid ((EFI_GUID *) (Identity + 1), &UserCredential->Identifier)) {
+ UserCredential->Title (
+ UserCredential,
+ &HiiHandle,
+ &ProvId
+ );
+ ProvStr = HiiGetString (HiiHandle, ProvId, NULL);
+ if (ProvStr != NULL) {
+ AddStr (&TmpStr, ProvStr);
+ FreePool (ProvStr);
+ }
+ break;
+ }
+ }
+ break;
+ }
+
+ ChkLen += Identity->Length;
+ }
+
+ if (TmpStr != NULL) {
+ HiiSetString (mCallbackInfo->HiiHandle, IpStringId, TmpStr, NULL);
+ FreePool (TmpStr);
+ }
+}
+
+
+/**
+ Display modify user information form.
+
+ This form displays, username, create Date, usage date, usage count, identity policy,
+ and access policy.
+
+ @param[in] UserIndex The index of the user in display list to modify.
+
+**/
+VOID
+ModifyUserInfo (
+ IN UINT8 UserIndex
+ )
+{
+ EFI_STATUS Status;
+ EFI_USER_PROFILE_HANDLE CurrentUser;
+ UINT32 CurrentAccessRight;
+ VOID *StartOpCodeHandle;
+ VOID *EndOpCodeHandle;
+ EFI_IFR_GUID_LABEL *StartLabel;
+ EFI_IFR_GUID_LABEL *EndLabel;
+
+ //
+ // 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_INFO_FUNC;
+
+ 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;
+
+ //
+ // Find the user profile to be modified.
+ //
+ mModifyUser = NULL;
+ Status = mUserManager->GetNext (mUserManager, &mModifyUser);
+ if (EFI_ERROR (Status)) {
+ return ;
+ }
+
+ while (UserIndex > 1) {
+ Status = mUserManager->GetNext (mUserManager, &mModifyUser);
+ if (EFI_ERROR (Status)) {
+ return ;
+ }
+ UserIndex--;
+ }
+
+ //
+ // Get user profile information.
+ //
+ GetAllUserInfo ();
+
+ //
+ // Update user name.
+ HiiSetString (
+ mCallbackInfo->HiiHandle,
+ STRING_TOKEN (STR_USER_NAME_VAL),
+ mUserInfo.UserName,
+ NULL
+ );
+
+ //
+ // Update create date.
+ //
+ if (mUserInfo.CreateDateExist) {
+ ResolveDate (&mUserInfo.CreateDate, STRING_TOKEN (STR_CREATE_DATE_VAL));
+ } else {
+ HiiSetString (
+ mCallbackInfo->HiiHandle,
+ STRING_TOKEN (STR_CREATE_DATE_VAL),
+ L"",
+ NULL
+ );
+ }
+
+ //
+ // Add usage date.
+ //
+ if (mUserInfo.UsageDateExist) {
+ ResolveDate (&mUserInfo.UsageDate, STRING_TOKEN (STR_USAGE_DATE_VAL));
+ } else {
+ HiiSetString (
+ mCallbackInfo->HiiHandle,
+ STRING_TOKEN (STR_USAGE_DATE_VAL),
+ L"",
+ NULL
+ );
+ }
+
+ //
+ // Add usage count.
+ //
+ ResolveCount ((UINT32) mUserInfo.UsageCount, STRING_TOKEN (STR_USAGE_COUNT_VAL));
+
+ //
+ // Add identity policy.
+ //
+ mUserManager->Current (mUserManager, &CurrentUser);
+ if (mModifyUser == CurrentUser) {
+ ResolveIdentityPolicy (
+ mUserInfo.IdentityPolicy,
+ mUserInfo.IdentityPolicyLen,
+ STRING_TOKEN (STR_IDENTIFY_POLICY_VAL)
+ );
+ HiiCreateGotoOpCode (
+ StartOpCodeHandle, // Container for opcodes
+ FORMID_MODIFY_IP, // Target Form ID
+ STRING_TOKEN (STR_IDENTIFY_POLICY), // Prompt text
+ STRING_TOKEN (STR_IDENTIFY_POLICY_VAL), // Help text
+ EFI_IFR_FLAG_CALLBACK, // Question flag
+ KEY_MODIFY_USER | KEY_SELECT_USER | KEY_MODIFY_IP // Question ID
+ );
+ }
+
+ //
+ // Add access policy.
+ //
+ Status = GetAccessRight (&CurrentAccessRight);
+ if (EFI_ERROR (Status)) {
+ CurrentAccessRight = EFI_USER_INFO_ACCESS_ENROLL_SELF;
+ }
+
+ if (CurrentAccessRight == EFI_USER_INFO_ACCESS_MANAGE) {
+ HiiCreateGotoOpCode (
+ StartOpCodeHandle, // Container for opcodes
+ FORMID_MODIFY_AP, // Target Form ID
+ STRING_TOKEN (STR_ACCESS_POLICY), // Prompt text
+ STRING_TOKEN (STR_NULL_STRING), // Help text
+ EFI_IFR_FLAG_CALLBACK, // Question flag
+ KEY_MODIFY_USER | KEY_SELECT_USER | KEY_MODIFY_AP // Question ID
+ );
+ }
+
+ HiiUpdateForm (
+ mCallbackInfo->HiiHandle, // HII handle
+ &gUserProfileManagerGuid, // Formset GUID
+ FORMID_USER_INFO, // Form ID
+ StartOpCodeHandle, // Label
+ EndOpCodeHandle // Replace data
+ );
+
+ HiiFreeOpCodeHandle (StartOpCodeHandle);
+ HiiFreeOpCodeHandle (EndOpCodeHandle);
+}
+
+
+/**
+ Get all the access policy info from current user info, and save in the global
+ variable.
+
+**/
+VOID
+ResolveAccessPolicy (
+ VOID
+ )
+{
+ UINTN OffSet;
+ EFI_USER_INFO_ACCESS_CONTROL Control;
+ UINTN ValLen;
+ UINT8 *AccessData;
+
+ //
+ // Set default value
+ //
+ mAccessInfo.AccessRight = EFI_USER_INFO_ACCESS_ENROLL_SELF;
+ mAccessInfo.AccessSetup = ACCESS_SETUP_RESTRICTED;
+ mAccessInfo.AccessBootOrder = EFI_USER_INFO_ACCESS_BOOT_ORDER_INSERT;
+
+ mAccessInfo.LoadPermitLen = 0;
+ mAccessInfo.LoadForbidLen = 0;
+ mAccessInfo.ConnectPermitLen = 0;
+ mAccessInfo.ConnectForbidLen = 0;
+
+ //
+ // Get each user access policy.
+ //
+ OffSet = 0;
+ while (OffSet < mUserInfo.AccessPolicyLen) {
+ CopyMem (&Control, mUserInfo.AccessPolicy + OffSet, sizeof (Control));
+ ValLen = Control.Size - sizeof (Control);
+ switch (Control.Type) {
+ case EFI_USER_INFO_ACCESS_ENROLL_SELF:
+ mAccessInfo.AccessRight = EFI_USER_INFO_ACCESS_ENROLL_SELF;
+ break;
+
+ case EFI_USER_INFO_ACCESS_ENROLL_OTHERS:
+ mAccessInfo.AccessRight = EFI_USER_INFO_ACCESS_ENROLL_OTHERS;
+ break;
+
+ case EFI_USER_INFO_ACCESS_MANAGE:
+ mAccessInfo.AccessRight = EFI_USER_INFO_ACCESS_MANAGE;
+ break;
+
+ case EFI_USER_INFO_ACCESS_SETUP:
+ AccessData = mUserInfo.AccessPolicy + OffSet + sizeof (Control);
+ if (CompareGuid ((EFI_GUID *) AccessData, &gEfiUserInfoAccessSetupNormalGuid)) {
+ mAccessInfo.AccessSetup = ACCESS_SETUP_NORMAL;
+ } else if (CompareGuid ((EFI_GUID *) AccessData, &gEfiUserInfoAccessSetupRestrictedGuid)) {
+ mAccessInfo.AccessSetup = ACCESS_SETUP_RESTRICTED;
+ } else if (CompareGuid ((EFI_GUID *) AccessData, &gEfiUserInfoAccessSetupAdminGuid)) {
+ mAccessInfo.AccessSetup = ACCESS_SETUP_ADMIN;
+ }
+ break;
+
+ case EFI_USER_INFO_ACCESS_BOOT_ORDER:
+ AccessData = mUserInfo.AccessPolicy + OffSet + sizeof (Control);
+ CopyMem (&mAccessInfo.AccessBootOrder, AccessData, sizeof (UINT32));
+ break;
+
+ case EFI_USER_INFO_ACCESS_FORBID_LOAD:
+ if (mAccessInfo.LoadForbid != NULL) {
+ FreePool (mAccessInfo.LoadForbid);
+ }
+
+ mAccessInfo.LoadForbid = AllocateZeroPool (ValLen);
+ if (mAccessInfo.LoadForbid != NULL) {
+ AccessData = mUserInfo.AccessPolicy + OffSet + sizeof (Control);
+ CopyMem (mAccessInfo.LoadForbid, AccessData, ValLen);
+ mAccessInfo.LoadForbidLen = ValLen;
+ }
+ break;
+
+ case EFI_USER_INFO_ACCESS_PERMIT_LOAD:
+ if (mAccessInfo.LoadPermit != NULL) {
+ FreePool (mAccessInfo.LoadPermit);
+ }
+
+ mAccessInfo.LoadPermit = AllocateZeroPool (ValLen);
+ if (mAccessInfo.LoadPermit != NULL) {
+ AccessData = mUserInfo.AccessPolicy + OffSet + sizeof (Control);
+ CopyMem (mAccessInfo.LoadPermit, AccessData, ValLen);
+ mAccessInfo.LoadPermitLen = ValLen;
+ }
+ break;
+
+ case EFI_USER_INFO_ACCESS_FORBID_CONNECT:
+ if (mAccessInfo.ConnectForbid != NULL) {
+ FreePool (mAccessInfo.ConnectForbid);
+ }
+
+ mAccessInfo.ConnectForbid = AllocateZeroPool (ValLen);
+ if (mAccessInfo.ConnectForbid != NULL) {
+ AccessData = mUserInfo.AccessPolicy + OffSet + sizeof (Control);
+ CopyMem (mAccessInfo.ConnectForbid, AccessData, ValLen);
+ mAccessInfo.ConnectForbidLen = ValLen;
+ }
+ break;
+
+ case EFI_USER_INFO_ACCESS_PERMIT_CONNECT:
+ if (mAccessInfo.ConnectPermit != NULL) {
+ FreePool (mAccessInfo.ConnectPermit);
+ }
+
+ mAccessInfo.ConnectPermit = AllocateZeroPool (ValLen);
+ if (mAccessInfo.ConnectPermit != NULL) {
+ AccessData = mUserInfo.AccessPolicy + OffSet + sizeof (Control);
+ CopyMem (mAccessInfo.ConnectPermit, AccessData, ValLen);
+ mAccessInfo.ConnectPermitLen = ValLen;
+ }
+ break;
+ }
+
+ OffSet += Control.Size;
+ }
+}
+
+
+/**
+ Find the specified info in User profile by the InfoType.
+
+ @param[in] User Handle of the user whose information will be searched.
+ @param[in] InfoType The user information type to find.
+ @param[out] UserInfo Points to user information handle found.
+
+ @retval EFI_SUCCESS Find the user information successfully.
+ @retval Others Fail to find the user information.
+
+**/
+EFI_STATUS
+FindInfoByType (
+ IN EFI_USER_PROFILE_HANDLE User,
+ IN UINT8 InfoType,
+ OUT EFI_USER_INFO_HANDLE *UserInfo
+ )
+{
+ EFI_STATUS Status;
+ EFI_USER_INFO *Info;
+ UINTN InfoSize;
+ UINTN MemSize;
+
+ if (UserInfo == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *UserInfo = NULL;
+ //
+ // Allocate user information memory.
+ //
+ MemSize = sizeof (EFI_USER_INFO) + 63;
+ Info = AllocateZeroPool (MemSize);
+ if (Info == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Get each user information.
+ //
+ while (TRUE) {
+ Status = mUserManager->GetNextInfo (mUserManager, User, UserInfo);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ //
+ // Get information.
+ //
+ InfoSize = MemSize;
+ Status = mUserManager->GetInfo (
+ mUserManager,
+ User,
+ *UserInfo,
+ Info,
+ &InfoSize
+ );
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ MemSize = InfoSize;
+ FreePool (Info);
+ Info = AllocateZeroPool (MemSize);
+ if (Info == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Status = mUserManager->GetInfo (
+ mUserManager,
+ User,
+ *UserInfo,
+ Info,
+ &InfoSize
+ );
+ }
+ if (Status == EFI_SUCCESS) {
+ if (Info->InfoType == InfoType) {
+ break;
+ }
+ }
+ }
+
+ FreePool (Info);
+ return Status;
+}
+
+
+/**
+ Display modify user access policy form.
+
+ In this form, access right, access setup and access boot order are dynamically
+ added. Load devicepath and connect devicepath are displayed too.
+
+**/
+VOID
+ModidyAccessPolicy (
+ VOID
+ )
+{
+ VOID *StartOpCodeHandle;
+ VOID *EndOpCodeHandle;
+ VOID *OptionsOpCodeHandle;
+ EFI_IFR_GUID_LABEL *StartLabel;
+ EFI_IFR_GUID_LABEL *EndLabel;
+ VOID *DefaultOpCodeHandle;
+
+ //
+ // 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_AP_MOD_FUNC;
+
+ 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;
+
+
+ //
+ // Resolve access policy information.
+ //
+ ResolveAccessPolicy ();
+
+ //
+ // Add access right one-of-code.
+ //
+ OptionsOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (OptionsOpCodeHandle != NULL);
+ DefaultOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (DefaultOpCodeHandle != NULL);
+
+ HiiCreateOneOfOptionOpCode (
+ OptionsOpCodeHandle,
+ STRING_TOKEN (STR_NORMAL),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_1,
+ EFI_USER_INFO_ACCESS_ENROLL_SELF
+ );
+
+ HiiCreateOneOfOptionOpCode (
+ OptionsOpCodeHandle,
+ STRING_TOKEN (STR_ENROLL),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_1,
+ EFI_USER_INFO_ACCESS_ENROLL_OTHERS
+ );
+
+ HiiCreateOneOfOptionOpCode (
+ OptionsOpCodeHandle,
+ STRING_TOKEN (STR_MANAGE),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_1,
+ EFI_USER_INFO_ACCESS_MANAGE
+ );
+
+ HiiCreateDefaultOpCode (
+ DefaultOpCodeHandle,
+ EFI_HII_DEFAULT_CLASS_STANDARD,
+ EFI_IFR_NUMERIC_SIZE_1,
+ mAccessInfo.AccessRight
+ );
+
+ HiiCreateOneOfOpCode (
+ StartOpCodeHandle, // Container for dynamic created opcodes
+ KEY_MODIFY_USER | KEY_SELECT_USER | KEY_MODIFY_AP | KEY_MODIFY_RIGHT, // Question ID
+ 0, // VarStore ID
+ 0, // Offset in Buffer Storage
+ STRING_TOKEN (STR_ACCESS_RIGHT), // Question prompt text
+ STRING_TOKEN (STR_ACCESS_RIGHT_HELP), // Question help text
+ EFI_IFR_FLAG_CALLBACK, // Question flag
+ EFI_IFR_NUMERIC_SIZE_1, // Data type of Question Value
+ OptionsOpCodeHandle, // Option Opcode list
+ DefaultOpCodeHandle // Default Opcode
+ );
+ HiiFreeOpCodeHandle (DefaultOpCodeHandle);
+ HiiFreeOpCodeHandle (OptionsOpCodeHandle);
+
+
+ //
+ // Add setup type one-of-code.
+ //
+ OptionsOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (OptionsOpCodeHandle != NULL);
+ DefaultOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (DefaultOpCodeHandle != NULL);
+
+ HiiCreateOneOfOptionOpCode (
+ OptionsOpCodeHandle,
+ STRING_TOKEN (STR_RESTRICTED),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_1,
+ ACCESS_SETUP_RESTRICTED
+ );
+
+ HiiCreateOneOfOptionOpCode (
+ OptionsOpCodeHandle,
+ STRING_TOKEN (STR_NORMAL),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_1,
+ ACCESS_SETUP_NORMAL
+ );
+
+ HiiCreateOneOfOptionOpCode (
+ OptionsOpCodeHandle,
+ STRING_TOKEN (STR_ADMIN),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_1,
+ ACCESS_SETUP_ADMIN
+ );
+
+ HiiCreateDefaultOpCode (
+ DefaultOpCodeHandle,
+ EFI_HII_DEFAULT_CLASS_STANDARD,
+ EFI_IFR_NUMERIC_SIZE_1,
+ mAccessInfo.AccessSetup
+ );
+
+ HiiCreateOneOfOpCode (
+ StartOpCodeHandle, // Container for dynamic created opcodes
+ KEY_MODIFY_USER | KEY_SELECT_USER | KEY_MODIFY_AP | KEY_MODIFY_SETUP, // Question ID
+ 0, // VarStore ID
+ 0, // Offset in Buffer Storage
+ STRING_TOKEN (STR_ACCESS_SETUP), // Question prompt text
+ STRING_TOKEN (STR_ACCESS_SETUP_HELP), // Question help text
+ EFI_IFR_FLAG_CALLBACK, // Question flag
+ EFI_IFR_NUMERIC_SIZE_1, // Data type of Question Value
+ OptionsOpCodeHandle, // Option Opcode list
+ DefaultOpCodeHandle // Default Opcode
+ );
+ HiiFreeOpCodeHandle (DefaultOpCodeHandle);
+ HiiFreeOpCodeHandle (OptionsOpCodeHandle);
+
+ //
+ // Add boot order one-of-code.
+ //
+ OptionsOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (OptionsOpCodeHandle != NULL);
+ DefaultOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (DefaultOpCodeHandle != NULL);
+
+ HiiCreateOneOfOptionOpCode (
+ OptionsOpCodeHandle,
+ STRING_TOKEN (STR_INSERT),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_4,
+ EFI_USER_INFO_ACCESS_BOOT_ORDER_INSERT
+ );
+
+ HiiCreateOneOfOptionOpCode (
+ OptionsOpCodeHandle,
+ STRING_TOKEN (STR_APPEND),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_4,
+ EFI_USER_INFO_ACCESS_BOOT_ORDER_APPEND
+ );
+
+ HiiCreateOneOfOptionOpCode (
+ OptionsOpCodeHandle,
+ STRING_TOKEN (STR_REPLACE),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_4,
+ EFI_USER_INFO_ACCESS_BOOT_ORDER_REPLACE
+ );
+
+ HiiCreateOneOfOptionOpCode (
+ OptionsOpCodeHandle,
+ STRING_TOKEN (STR_NODEFAULT),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_4,
+ EFI_USER_INFO_ACCESS_BOOT_ORDER_NODEFAULT
+ );
+
+ HiiCreateDefaultOpCode (
+ DefaultOpCodeHandle,
+ EFI_HII_DEFAULT_CLASS_STANDARD,
+ EFI_IFR_NUMERIC_SIZE_4,
+ mAccessInfo.AccessBootOrder
+ );
+
+ HiiCreateOneOfOpCode (
+ StartOpCodeHandle, // Container for dynamic created opcodes
+ KEY_MODIFY_USER | KEY_SELECT_USER | KEY_MODIFY_AP | KEY_MODIFY_BOOT, // Question ID
+ 0, // VarStore ID
+ 0, // Offset in Buffer Storage
+ STRING_TOKEN (STR_BOOR_ORDER), // Question prompt text
+ STRING_TOKEN (STR_BOOT_ORDER_HELP), // Question help text
+ EFI_IFR_FLAG_CALLBACK, // Question flag
+ EFI_IFR_NUMERIC_SIZE_1, // Data type of Question Value
+ OptionsOpCodeHandle, // Option Opcode list
+ DefaultOpCodeHandle // Default Opcode
+ );
+ HiiFreeOpCodeHandle (DefaultOpCodeHandle);
+ HiiFreeOpCodeHandle (OptionsOpCodeHandle);
+
+ //
+ // Update Form.
+ //
+ HiiUpdateForm (
+ mCallbackInfo->HiiHandle, // HII handle
+ &gUserProfileManagerGuid, // Formset GUID
+ FORMID_MODIFY_AP, // Form ID
+ StartOpCodeHandle, // Label for where to insert opcodes
+ EndOpCodeHandle // Replace data
+ );
+
+ HiiFreeOpCodeHandle (StartOpCodeHandle);
+ HiiFreeOpCodeHandle (EndOpCodeHandle);
+}
+
+
+/**
+ Expand access policy memory size.
+
+ @param[in] ValidLen The valid access policy length.
+ @param[in] ExpandLen The length that is needed to expand.
+
+**/
+VOID
+ExpandMemory (
+ IN UINTN ValidLen,
+ IN UINTN ExpandLen
+ )
+{
+ UINT8 *Mem;
+ UINTN Len;
+
+ //
+ // Expand memory.
+ //
+ Len = mUserInfo.AccessPolicyLen + (ExpandLen / 64 + 1) * 64;
+ Mem = AllocateZeroPool (Len);
+ ASSERT (Mem != NULL);
+
+ if (mUserInfo.AccessPolicy != NULL) {
+ CopyMem (Mem, mUserInfo.AccessPolicy, ValidLen);
+ FreePool (mUserInfo.AccessPolicy);
+ }
+
+ mUserInfo.AccessPolicy = Mem;
+ mUserInfo.AccessPolicyLen = Len;
+}
+
+
+/**
+ Get the username from user input, and update username string in the Hii
+ database with it.
+
+**/
+VOID
+ModifyUserName (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ CHAR16 UserName[USER_NAME_LENGTH];
+ UINTN Len;
+ EFI_INPUT_KEY Key;
+ EFI_USER_INFO_HANDLE UserInfo;
+ EFI_USER_INFO *Info;
+ EFI_USER_PROFILE_HANDLE TempUser;
+
+ //
+ // Get the new user name.
+ //
+ Len = sizeof (UserName);
+ Status = GetUserNameInput (&Len, UserName);
+ if (EFI_ERROR (Status)) {
+ if (Status != EFI_ABORTED) {
+ CreatePopUp (
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
+ &Key,
+ L"Failed To Get User Name.",
+ L"",
+ L"Please Press Any Key to Continue ...",
+ NULL
+ );
+ }
+ return ;
+ }
+
+ //
+ // Check whether the username had been used or not.
+ //
+ Info = AllocateZeroPool (sizeof (EFI_USER_INFO) + Len);
+ if (Info == NULL) {
+ return ;
+ }
+
+ 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 = (UINT32) (sizeof (EFI_USER_INFO) + Len);
+ CopyMem ((UINT8 *) (Info + 1), UserName, Len);
+
+ TempUser = NULL;
+ Status = mUserManager->Find (
+ mUserManager,
+ &TempUser,
+ NULL,
+ Info,
+ Info->InfoSize
+ );
+ if (!EFI_ERROR (Status)) {
+ CreatePopUp (
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
+ &Key,
+ L"The User Name Had Been Used.",
+ L"",
+ L"Please Use Other User Name",
+ NULL
+ );
+ FreePool (Info);
+ return ;
+ }
+
+ //
+ // Update username display in the form.
+ //
+ CopyMem (mUserInfo.UserName, UserName, Len);
+ HiiSetString (
+ mCallbackInfo->HiiHandle,
+ STRING_TOKEN (STR_USER_NAME_VAL),
+ mUserInfo.UserName,
+ NULL
+ );
+
+ //
+ // Save the user name.
+ //
+ Status = FindInfoByType (mModifyUser, EFI_USER_INFO_NAME_RECORD, &UserInfo);
+ if (!EFI_ERROR (Status)) {
+ mUserManager->SetInfo (
+ mUserManager,
+ mModifyUser,
+ &UserInfo,
+ Info,
+ Info->InfoSize
+ );
+ }
+ FreePool (Info);
+}
+
+
+/**
+ Display the form of the modifying user identity policy.
+
+**/
+VOID
+ModifyIdentityPolicy (
+ VOID
+ )
+{
+ UINTN Index;
+ CHAR16 *ProvStr;
+ EFI_STRING_ID ProvID;
+ EFI_HII_HANDLE HiiHandle;
+ VOID *OptionsOpCodeHandle;
+ VOID *StartOpCodeHandle;
+ VOID *EndOpCodeHandle;
+ EFI_IFR_GUID_LABEL *StartLabel;
+ EFI_IFR_GUID_LABEL *EndLabel;
+
+ //
+ // 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_IP_MOD_FUNC;
+
+ 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 credential providers
+ //.
+ if (mProviderInfo->Count > 0) {
+ OptionsOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (OptionsOpCodeHandle != NULL);
+
+ //
+ // Add credential provider Option OpCode.
+ //
+ for (Index = 0; Index < mProviderInfo->Count; Index++) {
+ mProviderInfo->Provider[Index]->Title (
+ mProviderInfo->Provider[Index],
+ &HiiHandle,
+ &ProvID
+ );
+ ProvStr = HiiGetString (HiiHandle, ProvID, NULL);
+ ProvID = HiiSetString (mCallbackInfo->HiiHandle, 0, ProvStr, NULL);
+ FreePool (ProvStr);
+ if (ProvID == 0) {
+ return ;
+ }
+
+ HiiCreateOneOfOptionOpCode (
+ OptionsOpCodeHandle,
+ ProvID,
+ 0,
+ EFI_IFR_NUMERIC_SIZE_1,
+ (UINT8) Index
+ );
+ }
+
+ HiiCreateOneOfOpCode (
+ StartOpCodeHandle, // Container for dynamic created opcodes
+ KEY_MODIFY_USER | KEY_SELECT_USER | KEY_MODIFY_IP | KEY_MODIFY_PROV, // Question ID
+ 0, // VarStore ID
+ 0, // Offset in Buffer Storage
+ STRING_TOKEN (STR_PROVIDER), // Question prompt text
+ STRING_TOKEN (STR_PROVIDER_HELP), // Question help text
+ EFI_IFR_FLAG_CALLBACK, // Question flag
+ EFI_IFR_NUMERIC_SIZE_1, // Data type of Question Value
+ OptionsOpCodeHandle, // Option Opcode list
+ NULL // Default Opcode is NULl
+ );
+
+ HiiFreeOpCodeHandle (OptionsOpCodeHandle);
+ }
+
+ //
+ // Add logical connector Option OpCode.
+ //
+ OptionsOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (OptionsOpCodeHandle != NULL);
+
+ HiiCreateOneOfOptionOpCode (
+ OptionsOpCodeHandle,
+ STRING_TOKEN (STR_AND_CON),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_1,
+ 0
+ );
+
+ HiiCreateOneOfOptionOpCode (
+ OptionsOpCodeHandle,
+ STRING_TOKEN (STR_OR_CON),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_1,
+ 1
+ );
+
+ HiiCreateOneOfOpCode (
+ StartOpCodeHandle, // Container for dynamic created opcodes
+ KEY_MODIFY_USER | KEY_SELECT_USER | KEY_MODIFY_IP | KEY_MODIFY_CONN, // Question ID
+ 0, // VarStore ID
+ 0, // Offset in Buffer Storage
+ STRING_TOKEN (STR_CONNECTOR), // Question prompt text
+ STRING_TOKEN (STR_CONNECTOR_HELP), // Question help text
+ EFI_IFR_FLAG_CALLBACK, // Question flag
+ EFI_IFR_NUMERIC_SIZE_1, // Data type of Question Value
+ OptionsOpCodeHandle, // Option Opcode list
+ NULL // Default Opcode is NULl
+ );
+
+ HiiFreeOpCodeHandle (OptionsOpCodeHandle);
+
+ //
+ // Update identity policy in the form.
+ //
+ ResolveIdentityPolicy (
+ mUserInfo.IdentityPolicy,
+ mUserInfo.IdentityPolicyLen,
+ STRING_TOKEN (STR_IDENTIFY_POLICY_VALUE)
+ );
+
+ if (mUserInfo.NewIdentityPolicy != NULL) {
+ FreePool (mUserInfo.NewIdentityPolicy);
+ mUserInfo.NewIdentityPolicy = NULL;
+ mUserInfo.NewIdentityPolicyLen = 0;
+ mUserInfo.NewIdentityPolicyModified = FALSE;
+ }
+ mProviderChoice = 0;
+ mConncetLogical = 0;
+
+ HiiUpdateForm (
+ mCallbackInfo->HiiHandle, // HII handle
+ &gUserProfileManagerGuid, // Formset GUID
+ FORMID_MODIFY_IP, // Form ID
+ StartOpCodeHandle, // Label for where to insert opcodes
+ EndOpCodeHandle // Replace data
+ );
+
+ HiiFreeOpCodeHandle (StartOpCodeHandle);
+ HiiFreeOpCodeHandle (EndOpCodeHandle);
+}
+
+
+/**
+ Get current user's access right.
+
+ @param[out] AccessRight Points to the buffer used for user's access right.
+
+ @retval EFI_SUCCESS Get current user access right successfully.
+ @retval others Fail to get current user access right.
+
+**/
+EFI_STATUS
+GetAccessRight (
+ OUT UINT32 *AccessRight
+ )
+{
+ EFI_STATUS Status;
+ EFI_USER_INFO_HANDLE UserInfo;
+ EFI_USER_INFO *Info;
+ UINTN InfoSize;
+ UINTN MemSize;
+ EFI_USER_INFO_ACCESS_CONTROL Access;
+ EFI_USER_PROFILE_HANDLE CurrentUser;
+ UINTN TotalLen;
+ UINTN CheckLen;
+
+ //
+ // Allocate user information memory.
+ //
+ MemSize = sizeof (EFI_USER_INFO) + 63;
+ Info = AllocateZeroPool (MemSize);
+ if (Info == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Get user access information.
+ //
+ UserInfo = NULL;
+ mUserManager->Current (mUserManager, &CurrentUser);
+ while (TRUE) {
+ InfoSize = MemSize;
+ //
+ // Get next user information.
+ //
+ Status = mUserManager->GetNextInfo (mUserManager, CurrentUser, &UserInfo);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ Status = mUserManager->GetInfo (
+ mUserManager,
+ CurrentUser,
+ UserInfo,
+ Info,
+ &InfoSize
+ );
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ MemSize = InfoSize;
+ FreePool (Info);
+ Info = AllocateZeroPool (MemSize);
+ if (Info == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Status = mUserManager->GetInfo (
+ mUserManager,
+ CurrentUser,
+ UserInfo,
+ Info,
+ &InfoSize
+ );
+ }
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ //
+ // Check user information.
+ //
+ if (Info->InfoType == EFI_USER_INFO_ACCESS_POLICY_RECORD) {
+ TotalLen = Info->InfoSize - sizeof (EFI_USER_INFO);
+ CheckLen = 0;
+ //
+ // Get specified access information.
+ //
+ while (CheckLen < TotalLen) {
+ CopyMem (&Access, (UINT8 *) (Info + 1) + CheckLen, sizeof (Access));
+ if ((Access.Type == EFI_USER_INFO_ACCESS_ENROLL_SELF) ||
+ (Access.Type == EFI_USER_INFO_ACCESS_ENROLL_OTHERS) ||
+ (Access.Type == EFI_USER_INFO_ACCESS_MANAGE)
+ ) {
+ *AccessRight = Access.Type;
+ FreePool (Info);
+ return EFI_SUCCESS;
+ }
+ CheckLen += Access.Size;
+ }
+ }
+ }
+ FreePool (Info);
+ return EFI_NOT_FOUND;
+}
+
diff --git a/Core/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/AuthService.c b/Core/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/AuthService.c
new file mode 100644
index 0000000000..490a8b3417
--- /dev/null
+++ b/Core/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/AuthService.c
@@ -0,0 +1,886 @@
+/** @file
+ Implement authentication services for the authenticated variable
+ service in UEFI2.2.
+
+Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "Variable.h"
+#include "AuthService.h"
+
+///
+/// Global database array for scratch
+///
+UINT32 mPubKeyNumber;
+UINT32 mPlatformMode;
+EFI_GUID mSignatureSupport[SIGSUPPORT_NUM] = {EFI_CERT_RSA2048_SHA256_GUID, EFI_CERT_RSA2048_SHA1_GUID};
+//
+// Public Exponent of RSA Key.
+//
+CONST UINT8 mRsaE[] = { 0x01, 0x00, 0x01 };
+
+/**
+ Initializes for authenticated varibale service.
+
+ @retval EFI_SUCCESS The function successfully executed.
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate enough memory resources.
+
+**/
+EFI_STATUS
+AutenticatedVariableServiceInitialize (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ VARIABLE_POINTER_TRACK Variable;
+ UINT8 VarValue;
+ UINT32 VarAttr;
+ UINTN DataSize;
+ UINTN CtxSize;
+ AUTHENTICATED_VARIABLE_HEADER VariableHeader;
+ BOOLEAN Valid;
+
+ ZeroMem (&VariableHeader, sizeof (AUTHENTICATED_VARIABLE_HEADER));
+
+ mVariableModuleGlobal->AuthenticatedVariableGuid[Physical] = &gEfiAuthenticatedVariableGuid;
+ mVariableModuleGlobal->CertRsa2048Sha256Guid[Physical] = &gEfiCertRsa2048Sha256Guid;
+ mVariableModuleGlobal->ImageSecurityDatabaseGuid[Physical] = &gEfiImageSecurityDatabaseGuid;
+
+ //
+ // Initialize hash context.
+ //
+ CtxSize = Sha256GetContextSize ();
+ mVariableModuleGlobal->HashContext[Physical] = AllocateRuntimePool (CtxSize);
+ ASSERT (mVariableModuleGlobal->HashContext[Physical] != NULL);
+ //
+ // Check "AuthVarKeyDatabase" variable's existence.
+ // If it doesn't exist, create a new one with initial value of 0 and EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
+ //
+ Status = FindVariable (
+ mVariableModuleGlobal->VariableName[Physical][VAR_AUTH_KEY_DB],
+ &gEfiAuthenticatedVariableGuid,
+ &Variable,
+ &mVariableModuleGlobal->VariableGlobal[Physical],
+ mVariableModuleGlobal->FvbInstance
+ );
+
+ if (Variable.CurrPtr == 0x0) {
+ VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;
+ VarValue = 0;
+ mPubKeyNumber = 0;
+ Status = UpdateVariable (
+ mVariableModuleGlobal->VariableName[Physical][VAR_AUTH_KEY_DB],
+ &gEfiAuthenticatedVariableGuid,
+ &VarValue,
+ sizeof(UINT8),
+ VarAttr,
+ 0,
+ 0,
+ FALSE,
+ mVariableModuleGlobal,
+ &Variable
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } else {
+ //
+ // Load database in global variable for cache.
+ //
+ Valid = IsValidVariableHeader (
+ Variable.CurrPtr,
+ Variable.Volatile,
+ &mVariableModuleGlobal->VariableGlobal[Physical],
+ mVariableModuleGlobal->FvbInstance,
+ &VariableHeader
+ );
+ ASSERT (Valid);
+
+ DataSize = DataSizeOfVariable (&VariableHeader);
+ ASSERT (DataSize <= MAX_KEYDB_SIZE);
+ GetVariableDataPtr (
+ Variable.CurrPtr,
+ Variable.Volatile,
+ &mVariableModuleGlobal->VariableGlobal[Physical],
+ mVariableModuleGlobal->FvbInstance,
+ (CHAR16 *) mVariableModuleGlobal->PubKeyStore
+ );
+
+ mPubKeyNumber = (UINT32) (DataSize / EFI_CERT_TYPE_RSA2048_SIZE);
+ }
+ //
+ // Check "SetupMode" variable's existence.
+ // If it doesn't exist, check PK database's existence to determine the value.
+ // Then create a new one with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
+ //
+ Status = FindVariable (
+ mVariableModuleGlobal->VariableName[Physical][VAR_SETUP_MODE],
+ &gEfiGlobalVariableGuid,
+ &Variable,
+ &mVariableModuleGlobal->VariableGlobal[Physical],
+ mVariableModuleGlobal->FvbInstance
+ );
+
+ if (Variable.CurrPtr == 0x0) {
+ Status = FindVariable (
+ mVariableModuleGlobal->VariableName[Physical][VAR_PLATFORM_KEY],
+ &gEfiGlobalVariableGuid,
+ &Variable,
+ &mVariableModuleGlobal->VariableGlobal[Physical],
+ mVariableModuleGlobal->FvbInstance
+ );
+ if (Variable.CurrPtr == 0x0) {
+ mPlatformMode = SETUP_MODE;
+ } else {
+ mPlatformMode = USER_MODE;
+ }
+
+ VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;
+ Status = UpdateVariable (
+ mVariableModuleGlobal->VariableName[Physical][VAR_SETUP_MODE],
+ &gEfiGlobalVariableGuid,
+ &mPlatformMode,
+ sizeof(UINT8),
+ VarAttr,
+ 0,
+ 0,
+ FALSE,
+ mVariableModuleGlobal,
+ &Variable
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } else {
+ GetVariableDataPtr (
+ Variable.CurrPtr,
+ Variable.Volatile,
+ &mVariableModuleGlobal->VariableGlobal[Physical],
+ mVariableModuleGlobal->FvbInstance,
+ (CHAR16 *) &mPlatformMode
+ );
+ }
+ //
+ // Check "SignatureSupport" variable's existence.
+ // If it doesn't exist, then create a new one with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
+ //
+ Status = FindVariable (
+ EFI_SIGNATURE_SUPPORT_NAME,
+ &gEfiGlobalVariableGuid,
+ &Variable,
+ &mVariableModuleGlobal->VariableGlobal[Physical],
+ mVariableModuleGlobal->FvbInstance
+ );
+
+ if (Variable.CurrPtr == 0x0) {
+ VarAttr = EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;
+ Status = UpdateVariable (
+ EFI_SIGNATURE_SUPPORT_NAME,
+ &gEfiGlobalVariableGuid,
+ mSignatureSupport,
+ SIGSUPPORT_NUM * sizeof(EFI_GUID),
+ VarAttr,
+ 0,
+ 0,
+ FALSE,
+ mVariableModuleGlobal,
+ &Variable
+ );
+ }
+
+ return Status;
+}
+
+/**
+ Add public key in store and return its index.
+
+ @param[in] VirtualMode The current calling mode for this function.
+ @param[in] Global The context of this Extended SAL Variable Services Class call.
+ @param[in] PubKey The input pointer to Public Key data.
+
+ @return The index of new added item.
+
+**/
+UINT32
+AddPubKeyInStore (
+ IN BOOLEAN VirtualMode,
+ IN ESAL_VARIABLE_GLOBAL *Global,
+ IN UINT8 *PubKey
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN IsFound;
+ UINT32 Index;
+ VARIABLE_POINTER_TRACK Variable;
+ UINT8 *Ptr;
+
+ if (PubKey == NULL) {
+ return 0;
+ }
+
+ Status = FindVariable (
+ Global->VariableName[VirtualMode][VAR_AUTH_KEY_DB],
+ Global->AuthenticatedVariableGuid[VirtualMode],
+ &Variable,
+ &Global->VariableGlobal[VirtualMode],
+ Global->FvbInstance
+ );
+ ASSERT_EFI_ERROR (Status);
+ //
+ // Check whether the public key entry does exist.
+ //
+ IsFound = FALSE;
+ for (Ptr = Global->PubKeyStore, Index = 1; Index <= mPubKeyNumber; Index++) {
+ if (CompareMem (Ptr, PubKey, EFI_CERT_TYPE_RSA2048_SIZE) == 0) {
+ IsFound = TRUE;
+ break;
+ }
+ Ptr += EFI_CERT_TYPE_RSA2048_SIZE;
+ }
+
+ if (!IsFound) {
+ //
+ // Add public key in database.
+ //
+ if (mPubKeyNumber == MAX_KEY_NUM) {
+ //
+ // Notes: Database is full, need enhancement here, currently just return 0.
+ //
+ return 0;
+ }
+
+ CopyMem (Global->PubKeyStore + mPubKeyNumber * EFI_CERT_TYPE_RSA2048_SIZE, PubKey, EFI_CERT_TYPE_RSA2048_SIZE);
+ Index = ++mPubKeyNumber;
+ //
+ // Update public key database variable.
+ //
+ Status = UpdateVariable (
+ Global->VariableName[VirtualMode][VAR_AUTH_KEY_DB],
+ Global->AuthenticatedVariableGuid[VirtualMode],
+ Global->PubKeyStore,
+ mPubKeyNumber * EFI_CERT_TYPE_RSA2048_SIZE,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS,
+ 0,
+ 0,
+ VirtualMode,
+ Global,
+ &Variable
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ return Index;
+}
+
+/**
+ Verify data payload with AuthInfo in EFI_CERT_TYPE_RSA2048_SHA256 type.
+ Follow the steps in UEFI2.2.
+
+ @param[in] VirtualMode The current calling mode for this function.
+ @param[in] Global The context of this Extended SAL Variable Services Class call.
+ @param[in] Data The pointer to data with AuthInfo.
+ @param[in] DataSize The size of Data.
+ @param[in] PubKey The public key used for verification.
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_SECURITY_VIOLATION Authentication failed.
+ @retval EFI_SUCCESS Authentication successful.
+
+**/
+EFI_STATUS
+VerifyDataPayload (
+ IN BOOLEAN VirtualMode,
+ IN ESAL_VARIABLE_GLOBAL *Global,
+ IN UINT8 *Data,
+ IN UINTN DataSize,
+ IN UINT8 *PubKey
+ )
+{
+ BOOLEAN Status;
+ EFI_VARIABLE_AUTHENTICATION *CertData;
+ EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlock;
+ UINT8 Digest[SHA256_DIGEST_SIZE];
+ VOID *Rsa;
+ VOID *HashContext;
+
+ Rsa = NULL;
+ CertData = NULL;
+ CertBlock = NULL;
+
+ if (Data == NULL || PubKey == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CertData = (EFI_VARIABLE_AUTHENTICATION *) Data;
+ CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);
+
+ //
+ // wCertificateType should be WIN_CERT_TYPE_EFI_GUID.
+ // Cert type should be EFI_CERT_TYPE_RSA2048_SHA256.
+ //
+ if ((CertData->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) ||
+ !CompareGuid (&CertData->AuthInfo.CertType, Global->CertRsa2048Sha256Guid[VirtualMode])
+ ) {
+ //
+ // Invalid AuthInfo type, return EFI_SECURITY_VIOLATION.
+ //
+ return EFI_SECURITY_VIOLATION;
+ }
+
+ //
+ // Hash data payload with SHA256.
+ //
+ ZeroMem (Digest, SHA256_DIGEST_SIZE);
+ HashContext = Global->HashContext[VirtualMode];
+ Status = Sha256Init (HashContext);
+ if (!Status) {
+ goto Done;
+ }
+ Status = Sha256Update (HashContext, Data + AUTHINFO_SIZE, (UINTN) (DataSize - AUTHINFO_SIZE));
+ if (!Status) {
+ goto Done;
+ }
+ //
+ // Hash Monotonic Count.
+ //
+ Status = Sha256Update (HashContext, &CertData->MonotonicCount, sizeof (UINT64));
+ if (!Status) {
+ goto Done;
+ }
+ Status = Sha256Final (HashContext, Digest);
+ if (!Status) {
+ goto Done;
+ }
+ //
+ // Generate & Initialize RSA Context.
+ //
+ 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, PubKey, 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,
+ Digest,
+ SHA256_DIGEST_SIZE,
+ CertBlock->Signature,
+ EFI_CERT_TYPE_RSA2048_SHA256_SIZE
+ );
+
+Done:
+ if (Rsa != NULL) {
+ RsaFree (Rsa);
+ }
+ if (Status) {
+ return EFI_SUCCESS;
+ } else {
+ return EFI_SECURITY_VIOLATION;
+ }
+}
+
+
+/**
+ Update platform mode.
+
+ @param[in] VirtualMode The current calling mode for this function.
+ @param[in] Global The context of this Extended SAL Variable Services Class call.
+ @param[in] Mode SETUP_MODE or USER_MODE.
+
+**/
+VOID
+UpdatePlatformMode (
+ IN BOOLEAN VirtualMode,
+ IN ESAL_VARIABLE_GLOBAL *Global,
+ IN UINT32 Mode
+ )
+{
+ EFI_STATUS Status;
+ VARIABLE_POINTER_TRACK Variable;
+ UINT32 VarAttr;
+
+ Status = FindVariable (
+ Global->VariableName[VirtualMode][VAR_SETUP_MODE],
+ Global->GlobalVariableGuid[VirtualMode],
+ &Variable,
+ &Global->VariableGlobal[VirtualMode],
+ Global->FvbInstance
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ mPlatformMode = Mode;
+ VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS;
+ Status = UpdateVariable (
+ Global->VariableName[VirtualMode][VAR_SETUP_MODE],
+ Global->GlobalVariableGuid[VirtualMode],
+ &mPlatformMode,
+ sizeof(UINT8),
+ VarAttr,
+ 0,
+ 0,
+ VirtualMode,
+ Global,
+ &Variable
+ );
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ Process variable with platform key for verification.
+
+ @param[in] VariableName The name of Variable to be found.
+ @param[in] VendorGuid The variable vendor GUID.
+ @param[in] Data The data pointer.
+ @param[in] DataSize The size of Data found. If size is less than the
+ data, this value contains the required size.
+ @param[in] VirtualMode The current calling mode for this function.
+ @param[in] Global The context of this Extended SAL Variable Services Class call.
+ @param[in] Variable The variable information which is used to keep track of variable usage.
+ @param[in] Attributes The attribute value of the variable.
+ @param[in] IsPk Indicates whether to process pk.
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_SECURITY_VIOLATION The variable does NOT pass the validation
+ check carried out by the firmware.
+ @retval EFI_SUCCESS The variable passed validation successfully.
+
+**/
+EFI_STATUS
+ProcessVarWithPk (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN VOID *Data,
+ IN UINTN DataSize,
+ IN BOOLEAN VirtualMode,
+ IN ESAL_VARIABLE_GLOBAL *Global,
+ IN VARIABLE_POINTER_TRACK *Variable,
+ IN UINT32 Attributes OPTIONAL,
+ IN BOOLEAN IsPk
+ )
+{
+ EFI_STATUS Status;
+ VARIABLE_POINTER_TRACK PkVariable;
+ EFI_SIGNATURE_LIST *OldPkList;
+ EFI_SIGNATURE_DATA *OldPkData;
+ EFI_VARIABLE_AUTHENTICATION *CertData;
+ AUTHENTICATED_VARIABLE_HEADER VariableHeader;
+ BOOLEAN Valid;
+
+ OldPkList = NULL;
+ ZeroMem (&VariableHeader, sizeof (AUTHENTICATED_VARIABLE_HEADER));
+
+ if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {
+ //
+ // PK and KEK should set EFI_VARIABLE_NON_VOLATILE attribute.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (mPlatformMode == USER_MODE) {
+ if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == 0) {
+ //
+ // In user mode, PK and KEK should set EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CertData = (EFI_VARIABLE_AUTHENTICATION *) Data;
+
+ if (Variable->CurrPtr != 0x0) {
+ Valid = IsValidVariableHeader (
+ Variable->CurrPtr,
+ Variable->Volatile,
+ &Global->VariableGlobal[VirtualMode],
+ Global->FvbInstance,
+ &VariableHeader
+ );
+ ASSERT (Valid);
+
+ if (CertData->MonotonicCount <= VariableHeader.MonotonicCount) {
+ //
+ // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.
+ //
+ return EFI_SECURITY_VIOLATION;
+ }
+ }
+ //
+ // Get platform key from variable.
+ //
+ Status = FindVariable (
+ Global->VariableName[VirtualMode][VAR_PLATFORM_KEY],
+ Global->GlobalVariableGuid[VirtualMode],
+ &PkVariable,
+ &Global->VariableGlobal[VirtualMode],
+ Global->FvbInstance
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ ZeroMem (Global->KeyList, MAX_KEYDB_SIZE);
+ GetVariableDataPtr (
+ PkVariable.CurrPtr,
+ PkVariable.Volatile,
+ &Global->VariableGlobal[VirtualMode],
+ Global->FvbInstance,
+ (CHAR16 *) Global->KeyList
+ );
+
+ OldPkList = (EFI_SIGNATURE_LIST *) Global->KeyList;
+ OldPkData = (EFI_SIGNATURE_DATA *) ((UINT8 *) OldPkList + sizeof (EFI_SIGNATURE_LIST) + OldPkList->SignatureHeaderSize);
+ Status = VerifyDataPayload (VirtualMode, Global, Data, DataSize, OldPkData->SignatureData);
+ if (!EFI_ERROR (Status)) {
+ Status = UpdateVariable (
+ VariableName,
+ VendorGuid,
+ (UINT8*)Data + AUTHINFO_SIZE,
+ DataSize - AUTHINFO_SIZE,
+ Attributes,
+ 0,
+ CertData->MonotonicCount,
+ VirtualMode,
+ Global,
+ Variable
+ );
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // If delete PK in user mode, need change to setup mode.
+ //
+ if ((DataSize == AUTHINFO_SIZE) && IsPk) {
+ UpdatePlatformMode (VirtualMode, Global, SETUP_MODE);
+ }
+ }
+ }
+ } else {
+ Status = UpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes, 0, 0, VirtualMode, Global, Variable);
+ //
+ // If enroll PK in setup mode, need change to user mode.
+ //
+ if ((DataSize != 0) && IsPk) {
+ UpdatePlatformMode (VirtualMode, Global, USER_MODE);
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Process variable with key exchange key for verification.
+
+ @param[in] VariableName The name of Variable to be found.
+ @param[in] VendorGuid The variable vendor GUID.
+ @param[in] Data The data pointer.
+ @param[in] DataSize The size of Data found. If size is less than the
+ data, this value contains the required size.
+ @param[in] VirtualMode The current calling mode for this function.
+ @param[in] Global The context of this Extended SAL Variable Services Class call.
+ @param[in] Variable The variable information which is used to keep track of variable usage.
+ @param[in] Attributes The attribute value of the variable.
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_SECURITY_VIOLATION The variable did NOT pass the validation
+ check carried out by the firmware.
+ @retval EFI_SUCCESS The variable passed validation successfully.
+
+**/
+EFI_STATUS
+ProcessVarWithKek (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN VOID *Data,
+ IN UINTN DataSize,
+ IN BOOLEAN VirtualMode,
+ IN ESAL_VARIABLE_GLOBAL *Global,
+ IN VARIABLE_POINTER_TRACK *Variable,
+ IN UINT32 Attributes OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ VARIABLE_POINTER_TRACK KekVariable;
+ EFI_SIGNATURE_LIST *KekList;
+ EFI_SIGNATURE_DATA *KekItem;
+ UINT32 KekCount;
+ EFI_VARIABLE_AUTHENTICATION *CertData;
+ EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlock;
+ BOOLEAN IsFound;
+ UINT32 Index;
+ AUTHENTICATED_VARIABLE_HEADER VariableHeader;
+ BOOLEAN Valid;
+
+ KekList = NULL;
+ ZeroMem (&VariableHeader, sizeof (AUTHENTICATED_VARIABLE_HEADER));
+
+ if (mPlatformMode == USER_MODE) {
+ if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == 0) {
+ //
+ // In user mode, should set EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CertData = (EFI_VARIABLE_AUTHENTICATION *) Data;
+ CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);
+ if (Variable->CurrPtr != 0x0) {
+ Valid = IsValidVariableHeader (
+ Variable->CurrPtr,
+ Variable->Volatile,
+ &Global->VariableGlobal[VirtualMode],
+ Global->FvbInstance,
+ &VariableHeader
+ );
+ ASSERT (Valid);
+
+ if (CertData->MonotonicCount <= VariableHeader.MonotonicCount) {
+ //
+ // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.
+ //
+ return EFI_SECURITY_VIOLATION;
+ }
+ }
+ //
+ // Get KEK database from variable.
+ //
+ Status = FindVariable (
+ Global->VariableName[VirtualMode][VAR_KEY_EXCHANGE_KEY],
+ Global->GlobalVariableGuid[VirtualMode],
+ &KekVariable,
+ &Global->VariableGlobal[VirtualMode],
+ Global->FvbInstance
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ ZeroMem (Global->KeyList, MAX_KEYDB_SIZE);
+ GetVariableDataPtr (
+ KekVariable.CurrPtr,
+ KekVariable.Volatile,
+ &Global->VariableGlobal[VirtualMode],
+ Global->FvbInstance,
+ (CHAR16 *) Global->KeyList
+ );
+ //
+ // Enumerate all Kek items in this list to verify the variable certificate data.
+ // If anyone is authenticated successfully, it means the variable is correct!
+ //
+ KekList = (EFI_SIGNATURE_LIST *) Global->KeyList;
+ IsFound = FALSE;
+ KekCount = (KekList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - KekList->SignatureHeaderSize) / KekList->SignatureSize;
+ KekItem = (EFI_SIGNATURE_DATA *) ((UINT8 *) KekList + sizeof (EFI_SIGNATURE_LIST) + KekList->SignatureHeaderSize);
+ 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);
+ }
+
+ if (!IsFound) {
+ return EFI_SECURITY_VIOLATION;
+ }
+
+ Status = VerifyDataPayload (VirtualMode, Global, Data, DataSize, CertBlock->PublicKey);
+ if (!EFI_ERROR (Status)) {
+ Status = UpdateVariable (
+ VariableName,
+ VendorGuid,
+ (UINT8*)Data + AUTHINFO_SIZE,
+ DataSize - AUTHINFO_SIZE,
+ Attributes,
+ 0,
+ CertData->MonotonicCount,
+ VirtualMode,
+ Global,
+ Variable
+ );
+ }
+ } else {
+ //
+ // If in setup mode, no authentication needed.
+ //
+ Status = UpdateVariable (
+ VariableName,
+ VendorGuid,
+ Data,
+ DataSize,
+ Attributes,
+ 0,
+ 0,
+ VirtualMode,
+ Global,
+ Variable
+ );
+ }
+
+ return Status;
+}
+
+/**
+ Process variable with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set, and return the index of associated public key.
+
+ @param[in] Data The data pointer.
+ @param[in] DataSize The size of Data found. If size is less than the
+ data, this value contains the required size.
+ @param[in] VirtualMode The current calling mode for this function.
+ @param[in] Global The context of this Extended SAL Variable Services Class call.
+ @param[in] Variable The variable information which is used to keep track of variable usage.
+ @param[in] Attributes The attribute value of the variable.
+ @param[out] KeyIndex The output index of corresponding public key in database.
+ @param[out] MonotonicCount The output value of corresponding Monotonic Count.
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_WRITE_PROTECTED The variable is write-protected and needs authentication with
+ EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
+ @retval EFI_SECURITY_VIOLATION The variable is with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
+ set, but the AuthInfo does NOT pass the validation
+ check carried out by the firmware.
+ @retval EFI_SUCCESS The variable is not write-protected, or passed validation successfully.
+
+**/
+EFI_STATUS
+VerifyVariable (
+ IN VOID *Data,
+ IN UINTN DataSize,
+ IN BOOLEAN VirtualMode,
+ IN ESAL_VARIABLE_GLOBAL *Global,
+ IN VARIABLE_POINTER_TRACK *Variable,
+ IN UINT32 Attributes OPTIONAL,
+ OUT UINT32 *KeyIndex OPTIONAL,
+ OUT UINT64 *MonotonicCount OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN IsDeletion;
+ BOOLEAN IsFirstTime;
+ UINT8 *PubKey;
+ EFI_VARIABLE_AUTHENTICATION *CertData;
+ EFI_CERT_BLOCK_RSA_2048_SHA256 *CertBlock;
+ AUTHENTICATED_VARIABLE_HEADER VariableHeader;
+ BOOLEAN Valid;
+
+ CertData = NULL;
+ CertBlock = NULL;
+ PubKey = NULL;
+ IsDeletion = FALSE;
+ Valid = FALSE;
+
+ if (KeyIndex != NULL) {
+ *KeyIndex = 0;
+ }
+ //
+ // Determine if first time SetVariable with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS.
+ //
+ ZeroMem (&VariableHeader, sizeof (AUTHENTICATED_VARIABLE_HEADER));
+ if (Variable->CurrPtr != 0x0) {
+ Valid = IsValidVariableHeader (
+ Variable->CurrPtr,
+ Variable->Volatile,
+ &Global->VariableGlobal[VirtualMode],
+ Global->FvbInstance,
+ &VariableHeader
+ );
+ ASSERT (Valid);
+ }
+
+ if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {
+ if (KeyIndex == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Determine current operation type.
+ //
+ if (DataSize == AUTHINFO_SIZE) {
+ IsDeletion = TRUE;
+ }
+ //
+ // Determine whether this is the first time with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
+ //
+ if (Variable->CurrPtr == 0x0) {
+ IsFirstTime = TRUE;
+ } else if (Valid &&(VariableHeader.Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == 0) {
+ IsFirstTime = TRUE;
+ } else {
+ *KeyIndex = VariableHeader.PubKeyIndex;
+ IsFirstTime = FALSE;
+ }
+ } else if (Valid && (VariableHeader.Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {
+ //
+ // If the variable is already write-protected, it always needs authentication before update.
+ //
+ return EFI_WRITE_PROTECTED;
+ } else {
+ //
+ // If without EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, set and attributes collision.
+ // That means it is not authenticated variable, just return EFI_SUCCESS.
+ //
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Get PubKey and check Monotonic Count value corresponding to the variable.
+ //
+ CertData = (EFI_VARIABLE_AUTHENTICATION *) Data;
+ CertBlock = (EFI_CERT_BLOCK_RSA_2048_SHA256 *) (CertData->AuthInfo.CertData);
+ PubKey = CertBlock->PublicKey;
+
+ if (MonotonicCount != NULL) {
+ //
+ // Update Monotonic Count value.
+ //
+ *MonotonicCount = CertData->MonotonicCount;
+ }
+
+ if (!IsFirstTime) {
+ //
+ // Check input PubKey.
+ //
+ if (CompareMem (PubKey, Global->PubKeyStore + (*KeyIndex - 1) * EFI_CERT_TYPE_RSA2048_SIZE, EFI_CERT_TYPE_RSA2048_SIZE) != 0) {
+ return EFI_SECURITY_VIOLATION;
+ }
+ //
+ // Compare the current monotonic count and ensure that it is greater than the last SetVariable
+ // operation with the EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute set.
+ //
+ if (CertData->MonotonicCount <= VariableHeader.MonotonicCount) {
+ //
+ // Monotonic count check fail, suspicious replay attack, return EFI_SECURITY_VIOLATION.
+ //
+ return EFI_SECURITY_VIOLATION;
+ }
+ }
+ //
+ // Verify the certificate in Data payload.
+ //
+ Status = VerifyDataPayload (VirtualMode, Global, Data, DataSize, PubKey);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Now, the signature has been verified!
+ //
+ if (IsFirstTime && !IsDeletion) {
+ //
+ // Update public key database variable if need and return the index.
+ //
+ *KeyIndex = AddPubKeyInStore (VirtualMode, Global, PubKey);
+ }
+ }
+
+ return Status;
+}
+
diff --git a/Core/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/AuthService.h b/Core/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/AuthService.h
new file mode 100644
index 0000000000..f3e15f61e2
--- /dev/null
+++ b/Core/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/AuthService.h
@@ -0,0 +1,151 @@
+/** @file
+ The internal header file includes the common header files, defines
+ internal structure and functions used by AuthService module.
+
+Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _AUTHSERVICE_H_
+#define _AUTHSERVICE_H_
+
+#define EFI_CERT_TYPE_RSA2048_SHA256_SIZE 256
+#define EFI_CERT_TYPE_RSA2048_SIZE 256
+
+///
+/// Size of AuthInfo prior to the data payload
+///
+#define AUTHINFO_SIZE (((UINTN)(((EFI_VARIABLE_AUTHENTICATION *) 0)->AuthInfo.CertData)) + sizeof (EFI_CERT_BLOCK_RSA_2048_SHA256))
+
+///
+/// Item number of support signature types.
+///
+#define SIGSUPPORT_NUM 2
+
+/**
+ Process variable with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set, and return the index of associated public key.
+
+ @param[in] Data The data pointer.
+ @param[in] DataSize The size of Data found. If size is less than the
+ data, this value contains the required size.
+ @param[in] VirtualMode The current calling mode for this function.
+ @param[in] Global The context of this Extended SAL Variable Services Class call.
+ @param[in] Variable The variable information which is used to keep track of variable usage.
+ @param[in] Attributes The attribute value of the variable.
+ @param[out] KeyIndex The output index of corresponding public key in database.
+ @param[out] MonotonicCount The output value of corresponding Monotonic Count.
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_WRITE_PROTECTED The variable is write-protected and needs authentication with
+ EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS set.
+ @retval EFI_SECURITY_VIOLATION The variable is with EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
+ set, but the AuthInfo does NOT pass the validation
+ check carried out by the firmware.
+ @retval EFI_SUCCESS The variable is not write-protected, or passed validation successfully.
+
+**/
+EFI_STATUS
+VerifyVariable (
+ IN VOID *Data,
+ IN UINTN DataSize,
+ IN BOOLEAN VirtualMode,
+ IN ESAL_VARIABLE_GLOBAL *Global,
+ IN VARIABLE_POINTER_TRACK *Variable,
+ IN UINT32 Attributes OPTIONAL,
+ OUT UINT32 *KeyIndex OPTIONAL,
+ OUT UINT64 *MonotonicCount OPTIONAL
+ );
+
+/**
+ Initializes for authenticated varibale service.
+
+ @retval EFI_SUCCESS The function successfully executed.
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate enough memory resources.
+
+**/
+EFI_STATUS
+AutenticatedVariableServiceInitialize (
+ VOID
+ );
+
+/**
+ Initializes for cryptlib service before use, include register algrithm and allocate scratch.
+
+**/
+VOID
+CryptLibraryInitialize (
+ VOID
+ );
+
+/**
+ Process variable with platform key for verification.
+
+ @param[in] VariableName The name of Variable to be found.
+ @param[in] VendorGuid Variable vendor GUID.
+ @param[in] Data The data pointer.
+ @param[in] DataSize The size of Data found. If size is less than the
+ data, this value contains the required size.
+ @param[in] VirtualMode The current calling mode for this function.
+ @param[in] Global The context of this Extended SAL Variable Services Class call.
+ @param[in] Variable The variable information which is used to keep track of variable usage.
+ @param[in] Attributes The attribute value of the variable.
+ @param[in] IsPk Indicates whether to process pk.
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_SECURITY_VIOLATION The variable does NOT pass the validation
+ check carried out by the firmware.
+ @retval EFI_SUCCESS The variable passed validation successfully.
+
+**/
+EFI_STATUS
+ProcessVarWithPk (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN VOID *Data,
+ IN UINTN DataSize,
+ IN BOOLEAN VirtualMode,
+ IN ESAL_VARIABLE_GLOBAL *Global,
+ IN VARIABLE_POINTER_TRACK *Variable,
+ IN UINT32 Attributes OPTIONAL,
+ IN BOOLEAN IsPk
+ );
+
+/**
+ Process variable with key exchange key for verification.
+
+ @param[in] VariableName The name of Variable to be found.
+ @param[in] VendorGuid The variable vendor GUID.
+ @param[in] Data The data pointer.
+ @param[in] DataSize Size of Data found. If size is less than the
+ data, this value contains the required size.
+ @param[in] VirtualMode The current calling mode for this function.
+ @param[in] Global The context of this Extended SAL Variable Services Class call.
+ @param[in] Variable The variable information which is used to keep track of variable usage.
+ @param[in] Attributes The attribute value of the variable.
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_SECURITY_VIOLATION The variable does NOT pass the validation
+ check carried out by the firmware.
+ @retval EFI_SUCCESS The variable passed validation successfully.
+
+**/
+EFI_STATUS
+ProcessVarWithKek (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN VOID *Data,
+ IN UINTN DataSize,
+ IN BOOLEAN VirtualMode,
+ IN ESAL_VARIABLE_GLOBAL *Global,
+ IN VARIABLE_POINTER_TRACK *Variable,
+ IN UINT32 Attributes OPTIONAL
+ );
+
+#endif
diff --git a/Core/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/EsalVariableDxeSal.inf b/Core/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/EsalVariableDxeSal.inf
new file mode 100644
index 0000000000..16caa30dad
--- /dev/null
+++ b/Core/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/EsalVariableDxeSal.inf
@@ -0,0 +1,105 @@
+## @file
+# Provides authenticated variable service for IPF platform
+#
+# This module installs variable arch protocol and variable write arch protocol to provide
+# four EFI_RUNTIME_SERVICES: SetVariable, GetVariable, GetNextVariableName and QueryVariableInfo.
+#
+# Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = EsalVariableDxeSal
+ MODULE_UNI_FILE = EsalVariableDxeSal.uni
+ FILE_GUID = 14610837-4E97-4427-96E0-21D9B2956996
+ MODULE_TYPE = DXE_SAL_DRIVER
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = VariableServiceInitialize
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IPF
+#
+# VIRTUAL_ADDRESS_MAP_CALLBACK = VariableClassAddressChangeEvent
+#
+
+[Sources.common]
+ InitVariable.c
+ Reclaim.c
+ Variable.c
+ Variable.h
+ AuthService.c
+ AuthService.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ CryptoPkg/CryptoPkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+ MemoryAllocationLib
+ BaseLib
+ SynchronizationLib
+ UefiLib
+ UefiBootServicesTableLib
+ BaseMemoryLib
+ DebugLib
+ UefiRuntimeLib
+ DxeServicesTableLib
+ UefiDriverEntryPoint
+ PcdLib
+ ExtendedSalLib
+ BaseCryptLib
+ HobLib
+
+[Protocols]
+ gEfiFirmwareVolumeBlockProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiFaultTolerantWriteProtocolGuid ## SOMETIMES_CONSUMES
+
+[Guids]
+ ## SOMETIMES_CONSUMES ## Variable:L"PK"
+ ## CONSUMES ## Variable:L"SetupMode"
+ ## PRODUCES ## Variable:L"SetupMode"
+ ## CONSUMES ## Variable:L"SignatureSupport"
+ ## PRODUCES ## Variable:L"SignatureSupport"
+ gEfiGlobalVariableGuid
+
+ ## PRODUCES ## GUID # Variable store header
+ ## CONSUMES ## GUID # Variable store header
+ ## SOMETIMES_CONSUMES ## HOB
+ ## SOMETIMES_PRODUCES ## SystemTable
+ gEfiAuthenticatedVariableGuid
+
+ gEfiEventVirtualAddressChangeGuid ## CONSUMES ## Event
+ gEfiCertRsa2048Sha256Guid ## CONSUMES ## GUID # Unique ID for the format of the CertType.
+
+ ## SOMETIMES_CONSUMES ## Variable:L"DB"
+ ## SOMETIMES_CONSUMES ## Variable:L"DBX"
+ gEfiImageSecurityDatabaseGuid
+
+[Pcd.common]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMaxHardwareErrorVariableSize ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdHwErrStorageSize ## CONSUMES
+
+[FeaturePcd.common]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdVariableCollectStatistics ## CONSUMES # statistic the information of variable.
+
+[Depex]
+ gEfiExtendedSalFvBlockServicesProtocolGuid AND gEfiFaultTolerantWriteProtocolGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ EsalVariableDxeSalExtra.uni \ No newline at end of file
diff --git a/Core/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/EsalVariableDxeSal.uni b/Core/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/EsalVariableDxeSal.uni
new file mode 100644
index 0000000000..08588fc10d
--- /dev/null
+++ b/Core/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/EsalVariableDxeSal.uni
@@ -0,0 +1,22 @@
+// /** @file
+// Provides authenticated variable service for IPF platform
+//
+// This module installs variable arch protocol and variable write arch protocol to provide
+// four EFI_RUNTIME_SERVICES: SetVariable, GetVariable, GetNextVariableName and QueryVariableInfo.
+//
+// Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides authenticated variable service for IPF platform"
+
+#string STR_MODULE_DESCRIPTION #language en-US "This module installs variable arch protocol and variable write arch protocol to provide four EFI_RUNTIME_SERVICES: SetVariable, GetVariable, GetNextVariableName and QueryVariableInfo."
+
diff --git a/Core/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/EsalVariableDxeSalExtra.uni b/Core/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/EsalVariableDxeSalExtra.uni
new file mode 100644
index 0000000000..cb65895210
--- /dev/null
+++ b/Core/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/EsalVariableDxeSalExtra.uni
@@ -0,0 +1,19 @@
+// /** @file
+// EsalVariableDxeSal Localized Strings and Content
+//
+// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Esal Authenticated Variable DXE"
+
+
diff --git a/Core/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/InitVariable.c b/Core/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/InitVariable.c
new file mode 100644
index 0000000000..0f1d645622
--- /dev/null
+++ b/Core/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/InitVariable.c
@@ -0,0 +1,247 @@
+/** @file
+ Entrypoint of Extended SAL variable service module.
+
+Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "Variable.h"
+#include "AuthService.h"
+
+//
+// Don't use module globals after the SetVirtualAddress map is signaled
+//
+EFI_EVENT mEfiVirtualNotifyEvent;
+
+/**
+ Common entry for Extended SAL Variable Services Class.
+
+ This is the common entry of all functions of Extended SAL Variable Services Class.
+
+ @param[in] FunctionId The Function ID of member function in Extended SAL Variable Services Class.
+ @param[in] Arg2 The 2nd parameter for SAL procedure call.
+ @param[in] Arg3 The 3rd parameter for SAL procedure call.
+ @param[in] Arg4 The 4th parameter for SAL procedure call.
+ @param[in] Arg5 The 5th parameter for SAL procedure call.
+ @param[in] Arg6 The 6th parameter for SAL procedure call.
+ @param[in] Arg7 The 7th parameter for SAL procedure call.
+ @param[in] Arg8 The 8th parameter for SAL procedure call.
+ @param[in] VirtualMode The current calling mode for this function.
+ @param[in] Global The context of this Extended SAL Variable Services Class call.
+
+ @return The register of SAL.
+
+**/
+SAL_RETURN_REGS
+EFIAPI
+EsalVariableCommonEntry (
+ IN UINT64 FunctionId,
+ IN UINT64 Arg2,
+ IN UINT64 Arg3,
+ IN UINT64 Arg4,
+ IN UINT64 Arg5,
+ IN UINT64 Arg6,
+ IN UINT64 Arg7,
+ IN UINT64 Arg8,
+ IN BOOLEAN VirtualMode,
+ IN ESAL_VARIABLE_GLOBAL *Global
+ )
+{
+ SAL_RETURN_REGS ReturnVal;
+
+ ReturnVal.r9 = 0;
+ ReturnVal.r10 = 0;
+ ReturnVal.r11 = 0;
+
+ switch (FunctionId) {
+ case EsalGetVariableFunctionId:
+ ReturnVal.Status = EsalGetVariable (
+ (CHAR16 *) Arg2,
+ (EFI_GUID *) Arg3,
+ (UINT32 *) Arg4,
+ (UINTN *) Arg5,
+ (VOID *) Arg6,
+ VirtualMode,
+ Global
+ );
+ return ReturnVal;
+
+ case EsalGetNextVariableNameFunctionId:
+ ReturnVal.Status = EsalGetNextVariableName (
+ (UINTN *) Arg2,
+ (CHAR16 *) Arg3,
+ (EFI_GUID *) Arg4,
+ VirtualMode,
+ Global
+ );
+ return ReturnVal;
+
+ case EsalSetVariableFunctionId:
+ ReturnVal.Status = EsalSetVariable (
+ (CHAR16 *) Arg2,
+ (EFI_GUID *) Arg3,
+ (UINT32) Arg4,
+ (UINTN) Arg5,
+ (VOID *) Arg6,
+ VirtualMode,
+ Global
+ );
+ return ReturnVal;
+
+ case EsalQueryVariableInfoFunctionId:
+ ReturnVal.Status = EsalQueryVariableInfo (
+ (UINT32) Arg2,
+ (UINT64 *) Arg3,
+ (UINT64 *) Arg4,
+ (UINT64 *) Arg5,
+ VirtualMode,
+ Global
+ );
+ return ReturnVal;
+
+ default:
+ ReturnVal.Status = EFI_SAL_INVALID_ARGUMENT;
+ return ReturnVal;
+ }
+}
+
+/**
+ Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.
+
+ This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
+ It convers pointer to new virtual address.
+
+ @param[in] Event The event whose notification function is being invoked.
+ @param[in] Context The pointer to the notification function's context.
+
+**/
+VOID
+EFIAPI
+VariableClassAddressChangeEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ UINTN Index;
+
+ CopyMem (
+ &mVariableModuleGlobal->VariableGlobal[Virtual],
+ &mVariableModuleGlobal->VariableGlobal[Physical],
+ sizeof (VARIABLE_GLOBAL)
+ );
+
+ EfiConvertPointer (
+ 0x0,
+ (VOID **) &mVariableModuleGlobal->VariableGlobal[Virtual].NonVolatileVariableBase
+ );
+ EfiConvertPointer (
+ 0x0,
+ (VOID **) &mVariableModuleGlobal->VariableGlobal[Virtual].VolatileVariableBase
+ );
+
+ mVariableModuleGlobal->PlatformLangCodes[Virtual] = mVariableModuleGlobal->PlatformLangCodes[Physical];
+ EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->PlatformLangCodes[Virtual]);
+
+ mVariableModuleGlobal->LangCodes[Virtual] = mVariableModuleGlobal->LangCodes[Physical];
+ EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->LangCodes[Virtual]);
+
+ mVariableModuleGlobal->PlatformLang[Virtual] = mVariableModuleGlobal->PlatformLang[Physical];
+ EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->PlatformLang[Virtual]);
+
+ CopyMem (
+ mVariableModuleGlobal->VariableName[Virtual],
+ mVariableModuleGlobal->VariableName[Physical],
+ sizeof (mVariableModuleGlobal->VariableName[Physical])
+ );
+ for (Index = 0; Index < NUM_VAR_NAME; Index++) {
+ EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->VariableName[Virtual][Index]);
+ }
+
+ mVariableModuleGlobal->GlobalVariableGuid[Virtual] = &gEfiGlobalVariableGuid;
+ EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->GlobalVariableGuid[Virtual]);
+
+ mVariableModuleGlobal->AuthenticatedVariableGuid[Virtual] = &gEfiAuthenticatedVariableGuid;
+ EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->AuthenticatedVariableGuid[Virtual]);
+
+ mVariableModuleGlobal->CertRsa2048Sha256Guid[Virtual] = &gEfiCertRsa2048Sha256Guid;
+ EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->CertRsa2048Sha256Guid[Virtual]);
+
+ mVariableModuleGlobal->ImageSecurityDatabaseGuid[Virtual] = &gEfiImageSecurityDatabaseGuid;
+ EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->ImageSecurityDatabaseGuid[Virtual]);
+
+ mVariableModuleGlobal->HashContext[Virtual] = mVariableModuleGlobal->HashContext[Physical];
+ EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->HashContext[Virtual]);
+}
+
+/**
+ Entry point of Extended SAL Variable service module.
+
+ This function is the entry point of Extended SAL Variable service module.
+ It registers all functions of Extended SAL Variable class, initializes
+ variable store for non-volatile and volatile variables, and registers
+ notification function for EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
+
+ @param[in] ImageHandle The Image handle of this driver.
+ @param[in] SystemTable The pointer of EFI_SYSTEM_TABLE.
+
+ @retval EFI_SUCCESS Extended SAL Variable Services Class successfully registered.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableServiceInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ VariableClassAddressChangeEvent,
+ NULL,
+ &gEfiEventVirtualAddressChangeGuid,
+ &mEfiVirtualNotifyEvent
+ );
+
+ ASSERT_EFI_ERROR (Status);
+
+ Status = VariableCommonInitialize (ImageHandle, SystemTable);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Authenticated variable initialize
+ //
+ Status = AutenticatedVariableServiceInitialize ();
+ ASSERT_EFI_ERROR (Status);
+
+ FlushHob2Nv ();
+
+ //
+ // Register All the Functions with Extended SAL Variable Services Class
+ //
+ RegisterEsalClass (
+ EFI_EXTENDED_SAL_VARIABLE_SERVICES_PROTOCOL_GUID_LO,
+ EFI_EXTENDED_SAL_VARIABLE_SERVICES_PROTOCOL_GUID_HI,
+ mVariableModuleGlobal,
+ EsalVariableCommonEntry,
+ EsalGetVariableFunctionId,
+ EsalVariableCommonEntry,
+ EsalGetNextVariableNameFunctionId,
+ EsalVariableCommonEntry,
+ EsalSetVariableFunctionId,
+ EsalVariableCommonEntry,
+ EsalQueryVariableInfoFunctionId,
+ NULL
+ );
+
+ return EFI_SUCCESS;
+}
diff --git a/Core/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/Reclaim.c b/Core/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/Reclaim.c
new file mode 100644
index 0000000000..1cbf9ac877
--- /dev/null
+++ b/Core/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/Reclaim.c
@@ -0,0 +1,262 @@
+/** @file
+ Handles non-volatile variable store garbage collection, using FTW
+ (Fault Tolerant Write) protocol.
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "Variable.h"
+
+/**
+ Gets firmware volume block handle by given address.
+
+ This function gets firmware volume block handle whose
+ address range contains the parameter Address.
+
+ @param[in] Address Address which should be contained
+ by returned FVB handle.
+ @param[out] FvbHandle Pointer to FVB handle for output.
+
+ @retval EFI_SUCCESS FVB handle successfully returned.
+ @retval EFI_NOT_FOUND Failed to find FVB handle by address.
+
+**/
+EFI_STATUS
+GetFvbHandleByAddress (
+ IN EFI_PHYSICAL_ADDRESS Address,
+ OUT EFI_HANDLE *FvbHandle
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE *HandleBuffer;
+ UINTN HandleCount;
+ UINTN Index;
+ EFI_PHYSICAL_ADDRESS FvbBaseAddress;
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
+
+ *FvbHandle = NULL;
+ //
+ // Locate all handles with Firmware Volume Block protocol
+ //
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiFirmwareVolumeBlockProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+ //
+ // Traverse all the handles, searching for the one containing parameter Address
+ //
+ for (Index = 0; Index < HandleCount; Index += 1) {
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiFirmwareVolumeBlockProtocolGuid,
+ (VOID **) &Fvb
+ );
+ if (EFI_ERROR (Status)) {
+ Status = EFI_NOT_FOUND;
+ break;
+ }
+ //
+ // Checks if the address range of this handle contains parameter Address
+ //
+ Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress);
+ if ((Address >= FvbBaseAddress) && (Address <= (FvbBaseAddress + FwVolHeader->FvLength))) {
+ *FvbHandle = HandleBuffer[Index];
+ Status = EFI_SUCCESS;
+ break;
+ }
+ }
+
+ FreePool (HandleBuffer);
+ return Status;
+}
+
+/**
+ Gets LBA of block and offset by given address.
+
+ This function gets the Logical Block Address (LBA) of firmware
+ volume block containing the given address, and the offset of
+ address on the block.
+
+ @param[in] Address Address which should be contained
+ by returned FVB handle.
+ @param[out] Lba The pointer to LBA for output.
+ @param[out] Offset The pointer to offset for output.
+
+ @retval EFI_SUCCESS LBA and offset successfully returned.
+ @retval EFI_NOT_FOUND Failed to find FVB handle by address.
+ @retval EFI_ABORTED Failed to find valid LBA and offset.
+
+**/
+EFI_STATUS
+GetLbaAndOffsetByAddress (
+ IN EFI_PHYSICAL_ADDRESS Address,
+ OUT EFI_LBA *Lba,
+ OUT UINTN *Offset
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE FvbHandle;
+ EFI_PHYSICAL_ADDRESS FvbBaseAddress;
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
+ EFI_FV_BLOCK_MAP_ENTRY *FvbMapEntry;
+ UINT32 LbaIndex;
+
+ *Lba = (EFI_LBA) (-1);
+ *Offset = 0;
+
+ //
+ // Gets firmware volume block handle by given address.
+ //
+ Status = GetFvbHandleByAddress (Address, &FvbHandle);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->HandleProtocol (
+ FvbHandle,
+ &gEfiFirmwareVolumeBlockProtocolGuid,
+ (VOID **) &Fvb
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Get the Base Address of FV
+ //
+ Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress);
+
+ //
+ // Get the (LBA, Offset) of Address
+ //
+ if ((Address >= FvbBaseAddress) && (Address <= (FvbBaseAddress + FwVolHeader->FvLength))) {
+ if ((FwVolHeader->FvLength) > (FwVolHeader->HeaderLength)) {
+ //
+ // BUGBUG: Assume one FV has one type of BlockLength
+ //
+ FvbMapEntry = &FwVolHeader->BlockMap[0];
+ for (LbaIndex = 1; LbaIndex <= FvbMapEntry->NumBlocks; LbaIndex += 1) {
+ if (Address < (FvbBaseAddress + FvbMapEntry->Length * LbaIndex)) {
+ //
+ // Found the (Lba, Offset)
+ //
+ *Lba = LbaIndex - 1;
+ *Offset = (UINTN) (Address - (FvbBaseAddress + FvbMapEntry->Length * (LbaIndex - 1)));
+ return EFI_SUCCESS;
+ }
+ }
+ }
+ }
+
+ return EFI_ABORTED;
+}
+
+/**
+ Writes a buffer to variable storage space.
+
+ This function writes a buffer to variable storage space into firmware
+ volume block device. The destination is specified by parameter
+ VariableBase. Fault Tolerant Write protocol is used for writing.
+
+ @param[in] VariableBase The base address of the variable to write.
+ @param[in] Buffer Points to the data buffer.
+ @param[in] BufferSize The number of bytes of the data Buffer.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_NOT_FOUND Fail to locate Fault Tolerant Write protocol.
+ @retval Other The function could not complete successfully.
+
+**/
+EFI_STATUS
+FtwVariableSpace (
+ IN EFI_PHYSICAL_ADDRESS VariableBase,
+ IN UINT8 *Buffer,
+ IN UINTN BufferSize
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE FvbHandle;
+ EFI_LBA VarLba;
+ UINTN VarOffset;
+ UINT8 *FtwBuffer;
+ UINTN FtwBufferSize;
+ EFI_FAULT_TOLERANT_WRITE_PROTOCOL *FtwProtocol;
+
+ //
+ // Locate Fault Tolerant Write protocol
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiFaultTolerantWriteProtocolGuid,
+ NULL,
+ (VOID **) &FtwProtocol
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+ //
+ // Gets firmware volume block handle by VariableBase.
+ //
+ Status = GetFvbHandleByAddress (VariableBase, &FvbHandle);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Gets LBA of block and offset by VariableBase.
+ //
+ Status = GetLbaAndOffsetByAddress (VariableBase, &VarLba, &VarOffset);
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ //
+ // Prepare for the variable data
+ //
+ FtwBufferSize = ((VARIABLE_STORE_HEADER *) ((UINTN) VariableBase))->Size;
+ FtwBuffer = AllocatePool (FtwBufferSize);
+ if (FtwBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ SetMem (FtwBuffer, FtwBufferSize, (UINT8) 0xff);
+ CopyMem (FtwBuffer, Buffer, BufferSize);
+
+ //
+ // FTW write record
+ //
+ Status = FtwProtocol->Write (
+ FtwProtocol,
+ VarLba, // LBA
+ VarOffset, // Offset
+ FtwBufferSize, // NumBytes,
+ NULL,
+ FvbHandle,
+ FtwBuffer
+ );
+
+ FreePool (FtwBuffer);
+ return Status;
+}
diff --git a/Core/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/Variable.c b/Core/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/Variable.c
new file mode 100644
index 0000000000..dfa85973f4
--- /dev/null
+++ b/Core/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/Variable.c
@@ -0,0 +1,3257 @@
+/** @file
+ The implementation of Extended SAL variable services.
+
+Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "Variable.h"
+#include "AuthService.h"
+
+//
+// Don't use module globals after the SetVirtualAddress map is signaled
+//
+ESAL_VARIABLE_GLOBAL *mVariableModuleGlobal;
+CHAR16 *mVariableName[NUM_VAR_NAME] = {
+ L"PlatformLangCodes",
+ L"LangCodes",
+ L"PlatformLang",
+ L"Lang",
+ L"HwErrRec",
+ AUTHVAR_KEYDB_NAME,
+ EFI_SETUP_MODE_NAME,
+ EFI_PLATFORM_KEY_NAME,
+ EFI_KEY_EXCHANGE_KEY_NAME
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED VARIABLE_INFO_ENTRY *gVariableInfo = NULL;
+
+//
+// The current Hii implementation accesses this variable a larg # of times on every boot.
+// Other common variables are only accessed a single time. This is why this cache algorithm
+// only targets a single variable. Probably to get an performance improvement out of
+// a Cache you would need a cache that improves the search performance for a variable.
+//
+VARIABLE_CACHE_ENTRY mVariableCache[] = {
+ {
+ &gEfiGlobalVariableGuid,
+ L"Lang",
+ 0x00000000,
+ 0x00,
+ NULL
+ },
+ {
+ &gEfiGlobalVariableGuid,
+ L"PlatformLang",
+ 0x00000000,
+ 0x00,
+ NULL
+ }
+};
+
+/**
+ Acquires lock only at boot time. Simply returns at runtime.
+
+ This is a temperary function which will be removed when
+ EfiAcquireLock() in UefiLib can handle the call in UEFI
+ Runtimer driver in RT phase.
+ It calls EfiAcquireLock() at boot time, and simply returns
+ at runtime.
+
+ @param[in] Lock A pointer to the lock to acquire.
+
+**/
+VOID
+AcquireLockOnlyAtBootTime (
+ IN EFI_LOCK *Lock
+ )
+{
+ if (!EfiAtRuntime ()) {
+ EfiAcquireLock (Lock);
+ }
+}
+
+/**
+ Releases lock only at boot time. Simply returns at runtime.
+
+ This is a temperary function which will be removed when
+ EfiReleaseLock() in UefiLib can handle the call in UEFI
+ Runtimer driver in RT phase.
+ It calls EfiReleaseLock() at boot time, and simply returns
+ at runtime
+
+ @param[in] Lock A pointer to the lock to release.
+
+**/
+VOID
+ReleaseLockOnlyAtBootTime (
+ IN EFI_LOCK *Lock
+ )
+{
+ if (!EfiAtRuntime ()) {
+ EfiReleaseLock (Lock);
+ }
+}
+
+/**
+ Reads/Writes variable storage, volatile or non-volatile.
+
+ This function reads or writes volatile or non-volatile variable stroage.
+ For volatile storage, it performs memory copy.
+ For non-volatile storage, it accesses data on firmware storage. Data
+ area to access can span multiple firmware blocks.
+
+ @param[in] Write TRUE - Write variable store.
+ FALSE - Read variable store.
+ @param[in] Global Pointer to VARAIBLE_GLOBAL structure.
+ @param[in] Volatile TRUE - Variable is volatile.
+ FALSE - Variable is non-volatile.
+ @param[in] Instance Instance of FV Block services.
+ @param[in] StartAddress Start address of data to access.
+ @param[in] DataSize Size of data to access.
+ @param[in, out] Buffer For write, pointer to the buffer from which data is written.
+ For read, pointer to the buffer to hold the data read.
+
+ @retval EFI_SUCCESS Variable store successfully accessed.
+ @retval EFI_INVALID_PARAMETER Data area to access exceeds valid variable storage.
+
+**/
+EFI_STATUS
+AccessVariableStore (
+ IN BOOLEAN Write,
+ IN VARIABLE_GLOBAL *Global,
+ IN BOOLEAN Volatile,
+ IN UINTN Instance,
+ IN EFI_PHYSICAL_ADDRESS StartAddress,
+ IN UINT32 DataSize,
+ IN OUT VOID *Buffer
+ )
+{
+ EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry;
+ UINTN BlockIndex;
+ UINTN LinearOffset;
+ UINTN CurrWriteSize;
+ UINTN CurrWritePtr;
+ UINT8 *CurrBuffer;
+ EFI_LBA LbaNumber;
+ UINTN Size;
+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
+ VARIABLE_STORE_HEADER *VolatileBase;
+ EFI_PHYSICAL_ADDRESS FvVolHdr;
+ EFI_STATUS Status;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+
+ FvVolHdr = 0;
+ FwVolHeader = NULL;
+
+ if (Volatile) {
+ //
+ // If data is volatile, simply calculate the data pointer and copy memory.
+ // Data pointer should point to the actual address where data is to be
+ // accessed.
+ //
+ VolatileBase = (VARIABLE_STORE_HEADER *) ((UINTN) Global->VolatileVariableBase);
+
+ if ((StartAddress + DataSize) > ((UINTN) ((UINT8 *) VolatileBase + VolatileBase->Size))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // For volatile variable, a simple memory copy is enough.
+ //
+ if (Write) {
+ CopyMem ((VOID *) StartAddress, Buffer, DataSize);
+ } else {
+ CopyMem (Buffer, (VOID *) StartAddress, DataSize);
+ }
+
+ return EFI_SUCCESS;
+ }
+
+ //
+ // If data is non-volatile, calculate firmware volume header and data pointer.
+ //
+ Status = (EFI_STATUS) EsalCall (
+ EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID_LO,
+ EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID_HI,
+ GetPhysicalAddressFunctionId,
+ Instance,
+ (UINT64) &FvVolHdr,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ ).Status;
+ ASSERT_EFI_ERROR (Status);
+
+ FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvVolHdr);
+ ASSERT (FwVolHeader != NULL);
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *)(FwVolHeader + 1);
+
+ if ((StartAddress + DataSize) > ((EFI_PHYSICAL_ADDRESS) (UINTN) ((CHAR8 *)VariableStoreHeader + VariableStoreHeader->Size))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ LinearOffset = (UINTN) FwVolHeader;
+ CurrWritePtr = StartAddress;
+ CurrWriteSize = DataSize;
+ CurrBuffer = Buffer;
+ LbaNumber = 0;
+
+ if (CurrWritePtr < LinearOffset) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Traverse data blocks of this firmware storage to find the one where CurrWritePtr locates
+ //
+ for (PtrBlockMapEntry = FwVolHeader->BlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) {
+ for (BlockIndex = 0; BlockIndex < PtrBlockMapEntry->NumBlocks; BlockIndex++) {
+ if ((CurrWritePtr >= LinearOffset) && (CurrWritePtr < LinearOffset + PtrBlockMapEntry->Length)) {
+ //
+ // Check to see if the data area to access spans multiple blocks.
+ //
+ if ((CurrWritePtr + CurrWriteSize) <= (LinearOffset + PtrBlockMapEntry->Length)) {
+ //
+ // If data area to access is contained in one block, just access and return.
+ //
+ if (Write) {
+ Status = (EFI_STATUS) EsalCall (
+ EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID_LO,
+ EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID_HI,
+ WriteFunctionId,
+ Instance,
+ LbaNumber,
+ (CurrWritePtr - LinearOffset),
+ (UINT64) &CurrWriteSize,
+ (UINT64) CurrBuffer,
+ 0,
+ 0
+ ).Status;
+ } else {
+ Status = (EFI_STATUS) EsalCall (
+ EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID_LO,
+ EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID_HI,
+ ReadFunctionId,
+ Instance,
+ LbaNumber,
+ (CurrWritePtr - LinearOffset),
+ (UINT64) &CurrWriteSize,
+ (UINT64) CurrBuffer,
+ 0,
+ 0
+ ).Status;
+ }
+ return Status;
+ } else {
+ //
+ // If data area to access spans multiple blocks, access this one and adjust for the next one.
+ //
+ Size = (UINT32) (LinearOffset + PtrBlockMapEntry->Length - CurrWritePtr);
+ if (Write) {
+ Status = (EFI_STATUS) EsalCall (
+ EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID_LO,
+ EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID_HI,
+ WriteFunctionId,
+ Instance,
+ LbaNumber,
+ (CurrWritePtr - LinearOffset),
+ (UINT64) &Size,
+ (UINT64) CurrBuffer,
+ 0,
+ 0
+ ).Status;
+ } else {
+ Status = (EFI_STATUS) EsalCall (
+ EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID_LO,
+ EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID_HI,
+ ReadFunctionId,
+ Instance,
+ LbaNumber,
+ (CurrWritePtr - LinearOffset),
+ (UINT64) &Size,
+ (UINT64) CurrBuffer,
+ 0,
+ 0
+ ).Status;
+ }
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Adjust for the remaining data.
+ //
+ CurrWritePtr = LinearOffset + PtrBlockMapEntry->Length;
+ CurrBuffer = CurrBuffer + Size;
+ CurrWriteSize = CurrWriteSize - Size;
+ }
+ }
+
+ LinearOffset += PtrBlockMapEntry->Length;
+ LbaNumber++;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Retrieves header of volatile or non-volatile variable stroage.
+
+ @param[in] VarStoreAddress Start address of variable storage.
+ @param[in] Volatile TRUE - Variable storage is volatile.
+ FALSE - Variable storage is non-volatile.
+ @param[in] Global Pointer to VARAIBLE_GLOBAL structure.
+ @param[in] Instance Instance of FV Block services.
+ @param[out] VarStoreHeader Pointer to VARIABLE_STORE_HEADER for output.
+
+**/
+VOID
+GetVarStoreHeader (
+ IN EFI_PHYSICAL_ADDRESS VarStoreAddress,
+ IN BOOLEAN Volatile,
+ IN VARIABLE_GLOBAL *Global,
+ IN UINTN Instance,
+ OUT VARIABLE_STORE_HEADER *VarStoreHeader
+ )
+{
+ EFI_STATUS Status;
+
+ Status = AccessVariableStore (
+ FALSE,
+ Global,
+ Volatile,
+ Instance,
+ VarStoreAddress,
+ sizeof (VARIABLE_STORE_HEADER),
+ VarStoreHeader
+ );
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ Checks variable header.
+
+ This function checks if variable header is valid or not.
+
+ @param[in] VariableAddress Start address of variable header.
+ @param[in] Volatile TRUE - Variable is volatile.
+ FALSE - Variable is non-volatile.
+ @param[in] Global Pointer to VARAIBLE_GLOBAL structure.
+ @param[in] Instance Instance of FV Block services.
+ @param[out] VariableHeader Pointer to AUTHENTICATED_VARIABLE_HEADER for output.
+
+ @retval TRUE Variable header is valid.
+ @retval FALSE Variable header is not valid.
+
+**/
+BOOLEAN
+IsValidVariableHeader (
+ IN EFI_PHYSICAL_ADDRESS VariableAddress,
+ IN BOOLEAN Volatile,
+ IN VARIABLE_GLOBAL *Global,
+ IN UINTN Instance,
+ OUT AUTHENTICATED_VARIABLE_HEADER *VariableHeader OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ AUTHENTICATED_VARIABLE_HEADER LocalVariableHeader;
+
+ Status = AccessVariableStore (
+ FALSE,
+ Global,
+ Volatile,
+ Instance,
+ VariableAddress,
+ sizeof (AUTHENTICATED_VARIABLE_HEADER),
+ &LocalVariableHeader
+ );
+
+ if (EFI_ERROR (Status) || LocalVariableHeader.StartId != VARIABLE_DATA) {
+ return FALSE;
+ }
+
+ if (VariableHeader != NULL) {
+ CopyMem (VariableHeader, &LocalVariableHeader, sizeof (AUTHENTICATED_VARIABLE_HEADER));
+ }
+
+ return TRUE;
+}
+
+/**
+ Gets status of variable store.
+
+ This function gets the current status of variable store.
+
+ @param[in] VarStoreHeader Pointer to header of variable store.
+
+ @retval EfiRaw Variable store status is raw.
+ @retval EfiValid Variable store status is valid.
+ @retval EfiInvalid Variable store status is invalid.
+
+**/
+VARIABLE_STORE_STATUS
+GetVariableStoreStatus (
+ IN VARIABLE_STORE_HEADER *VarStoreHeader
+ )
+{
+
+ if (CompareGuid (&VarStoreHeader->Signature, &gEfiAuthenticatedVariableGuid) &&
+ VarStoreHeader->Format == VARIABLE_STORE_FORMATTED &&
+ VarStoreHeader->State == VARIABLE_STORE_HEALTHY
+ ) {
+
+ return EfiValid;
+ } else if (((UINT32 *)(&VarStoreHeader->Signature))[0] == 0xffffffff &&
+ ((UINT32 *)(&VarStoreHeader->Signature))[1] == 0xffffffff &&
+ ((UINT32 *)(&VarStoreHeader->Signature))[2] == 0xffffffff &&
+ ((UINT32 *)(&VarStoreHeader->Signature))[3] == 0xffffffff &&
+ VarStoreHeader->Size == 0xffffffff &&
+ VarStoreHeader->Format == 0xff &&
+ VarStoreHeader->State == 0xff
+ ) {
+
+ return EfiRaw;
+ } else {
+ return EfiInvalid;
+ }
+}
+
+/**
+ Gets the size of variable name.
+
+ This function gets the size of variable name.
+ The variable is specified by its variable header.
+ If variable header contains raw data, just return 0.
+
+ @param[in] Variable Pointer to the variable header.
+
+ @return Size of variable name in bytes.
+
+**/
+UINTN
+NameSizeOfVariable (
+ IN AUTHENTICATED_VARIABLE_HEADER *Variable
+ )
+{
+ if (Variable->State == (UINT8) (-1) ||
+ Variable->DataSize == (UINT32) -1 ||
+ Variable->NameSize == (UINT32) -1 ||
+ Variable->Attributes == (UINT32) -1) {
+ return 0;
+ }
+ return (UINTN) Variable->NameSize;
+}
+
+/**
+ Gets the size of variable data area.
+
+ This function gets the size of variable data area.
+ The variable is specified by its variable header.
+ If variable header contains raw data, just return 0.
+
+ @param[in] Variable Pointer to the variable header.
+
+ @return Size of variable data area in bytes.
+
+**/
+UINTN
+DataSizeOfVariable (
+ IN AUTHENTICATED_VARIABLE_HEADER *Variable
+ )
+{
+ if (Variable->State == (UINT8) -1 ||
+ Variable->DataSize == (UINT32) -1 ||
+ Variable->NameSize == (UINT32) -1 ||
+ Variable->Attributes == (UINT32) -1) {
+ return 0;
+ }
+ return (UINTN) Variable->DataSize;
+}
+
+/**
+ Gets the pointer to variable name.
+
+ This function gets the pointer to variable name.
+ The variable is specified by its variable header.
+
+ @param[in] VariableAddress Start address of variable header.
+ @param[in] Volatile TRUE - Variable is volatile.
+ FALSE - Variable is non-volatile.
+ @param[in] Global Pointer to VARAIBLE_GLOBAL structure.
+ @param[in] Instance Instance of FV Block services.
+ @param[out] VariableName Buffer to hold variable name for output.
+
+**/
+VOID
+GetVariableNamePtr (
+ IN EFI_PHYSICAL_ADDRESS VariableAddress,
+ IN BOOLEAN Volatile,
+ IN VARIABLE_GLOBAL *Global,
+ IN UINTN Instance,
+ OUT CHAR16 *VariableName
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS Address;
+ AUTHENTICATED_VARIABLE_HEADER VariableHeader;
+ BOOLEAN IsValid;
+
+ IsValid = IsValidVariableHeader (VariableAddress, Volatile, Global, Instance, &VariableHeader);
+ ASSERT (IsValid);
+
+ //
+ // Name area follows variable header.
+ //
+ Address = VariableAddress + sizeof (AUTHENTICATED_VARIABLE_HEADER);
+
+ Status = AccessVariableStore (
+ FALSE,
+ Global,
+ Volatile,
+ Instance,
+ Address,
+ VariableHeader.NameSize,
+ VariableName
+ );
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ Gets the pointer to variable data area.
+
+ This function gets the pointer to variable data area.
+ The variable is specified by its variable header.
+
+ @param[in] VariableAddress Start address of variable header.
+ @param[in] Volatile TRUE - Variable is volatile.
+ FALSE - Variable is non-volatile.
+ @param[in] Global Pointer to VARAIBLE_GLOBAL structure.
+ @param[in] Instance Instance of FV Block services.
+ @param[out] VariableData Buffer to hold variable data for output.
+
+**/
+VOID
+GetVariableDataPtr (
+ IN EFI_PHYSICAL_ADDRESS VariableAddress,
+ IN BOOLEAN Volatile,
+ IN VARIABLE_GLOBAL *Global,
+ IN UINTN Instance,
+ OUT CHAR16 *VariableData
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS Address;
+ AUTHENTICATED_VARIABLE_HEADER VariableHeader;
+ BOOLEAN IsValid;
+
+ IsValid = IsValidVariableHeader (VariableAddress, Volatile, Global, Instance, &VariableHeader);
+ ASSERT (IsValid);
+
+ //
+ // Data area follows variable name.
+ // Be careful about pad size for alignment
+ //
+ Address = VariableAddress + sizeof (AUTHENTICATED_VARIABLE_HEADER);
+ Address += NameSizeOfVariable (&VariableHeader);
+ Address += GET_PAD_SIZE (NameSizeOfVariable (&VariableHeader));
+
+ Status = AccessVariableStore (
+ FALSE,
+ Global,
+ Volatile,
+ Instance,
+ Address,
+ VariableHeader.DataSize,
+ VariableData
+ );
+ ASSERT_EFI_ERROR (Status);
+}
+
+
+/**
+ Gets the pointer to the next variable header.
+
+ This function gets the pointer to the next variable header.
+ The variable is specified by its variable header.
+
+ @param[in] VariableAddress Start address of variable header.
+ @param[in] Volatile TRUE - Variable is volatile.
+ FALSE - Variable is non-volatile.
+ @param[in] Global Pointer to VARAIBLE_GLOBAL structure.
+ @param[in] Instance Instance of FV Block services.
+
+ @return Pointer to the next variable header.
+ NULL if variable header is invalid.
+
+**/
+EFI_PHYSICAL_ADDRESS
+GetNextVariablePtr (
+ IN EFI_PHYSICAL_ADDRESS VariableAddress,
+ IN BOOLEAN Volatile,
+ IN VARIABLE_GLOBAL *Global,
+ IN UINTN Instance
+ )
+{
+ EFI_PHYSICAL_ADDRESS Address;
+ AUTHENTICATED_VARIABLE_HEADER VariableHeader;
+
+ if (!IsValidVariableHeader (VariableAddress, Volatile, Global, Instance, &VariableHeader)) {
+ return 0x0;
+ }
+
+ //
+ // Header of next variable follows data area of this variable
+ //
+ Address = VariableAddress + sizeof (AUTHENTICATED_VARIABLE_HEADER);
+ Address += NameSizeOfVariable (&VariableHeader);
+ Address += GET_PAD_SIZE (NameSizeOfVariable (&VariableHeader));
+ Address += DataSizeOfVariable (&VariableHeader);
+ Address += GET_PAD_SIZE (DataSizeOfVariable (&VariableHeader));
+
+ //
+ // Be careful about pad size for alignment
+ //
+ return HEADER_ALIGN (Address);
+}
+
+/**
+ Gets the pointer to the first variable header in given variable store area.
+
+ This function gets the pointer to the first variable header in given variable
+ store area. The variable store area is given by its start address.
+
+ @param[in] VarStoreHeaderAddress Pointer to the header of variable store area.
+
+ @return Pointer to the first variable header.
+
+**/
+EFI_PHYSICAL_ADDRESS
+GetStartPointer (
+ IN EFI_PHYSICAL_ADDRESS VarStoreHeaderAddress
+ )
+{
+ return HEADER_ALIGN (VarStoreHeaderAddress + sizeof (VARIABLE_STORE_HEADER));
+}
+
+/**
+ Gets the pointer to the end of given variable store area.
+
+ This function gets the pointer to the end of given variable store area.
+ The variable store area is given by its start address.
+
+ @param[in] VarStoreHeaderAddress Pointer to the header of variable store area.
+ @param[in] Volatile TRUE - Variable is volatile.
+ FALSE - Variable is non-volatile.
+ @param[in] Global Pointer to VARAIBLE_GLOBAL structure.
+ @param[in] Instance Instance of FV Block services.
+
+ @return Pointer to the end of given variable store area.
+
+**/
+EFI_PHYSICAL_ADDRESS
+GetEndPointer (
+ IN EFI_PHYSICAL_ADDRESS VarStoreHeaderAddress,
+ IN BOOLEAN Volatile,
+ IN VARIABLE_GLOBAL *Global,
+ IN UINTN Instance
+ )
+{
+ EFI_STATUS Status;
+ VARIABLE_STORE_HEADER VariableStoreHeader;
+
+ Status = AccessVariableStore (
+ FALSE,
+ Global,
+ Volatile,
+ Instance,
+ VarStoreHeaderAddress,
+ sizeof (VARIABLE_STORE_HEADER),
+ &VariableStoreHeader
+ );
+
+ ASSERT_EFI_ERROR (Status);
+ return HEADER_ALIGN (VarStoreHeaderAddress + VariableStoreHeader.Size);
+}
+
+/**
+ Updates variable info entry in EFI system table for statistical information.
+
+ Routine used to track statistical information about variable usage.
+ The data is stored in the EFI system table so it can be accessed later.
+ VariableInfo.efi can dump out the table. Only Boot Services variable
+ accesses are tracked by this code. The PcdVariableCollectStatistics
+ build flag controls if this feature is enabled.
+ A read that hits in the cache will have Read and Cache true for
+ the transaction. Data is allocated by this routine, but never
+ freed.
+
+ @param[in] VariableName Name of the Variable to track.
+ @param[in] VendorGuid Guid of the Variable to track.
+ @param[in] Volatile TRUE if volatile FALSE if non-volatile.
+ @param[in] Read TRUE if GetVariable() was called.
+ @param[in] Write TRUE if SetVariable() was called.
+ @param[in] Delete TRUE if deleted via SetVariable().
+ @param[in] Cache TRUE for a cache hit.
+
+**/
+VOID
+UpdateVariableInfo (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN BOOLEAN Volatile,
+ IN BOOLEAN Read,
+ IN BOOLEAN Write,
+ IN BOOLEAN Delete,
+ IN BOOLEAN Cache
+ )
+{
+ VARIABLE_INFO_ENTRY *Entry;
+
+ if (FeaturePcdGet (PcdVariableCollectStatistics)) {
+
+ if (EfiAtRuntime ()) {
+ //
+ // Don't collect statistics at runtime
+ //
+ return;
+ }
+
+ if (gVariableInfo == NULL) {
+ //
+ // on the first call allocate a entry and place a pointer to it in
+ // the EFI System Table
+ //
+ gVariableInfo = AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY));
+ ASSERT (gVariableInfo != NULL);
+
+ CopyGuid (&gVariableInfo->VendorGuid, VendorGuid);
+ gVariableInfo->Name = AllocatePool (StrSize (VariableName));
+ ASSERT (gVariableInfo->Name != NULL);
+ StrCpyS (gVariableInfo->Name, StrSize (VariableName) / sizeof (CHAR16), VariableName);
+ gVariableInfo->Volatile = Volatile;
+
+ gBS->InstallConfigurationTable (&gEfiAuthenticatedVariableGuid, gVariableInfo);
+ }
+
+
+ for (Entry = gVariableInfo; Entry != NULL; Entry = Entry->Next) {
+ if (CompareGuid (VendorGuid, &Entry->VendorGuid)) {
+ if (StrCmp (VariableName, Entry->Name) == 0) {
+ //
+ // Find the entry matching both variable name and vender GUID,
+ // and update counters for all types.
+ //
+ if (Read) {
+ Entry->ReadCount++;
+ }
+ if (Write) {
+ Entry->WriteCount++;
+ }
+ if (Delete) {
+ Entry->DeleteCount++;
+ }
+ if (Cache) {
+ Entry->CacheCount++;
+ }
+
+ return;
+ }
+ }
+
+ if (Entry->Next == NULL) {
+ //
+ // If the entry is not in the table add it.
+ // Next iteration of the loop will fill in the data
+ //
+ Entry->Next = AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY));
+ ASSERT (Entry->Next != NULL);
+
+ CopyGuid (&Entry->Next->VendorGuid, VendorGuid);
+ Entry->Next->Name = AllocatePool (StrSize (VariableName));
+ ASSERT (Entry->Next->Name != NULL);
+ StrCpyS (Entry->Next->Name, StrSize (VariableName) / sizeof (CHAR16), VariableName);
+ Entry->Next->Volatile = Volatile;
+ }
+
+ }
+ }
+}
+
+/**
+ Updates variable in cache.
+
+ This function searches the variable cache. If the variable to set exists in the cache,
+ it updates the variable in cache. It has the same parameters with UEFI SetVariable()
+ service.
+
+ @param[in] VariableName A Null-terminated Unicode string that is the name of the vendor's
+ variable. Each VariableName is unique for each VendorGuid.
+ @param[in] VendorGuid A unique identifier for the vendor.
+ @param[in] Attributes Attributes bitmask to set for the variable.
+ @param[in] DataSize The size in bytes of the Data buffer. A size of zero causes the
+ variable to be deleted.
+ @param[in] Data The contents for the variable.
+
+**/
+VOID
+UpdateVariableCache (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT32 Attributes,
+ IN UINTN DataSize,
+ IN VOID *Data
+ )
+{
+ VARIABLE_CACHE_ENTRY *Entry;
+ UINTN Index;
+
+ if (EfiAtRuntime ()) {
+ //
+ // Don't use the cache at runtime
+ //
+ return;
+ }
+
+ //
+ // Searches cache for the variable to update. If it exists, update it.
+ //
+ for (Index = 0, Entry = mVariableCache; Index < sizeof (mVariableCache)/sizeof (VARIABLE_CACHE_ENTRY); Index++, Entry++) {
+ if (CompareGuid (VendorGuid, Entry->Guid)) {
+ if (StrCmp (VariableName, Entry->Name) == 0) {
+ Entry->Attributes = Attributes;
+ if (DataSize == 0) {
+ //
+ // If DataSize is 0, delete the variable.
+ //
+ if (Entry->DataSize != 0) {
+ FreePool (Entry->Data);
+ }
+ Entry->DataSize = DataSize;
+ } else if (DataSize == Entry->DataSize) {
+ //
+ // If size of data does not change, simply copy data
+ //
+ CopyMem (Entry->Data, Data, DataSize);
+ } else {
+ //
+ // If size of data changes, allocate pool and copy data.
+ //
+ Entry->Data = AllocatePool (DataSize);
+ ASSERT (Entry->Data != NULL);
+ Entry->DataSize = DataSize;
+ CopyMem (Entry->Data, Data, DataSize);
+ }
+ }
+ }
+ }
+}
+
+
+/**
+ Search the cache to check if the variable is in it.
+
+ This function searches the variable cache. If the variable to find exists, return its data
+ and attributes.
+
+ @param[in] VariableName A Null-terminated Unicode string that is the name of the vendor's
+ variable. Each VariableName is unique for each VendorGuid.
+ @param[in] VendorGuid A unique identifier for the vendor
+ @param[out] Attributes Pointer to the attributes bitmask of the variable for output.
+ @param[in, out] DataSize On input, size of the buffer of Data.
+ On output, size of the variable's data.
+ @param[out] Data Pointer to the data buffer for output.
+
+ @retval EFI_SUCCESS VariableGuid & VariableName data was returned.
+ @retval EFI_NOT_FOUND No matching variable found in cache.
+ @retval EFI_BUFFER_TOO_SMALL *DataSize is smaller than size of the variable's data to return.
+
+**/
+EFI_STATUS
+FindVariableInCache (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ OUT UINT32 *Attributes OPTIONAL,
+ IN OUT UINTN *DataSize,
+ OUT VOID *Data
+ )
+{
+ VARIABLE_CACHE_ENTRY *Entry;
+ UINTN Index;
+
+ if (EfiAtRuntime ()) {
+ //
+ // Don't use the cache at runtime
+ //
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Searches cache for the variable
+ //
+ for (Index = 0, Entry = mVariableCache; Index < sizeof (mVariableCache)/sizeof (VARIABLE_CACHE_ENTRY); Index++, Entry++) {
+ if (CompareGuid (VendorGuid, Entry->Guid)) {
+ if (StrCmp (VariableName, Entry->Name) == 0) {
+ if (Entry->DataSize == 0) {
+ //
+ // Variable has been deleted so return EFI_NOT_FOUND
+ //
+ return EFI_NOT_FOUND;
+ } else if (Entry->DataSize > *DataSize) {
+ //
+ // If buffer is too small, return the size needed and EFI_BUFFER_TOO_SMALL
+ //
+ *DataSize = Entry->DataSize;
+ return EFI_BUFFER_TOO_SMALL;
+ } else {
+ //
+ // If buffer is large enough, return the data
+ //
+ *DataSize = Entry->DataSize;
+ CopyMem (Data, Entry->Data, Entry->DataSize);
+ //
+ // If Attributes is not NULL, return the variable's attribute.
+ //
+ if (Attributes != NULL) {
+ *Attributes = Entry->Attributes;
+ }
+ return EFI_SUCCESS;
+ }
+ }
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Finds variable in volatile and non-volatile storage areas.
+
+ This code finds variable in volatile and non-volatile storage areas.
+ If VariableName is an empty string, then we just return the first
+ qualified variable without comparing VariableName and VendorGuid.
+ Otherwise, VariableName and VendorGuid are compared.
+
+ @param[in] VariableName Name of the variable to be found.
+ @param[in] VendorGuid Vendor GUID to be found.
+ @param[out] PtrTrack VARIABLE_POINTER_TRACK structure for output,
+ including the range searched and the target position.
+ @param[in] Global Pointer to VARIABLE_GLOBAL structure, including
+ base of volatile variable storage area, base of
+ NV variable storage area, and a lock.
+ @param[in] Instance Instance of FV Block services.
+
+ @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, while
+ VendorGuid is NULL.
+ @retval EFI_SUCCESS Variable successfully found.
+ @retval EFI_INVALID_PARAMETER Variable not found.
+
+**/
+EFI_STATUS
+FindVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ OUT VARIABLE_POINTER_TRACK *PtrTrack,
+ IN VARIABLE_GLOBAL *Global,
+ IN UINTN Instance
+ )
+{
+ EFI_PHYSICAL_ADDRESS Variable[2];
+ EFI_PHYSICAL_ADDRESS InDeletedVariable;
+ EFI_PHYSICAL_ADDRESS VariableStoreHeader[2];
+ UINTN InDeletedStorageIndex;
+ UINTN Index;
+ CHAR16 LocalVariableName[MAX_NAME_SIZE];
+ BOOLEAN Volatile;
+ AUTHENTICATED_VARIABLE_HEADER VariableHeader;
+
+ //
+ // 0: Volatile, 1: Non-Volatile
+ // The index and attributes mapping must be kept in this order as RuntimeServiceGetNextVariableName
+ // make use of this mapping to implement search algorithme.
+ //
+ VariableStoreHeader[0] = Global->VolatileVariableBase;
+ VariableStoreHeader[1] = Global->NonVolatileVariableBase;
+
+ //
+ // Start Pointers for the variable.
+ // Actual Data Pointer where data can be written.
+ //
+ Variable[0] = GetStartPointer (VariableStoreHeader[0]);
+ Variable[1] = GetStartPointer (VariableStoreHeader[1]);
+
+ if (VariableName[0] != 0 && VendorGuid == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Find the variable by walk through volatile and then non-volatile variable store
+ //
+ InDeletedVariable = 0x0;
+ InDeletedStorageIndex = 0;
+ Volatile = TRUE;
+ for (Index = 0; Index < 2; Index++) {
+ if (Index == 1) {
+ Volatile = FALSE;
+ }
+ while (IsValidVariableHeader (Variable[Index], Volatile, Global, Instance, &VariableHeader)) {
+ if (VariableHeader.State == VAR_ADDED ||
+ VariableHeader.State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)
+ ) {
+ if (!EfiAtRuntime () || ((VariableHeader.Attributes & EFI_VARIABLE_RUNTIME_ACCESS) != 0)) {
+ if (VariableName[0] == 0) {
+ //
+ // If VariableName is an empty string, then we just find the first qualified variable
+ // without comparing VariableName and VendorGuid
+ //
+ if (VariableHeader.State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
+ //
+ // If variable is in delete transition, record it.
+ //
+ InDeletedVariable = Variable[Index];
+ InDeletedStorageIndex = Index;
+ } else {
+ //
+ // If variable is not in delete transition, return it.
+ //
+ PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader[Index]);
+ PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader[Index], Volatile, Global, Instance);
+ PtrTrack->CurrPtr = Variable[Index];
+ PtrTrack->Volatile = Volatile;
+
+ return EFI_SUCCESS;
+ }
+ } else {
+ //
+ // If VariableName is not an empty string, then VariableName and VendorGuid are compared.
+ //
+ if (CompareGuid (VendorGuid, &VariableHeader.VendorGuid)) {
+ GetVariableNamePtr (
+ Variable[Index],
+ Volatile,
+ Global,
+ Instance,
+ LocalVariableName
+ );
+
+ ASSERT (NameSizeOfVariable (&VariableHeader) != 0);
+ if (CompareMem (VariableName, LocalVariableName, NameSizeOfVariable (&VariableHeader)) == 0) {
+ if (VariableHeader.State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
+ //
+ // If variable is in delete transition, record it.
+ // We will use if only no VAR_ADDED variable is found.
+ //
+ InDeletedVariable = Variable[Index];
+ InDeletedStorageIndex = Index;
+ } else {
+ //
+ // If variable is not in delete transition, return it.
+ //
+ PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader[Index]);
+ PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader[Index], Volatile, Global, Instance);
+ PtrTrack->CurrPtr = Variable[Index];
+ PtrTrack->Volatile = Volatile;
+
+ return EFI_SUCCESS;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ Variable[Index] = GetNextVariablePtr (
+ Variable[Index],
+ Volatile,
+ Global,
+ Instance
+ );
+ }
+ if (InDeletedVariable != 0x0) {
+ //
+ // If no VAR_ADDED variable is found, and only variable in delete transition, then use this one.
+ //
+ PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader[InDeletedStorageIndex]);
+ PtrTrack->EndPtr = GetEndPointer (
+ VariableStoreHeader[InDeletedStorageIndex],
+ (BOOLEAN)(InDeletedStorageIndex == 0),
+ Global,
+ Instance
+ );
+ PtrTrack->CurrPtr = InDeletedVariable;
+ PtrTrack->Volatile = (BOOLEAN)(InDeletedStorageIndex == 0);
+ return EFI_SUCCESS;
+ }
+ }
+ PtrTrack->CurrPtr = 0x0;
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Variable store garbage collection and reclaim operation.
+
+ @param[in] VariableBase Base address of variable store area.
+ @param[out] LastVariableOffset Offset of last variable.
+ @param[in] IsVolatile The variable store is volatile or not,
+ if it is non-volatile, need FTW.
+ @param[in] VirtualMode Current calling mode for this function.
+ @param[in] Global Context of this Extended SAL Variable Services Class call.
+ @param[in] UpdatingVariable Pointer to header of the variable that is being updated.
+
+ @retval EFI_SUCCESS Variable store successfully reclaimed.
+ @retval EFI_OUT_OF_RESOURCES Fail to allocate memory buffer to hold all valid variables.
+
+**/
+EFI_STATUS
+Reclaim (
+ IN EFI_PHYSICAL_ADDRESS VariableBase,
+ OUT UINTN *LastVariableOffset,
+ IN BOOLEAN IsVolatile,
+ IN BOOLEAN VirtualMode,
+ IN ESAL_VARIABLE_GLOBAL *Global,
+ IN EFI_PHYSICAL_ADDRESS UpdatingVariable
+ )
+{
+ EFI_PHYSICAL_ADDRESS Variable;
+ EFI_PHYSICAL_ADDRESS AddedVariable;
+ EFI_PHYSICAL_ADDRESS NextVariable;
+ EFI_PHYSICAL_ADDRESS NextAddedVariable;
+ VARIABLE_STORE_HEADER VariableStoreHeader;
+ AUTHENTICATED_VARIABLE_HEADER VariableHeader;
+ AUTHENTICATED_VARIABLE_HEADER AddedVariableHeader;
+ CHAR16 VariableName[MAX_NAME_SIZE];
+ CHAR16 AddedVariableName[MAX_NAME_SIZE];
+ UINT8 *ValidBuffer;
+ UINTN MaximumBufferSize;
+ UINTN VariableSize;
+ UINTN NameSize;
+ UINT8 *CurrPtr;
+ BOOLEAN FoundAdded;
+ EFI_STATUS Status;
+ VARIABLE_GLOBAL *VariableGlobal;
+ UINT32 Instance;
+
+ VariableGlobal = &Global->VariableGlobal[VirtualMode];
+ Instance = Global->FvbInstance;
+
+ GetVarStoreHeader (VariableBase, IsVolatile, VariableGlobal, Instance, &VariableStoreHeader);
+ //
+ // recaluate the total size of Common/HwErr type variables in non-volatile area.
+ //
+ if (!IsVolatile) {
+ Global->CommonVariableTotalSize = 0;
+ Global->HwErrVariableTotalSize = 0;
+ }
+
+ //
+ // Calculate the size of buffer needed to gather all valid variables
+ //
+ Variable = GetStartPointer (VariableBase);
+ MaximumBufferSize = sizeof (VARIABLE_STORE_HEADER);
+
+ while (IsValidVariableHeader (Variable, IsVolatile, VariableGlobal, Instance, &VariableHeader)) {
+ NextVariable = GetNextVariablePtr (Variable, IsVolatile, VariableGlobal, Instance);
+ //
+ // Collect VAR_ADDED variables, and variables in delete transition status.
+ //
+ if (VariableHeader.State == VAR_ADDED ||
+ VariableHeader.State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)
+ ) {
+ VariableSize = NextVariable - Variable;
+ MaximumBufferSize += VariableSize;
+ }
+
+ Variable = NextVariable;
+ }
+
+ //
+ // Reserve the 1 Bytes with Oxff to identify the
+ // end of the variable buffer.
+ //
+ MaximumBufferSize += 1;
+ ValidBuffer = AllocatePool (MaximumBufferSize);
+ if (ValidBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ SetMem (ValidBuffer, MaximumBufferSize, 0xff);
+
+ //
+ // Copy variable store header
+ //
+ CopyMem (ValidBuffer, &VariableStoreHeader, sizeof (VARIABLE_STORE_HEADER));
+ CurrPtr = (UINT8 *) GetStartPointer ((EFI_PHYSICAL_ADDRESS) ValidBuffer);
+
+ //
+ // Reinstall all ADDED variables
+ //
+ Variable = GetStartPointer (VariableBase);
+ while (IsValidVariableHeader (Variable, IsVolatile, VariableGlobal, Instance, &VariableHeader)) {
+ NextVariable = GetNextVariablePtr (Variable, IsVolatile, VariableGlobal, Instance);
+ if (VariableHeader.State == VAR_ADDED) {
+ VariableSize = NextVariable - Variable;
+ CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize);
+ CurrPtr += VariableSize;
+ if ((!IsVolatile) && ((((AUTHENTICATED_VARIABLE_HEADER*)Variable)->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
+ Global->HwErrVariableTotalSize += VariableSize;
+ } else if ((!IsVolatile) && ((((AUTHENTICATED_VARIABLE_HEADER*)Variable)->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
+ Global->CommonVariableTotalSize += VariableSize;
+ }
+ }
+ Variable = NextVariable;
+ }
+ //
+ // Reinstall in delete transition variables
+ //
+ Variable = GetStartPointer (VariableBase);
+ while (IsValidVariableHeader (Variable, IsVolatile, VariableGlobal, Instance, &VariableHeader)) {
+ NextVariable = GetNextVariablePtr (Variable, IsVolatile, VariableGlobal, Instance);
+ if (VariableHeader.State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
+
+ //
+ // Buffer has cached all ADDED variable.
+ // Per IN_DELETED variable, we have to guarantee that
+ // no ADDED one in previous buffer.
+ //
+ FoundAdded = FALSE;
+ AddedVariable = GetStartPointer ((EFI_PHYSICAL_ADDRESS) ValidBuffer);
+ while (IsValidVariableHeader (AddedVariable, IsVolatile, VariableGlobal, Instance, &AddedVariableHeader)) {
+ NextAddedVariable = GetNextVariablePtr (AddedVariable, IsVolatile, VariableGlobal, Instance);
+ NameSize = NameSizeOfVariable (&AddedVariableHeader);
+ if (CompareGuid (&AddedVariableHeader.VendorGuid, &VariableHeader.VendorGuid) &&
+ NameSize == NameSizeOfVariable (&VariableHeader)
+ ) {
+ GetVariableNamePtr (Variable, IsVolatile, VariableGlobal, Instance, VariableName);
+ GetVariableNamePtr (AddedVariable, IsVolatile, VariableGlobal, Instance, AddedVariableName);
+ if (CompareMem (VariableName, AddedVariableName, NameSize) == 0) {
+ //
+ // If ADDED variable with the same name and vender GUID has been reinstalled,
+ // then discard this IN_DELETED copy.
+ //
+ FoundAdded = TRUE;
+ break;
+ }
+ }
+ AddedVariable = NextAddedVariable;
+ }
+ //
+ // Add IN_DELETE variables that have not been added to buffer
+ //
+ if (!FoundAdded) {
+ VariableSize = NextVariable - Variable;
+ CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize);
+ if (Variable != UpdatingVariable) {
+ //
+ // Make this IN_DELETE instance valid if:
+ // 1. No valid instance of this variable exists.
+ // 2. It is not the variable that is going to be updated.
+ //
+ ((AUTHENTICATED_VARIABLE_HEADER *) CurrPtr)->State = VAR_ADDED;
+ }
+ CurrPtr += VariableSize;
+ if ((!IsVolatile) && ((((AUTHENTICATED_VARIABLE_HEADER*)Variable)->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
+ Global->HwErrVariableTotalSize += VariableSize;
+ } else if ((!IsVolatile) && ((((AUTHENTICATED_VARIABLE_HEADER*)Variable)->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
+ Global->CommonVariableTotalSize += VariableSize;
+ }
+ }
+ }
+ Variable = NextVariable;
+ }
+
+ if (IsVolatile) {
+ //
+ // If volatile variable store, just copy valid buffer
+ //
+ SetMem ((UINT8 *) (UINTN) VariableBase, VariableStoreHeader.Size, 0xff);
+ CopyMem ((UINT8 *) (UINTN) VariableBase, ValidBuffer, (UINTN) (CurrPtr - (UINT8 *) ValidBuffer));
+ Status = EFI_SUCCESS;
+ } else {
+ //
+ // If non-volatile variable store, perform FTW here.
+ // Write ValidBuffer to destination specified by VariableBase.
+ //
+ Status = FtwVariableSpace (
+ VariableBase,
+ ValidBuffer,
+ (UINTN) (CurrPtr - (UINT8 *) ValidBuffer)
+ );
+ }
+ if (!EFI_ERROR (Status)) {
+ *LastVariableOffset = (UINTN) (CurrPtr - (UINT8 *) ValidBuffer);
+ } else {
+ *LastVariableOffset = 0;
+ }
+
+ FreePool (ValidBuffer);
+
+ return Status;
+}
+
+/**
+ Get index from supported language codes according to language string.
+
+ This code is used to get corresponding index in supported language codes. It can handle
+ RFC4646 and ISO639 language tags.
+ In ISO639 language tags, take 3-characters as a delimitation to find matched string and calculate the index.
+ In RFC4646 language tags, take semicolon as a delimitation to find matched string and calculate the index.
+
+ For example:
+ SupportedLang = "engfraengfra"
+ Lang = "eng"
+ Iso639Language = TRUE
+ The return value is "0".
+ Another example:
+ SupportedLang = "en;fr;en-US;fr-FR"
+ Lang = "fr-FR"
+ Iso639Language = FALSE
+ The return value is "3".
+
+ @param[in] SupportedLang Platform supported language codes.
+ @param[in] Lang Configured language.
+ @param[in] Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC4646.
+
+ @return The index of language in the language codes.
+
+**/
+UINTN
+GetIndexFromSupportedLangCodes(
+ IN CHAR8 *SupportedLang,
+ IN CHAR8 *Lang,
+ IN BOOLEAN Iso639Language
+ )
+{
+ UINTN Index;
+ UINTN CompareLength;
+ UINTN LanguageLength;
+
+ if (Iso639Language) {
+ CompareLength = ISO_639_2_ENTRY_SIZE;
+ for (Index = 0; Index < AsciiStrLen (SupportedLang); Index += CompareLength) {
+ if (AsciiStrnCmp (Lang, SupportedLang + Index, CompareLength) == 0) {
+ //
+ // Successfully find the index of Lang string in SupportedLang string.
+ //
+ Index = Index / CompareLength;
+ return Index;
+ }
+ }
+ ASSERT (FALSE);
+ return 0;
+ } else {
+ //
+ // Compare RFC4646 language code
+ //
+ Index = 0;
+ for (LanguageLength = 0; Lang[LanguageLength] != '\0'; LanguageLength++);
+
+ for (Index = 0; *SupportedLang != '\0'; Index++, SupportedLang += CompareLength) {
+ //
+ // Skip ';' characters in SupportedLang
+ //
+ for (; *SupportedLang != '\0' && *SupportedLang == ';'; SupportedLang++);
+ //
+ // Determine the length of the next language code in SupportedLang
+ //
+ for (CompareLength = 0; SupportedLang[CompareLength] != '\0' && SupportedLang[CompareLength] != ';'; CompareLength++);
+
+ if ((CompareLength == LanguageLength) &&
+ (AsciiStrnCmp (Lang, SupportedLang, CompareLength) == 0)) {
+ //
+ // Successfully find the index of Lang string in SupportedLang string.
+ //
+ return Index;
+ }
+ }
+ ASSERT (FALSE);
+ return 0;
+ }
+}
+
+/**
+ Get language string from supported language codes according to index.
+
+ This code is used to get corresponding language string in supported language codes. It can handle
+ RFC4646 and ISO639 language tags.
+ In ISO639 language tags, take 3-characters as a delimitation. Find language string according to the index.
+ In RFC4646 language tags, take semicolon as a delimitation. Find language string according to the index.
+
+ For example:
+ SupportedLang = "engfraengfra"
+ Index = "1"
+ Iso639Language = TRUE
+ The return value is "fra".
+ Another example:
+ SupportedLang = "en;fr;en-US;fr-FR"
+ Index = "1"
+ Iso639Language = FALSE
+ The return value is "fr".
+
+ @param[in] SupportedLang Platform supported language codes.
+ @param[in] Index the index in supported language codes.
+ @param[in] Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC4646.
+ @param[in] VirtualMode Current calling mode for this function.
+ @param[in] Global Context of this Extended SAL Variable Services Class call.
+
+ @return The language string in the language codes.
+
+**/
+CHAR8 *
+GetLangFromSupportedLangCodes (
+ IN CHAR8 *SupportedLang,
+ IN UINTN Index,
+ IN BOOLEAN Iso639Language,
+ IN BOOLEAN VirtualMode,
+ IN ESAL_VARIABLE_GLOBAL *Global
+ )
+{
+ UINTN SubIndex;
+ UINTN CompareLength;
+ CHAR8 *Supported;
+
+ SubIndex = 0;
+ Supported = SupportedLang;
+ if (Iso639Language) {
+ //
+ // according to the index of Lang string in SupportedLang string to get the language.
+ // As this code will be invoked in RUNTIME, therefore there is not memory allocate/free operation.
+ // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.
+ //
+ CompareLength = ISO_639_2_ENTRY_SIZE;
+ Global->Lang[CompareLength] = '\0';
+ return CopyMem (Global->Lang, SupportedLang + Index * CompareLength, CompareLength);
+
+ } else {
+ while (TRUE) {
+ //
+ // take semicolon as delimitation, sequentially traverse supported language codes.
+ //
+ for (CompareLength = 0; *Supported != ';' && *Supported != '\0'; CompareLength++) {
+ Supported++;
+ }
+ if ((*Supported == '\0') && (SubIndex != Index)) {
+ //
+ // Have completed the traverse, but not find corrsponding string.
+ // This case is not allowed to happen.
+ //
+ ASSERT(FALSE);
+ return NULL;
+ }
+ if (SubIndex == Index) {
+ //
+ // according to the index of Lang string in SupportedLang string to get the language.
+ // As this code will be invoked in RUNTIME, therefore there is not memory allocate/free operation.
+ // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.
+ //
+ Global->PlatformLang[VirtualMode][CompareLength] = '\0';
+ return CopyMem (Global->PlatformLang[VirtualMode], Supported - CompareLength, CompareLength);
+ }
+ SubIndex++;
+
+ //
+ // Skip ';' characters in Supported
+ //
+ for (; *Supported != '\0' && *Supported == ';'; Supported++);
+ }
+ }
+}
+
+/**
+ Returns a pointer to an allocated buffer that contains the best matching language
+ from a set of supported languages.
+
+ This function supports both ISO 639-2 and RFC 4646 language codes, but language
+ code types may not be mixed in a single call to this function. This function
+ supports a variable argument list that allows the caller to pass in a prioritized
+ list of language codes to test against all the language codes in SupportedLanguages.
+
+ If SupportedLanguages is NULL, then ASSERT().
+
+ @param[in] SupportedLanguages A pointer to a Null-terminated ASCII string that
+ contains a set of language codes in the format
+ specified by Iso639Language.
+ @param[in] Iso639Language If TRUE, then all language codes are assumed to be
+ in ISO 639-2 format. If FALSE, then all language
+ codes are assumed to be in RFC 4646 language format.
+ @param[in] VirtualMode Current calling mode for this function.
+ @param[in] ... A variable argument list that contains pointers to
+ Null-terminated ASCII strings that contain one or more
+ language codes in the format specified by Iso639Language.
+ The first language code from each of these language
+ code lists is used to determine if it is an exact or
+ close match to any of the language codes in
+ SupportedLanguages. Close matches only apply to RFC 4646
+ language codes, and the matching algorithm from RFC 4647
+ is used to determine if a close match is present. If
+ an exact or close match is found, then the matching
+ language code from SupportedLanguages is returned. If
+ no matches are found, then the next variable argument
+ parameter is evaluated. The variable argument list
+ is terminated by a NULL.
+
+ @retval NULL The best matching language could not be found in SupportedLanguages.
+ @retval NULL There are not enough resources available to return the best matching
+ language.
+ @retval Other A pointer to a Null-terminated ASCII string that is the best matching
+ language in SupportedLanguages.
+
+**/
+CHAR8 *
+VariableGetBestLanguage (
+ IN CONST CHAR8 *SupportedLanguages,
+ IN BOOLEAN Iso639Language,
+ IN BOOLEAN VirtualMode,
+ ...
+ )
+{
+ VA_LIST Args;
+ CHAR8 *Language;
+ UINTN CompareLength;
+ UINTN LanguageLength;
+ CONST CHAR8 *Supported;
+ CHAR8 *Buffer;
+
+ ASSERT (SupportedLanguages != NULL);
+
+ VA_START (Args, VirtualMode);
+ while ((Language = VA_ARG (Args, CHAR8 *)) != NULL) {
+ //
+ // Default to ISO 639-2 mode
+ //
+ CompareLength = 3;
+ LanguageLength = MIN (3, AsciiStrLen (Language));
+
+ //
+ // If in RFC 4646 mode, then determine the length of the first RFC 4646 language code in Language
+ //
+ if (!Iso639Language) {
+ for (LanguageLength = 0; Language[LanguageLength] != 0 && Language[LanguageLength] != ';'; LanguageLength++);
+ }
+
+ //
+ // Trim back the length of Language used until it is empty
+ //
+ while (LanguageLength > 0) {
+ //
+ // Loop through all language codes in SupportedLanguages
+ //
+ for (Supported = SupportedLanguages; *Supported != '\0'; Supported += CompareLength) {
+ //
+ // In RFC 4646 mode, then Loop through all language codes in SupportedLanguages
+ //
+ if (!Iso639Language) {
+ //
+ // Skip ';' characters in Supported
+ //
+ for (; *Supported != '\0' && *Supported == ';'; Supported++);
+ //
+ // Determine the length of the next language code in Supported
+ //
+ for (CompareLength = 0; Supported[CompareLength] != 0 && Supported[CompareLength] != ';'; CompareLength++);
+ //
+ // If Language is longer than the Supported, then skip to the next language
+ //
+ if (LanguageLength > CompareLength) {
+ continue;
+ }
+ }
+ //
+ // See if the first LanguageLength characters in Supported match Language
+ //
+ if (AsciiStrnCmp (Supported, Language, LanguageLength) == 0) {
+ VA_END (Args);
+
+ Buffer = Iso639Language ? mVariableModuleGlobal->Lang : mVariableModuleGlobal->PlatformLang[VirtualMode];
+ Buffer[CompareLength] = '\0';
+ return CopyMem (Buffer, Supported, CompareLength);
+ }
+ }
+
+ if (Iso639Language) {
+ //
+ // If ISO 639 mode, then each language can only be tested once
+ //
+ LanguageLength = 0;
+ } else {
+ //
+ // If RFC 4646 mode, then trim Language from the right to the next '-' character
+ //
+ for (LanguageLength--; LanguageLength > 0 && Language[LanguageLength] != '-'; LanguageLength--);
+ }
+ }
+ }
+ VA_END (Args);
+
+ //
+ // No matches were found
+ //
+ return NULL;
+}
+
+/**
+ Hook the operations in PlatformLangCodes, LangCodes, PlatformLang and Lang.
+
+ When setting Lang/LangCodes, simultaneously update PlatformLang/PlatformLangCodes.
+ According to UEFI spec, PlatformLangCodes/LangCodes are only set once in firmware initialization,
+ and are read-only. Therefore, in variable driver, only store the original value for other use.
+
+ @param[in] VariableName Name of variable.
+ @param[in] Data Variable data.
+ @param[in] DataSize Size of data. 0 means delete.
+ @param[in] VirtualMode Current calling mode for this function.
+ @param[in] Global Context of this Extended SAL Variable Services Class call.
+
+**/
+VOID
+AutoUpdateLangVariable(
+ IN CHAR16 *VariableName,
+ IN VOID *Data,
+ IN UINTN DataSize,
+ IN BOOLEAN VirtualMode,
+ IN ESAL_VARIABLE_GLOBAL *Global
+ )
+{
+ EFI_STATUS Status;
+ CHAR8 *BestPlatformLang;
+ CHAR8 *BestLang;
+ UINTN Index;
+ UINT32 Attributes;
+ VARIABLE_POINTER_TRACK Variable;
+ BOOLEAN SetLanguageCodes;
+ CHAR16 **PredefinedVariableName;
+ VARIABLE_GLOBAL *VariableGlobal;
+ UINT32 Instance;
+
+ //
+ // Don't do updates for delete operation
+ //
+ if (DataSize == 0) {
+ return;
+ }
+
+ SetLanguageCodes = FALSE;
+ VariableGlobal = &Global->VariableGlobal[VirtualMode];
+ Instance = Global->FvbInstance;
+
+
+ PredefinedVariableName = &Global->VariableName[VirtualMode][0];
+ if (StrCmp (VariableName, PredefinedVariableName[VAR_PLATFORM_LANG_CODES]) == 0) {
+ //
+ // PlatformLangCodes is a volatile variable, so it can not be updated at runtime.
+ //
+ if (EfiAtRuntime ()) {
+ return;
+ }
+
+ SetLanguageCodes = TRUE;
+
+ //
+ // According to UEFI spec, PlatformLangCodes is only set once in firmware initialization, and is read-only
+ // Therefore, in variable driver, only store the original value for other use.
+ //
+ if (Global->PlatformLangCodes[VirtualMode] != NULL) {
+ FreePool (Global->PlatformLangCodes[VirtualMode]);
+ }
+ Global->PlatformLangCodes[VirtualMode] = AllocateRuntimeCopyPool (DataSize, Data);
+ ASSERT (Global->PlatformLangCodes[VirtualMode] != NULL);
+
+ //
+ // PlatformLang holds a single language from PlatformLangCodes,
+ // so the size of PlatformLangCodes is enough for the PlatformLang.
+ //
+ if (Global->PlatformLang[VirtualMode] != NULL) {
+ FreePool (Global->PlatformLang[VirtualMode]);
+ }
+ Global->PlatformLang[VirtualMode] = AllocateRuntimePool (DataSize);
+ ASSERT (Global->PlatformLang[VirtualMode] != NULL);
+
+ } else if (StrCmp (VariableName, PredefinedVariableName[VAR_LANG_CODES]) == 0) {
+ //
+ // LangCodes is a volatile variable, so it can not be updated at runtime.
+ //
+ if (EfiAtRuntime ()) {
+ return;
+ }
+
+ SetLanguageCodes = TRUE;
+
+ //
+ // According to UEFI spec, LangCodes is only set once in firmware initialization, and is read-only
+ // Therefore, in variable driver, only store the original value for other use.
+ //
+ if (Global->LangCodes[VirtualMode] != NULL) {
+ FreePool (Global->LangCodes[VirtualMode]);
+ }
+ Global->LangCodes[VirtualMode] = AllocateRuntimeCopyPool (DataSize, Data);
+ ASSERT (Global->LangCodes[VirtualMode] != NULL);
+ }
+
+ if (SetLanguageCodes
+ && (Global->PlatformLangCodes[VirtualMode] != NULL)
+ && (Global->LangCodes[VirtualMode] != NULL)) {
+ //
+ // Update Lang if PlatformLang is already set
+ // Update PlatformLang if Lang is already set
+ //
+ Status = FindVariable (PredefinedVariableName[VAR_PLATFORM_LANG], Global->GlobalVariableGuid[VirtualMode], &Variable, VariableGlobal, Instance);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Update Lang
+ //
+ VariableName = PredefinedVariableName[VAR_PLATFORM_LANG];
+ } else {
+ Status = FindVariable (PredefinedVariableName[VAR_LANG], Global->GlobalVariableGuid[VirtualMode], &Variable, VariableGlobal, Instance);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Update PlatformLang
+ //
+ VariableName = PredefinedVariableName[VAR_LANG];
+ } else {
+ //
+ // Neither PlatformLang nor Lang is set, directly return
+ //
+ return;
+ }
+ }
+ Data = (VOID *) GetEndPointer (VariableGlobal->VolatileVariableBase, TRUE, VariableGlobal, Instance);
+ GetVariableDataPtr ((EFI_PHYSICAL_ADDRESS) Variable.CurrPtr, Variable.Volatile, VariableGlobal, Instance, (CHAR16 *) Data);
+
+ Status = AccessVariableStore (
+ FALSE,
+ VariableGlobal,
+ Variable.Volatile,
+ Instance,
+ (UINTN) &(((AUTHENTICATED_VARIABLE_HEADER *)Variable.CurrPtr)->DataSize),
+ sizeof (DataSize),
+ &DataSize
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ //
+ // According to UEFI spec, "Lang" and "PlatformLang" is NV|BS|RT attributions.
+ //
+ Attributes = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS;
+
+ if (StrCmp (VariableName, PredefinedVariableName[VAR_PLATFORM_LANG]) == 0) {
+ //
+ // Update Lang when PlatformLangCodes/LangCodes were set.
+ //
+ if ((Global->PlatformLangCodes[VirtualMode] != NULL) && (Global->LangCodes[VirtualMode] != NULL)) {
+ //
+ // When setting PlatformLang, firstly get most matched language string from supported language codes.
+ //
+ BestPlatformLang = VariableGetBestLanguage (Global->PlatformLangCodes[VirtualMode], FALSE, VirtualMode, Data, NULL);
+ if (BestPlatformLang != NULL) {
+ //
+ // Get the corresponding index in language codes.
+ //
+ Index = GetIndexFromSupportedLangCodes (Global->PlatformLangCodes[VirtualMode], BestPlatformLang, FALSE);
+
+ //
+ // Get the corresponding ISO639 language tag according to RFC4646 language tag.
+ //
+ BestLang = GetLangFromSupportedLangCodes (Global->LangCodes[VirtualMode], Index, TRUE, VirtualMode, Global);
+
+ //
+ // Successfully convert PlatformLang to Lang, and set the BestLang value into Lang variable simultaneously.
+ //
+ FindVariable (PredefinedVariableName[VAR_LANG], Global->GlobalVariableGuid[VirtualMode], &Variable, VariableGlobal, Instance);
+
+ Status = UpdateVariable (
+ PredefinedVariableName[VAR_LANG],
+ Global->GlobalVariableGuid[VirtualMode],
+ BestLang,
+ ISO_639_2_ENTRY_SIZE + 1,
+ Attributes,
+ 0,
+ 0,
+ VirtualMode,
+ Global,
+ &Variable
+ );
+
+ DEBUG ((EFI_D_INFO, "Variable Driver Auto Update PlatformLang, PlatformLang:%a, Lang:%a\n", BestPlatformLang, BestLang));
+
+ ASSERT_EFI_ERROR (Status);
+ }
+ }
+
+ } else if (StrCmp (VariableName, PredefinedVariableName[VAR_LANG]) == 0) {
+ //
+ // Update PlatformLang when PlatformLangCodes/LangCodes were set.
+ //
+ if ((Global->PlatformLangCodes[VirtualMode] != NULL) && (Global->LangCodes[VirtualMode] != NULL)) {
+ //
+ // When setting Lang, firstly get most matched language string from supported language codes.
+ //
+ BestLang = VariableGetBestLanguage (Global->LangCodes[VirtualMode], TRUE, VirtualMode, Data, NULL);
+ if (BestLang != NULL) {
+ //
+ // Get the corresponding index in language codes.
+ //
+ Index = GetIndexFromSupportedLangCodes (Global->LangCodes[VirtualMode], BestLang, TRUE);
+
+ //
+ // Get the corresponding RFC4646 language tag according to ISO639 language tag.
+ //
+ BestPlatformLang = GetLangFromSupportedLangCodes (Global->PlatformLangCodes[VirtualMode], Index, FALSE, VirtualMode, Global);
+
+ //
+ // Successfully convert Lang to PlatformLang, and set the BestPlatformLang value into PlatformLang variable simultaneously.
+ //
+ FindVariable (PredefinedVariableName[VAR_PLATFORM_LANG], Global->GlobalVariableGuid[VirtualMode], &Variable, VariableGlobal, Instance);
+
+ Status = UpdateVariable (
+ PredefinedVariableName[VAR_PLATFORM_LANG],
+ Global->GlobalVariableGuid[VirtualMode],
+ BestPlatformLang,
+ AsciiStrSize (BestPlatformLang),
+ Attributes,
+ 0,
+ 0,
+ VirtualMode,
+ Global,
+ &Variable
+ );
+
+ DEBUG ((EFI_D_INFO, "Variable Driver Auto Update Lang, Lang:%a, PlatformLang:%a\n", BestLang, BestPlatformLang));
+ ASSERT_EFI_ERROR (Status);
+ }
+ }
+ }
+}
+
+/**
+ Update the variable region with Variable information. These are the same
+ arguments as the EFI Variable services.
+
+ @param[in] VariableName Name of variable.
+ @param[in] VendorGuid Guid of variable.
+ @param[in] Data Variable data.
+ @param[in] DataSize Size of data. 0 means delete.
+ @param[in] Attributes Attributes of the variable.
+ @param[in] KeyIndex Index of associated public key.
+ @param[in] MonotonicCount Value of associated monotonic count.
+ @param[in] VirtualMode Current calling mode for this function.
+ @param[in] Global Context of this Extended SAL Variable Services Class call.
+ @param[in] Variable The variable information which is used to keep track of variable usage.
+
+ @retval EFI_SUCCESS The update operation is success.
+ @retval EFI_OUT_OF_RESOURCES Variable region is full, can not write other data into this region.
+
+**/
+EFI_STATUS
+EFIAPI
+UpdateVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN VOID *Data,
+ IN UINTN DataSize,
+ IN UINT32 Attributes OPTIONAL,
+ IN UINT32 KeyIndex OPTIONAL,
+ IN UINT64 MonotonicCount OPTIONAL,
+ IN BOOLEAN VirtualMode,
+ IN ESAL_VARIABLE_GLOBAL *Global,
+ IN VARIABLE_POINTER_TRACK *Variable
+ )
+{
+ EFI_STATUS Status;
+ AUTHENTICATED_VARIABLE_HEADER *NextVariable;
+ UINTN VarNameOffset;
+ UINTN VarDataOffset;
+ UINTN VarNameSize;
+ UINTN VarSize;
+ BOOLEAN Volatile;
+ UINT8 State;
+ AUTHENTICATED_VARIABLE_HEADER VariableHeader;
+ AUTHENTICATED_VARIABLE_HEADER *NextVariableHeader;
+ BOOLEAN Valid;
+ BOOLEAN Reclaimed;
+ VARIABLE_STORE_HEADER VariableStoreHeader;
+ UINTN ScratchSize;
+ VARIABLE_GLOBAL *VariableGlobal;
+ UINT32 Instance;
+
+ VariableGlobal = &Global->VariableGlobal[VirtualMode];
+ Instance = Global->FvbInstance;
+
+ Reclaimed = FALSE;
+
+ if (Variable->CurrPtr != 0) {
+
+ Valid = IsValidVariableHeader (Variable->CurrPtr, Variable->Volatile, VariableGlobal, Instance, &VariableHeader);
+ if (!Valid) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+
+ //
+ // Update/Delete existing variable
+ //
+ Volatile = Variable->Volatile;
+
+ if (EfiAtRuntime ()) {
+ //
+ // If EfiAtRuntime and the variable is Volatile and Runtime Access,
+ // the volatile is ReadOnly, and SetVariable should be aborted and
+ // return EFI_WRITE_PROTECTED.
+ //
+ if (Variable->Volatile) {
+ Status = EFI_WRITE_PROTECTED;
+ goto Done;
+ }
+ //
+ // Only variable have NV attribute can be updated/deleted in Runtime
+ //
+ if ((VariableHeader.Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ }
+ //
+ // Setting a data variable with no access, or zero DataSize attributes
+ // specified causes it to be deleted.
+ //
+ if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) {
+ State = VariableHeader.State;
+ State &= VAR_DELETED;
+
+ Status = AccessVariableStore (
+ TRUE,
+ VariableGlobal,
+ Variable->Volatile,
+ Instance,
+ (UINTN) &(((AUTHENTICATED_VARIABLE_HEADER *)Variable->CurrPtr)->State),
+ sizeof (UINT8),
+ &State
+ );
+ if (!EFI_ERROR (Status)) {
+ UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, FALSE, TRUE, FALSE);
+ UpdateVariableCache (VariableName, VendorGuid, Attributes, DataSize, Data);
+ }
+ goto Done;
+ }
+ //
+ // Logic comes here to update variable.
+ // If the variable is marked valid and the same data has been passed in
+ // then return to the caller immediately.
+ //
+ if (DataSizeOfVariable (&VariableHeader) == DataSize) {
+ NextVariable = (AUTHENTICATED_VARIABLE_HEADER *)GetEndPointer (VariableGlobal->VolatileVariableBase, TRUE, VariableGlobal, Instance);
+ GetVariableDataPtr (Variable->CurrPtr, Variable->Volatile, VariableGlobal, Instance, (CHAR16 *) NextVariable);
+ if (CompareMem (Data, (VOID *) NextVariable, DataSize) == 0) {
+ UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, TRUE, FALSE, FALSE);
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+ }
+ if ((VariableHeader.State == VAR_ADDED) ||
+ (VariableHeader.State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION))) {
+ //
+ // If new data is different from the old one, mark the old one as VAR_IN_DELETED_TRANSITION.
+ // It will be deleted if new variable is successfully written.
+ //
+ State = VariableHeader.State;
+ State &= VAR_IN_DELETED_TRANSITION;
+
+ Status = AccessVariableStore (
+ TRUE,
+ VariableGlobal,
+ Variable->Volatile,
+ Instance,
+ (UINTN) &(((AUTHENTICATED_VARIABLE_HEADER *)Variable->CurrPtr)->State),
+ sizeof (UINT8),
+ &State
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ }
+ } else {
+ //
+ // Create a new variable
+ //
+
+ //
+ // Make sure we are trying to create a new variable.
+ // Setting a data variable with no access, or zero DataSize attributes means to delete it.
+ //
+ if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+
+ //
+ // Only variable have NV|RT attribute can be created in Runtime
+ //
+ if (EfiAtRuntime () &&
+ (((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) || ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0))) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+ }
+
+ //
+ // Function part - create a new variable and copy the data.
+ // Both update a variable and create a variable will come here.
+ //
+ // Tricky part: Use scratch data area at the end of volatile variable store
+ // as a temporary storage.
+ //
+ NextVariable = (AUTHENTICATED_VARIABLE_HEADER *)GetEndPointer (VariableGlobal->VolatileVariableBase, TRUE, VariableGlobal, Instance);
+ ScratchSize = MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize));
+ NextVariableHeader = (AUTHENTICATED_VARIABLE_HEADER *) NextVariable;
+
+ SetMem (NextVariableHeader, ScratchSize, 0xff);
+
+ NextVariableHeader->StartId = VARIABLE_DATA;
+ NextVariableHeader->Attributes = Attributes;
+ NextVariableHeader->PubKeyIndex = KeyIndex;
+ NextVariableHeader->MonotonicCount = MonotonicCount;
+ NextVariableHeader->Reserved = 0;
+ VarNameOffset = sizeof (AUTHENTICATED_VARIABLE_HEADER);
+ VarNameSize = StrSize (VariableName);
+ CopyMem (
+ (UINT8 *) ((UINTN)NextVariable + VarNameOffset),
+ VariableName,
+ VarNameSize
+ );
+ VarDataOffset = VarNameOffset + VarNameSize + GET_PAD_SIZE (VarNameSize);
+ CopyMem (
+ (UINT8 *) ((UINTN)NextVariable + VarDataOffset),
+ Data,
+ DataSize
+ );
+ CopyMem (&NextVariableHeader->VendorGuid, VendorGuid, sizeof (EFI_GUID));
+ //
+ // There will be pad bytes after Data, the NextVariable->NameSize and
+ // NextVariable->DataSize should not include pad size so that variable
+ // service can get actual size in GetVariable.
+ //
+ NextVariableHeader->NameSize = (UINT32)VarNameSize;
+ NextVariableHeader->DataSize = (UINT32)DataSize;
+
+ //
+ // The actual size of the variable that stores in storage should
+ // include pad size.
+ //
+ VarSize = VarDataOffset + DataSize + GET_PAD_SIZE (DataSize);
+ if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
+ //
+ // Create a nonvolatile variable
+ //
+ Volatile = FALSE;
+
+ GetVarStoreHeader (VariableGlobal->NonVolatileVariableBase, FALSE, VariableGlobal, Instance, &VariableStoreHeader);
+ if ((((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0)
+ && ((HEADER_ALIGN (VarSize) + Global->HwErrVariableTotalSize) > PcdGet32(PcdHwErrStorageSize)))
+ || (((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0)
+ && ((HEADER_ALIGN (VarSize) + Global->CommonVariableTotalSize) > VariableStoreHeader.Size - sizeof (VARIABLE_STORE_HEADER) - PcdGet32(PcdHwErrStorageSize)))) {
+ if (EfiAtRuntime ()) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ //
+ // Perform garbage collection & reclaim operation
+ //
+ Status = Reclaim (VariableGlobal->NonVolatileVariableBase, &(Global->NonVolatileLastVariableOffset), FALSE, VirtualMode, Global, Variable->CurrPtr);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Reclaimed = TRUE;
+ //
+ // If still no enough space, return out of resources
+ //
+ if ((((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0)
+ && ((HEADER_ALIGN (VarSize) + Global->HwErrVariableTotalSize) > PcdGet32(PcdHwErrStorageSize)))
+ || (((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0)
+ && ((HEADER_ALIGN (VarSize) + Global->CommonVariableTotalSize) > VariableStoreHeader.Size - sizeof (VARIABLE_STORE_HEADER) - PcdGet32(PcdHwErrStorageSize)))) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ }
+ //
+ // Four steps
+ // 1. Write variable header
+ // 2. Set variable state to header valid
+ // 3. Write variable data
+ // 4. Set variable state to valid
+ //
+ //
+ // Step 1:
+ //
+ Status = AccessVariableStore (
+ TRUE,
+ VariableGlobal,
+ FALSE,
+ Instance,
+ VariableGlobal->NonVolatileVariableBase + Global->NonVolatileLastVariableOffset,
+ sizeof (AUTHENTICATED_VARIABLE_HEADER),
+ (UINT8 *) NextVariable
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Step 2:
+ //
+ NextVariableHeader->State = VAR_HEADER_VALID_ONLY;
+ Status = AccessVariableStore (
+ TRUE,
+ VariableGlobal,
+ FALSE,
+ Instance,
+ VariableGlobal->NonVolatileVariableBase + Global->NonVolatileLastVariableOffset,
+ sizeof (AUTHENTICATED_VARIABLE_HEADER),
+ (UINT8 *) NextVariable
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ //
+ // Step 3:
+ //
+ Status = AccessVariableStore (
+ TRUE,
+ VariableGlobal,
+ FALSE,
+ Instance,
+ VariableGlobal->NonVolatileVariableBase + Global->NonVolatileLastVariableOffset + sizeof (AUTHENTICATED_VARIABLE_HEADER),
+ (UINT32) VarSize - sizeof (AUTHENTICATED_VARIABLE_HEADER),
+ (UINT8 *) NextVariable + sizeof (AUTHENTICATED_VARIABLE_HEADER)
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ //
+ // Step 4:
+ //
+ NextVariableHeader->State = VAR_ADDED;
+ Status = AccessVariableStore (
+ TRUE,
+ VariableGlobal,
+ FALSE,
+ Instance,
+ VariableGlobal->NonVolatileVariableBase + Global->NonVolatileLastVariableOffset,
+ sizeof (AUTHENTICATED_VARIABLE_HEADER),
+ (UINT8 *) NextVariable
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Global->NonVolatileLastVariableOffset += HEADER_ALIGN (VarSize);
+
+ if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) {
+ Global->HwErrVariableTotalSize += HEADER_ALIGN (VarSize);
+ } else {
+ Global->CommonVariableTotalSize += HEADER_ALIGN (VarSize);
+ }
+ } else {
+ //
+ // Create a volatile variable
+ //
+ Volatile = TRUE;
+
+ if ((UINT32) (HEADER_ALIGN(VarSize) + Global->VolatileLastVariableOffset) >
+ ((VARIABLE_STORE_HEADER *) ((UINTN) (VariableGlobal->VolatileVariableBase)))->Size) {
+ //
+ // Perform garbage collection & reclaim operation
+ //
+ Status = Reclaim (VariableGlobal->VolatileVariableBase, &Global->VolatileLastVariableOffset, TRUE, VirtualMode, Global, Variable->CurrPtr);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ //
+ // If still no enough space, return out of resources
+ //
+ if ((UINT32) (HEADER_ALIGN (VarSize) + Global->VolatileLastVariableOffset) >
+ ((VARIABLE_STORE_HEADER *) ((UINTN) (VariableGlobal->VolatileVariableBase)))->Size
+ ) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ Reclaimed = TRUE;
+ }
+
+ NextVariableHeader->State = VAR_ADDED;
+ Status = AccessVariableStore (
+ TRUE,
+ VariableGlobal,
+ TRUE,
+ Instance,
+ VariableGlobal->VolatileVariableBase + Global->VolatileLastVariableOffset,
+ (UINT32) VarSize,
+ (UINT8 *) NextVariable
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Global->VolatileLastVariableOffset += HEADER_ALIGN (VarSize);
+ }
+ //
+ // Mark the old variable as deleted
+ // If storage has just been reclaimed, the old variable marked as VAR_IN_DELETED_TRANSITION
+ // has already been eliminated, so no need to delete it.
+ //
+ if (!Reclaimed && !EFI_ERROR (Status) && Variable->CurrPtr != 0) {
+ State = ((AUTHENTICATED_VARIABLE_HEADER *)Variable->CurrPtr)->State;
+ State &= VAR_DELETED;
+
+ Status = AccessVariableStore (
+ TRUE,
+ VariableGlobal,
+ Variable->Volatile,
+ Instance,
+ (UINTN) &(((AUTHENTICATED_VARIABLE_HEADER *)Variable->CurrPtr)->State),
+ sizeof (UINT8),
+ &State
+ );
+ }
+
+ if (!EFI_ERROR (Status)) {
+ UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, TRUE, FALSE, FALSE);
+ UpdateVariableCache (VariableName, VendorGuid, Attributes, DataSize, Data);
+ }
+
+Done:
+ return Status;
+}
+
+/**
+ Implements EsalGetVariable function of Extended SAL Variable Services Class.
+
+ This function implements EsalGetVariable function of Extended SAL Variable Services Class.
+ It is equivalent in functionality to the EFI Runtime Service GetVariable().
+
+ @param[in] VariableName A Null-terminated Unicode string that is the name of
+ the vendor's variable.
+ @param[in] VendorGuid A unique identifier for the vendor.
+ @param[out] Attributes If not NULL, a pointer to the memory location to return the
+ attributes bitmask for the variable.
+ @param[in, out] DataSize Size of Data found. If size is less than the
+ data, this value contains the required size.
+ @param[out] Data On input, the size in bytes of the return Data buffer.
+ On output, the size of data returned in Data.
+ @param[in] VirtualMode Current calling mode for this function.
+ @param[in] Global Context of this Extended SAL Variable Services Class call.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_NOT_FOUND The variable was not found.
+ @retval EFI_BUFFER_TOO_SMALL DataSize is too small for the result. DataSize has
+ been updated with the size needed to complete the request.
+ @retval EFI_INVALID_PARAMETER VariableName is NULL.
+ @retval EFI_INVALID_PARAMETER VendorGuid is NULL.
+ @retval EFI_INVALID_PARAMETER DataSize is NULL.
+ @retval EFI_INVALID_PARAMETER DataSize is not too small and Data is NULL.
+ @retval EFI_DEVICE_ERROR The variable could not be retrieved due to a hardware error.
+ @retval EFI_SECURITY_VIOLATION The variable could not be retrieved due to an authentication failure.
+
+**/
+EFI_STATUS
+EFIAPI
+EsalGetVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ OUT UINT32 *Attributes OPTIONAL,
+ IN OUT UINTN *DataSize,
+ OUT VOID *Data,
+ IN BOOLEAN VirtualMode,
+ IN ESAL_VARIABLE_GLOBAL *Global
+ )
+{
+ VARIABLE_POINTER_TRACK Variable;
+ UINTN VarDataSize;
+ EFI_STATUS Status;
+ AUTHENTICATED_VARIABLE_HEADER VariableHeader;
+ BOOLEAN Valid;
+ VARIABLE_GLOBAL *VariableGlobal;
+ UINT32 Instance;
+
+ if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ VariableGlobal = &Global->VariableGlobal[VirtualMode];
+ Instance = Global->FvbInstance;
+
+ AcquireLockOnlyAtBootTime(&VariableGlobal->VariableServicesLock);
+
+ //
+ // Check if this variable exists in cache.
+ //
+ Status = FindVariableInCache (VariableName, VendorGuid, Attributes, DataSize, Data);
+ if ((Status == EFI_BUFFER_TOO_SMALL) || (Status == EFI_SUCCESS)){
+ //
+ // If variable exists in cache, just update statistical information for it and finish.
+ // Here UpdateVariableInfo() has already retrieved data & attributes for output.
+ //
+ UpdateVariableInfo (VariableName, VendorGuid, FALSE, TRUE, FALSE, FALSE, TRUE);
+ goto Done;
+ }
+ //
+ // If variable does not exist in cache, search for it in variable storage area.
+ //
+ Status = FindVariable (VariableName, VendorGuid, &Variable, VariableGlobal, Instance);
+ if (Variable.CurrPtr == 0x0 || EFI_ERROR (Status)) {
+ //
+ // If it cannot be found in variable storage area, goto Done.
+ //
+ goto Done;
+ }
+
+ Valid = IsValidVariableHeader (Variable.CurrPtr, Variable.Volatile, VariableGlobal, Instance, &VariableHeader);
+ if (!Valid) {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+ //
+ // If variable exists, but not in cache, get its data and attributes, update
+ // statistical information, and update cache.
+ //
+ VarDataSize = DataSizeOfVariable (&VariableHeader);
+ ASSERT (VarDataSize != 0);
+
+ if (*DataSize >= VarDataSize) {
+ if (Data == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ goto Done;
+ }
+
+ GetVariableDataPtr (
+ Variable.CurrPtr,
+ Variable.Volatile,
+ VariableGlobal,
+ Instance,
+ Data
+ );
+ if (Attributes != NULL) {
+ *Attributes = VariableHeader.Attributes;
+ }
+
+ *DataSize = VarDataSize;
+ UpdateVariableInfo (VariableName, VendorGuid, Variable.Volatile, TRUE, FALSE, FALSE, FALSE);
+ UpdateVariableCache (VariableName, VendorGuid, VariableHeader.Attributes, VarDataSize, Data);
+
+ Status = EFI_SUCCESS;
+ goto Done;
+ } else {
+ //
+ // If DataSize is too small for the result, return EFI_BUFFER_TOO_SMALL.
+ //
+ *DataSize = VarDataSize;
+ Status = EFI_BUFFER_TOO_SMALL;
+ goto Done;
+ }
+
+Done:
+ ReleaseLockOnlyAtBootTime (&VariableGlobal->VariableServicesLock);
+ return Status;
+}
+
+/**
+ Implements EsalGetNextVariableName function of Extended SAL Variable Services Class.
+
+ This function implements EsalGetNextVariableName function of Extended SAL Variable Services Class.
+ It is equivalent in functionality to the EFI Runtime Service GetNextVariableName().
+
+ @param[in, out] VariableNameSize Size of the variable
+ @param[in, out] VariableName On input, supplies the last VariableName that was returned by GetNextVariableName().
+ On output, returns the Null-terminated Unicode string of the current variable.
+ @param[in, out] VendorGuid On input, supplies the last VendorGuid that was returned by GetNextVariableName().
+ On output, returns the VendorGuid of the current variable.
+ @param[in] VirtualMode Current calling mode for this function.
+ @param[in] Global Context of this Extended SAL Variable Services Class call.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_NOT_FOUND The next variable was not found.
+ @retval EFI_BUFFER_TOO_SMALL VariableNameSize is too small for the result.
+ VariableNameSize has been updated with the size needed to complete the request.
+ @retval EFI_INVALID_PARAMETER VariableNameSize is NULL.
+ @retval EFI_INVALID_PARAMETER VariableName is NULL.
+ @retval EFI_INVALID_PARAMETER VendorGuid is NULL.
+ @retval EFI_DEVICE_ERROR The variable name could not be retrieved due to a hardware error.
+
+**/
+EFI_STATUS
+EFIAPI
+EsalGetNextVariableName (
+ IN OUT UINTN *VariableNameSize,
+ IN OUT CHAR16 *VariableName,
+ IN OUT EFI_GUID *VendorGuid,
+ IN BOOLEAN VirtualMode,
+ IN ESAL_VARIABLE_GLOBAL *Global
+ )
+{
+ VARIABLE_POINTER_TRACK Variable;
+ UINTN VarNameSize;
+ EFI_STATUS Status;
+ AUTHENTICATED_VARIABLE_HEADER VariableHeader;
+ VARIABLE_GLOBAL *VariableGlobal;
+ UINT32 Instance;
+
+ if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ VariableGlobal = &Global->VariableGlobal[VirtualMode];
+ Instance = Global->FvbInstance;
+
+ AcquireLockOnlyAtBootTime(&VariableGlobal->VariableServicesLock);
+
+ Status = FindVariable (VariableName, VendorGuid, &Variable, VariableGlobal, Instance);
+ //
+ // If the variable does not exist, goto Done and return.
+ //
+ if (Variable.CurrPtr == 0x0 || EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ if (VariableName[0] != 0) {
+ //
+ // If variable name is not NULL, get next variable
+ //
+ Variable.CurrPtr = GetNextVariablePtr (
+ Variable.CurrPtr,
+ Variable.Volatile,
+ VariableGlobal,
+ Instance
+ );
+ }
+
+ while (TRUE) {
+ if (Variable.CurrPtr >= Variable.EndPtr || Variable.CurrPtr == 0x0) {
+ //
+ // If fail to find a variable in current area, reverse the volatile attribute of area to search.
+ //
+ Variable.Volatile = (BOOLEAN) (Variable.Volatile ^ ((BOOLEAN) 0x1));
+ //
+ // Here we depend on the searching sequence of FindVariable().
+ // It first searches volatile area, then NV area.
+ // So if the volatile attribute after switching is non-volatile, it means that we have finished searching volatile area,
+ // and EFI_NOT_FOUND is returnd.
+ // Otherwise, it means that we have finished searchig non-volatile area, and we will continue to search volatile area.
+ //
+ if (!Variable.Volatile) {
+ Variable.StartPtr = GetStartPointer (VariableGlobal->NonVolatileVariableBase);
+ Variable.EndPtr = GetEndPointer (VariableGlobal->NonVolatileVariableBase, FALSE, VariableGlobal, Instance);
+ } else {
+ Status = EFI_NOT_FOUND;
+ goto Done;
+ }
+
+ Variable.CurrPtr = Variable.StartPtr;
+ if (!IsValidVariableHeader (Variable.CurrPtr, Variable.Volatile, VariableGlobal, Instance, NULL)) {
+ continue;
+ }
+ }
+ //
+ // Variable is found
+ //
+ if (IsValidVariableHeader (Variable.CurrPtr, Variable.Volatile, VariableGlobal, Instance, &VariableHeader)) {
+ if ((VariableHeader.State == VAR_ADDED) &&
+ (!(EfiAtRuntime () && ((VariableHeader.Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)))) {
+ VarNameSize = NameSizeOfVariable (&VariableHeader);
+ ASSERT (VarNameSize != 0);
+
+ if (VarNameSize <= *VariableNameSize) {
+ GetVariableNamePtr (
+ Variable.CurrPtr,
+ Variable.Volatile,
+ VariableGlobal,
+ Instance,
+ VariableName
+ );
+ CopyMem (
+ VendorGuid,
+ &VariableHeader.VendorGuid,
+ sizeof (EFI_GUID)
+ );
+ Status = EFI_SUCCESS;
+ } else {
+ Status = EFI_BUFFER_TOO_SMALL;
+ }
+
+ *VariableNameSize = VarNameSize;
+ goto Done;
+ }
+ }
+
+ Variable.CurrPtr = GetNextVariablePtr (
+ Variable.CurrPtr,
+ Variable.Volatile,
+ VariableGlobal,
+ Instance
+ );
+ }
+
+Done:
+ ReleaseLockOnlyAtBootTime (&VariableGlobal->VariableServicesLock);
+ return Status;
+}
+
+/**
+ Implements EsalSetVariable function of Extended SAL Variable Services Class.
+
+ This function implements EsalSetVariable function of Extended SAL Variable Services Class.
+ It is equivalent in functionality to the EFI Runtime Service SetVariable().
+
+ @param[in] VariableName A Null-terminated Unicode string that is the name of the vendor's
+ variable. Each VariableName is unique for each
+ VendorGuid. VariableName must contain 1 or more
+ Unicode characters. If VariableName is an empty Unicode
+ string, then EFI_INVALID_PARAMETER is returned.
+ @param[in] VendorGuid A unique identifier for the vendor.
+ @param[in] Attributes Attributes bitmask to set for the variable.
+ @param[in] DataSize The size in bytes of the Data buffer. A size of zero causes the
+ variable to be deleted.
+ @param[in] Data The contents for the variable.
+ @param[in] VirtualMode Current calling mode for this function.
+ @param[in] Global Context of this Extended SAL Variable Services Class call.
+
+ @retval EFI_SUCCESS The firmware has successfully stored the variable and its data as
+ defined by the Attributes.
+ @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied, or the
+ DataSize exceeds the maximum allowed.
+ @retval EFI_INVALID_PARAMETER VariableName is an empty Unicode string.
+ @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 due to a hardware failure.
+ @retval EFI_WRITE_PROTECTED The variable in question is read-only.
+ @retval EFI_WRITE_PROTECTED The variable in question cannot be deleted.
+ @retval EFI_SECURITY_VIOLATION The variable could not be retrieved due to an authentication failure.
+ @retval EFI_NOT_FOUND The variable trying to be updated or deleted was not found.
+
+**/
+EFI_STATUS
+EFIAPI
+EsalSetVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT32 Attributes,
+ IN UINTN DataSize,
+ IN VOID *Data,
+ IN BOOLEAN VirtualMode,
+ IN ESAL_VARIABLE_GLOBAL *Global
+ )
+{
+ VARIABLE_POINTER_TRACK Variable;
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS NextVariable;
+ EFI_PHYSICAL_ADDRESS Point;
+ VARIABLE_GLOBAL *VariableGlobal;
+ UINT32 Instance;
+ UINT32 KeyIndex;
+ UINT64 MonotonicCount;
+ UINTN PayloadSize;
+
+ //
+ // Check input parameters
+ //
+ if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (DataSize != 0 && Data == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // EFI_VARIABLE_RUNTIME_ACCESS bit cannot be set without EFI_VARIABLE_BOOTSERVICE_ACCESS bit.
+ //
+ if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) {
+ if (DataSize < AUTHINFO_SIZE) {
+ //
+ // Try to write Authencated Variable without AuthInfo
+ //
+ return EFI_SECURITY_VIOLATION;
+ }
+ PayloadSize = DataSize - AUTHINFO_SIZE;
+ } else {
+ PayloadSize = DataSize;
+ }
+
+
+ if ((UINTN)(~0) - PayloadSize < StrSize(VariableName)){
+ //
+ // Prevent whole variable size overflow
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+
+ VariableGlobal = &Global->VariableGlobal[VirtualMode];
+ Instance = Global->FvbInstance;
+
+ if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
+ //
+ // For variable for hardware error record, the size of the VariableName, including the Unicode Null
+ // in bytes plus the DataSize is limited to maximum size of PcdGet32(PcdMaxHardwareErrorVariableSize) bytes.
+ //
+ if (StrSize (VariableName) + PayloadSize > PcdGet32(PcdMaxHardwareErrorVariableSize) - sizeof (AUTHENTICATED_VARIABLE_HEADER)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // According to UEFI spec, HARDWARE_ERROR_RECORD variable name convention should be L"HwErrRecXXXX"
+ //
+ if (StrnCmp (VariableName, \
+ Global->VariableName[VirtualMode][VAR_HW_ERR_REC], \
+ StrLen(Global->VariableName[VirtualMode][VAR_HW_ERR_REC])) != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+ } else {
+ //
+ // For variable not for hardware error record, the size of the VariableName, including the
+ // Unicode Null in bytes plus the DataSize is limited to maximum size of PcdGet32(PcdMaxVariableSize) bytes.
+ //
+ if (StrSize (VariableName) + PayloadSize > PcdGet32(PcdMaxVariableSize) - sizeof (AUTHENTICATED_VARIABLE_HEADER)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ AcquireLockOnlyAtBootTime(&VariableGlobal->VariableServicesLock);
+
+ //
+ // Consider reentrant in MCA/INIT/NMI. It needs be reupdated;
+ //
+ if (InterlockedIncrement (&Global->ReentrantState) > 1) {
+ Point = VariableGlobal->NonVolatileVariableBase;;
+ //
+ // Parse non-volatile variable data and get last variable offset
+ //
+ NextVariable = GetStartPointer (Point);
+ while (IsValidVariableHeader (NextVariable, FALSE, VariableGlobal, Instance, NULL)) {
+ NextVariable = GetNextVariablePtr (NextVariable, FALSE, VariableGlobal, Instance);
+ }
+ Global->NonVolatileLastVariableOffset = NextVariable - Point;
+ }
+
+ //
+ // Check whether the input variable exists
+ //
+
+ Status = FindVariable (VariableName, VendorGuid, &Variable, VariableGlobal, Instance);
+
+ //
+ // Hook the operation of setting PlatformLangCodes/PlatformLang and LangCodes/Lang
+ //
+ AutoUpdateLangVariable (VariableName, Data, PayloadSize, VirtualMode, Global);
+
+ //
+ // Process PK, KEK, Sigdb seperately
+ //
+ if (CompareGuid (VendorGuid, Global->GlobalVariableGuid[VirtualMode]) && (StrCmp (VariableName, Global->VariableName[VirtualMode][VAR_PLATFORM_KEY]) == 0)) {
+ Status = ProcessVarWithPk (VariableName, VendorGuid, Data, DataSize, VirtualMode, Global, &Variable, Attributes, TRUE);
+ } else if (CompareGuid (VendorGuid, Global->GlobalVariableGuid[VirtualMode]) && (StrCmp (VariableName, Global->VariableName[VirtualMode][VAR_KEY_EXCHANGE_KEY]) == 0)) {
+ Status = ProcessVarWithPk (VariableName, VendorGuid, Data, DataSize, VirtualMode, Global, &Variable, Attributes, FALSE);
+ } else if (CompareGuid (VendorGuid, Global->ImageSecurityDatabaseGuid[VirtualMode])) {
+ Status = ProcessVarWithKek (VariableName, VendorGuid, Data, DataSize, VirtualMode, Global, &Variable, Attributes);
+ } else {
+ Status = VerifyVariable (Data, DataSize, VirtualMode, Global, &Variable, Attributes, &KeyIndex, &MonotonicCount);
+ if (!EFI_ERROR(Status)) {
+ //
+ // Verification pass
+ //
+ if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {
+ //
+ // Cut the certificate size before set
+ //
+ Status = UpdateVariable (
+ VariableName,
+ VendorGuid,
+ (UINT8*)Data + AUTHINFO_SIZE,
+ DataSize - AUTHINFO_SIZE,
+ Attributes,
+ KeyIndex,
+ MonotonicCount,
+ VirtualMode,
+ Global,
+ &Variable
+ );
+ } else {
+ //
+ // Update variable as usual
+ //
+ Status = UpdateVariable (
+ VariableName,
+ VendorGuid,
+ Data,
+ DataSize,
+ Attributes,
+ 0,
+ 0,
+ VirtualMode,
+ Global,
+ &Variable
+ );
+ }
+ }
+ }
+
+ InterlockedDecrement (&Global->ReentrantState);
+ ReleaseLockOnlyAtBootTime (&VariableGlobal->VariableServicesLock);
+ return Status;
+}
+
+/**
+ Implements EsalQueryVariableInfo function of Extended SAL Variable Services Class.
+
+ This function implements EsalQueryVariableInfo function of Extended SAL Variable Services Class.
+ It is equivalent in functionality to the EFI Runtime Service QueryVariableInfo().
+
+ @param[in] Attributes Attributes bitmask to specify the type of variables
+ on which to return information.
+ @param[out] MaximumVariableStorageSize On output the maximum size of the storage space available for
+ the EFI variables associated with the attributes specified.
+ @param[out] RemainingVariableStorageSize Returns the remaining size of the storage space available for EFI
+ variables associated with the attributes specified.
+ @param[out] MaximumVariableSize Returns the maximum size of an individual EFI variable
+ associated with the attributes specified.
+ @param[in] VirtualMode Current calling mode for this function
+ @param[in] Global Context of this Extended SAL Variable Services Class call
+
+ @retval EFI_SUCCESS Valid answer returned.
+ @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied.
+ @retval EFI_UNSUPPORTED The attribute is not supported on this platform, and the
+ MaximumVariableStorageSize, RemainingVariableStorageSize,
+ MaximumVariableSize are undefined.
+**/
+EFI_STATUS
+EFIAPI
+EsalQueryVariableInfo (
+ IN UINT32 Attributes,
+ OUT UINT64 *MaximumVariableStorageSize,
+ OUT UINT64 *RemainingVariableStorageSize,
+ OUT UINT64 *MaximumVariableSize,
+ IN BOOLEAN VirtualMode,
+ IN ESAL_VARIABLE_GLOBAL *Global
+ )
+{
+ EFI_PHYSICAL_ADDRESS Variable;
+ EFI_PHYSICAL_ADDRESS NextVariable;
+ UINT64 VariableSize;
+ EFI_PHYSICAL_ADDRESS VariableStoreHeaderAddress;
+ BOOLEAN Volatile;
+ VARIABLE_STORE_HEADER VarStoreHeader;
+ AUTHENTICATED_VARIABLE_HEADER VariableHeader;
+ UINT64 CommonVariableTotalSize;
+ UINT64 HwErrVariableTotalSize;
+ VARIABLE_GLOBAL *VariableGlobal;
+ UINT32 Instance;
+
+ CommonVariableTotalSize = 0;
+ HwErrVariableTotalSize = 0;
+
+ if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == 0) {
+ //
+ // Make sure the Attributes combination is supported by the platform.
+ //
+ return EFI_UNSUPPORTED;
+ } else if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {
+ //
+ // Make sure if runtime bit is set, boot service bit is set also.
+ //
+ return EFI_INVALID_PARAMETER;
+ } else if (EfiAtRuntime () && ((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)) {
+ //
+ // Make sure RT Attribute is set if we are in Runtime phase.
+ //
+ return EFI_INVALID_PARAMETER;
+ } else if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
+ //
+ // Make sure Hw Attribute is set with NV.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+
+ VariableGlobal = &Global->VariableGlobal[VirtualMode];
+ Instance = Global->FvbInstance;
+
+ AcquireLockOnlyAtBootTime(&VariableGlobal->VariableServicesLock);
+
+ if((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {
+ //
+ // Query is Volatile related.
+ //
+ Volatile = TRUE;
+ VariableStoreHeaderAddress = VariableGlobal->VolatileVariableBase;
+ } else {
+ //
+ // Query is Non-Volatile related.
+ //
+ Volatile = FALSE;
+ VariableStoreHeaderAddress = VariableGlobal->NonVolatileVariableBase;
+ }
+
+ //
+ // Now let's fill *MaximumVariableStorageSize *RemainingVariableStorageSize
+ // with the storage size (excluding the storage header size).
+ //
+ GetVarStoreHeader (VariableStoreHeaderAddress, Volatile, VariableGlobal, Instance, &VarStoreHeader);
+
+ *MaximumVariableStorageSize = VarStoreHeader.Size - sizeof (VARIABLE_STORE_HEADER);
+
+ // Harware error record variable needs larger size.
+ //
+ if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
+ *MaximumVariableStorageSize = PcdGet32(PcdHwErrStorageSize);
+ *MaximumVariableSize = PcdGet32(PcdMaxHardwareErrorVariableSize) - sizeof (AUTHENTICATED_VARIABLE_HEADER);
+ } else {
+ if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
+ ASSERT (PcdGet32(PcdHwErrStorageSize) < VarStoreHeader.Size);
+ *MaximumVariableStorageSize = VarStoreHeader.Size - sizeof (VARIABLE_STORE_HEADER) - PcdGet32(PcdHwErrStorageSize);
+ }
+
+ //
+ // Let *MaximumVariableSize be PcdGet32(PcdMaxVariableSize) with the exception of the variable header size.
+ //
+ *MaximumVariableSize = PcdGet32(PcdMaxVariableSize) - sizeof (AUTHENTICATED_VARIABLE_HEADER);
+ }
+
+ //
+ // Point to the starting address of the variables.
+ //
+ Variable = GetStartPointer (VariableStoreHeaderAddress);
+
+ //
+ // Now walk through the related variable store.
+ //
+ while (IsValidVariableHeader (Variable, Volatile, VariableGlobal, Instance, &VariableHeader) &&
+ (Variable < GetEndPointer (VariableStoreHeaderAddress, Volatile, VariableGlobal, Instance))) {
+ NextVariable = GetNextVariablePtr (Variable, Volatile, VariableGlobal, Instance);
+ VariableSize = NextVariable - Variable;
+
+ if (EfiAtRuntime ()) {
+ //
+ // we don't take the state of the variables in mind
+ // when calculating RemainingVariableStorageSize,
+ // since the space occupied by variables not marked with
+ // VAR_ADDED is not allowed to be reclaimed in Runtime.
+ //
+ if ((VariableHeader.Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
+ HwErrVariableTotalSize += VariableSize;
+ } else {
+ CommonVariableTotalSize += VariableSize;
+ }
+ } else {
+ //
+ // Only care about Variables with State VAR_ADDED,because
+ // the space not marked as VAR_ADDED is reclaimable now.
+ //
+ if (VariableHeader.State == VAR_ADDED) {
+ if ((VariableHeader.Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
+ HwErrVariableTotalSize += VariableSize;
+ } else {
+ CommonVariableTotalSize += VariableSize;
+ }
+ }
+ }
+
+ //
+ // Go to the next one
+ //
+ Variable = NextVariable;
+ }
+
+ if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD){
+ *RemainingVariableStorageSize = *MaximumVariableStorageSize - HwErrVariableTotalSize;
+ }else {
+ *RemainingVariableStorageSize = *MaximumVariableStorageSize - CommonVariableTotalSize;
+ }
+
+ if (*RemainingVariableStorageSize < sizeof (AUTHENTICATED_VARIABLE_HEADER)) {
+ *MaximumVariableSize = 0;
+ } else if ((*RemainingVariableStorageSize - sizeof (AUTHENTICATED_VARIABLE_HEADER)) < *MaximumVariableSize) {
+ *MaximumVariableSize = *RemainingVariableStorageSize - sizeof (AUTHENTICATED_VARIABLE_HEADER);
+ }
+
+ ReleaseLockOnlyAtBootTime (&VariableGlobal->VariableServicesLock);
+ return EFI_SUCCESS;
+}
+
+/**
+ Notification function of EVT_GROUP_READY_TO_BOOT event group.
+
+ This is a notification function registered on EVT_GROUP_READY_TO_BOOT event group.
+ When the Boot Manager is about to load and execute a boot option, it reclaims variable
+ storage if free size is below the threshold.
+
+ @param[in] Event Event whose notification function is being invoked.
+ @param[in] Context Pointer to the notification function's context.
+
+**/
+VOID
+EFIAPI
+ReclaimForOS(
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ UINT32 VarSize;
+ EFI_STATUS Status;
+ UINTN CommonVariableSpace;
+ UINTN RemainingCommonVariableSpace;
+ UINTN RemainingHwErrVariableSpace;
+
+ VarSize = ((VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase))->Size;
+ Status = EFI_SUCCESS;
+ //
+ //Allowable max size of common variable storage space
+ //
+ CommonVariableSpace = VarSize - sizeof (VARIABLE_STORE_HEADER) - PcdGet32(PcdHwErrStorageSize);
+
+ RemainingCommonVariableSpace = CommonVariableSpace - mVariableModuleGlobal->CommonVariableTotalSize;
+
+ RemainingHwErrVariableSpace = PcdGet32 (PcdHwErrStorageSize) - mVariableModuleGlobal->HwErrVariableTotalSize;
+ //
+ // If the free area is below a threshold, then performs reclaim operation.
+ //
+ if ((RemainingCommonVariableSpace < PcdGet32 (PcdMaxVariableSize))
+ || ((PcdGet32 (PcdHwErrStorageSize) != 0) &&
+ (RemainingHwErrVariableSpace < PcdGet32 (PcdMaxHardwareErrorVariableSize)))){
+ Status = Reclaim (
+ mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase,
+ &mVariableModuleGlobal->NonVolatileLastVariableOffset,
+ FALSE,
+ Physical,
+ mVariableModuleGlobal,
+ 0x0
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+}
+
+/**
+ Flush the HOB variable to NV variable storage.
+**/
+VOID
+FlushHob2Nv (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ VOID *GuidHob;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+ AUTHENTICATED_VARIABLE_HEADER *VariableHeader;
+ //
+ // Get HOB variable store.
+ //
+ GuidHob = GetFirstGuidHob (&gEfiAuthenticatedVariableGuid);
+ if (GuidHob != NULL) {
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *) GET_GUID_HOB_DATA (GuidHob);
+ if (CompareGuid (&VariableStoreHeader->Signature, &gEfiAuthenticatedVariableGuid) &&
+ (VariableStoreHeader->Format == VARIABLE_STORE_FORMATTED) &&
+ (VariableStoreHeader->State == VARIABLE_STORE_HEALTHY)
+ ) {
+ DEBUG ((EFI_D_INFO, "HOB Variable Store appears to be valid.\n"));
+ //
+ // Flush the HOB variable to NV Variable storage.
+ //
+ for ( VariableHeader = (AUTHENTICATED_VARIABLE_HEADER *) HEADER_ALIGN (VariableStoreHeader + 1)
+ ; (VariableHeader < (AUTHENTICATED_VARIABLE_HEADER *) HEADER_ALIGN ((UINTN) VariableStoreHeader + VariableStoreHeader->Size)
+ &&
+ (VariableHeader->StartId == VARIABLE_DATA))
+ ; VariableHeader = (AUTHENTICATED_VARIABLE_HEADER *) HEADER_ALIGN ((UINTN) (VariableHeader + 1)
+ + VariableHeader->NameSize + GET_PAD_SIZE (VariableHeader->NameSize)
+ + VariableHeader->DataSize + GET_PAD_SIZE (VariableHeader->DataSize)
+ )
+ ) {
+ ASSERT (VariableHeader->State == VAR_ADDED);
+ ASSERT ((VariableHeader->Attributes & EFI_VARIABLE_NON_VOLATILE) != 0);
+ Status = EsalSetVariable (
+ (CHAR16 *) (VariableHeader + 1),
+ &VariableHeader->VendorGuid,
+ VariableHeader->Attributes,
+ VariableHeader->DataSize,
+ (UINT8 *) (VariableHeader + 1) + VariableHeader->NameSize + GET_PAD_SIZE (VariableHeader->NameSize),
+ Physical,
+ mVariableModuleGlobal
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+ }
+ }
+}
+
+/**
+ Initializes variable store area for non-volatile and volatile variable.
+
+ This function allocates and initializes memory space for global context of ESAL
+ variable service and variable store area for non-volatile and volatile variable.
+
+ @param[in] ImageHandle The Image handle of this driver.
+ @param[in] SystemTable The pointer of EFI_SYSTEM_TABLE.
+
+ @retval EFI_SUCCESS Function successfully executed.
+ @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
+
+**/
+EFI_STATUS
+VariableCommonInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
+ EFI_PHYSICAL_ADDRESS CurrPtr;
+ VARIABLE_STORE_HEADER *VolatileVariableStore;
+ VARIABLE_STORE_HEADER *VariableStoreHeader;
+ EFI_PHYSICAL_ADDRESS Variable;
+ EFI_PHYSICAL_ADDRESS NextVariable;
+ UINTN VariableSize;
+ UINT32 Instance;
+ EFI_PHYSICAL_ADDRESS FvVolHdr;
+ EFI_PHYSICAL_ADDRESS TempVariableStoreHeader;
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor;
+ UINT64 BaseAddress;
+ UINT64 Length;
+ UINTN Index;
+ UINT8 Data;
+ EFI_PHYSICAL_ADDRESS VariableStoreBase;
+ UINT64 VariableStoreLength;
+ EFI_EVENT ReadyToBootEvent;
+ UINTN ScratchSize;
+
+ //
+ // Allocate memory for mVariableModuleGlobal
+ //
+ mVariableModuleGlobal = AllocateRuntimeZeroPool (sizeof (ESAL_VARIABLE_GLOBAL));
+ if (mVariableModuleGlobal == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ mVariableModuleGlobal->GlobalVariableGuid[Physical] = &gEfiGlobalVariableGuid;
+ CopyMem (
+ mVariableModuleGlobal->VariableName[Physical],
+ mVariableName,
+ sizeof (mVariableName)
+ );
+
+ EfiInitializeLock(&mVariableModuleGlobal->VariableGlobal[Physical].VariableServicesLock, TPL_NOTIFY);
+
+ //
+ // Note that in EdkII variable driver implementation, Hardware Error Record type variable
+ // is stored with common variable in the same NV region. So the platform integrator should
+ // ensure that the value of PcdHwErrStorageSize is less than or equal to the value of
+ // PcdFlashNvStorageVariableSize.
+ //
+ ASSERT (PcdGet32(PcdHwErrStorageSize) <= PcdGet32 (PcdFlashNvStorageVariableSize));
+
+ //
+ // Allocate memory for volatile variable store
+ //
+ ScratchSize = MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize));
+ VolatileVariableStore = AllocateRuntimePool (PcdGet32 (PcdVariableStoreSize) + ScratchSize);
+ if (VolatileVariableStore == NULL) {
+ FreePool (mVariableModuleGlobal);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ SetMem (VolatileVariableStore, PcdGet32 (PcdVariableStoreSize) + ScratchSize, 0xff);
+
+ //
+ // Variable Specific Data
+ //
+ mVariableModuleGlobal->VariableGlobal[Physical].VolatileVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VolatileVariableStore;
+ mVariableModuleGlobal->VolatileLastVariableOffset = (UINTN) GetStartPointer ((EFI_PHYSICAL_ADDRESS) VolatileVariableStore) - (UINTN) VolatileVariableStore;
+
+ CopyGuid (&VolatileVariableStore->Signature, &gEfiAuthenticatedVariableGuid);
+ VolatileVariableStore->Size = PcdGet32 (PcdVariableStoreSize);
+ VolatileVariableStore->Format = VARIABLE_STORE_FORMATTED;
+ VolatileVariableStore->State = VARIABLE_STORE_HEALTHY;
+ VolatileVariableStore->Reserved = 0;
+ VolatileVariableStore->Reserved1 = 0;
+
+ //
+ // Get non volatile varaible store
+ //
+ TempVariableStoreHeader = (UINT64) PcdGet32 (PcdFlashNvStorageVariableBase);
+ VariableStoreBase = TempVariableStoreHeader + \
+ (((EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) (TempVariableStoreHeader)) -> HeaderLength);
+ VariableStoreLength = (UINT64) PcdGet32 (PcdFlashNvStorageVariableSize) - \
+ (((EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) (TempVariableStoreHeader)) -> HeaderLength);
+ //
+ // Mark the variable storage region of the FLASH as RUNTIME
+ //
+ BaseAddress = VariableStoreBase & (~EFI_PAGE_MASK);
+ Length = VariableStoreLength + (VariableStoreBase - BaseAddress);
+ Length = (Length + EFI_PAGE_SIZE - 1) & (~EFI_PAGE_MASK);
+
+ Status = gDS->GetMemorySpaceDescriptor (BaseAddress, &GcdDescriptor);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = gDS->SetMemorySpaceAttributes (
+ BaseAddress,
+ Length,
+ GcdDescriptor.Attributes | EFI_MEMORY_RUNTIME
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ //
+ // Get address of non volatile variable store base.
+ //
+ mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase = VariableStoreBase;
+
+ //
+ // Check Integrity
+ //
+ //
+ // Find the Correct Instance of the FV Block Service.
+ //
+ Instance = 0;
+ CurrPtr = mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase;
+
+ do {
+ FvVolHdr = 0;
+ Status = (EFI_STATUS) EsalCall (
+ EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID_LO,
+ EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID_HI,
+ GetPhysicalAddressFunctionId,
+ Instance,
+ (UINT64) &FvVolHdr,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ ).Status;
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvVolHdr);
+ ASSERT (FwVolHeader != NULL);
+ if (CurrPtr >= (EFI_PHYSICAL_ADDRESS) FwVolHeader &&
+ CurrPtr < ((EFI_PHYSICAL_ADDRESS) FwVolHeader + FwVolHeader->FvLength)) {
+ mVariableModuleGlobal->FvbInstance = Instance;
+ break;
+ }
+
+ Instance++;
+ } while (Status == EFI_SUCCESS);
+
+ VariableStoreHeader = (VARIABLE_STORE_HEADER *) CurrPtr;
+ if (GetVariableStoreStatus (VariableStoreHeader) == EfiValid) {
+ if (~VariableStoreHeader->Size == 0) {
+ Status = AccessVariableStore (
+ TRUE,
+ &mVariableModuleGlobal->VariableGlobal[Physical],
+ FALSE,
+ mVariableModuleGlobal->FvbInstance,
+ (UINTN) &VariableStoreHeader->Size,
+ sizeof (UINT32),
+ (UINT8 *) &VariableStoreLength
+ );
+ //
+ // As Variables are stored in NV storage, which are slow devices,such as flash.
+ // Variable operation may skip checking variable program result to improve performance,
+ // We can assume Variable program is OK through some check point.
+ // Variable Store Size Setting should be the first Variable write operation,
+ // We can assume all Read/Write is OK if we can set Variable store size successfully.
+ // If write fail, we will assert here.
+ //
+ ASSERT(VariableStoreHeader->Size == VariableStoreLength);
+
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ }
+
+ mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase = (EFI_PHYSICAL_ADDRESS) ((UINTN) CurrPtr);
+ //
+ // Parse non-volatile variable data and get last variable offset.
+ //
+ Variable = GetStartPointer (CurrPtr);
+ Status = EFI_SUCCESS;
+
+ while (IsValidVariableHeader (Variable, FALSE, &(mVariableModuleGlobal->VariableGlobal[Physical]), Instance, NULL)) {
+ NextVariable = GetNextVariablePtr (
+ Variable,
+ FALSE,
+ &(mVariableModuleGlobal->VariableGlobal[Physical]),
+ Instance
+ );
+ VariableSize = NextVariable - Variable;
+ if ((((AUTHENTICATED_VARIABLE_HEADER *)Variable)->Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
+ mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize;
+ } else {
+ mVariableModuleGlobal->CommonVariableTotalSize += VariableSize;
+ }
+
+ Variable = NextVariable;
+ }
+
+ mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) Variable - (UINTN) CurrPtr;
+
+ //
+ // Check if the free area is really free.
+ //
+ for (Index = mVariableModuleGlobal->NonVolatileLastVariableOffset; Index < VariableStoreHeader->Size; Index++) {
+ Data = ((UINT8 *) (UINTN) mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase)[Index];
+ if (Data != 0xff) {
+ //
+ // There must be something wrong in variable store, do reclaim operation.
+ //
+ Status = Reclaim (
+ mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase,
+ &mVariableModuleGlobal->NonVolatileLastVariableOffset,
+ FALSE,
+ Physical,
+ mVariableModuleGlobal,
+ 0x0
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ break;
+ }
+ }
+
+ //
+ // Register the event handling function to reclaim variable for OS usage.
+ //
+ Status = EfiCreateEventReadyToBootEx (
+ TPL_NOTIFY,
+ ReclaimForOS,
+ NULL,
+ &ReadyToBootEvent
+ );
+ } else {
+ Status = EFI_VOLUME_CORRUPTED;
+ DEBUG((EFI_D_ERROR, "Variable Store header is corrupted\n"));
+ }
+
+Done:
+ if (EFI_ERROR (Status)) {
+ FreePool (mVariableModuleGlobal);
+ FreePool (VolatileVariableStore);
+ }
+
+ return Status;
+}
diff --git a/Core/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/Variable.h b/Core/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/Variable.h
new file mode 100644
index 0000000000..b32ef741bf
--- /dev/null
+++ b/Core/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/Variable.h
@@ -0,0 +1,505 @@
+/** @file
+ Internal header file for Extended SAL variable service module.
+
+Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _VARIABLE_H_
+#define _VARIABLE_H_
+
+#include <PiDxe.h>
+
+#include <Protocol/VariableWrite.h>
+#include <Protocol/FaultTolerantWrite.h>
+#include <Protocol/FirmwareVolumeBlock.h>
+#include <Protocol/Variable.h>
+#include <Protocol/ExtendedSalBootService.h>
+#include <Protocol/ExtendedSalServiceClasses.h>
+
+#include <Guid/GlobalVariable.h>
+#include <Guid/AuthenticatedVariableFormat.h>
+#include <Guid/ImageAuthentication.h>
+#include <Guid/EventGroup.h>
+
+#include <Library/PcdLib.h>
+#include <Library/HobLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/UefiRuntimeLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseLib.h>
+#include <Library/SynchronizationLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/ExtendedSalLib.h>
+#include <Library/BaseCryptLib.h>
+
+#define MAX_NAME_SIZE 0x100
+#define NUM_VAR_NAME 9 // Number of pre-defined variable name to be referenced
+#define VAR_PLATFORM_LANG_CODES 0 // Index of "PlatformLangCodes" variable
+#define VAR_LANG_CODES 1 // Index of "LangCodes" variable
+#define VAR_PLATFORM_LANG 2 // Index of "PlatformLang" variable
+#define VAR_LANG 3 // Index of "Lang" variable
+#define VAR_HW_ERR_REC 4 // Index of "HwErrRecXXXX" variable
+#define VAR_AUTH_KEY_DB 5 // Index of "AuthVarKeyDatabase" variable
+#define VAR_SETUP_MODE 6 // Index of "SetupMode" variable
+#define VAR_PLATFORM_KEY 7 // Index of "PK" variable
+#define VAR_KEY_EXCHANGE_KEY 8 // Index of "KEK" variable
+
+///
+/// "AuthVarKeyDatabase" variable for the Public Key store.
+///
+#define AUTHVAR_KEYDB_NAME L"AuthVarKeyDatabase"
+#define AUTHVAR_KEYDB_NAME_SIZE 38
+
+///
+/// The maximum size of the public key database, restricted by maximum individal EFI
+/// varible size, and excluding the variable header and name size.
+///
+#define MAX_KEYDB_SIZE (FixedPcdGet32 (PcdMaxVariableSize) - sizeof (AUTHENTICATED_VARIABLE_HEADER) - AUTHVAR_KEYDB_NAME_SIZE)
+#define MAX_KEY_NUM (MAX_KEYDB_SIZE / EFI_CERT_TYPE_RSA2048_SIZE)
+
+///
+/// The size of a 3 character ISO639 language code.
+///
+#define ISO_639_2_ENTRY_SIZE 3
+
+typedef enum {
+ Physical,
+ Virtual
+} VARIABLE_POINTER_TYPE;
+
+typedef struct {
+ EFI_PHYSICAL_ADDRESS CurrPtr;
+ EFI_PHYSICAL_ADDRESS EndPtr;
+ EFI_PHYSICAL_ADDRESS StartPtr;
+ BOOLEAN Volatile;
+} VARIABLE_POINTER_TRACK;
+
+typedef struct {
+ EFI_PHYSICAL_ADDRESS VolatileVariableBase;
+ EFI_PHYSICAL_ADDRESS NonVolatileVariableBase;
+ EFI_LOCK VariableServicesLock;
+} VARIABLE_GLOBAL;
+
+typedef struct {
+ VARIABLE_GLOBAL VariableGlobal[2];
+ CHAR16 *VariableName[2][NUM_VAR_NAME];
+ EFI_GUID *GlobalVariableGuid[2];
+ UINTN VolatileLastVariableOffset;
+ UINTN NonVolatileLastVariableOffset;
+ UINTN CommonVariableTotalSize;
+ UINTN HwErrVariableTotalSize;
+ CHAR8 *PlatformLangCodes[2];
+ CHAR8 *LangCodes[2];
+ CHAR8 *PlatformLang[2];
+ CHAR8 Lang[ISO_639_2_ENTRY_SIZE + 1];
+ UINT32 FvbInstance;
+ UINT32 ReentrantState;
+ EFI_GUID *AuthenticatedVariableGuid[2];
+ EFI_GUID *CertRsa2048Sha256Guid[2];
+ EFI_GUID *ImageSecurityDatabaseGuid[2];
+ VOID *HashContext[2]; // Hash context pointer
+ UINT8 KeyList[MAX_KEYDB_SIZE]; // Cached Platform Key list
+ UINT8 PubKeyStore[MAX_KEYDB_SIZE]; // Cached Public Key list
+} ESAL_VARIABLE_GLOBAL;
+
+typedef struct {
+ EFI_GUID *Guid;
+ CHAR16 *Name;
+ UINT32 Attributes;
+ UINTN DataSize;
+ VOID *Data;
+} VARIABLE_CACHE_ENTRY;
+
+
+extern ESAL_VARIABLE_GLOBAL *mVariableModuleGlobal;
+
+//
+// Functions
+//
+
+/**
+ Initializes variable store area for non-volatile and volatile variable.
+
+ This function allocates and initializes memory space for global context of ESAL
+ variable service and variable store area for non-volatile and volatile variable.
+
+ @param[in] ImageHandle The Image handle of this driver.
+ @param[in] SystemTable The pointer of EFI_SYSTEM_TABLE.
+
+ @retval EFI_SUCCESS Function successfully executed.
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate enough memory resource.
+
+**/
+EFI_STATUS
+VariableCommonInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+/**
+ Entry point of Extended SAL Variable service module.
+
+ This function is the entry point of Extended SAL Variable service module.
+ It registers all functions of Extended SAL Variable class, initializes
+ variable store for non-volatile and volatile variables, and registers
+ notification function for EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
+
+ @param[in] ImageHandle The Image handle of this driver.
+ @param[in] SystemTable The pointer of EFI_SYSTEM_TABLE.
+
+ @retval EFI_SUCCESS Extended SAL Variable Services Class successfully registered.
+
+**/
+EFI_STATUS
+EFIAPI
+VariableServiceInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+/**
+ Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.
+
+ This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
+ It convers pointer to new virtual address.
+
+ @param[in] Event The event whose notification function is being invoked.
+ @param[in] Context The pointer to the notification function's context.
+
+**/
+VOID
+EFIAPI
+VariableClassAddressChangeEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ Implements EsalGetVariable function of Extended SAL Variable Services Class.
+
+ This function implements EsalGetVariable function of Extended SAL Variable Services Class.
+ It is equivalent in functionality to the EFI Runtime Service GetVariable().
+
+ @param[in] VariableName A Null-terminated Unicode string that is the name of
+ the vendor's variable.
+ @param[in] VendorGuid A unique identifier for the vendor.
+ @param[out] Attributes If not NULL, a pointer to the memory location to return the
+ attributes bitmask for the variable.
+ @param[in, out] DataSize Size of Data found. If size is less than the
+ data, this value contains the required size.
+ @param[out] Data On input, the size in bytes of the return Data buffer.
+ On output, the size of data returned in Data.
+ @param[in] VirtualMode Current calling mode for this function.
+ @param[in] Global Context of this Extended SAL Variable Services Class call.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_NOT_FOUND The variable was not found.
+ @retval EFI_BUFFER_TOO_SMALL DataSize is too small for the result. DataSize has
+ been updated with the size needed to complete the request.
+ @retval EFI_INVALID_PARAMETER VariableName is NULL.
+ @retval EFI_INVALID_PARAMETER VendorGuid is NULL.
+ @retval EFI_INVALID_PARAMETER DataSize is NULL.
+ @retval EFI_INVALID_PARAMETER DataSize is not too small and Data is NULL.
+ @retval EFI_DEVICE_ERROR The variable could not be retrieved due to a hardware error.
+ @retval EFI_SECURITY_VIOLATION The variable could not be retrieved due to an authentication failure.
+
+**/
+EFI_STATUS
+EFIAPI
+EsalGetVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ OUT UINT32 *Attributes OPTIONAL,
+ IN OUT UINTN *DataSize,
+ OUT VOID *Data,
+ IN BOOLEAN VirtualMode,
+ IN ESAL_VARIABLE_GLOBAL *Global
+ );
+
+/**
+ Implements EsalGetNextVariableName function of Extended SAL Variable Services Class.
+
+ This function implements EsalGetNextVariableName function of Extended SAL Variable Services Class.
+ It is equivalent in functionality to the EFI Runtime Service GetNextVariableName().
+
+ @param[in, out] VariableNameSize Size of the variable
+ @param[in, out] VariableName On input, supplies the last VariableName that was returned by GetNextVariableName().
+ On output, returns the Null-terminated Unicode string of the current variable.
+ @param[in, out] VendorGuid On input, supplies the last VendorGuid that was returned by GetNextVariableName().
+ On output, returns the VendorGuid of the current variable.
+ @param[in] VirtualMode Current calling mode for this function.
+ @param[in] Global Context of this Extended SAL Variable Services Class call.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_NOT_FOUND The next variable was not found.
+ @retval EFI_BUFFER_TOO_SMALL VariableNameSize is too small for the result.
+ VariableNameSize has been updated with the size needed to complete the request.
+ @retval EFI_INVALID_PARAMETER VariableNameSize is NULL.
+ @retval EFI_INVALID_PARAMETER VariableName is NULL.
+ @retval EFI_INVALID_PARAMETER VendorGuid is NULL.
+ @retval EFI_DEVICE_ERROR The variable name could not be retrieved due to a hardware error.
+
+**/
+EFI_STATUS
+EFIAPI
+EsalGetNextVariableName (
+ IN OUT UINTN *VariableNameSize,
+ IN OUT CHAR16 *VariableName,
+ IN OUT EFI_GUID *VendorGuid,
+ IN BOOLEAN VirtualMode,
+ IN ESAL_VARIABLE_GLOBAL *Global
+ );
+
+/**
+ Implements EsalSetVariable function of Extended SAL Variable Services Class.
+
+ This function implements EsalSetVariable function of Extended SAL Variable Services Class.
+ It is equivalent in functionality to the EFI Runtime Service SetVariable().
+
+ @param[in] VariableName A Null-terminated Unicode string that is the name of the vendor's
+ variable. Each VariableName is unique for each
+ VendorGuid. VariableName must contain 1 or more
+ Unicode characters. If VariableName is an empty Unicode
+ string, then EFI_INVALID_PARAMETER is returned.
+ @param[in] VendorGuid A unique identifier for the vendor.
+ @param[in] Attributes Attributes bitmask to set for the variable.
+ @param[in] DataSize The size in bytes of the Data buffer. A size of zero causes the
+ variable to be deleted.
+ @param[in] Data The contents for the variable.
+ @param[in] VirtualMode Current calling mode for this function.
+ @param[in] Global Context of this Extended SAL Variable Services Class call.
+
+ @retval EFI_SUCCESS The firmware has successfully stored the variable and its data as
+ defined by the Attributes.
+ @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied, or the
+ DataSize exceeds the maximum allowed.
+ @retval EFI_INVALID_PARAMETER VariableName is an empty Unicode string.
+ @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 due to a hardware failure.
+ @retval EFI_WRITE_PROTECTED The variable in question is read-only.
+ @retval EFI_WRITE_PROTECTED The variable in question cannot be deleted.
+ @retval EFI_SECURITY_VIOLATION The variable could not be retrieved due to an authentication failure.
+ @retval EFI_NOT_FOUND The variable trying to be updated or deleted was not found.
+
+**/
+EFI_STATUS
+EFIAPI
+EsalSetVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT32 Attributes,
+ IN UINTN DataSize,
+ IN VOID *Data,
+ IN BOOLEAN VirtualMode,
+ IN ESAL_VARIABLE_GLOBAL *Global
+ );
+
+/**
+ Implements EsalQueryVariableInfo function of Extended SAL Variable Services Class.
+
+ This function implements EsalQueryVariableInfo function of Extended SAL Variable Services Class.
+ It is equivalent in functionality to the EFI Runtime Service QueryVariableInfo().
+
+ @param[in] Attributes Attributes bitmask to specify the type of variables
+ on which to return information.
+ @param[out] MaximumVariableStorageSize On output the maximum size of the storage space available for
+ the EFI variables associated with the attributes specified.
+ @param[out] RemainingVariableStorageSize Returns the remaining size of the storage space available for EFI
+ variables associated with the attributes specified.
+ @param[out] MaximumVariableSize Returns the maximum size of an individual EFI variable
+ associated with the attributes specified.
+ @param[in] VirtualMode Current calling mode for this function
+ @param[in] Global Context of this Extended SAL Variable Services Class call
+
+ @retval EFI_SUCCESS Valid answer returned.
+ @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied.
+ @retval EFI_UNSUPPORTED The attribute is not supported on this platform, and the
+ MaximumVariableStorageSize, RemainingVariableStorageSize,
+ MaximumVariableSize are undefined.
+**/
+EFI_STATUS
+EFIAPI
+EsalQueryVariableInfo (
+ IN UINT32 Attributes,
+ OUT UINT64 *MaximumVariableStorageSize,
+ OUT UINT64 *RemainingVariableStorageSize,
+ OUT UINT64 *MaximumVariableSize,
+ IN BOOLEAN VirtualMode,
+ IN ESAL_VARIABLE_GLOBAL *Global
+ );
+
+/**
+ Writes a buffer to variable storage space.
+
+ This function writes a buffer to variable storage space into firmware
+ volume block device. The destination is specified by parameter
+ VariableBase. Fault Tolerant Write protocol is used for writing.
+
+ @param[in] VariableBase The base address of the variable to write.
+ @param[in] Buffer Points to the data buffer.
+ @param[in] BufferSize The number of bytes of the data Buffer.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_NOT_FOUND Fail to locate Fault Tolerant Write protocol.
+ @retval Other The function could not complete successfully.
+
+**/
+EFI_STATUS
+FtwVariableSpace (
+ IN EFI_PHYSICAL_ADDRESS VariableBase,
+ IN UINT8 *Buffer,
+ IN UINTN BufferSize
+ );
+
+/**
+ Finds variable in volatile and non-volatile storage areas.
+
+ This code finds variable in volatile and non-volatile storage areas.
+ If VariableName is an empty string, then we just return the first
+ qualified variable without comparing VariableName and VendorGuid.
+ Otherwise, VariableName and VendorGuid are compared.
+
+ @param[in] VariableName Name of the variable to be found.
+ @param[in] VendorGuid Vendor GUID to be found.
+ @param[out] PtrTrack VARIABLE_POINTER_TRACK structure for output,
+ including the range searched and the target position.
+ @param[in] Global Pointer to VARIABLE_GLOBAL structure, including
+ base of volatile variable storage area, base of
+ NV variable storage area, and a lock.
+ @param[in] Instance Instance of FV Block services.
+
+ @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, while
+ VendorGuid is NULL.
+ @retval EFI_SUCCESS Variable successfully found.
+ @retval EFI_INVALID_PARAMETER Variable not found.
+
+**/
+EFI_STATUS
+FindVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ OUT VARIABLE_POINTER_TRACK *PtrTrack,
+ IN VARIABLE_GLOBAL *Global,
+ IN UINTN Instance
+ );
+
+/**
+ Gets the pointer to variable data area.
+
+ This function gets the pointer to variable data area.
+ The variable is specified by its variable header.
+
+ @param[in] VariableAddress Start address of variable header.
+ @param[in] Volatile TRUE - Variable is volatile.
+ FALSE - Variable is non-volatile.
+ @param[in] Global Pointer to VARAIBLE_GLOBAL structure.
+ @param[in] Instance Instance of FV Block services.
+ @param[out] VariableData Buffer to hold variable data for output.
+
+**/
+VOID
+GetVariableDataPtr (
+ IN EFI_PHYSICAL_ADDRESS VariableAddress,
+ IN BOOLEAN Volatile,
+ IN VARIABLE_GLOBAL *Global,
+ IN UINTN Instance,
+ OUT CHAR16 *VariableData
+ );
+
+/**
+ Gets the size of variable data area.
+
+ This function gets the size of variable data area.
+ The variable is specified by its variable header.
+ If variable header contains raw data, just return 0.
+
+ @param[in] Variable Pointer to the variable header.
+
+ @return Size of variable data area in bytes.
+
+**/
+UINTN
+DataSizeOfVariable (
+ IN AUTHENTICATED_VARIABLE_HEADER *Variable
+ );
+
+/**
+ Update the variable region with Variable information. These are the same
+ arguments as the EFI Variable services.
+
+ @param[in] VariableName Name of variable.
+ @param[in] VendorGuid Guid of variable.
+ @param[in] Data Variable data.
+ @param[in] DataSize Size of data. 0 means delete.
+ @param[in] Attributes Attributes of the variable.
+ @param[in] KeyIndex Index of associated public key.
+ @param[in] MonotonicCount Value of associated monotonic count.
+ @param[in] VirtualMode Current calling mode for this function.
+ @param[in] Global Context of this Extended SAL Variable Services Class call.
+ @param[in] Variable The variable information which is used to keep track of variable usage.
+
+ @retval EFI_SUCCESS The update operation is success.
+ @retval EFI_OUT_OF_RESOURCES Variable region is full, can not write other data into this region.
+
+**/
+EFI_STATUS
+EFIAPI
+UpdateVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN VOID *Data,
+ IN UINTN DataSize,
+ IN UINT32 Attributes OPTIONAL,
+ IN UINT32 KeyIndex OPTIONAL,
+ IN UINT64 MonotonicCount OPTIONAL,
+ IN BOOLEAN VirtualMode,
+ IN ESAL_VARIABLE_GLOBAL *Global,
+ IN VARIABLE_POINTER_TRACK *Variable
+ );
+
+/**
+ Checks variable header.
+
+ This function checks if variable header is valid or not.
+
+ @param[in] VariableAddress Start address of variable header.
+ @param[in] Volatile TRUE - Variable is volatile.
+ FALSE - Variable is non-volatile.
+ @param[in] Global Pointer to VARAIBLE_GLOBAL structure.
+ @param[in] Instance Instance of FV Block services.
+ @param[out] VariableHeader Pointer to AUTHENTICATED_VARIABLE_HEADER for output.
+
+ @retval TRUE Variable header is valid.
+ @retval FALSE Variable header is not valid.
+
+**/
+BOOLEAN
+IsValidVariableHeader (
+ IN EFI_PHYSICAL_ADDRESS VariableAddress,
+ IN BOOLEAN Volatile,
+ IN VARIABLE_GLOBAL *Global,
+ IN UINTN Instance,
+ OUT AUTHENTICATED_VARIABLE_HEADER *VariableHeader OPTIONAL
+ );
+
+/**
+ Flush the HOB variable to NV variable storage.
+**/
+VOID
+FlushHob2Nv (
+ VOID
+ );
+
+#endif
diff --git a/Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfig.vfr b/Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfig.vfr
new file mode 100644
index 0000000000..bbecff2b08
--- /dev/null
+++ b/Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfig.vfr
@@ -0,0 +1,570 @@
+/** @file
+ VFR file used by the SecureBoot configuration component.
+
+Copyright (c) 2011 - 2017, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "SecureBootConfigNvData.h"
+
+formset
+ guid = SECUREBOOT_CONFIG_FORM_SET_GUID,
+ title = STRING_TOKEN(STR_SECUREBOOT_TITLE),
+ help = STRING_TOKEN(STR_SECUREBOOT_HELP),
+ classguid = EFI_HII_PLATFORM_SETUP_FORMSET_GUID,
+
+ varstore SECUREBOOT_CONFIGURATION,
+ varid = SECUREBOOT_CONFIGURATION_VARSTORE_ID,
+ name = SECUREBOOT_CONFIGURATION,
+ guid = SECUREBOOT_CONFIG_FORM_SET_GUID;
+
+ //
+ // ##1 Form "Secure Boot Configuration"
+ //
+ form formid = SECUREBOOT_CONFIGURATION_FORM_ID,
+ title = STRING_TOKEN(STR_SECUREBOOT_TITLE);
+
+ subtitle text = STRING_TOKEN(STR_NULL);
+
+ text
+ help = STRING_TOKEN(STR_SECURE_BOOT_STATE_HELP),
+ text = STRING_TOKEN(STR_SECURE_BOOT_STATE_PROMPT),
+ text = STRING_TOKEN(STR_SECURE_BOOT_STATE_CONTENT);
+
+ //
+ // Display of Check Box: Attempt Secure Boot
+ //
+ grayoutif ideqval SECUREBOOT_CONFIGURATION.HideSecureBoot == 1 OR NOT ideqval SECUREBOOT_CONFIGURATION.PhysicalPresent == 1;
+ checkbox varid = SECUREBOOT_CONFIGURATION.AttemptSecureBoot,
+ questionid = KEY_SECURE_BOOT_ENABLE,
+ prompt = STRING_TOKEN(STR_SECURE_BOOT_PROMPT),
+ help = STRING_TOKEN(STR_SECURE_BOOT_HELP),
+ flags = INTERACTIVE | RESET_REQUIRED,
+ endcheckbox;
+ endif;
+
+ //
+ // Display of Oneof: 'Secure Boot Mode'
+ //
+ oneof name = SecureBootMode,
+ questionid = KEY_SECURE_BOOT_MODE,
+ prompt = STRING_TOKEN(STR_SECURE_BOOT_MODE_PROMPT),
+ help = STRING_TOKEN(STR_SECURE_BOOT_MODE_HELP),
+ flags = INTERACTIVE | NUMERIC_SIZE_1,
+ option text = STRING_TOKEN(STR_STANDARD_MODE), value = SECURE_BOOT_MODE_STANDARD, flags = DEFAULT;
+ option text = STRING_TOKEN(STR_CUSTOM_MODE), value = SECURE_BOOT_MODE_CUSTOM, flags = 0;
+ endoneof;
+
+ //
+ // Display of 'Current Secure Boot Mode'
+ //
+ suppressif questionref(SecureBootMode) == SECURE_BOOT_MODE_STANDARD;
+ grayoutif NOT ideqval SECUREBOOT_CONFIGURATION.PhysicalPresent == 1;
+ goto FORMID_SECURE_BOOT_OPTION_FORM,
+ prompt = STRING_TOKEN(STR_SECURE_BOOT_OPTION),
+ help = STRING_TOKEN(STR_SECURE_BOOT_OPTION_HELP),
+ flags = INTERACTIVE,
+ key = KEY_SECURE_BOOT_OPTION;
+ endif;
+ endif;
+
+ endform;
+
+ //
+ // ##2 Form: 'Custom Secure Boot Options'
+ //
+ form formid = FORMID_SECURE_BOOT_OPTION_FORM,
+ title = STRING_TOKEN(STR_SECURE_BOOT_OPTION_TITLE);
+
+ subtitle text = STRING_TOKEN(STR_NULL);
+
+ goto FORMID_SECURE_BOOT_PK_OPTION_FORM,
+ prompt = STRING_TOKEN(STR_SECURE_BOOT_PK_OPTION),
+ help = STRING_TOKEN(STR_SECURE_BOOT_PK_OPTION_HELP),
+ flags = INTERACTIVE,
+ key = KEY_SECURE_BOOT_PK_OPTION;
+
+ subtitle text = STRING_TOKEN(STR_NULL);
+
+ goto FORMID_SECURE_BOOT_KEK_OPTION_FORM,
+ prompt = STRING_TOKEN(STR_SECURE_BOOT_KEK_OPTION),
+ help = STRING_TOKEN(STR_SECURE_BOOT_KEK_OPTION_HELP),
+ flags = INTERACTIVE,
+ key = KEY_SECURE_BOOT_KEK_OPTION;
+
+ subtitle text = STRING_TOKEN(STR_NULL);
+
+ goto FORMID_SECURE_BOOT_DB_OPTION_FORM,
+ prompt = STRING_TOKEN(STR_SECURE_BOOT_DB_OPTION),
+ help = STRING_TOKEN(STR_SECURE_BOOT_DB_OPTION_HELP),
+ flags = INTERACTIVE,
+ key = KEY_SECURE_BOOT_DB_OPTION;
+
+ subtitle text = STRING_TOKEN(STR_NULL);
+
+ goto FORMID_SECURE_BOOT_DBX_OPTION_FORM,
+ prompt = STRING_TOKEN(STR_SECURE_BOOT_DBX_OPTION),
+ help = STRING_TOKEN(STR_SECURE_BOOT_DBX_OPTION_HELP),
+ flags = INTERACTIVE,
+ key = KEY_SECURE_BOOT_DBX_OPTION;
+
+ subtitle text = STRING_TOKEN(STR_NULL);
+
+ goto FORMID_SECURE_BOOT_DBT_OPTION_FORM,
+ prompt = STRING_TOKEN(STR_SECURE_BOOT_DBT_OPTION),
+ help = STRING_TOKEN(STR_SECURE_BOOT_DBT_OPTION_HELP),
+ flags = INTERACTIVE,
+ key = KEY_SECURE_BOOT_DBT_OPTION;
+
+ endform;
+
+ //
+ // ##3 Form: 'PK Options'
+ //
+ form formid = FORMID_SECURE_BOOT_PK_OPTION_FORM,
+ title = STRING_TOKEN(STR_SECURE_BOOT_PK_OPTION);
+
+ subtitle text = STRING_TOKEN(STR_NULL);
+
+ //
+ // Display of 'Enroll PK'
+ //
+ grayoutif ideqval SECUREBOOT_CONFIGURATION.HasPk == 1;
+ goto FORMID_ENROLL_PK_FORM,
+ prompt = STRING_TOKEN(STR_ENROLL_PK),
+ help = STRING_TOKEN(STR_ENROLL_PK_HELP),
+ flags = INTERACTIVE,
+ key = KEY_ENROLL_PK;
+ endif;
+
+ subtitle text = STRING_TOKEN(STR_NULL);
+
+ //
+ // Display of Check Box: 'Delete Pk'
+ //
+ grayoutif ideqval SECUREBOOT_CONFIGURATION.HideSecureBoot == 1;
+ checkbox varid = SECUREBOOT_CONFIGURATION.DeletePk,
+ questionid = KEY_SECURE_BOOT_DELETE_PK,
+ prompt = STRING_TOKEN(STR_DELETE_PK),
+ help = STRING_TOKEN(STR_DELETE_PK_HELP),
+ flags = INTERACTIVE | RESET_REQUIRED,
+ endcheckbox;
+ endif;
+ endform;
+
+ //
+ // ##4 Form: 'Enroll PK'
+ //
+ form formid = FORMID_ENROLL_PK_FORM,
+ title = STRING_TOKEN(STR_ENROLL_PK);
+
+ subtitle text = STRING_TOKEN(STR_NULL);
+
+ goto FORMID_ENROLL_PK_FORM,
+ prompt = STRING_TOKEN(STR_SECURE_BOOT_ENROLL_PK_FILE),
+ help = STRING_TOKEN(STR_SECURE_BOOT_ENROLL_PK_FILE),
+ flags = INTERACTIVE,
+ key = FORMID_ENROLL_PK_FORM;
+
+ subtitle text = STRING_TOKEN(STR_NULL);
+ label FORMID_ENROLL_PK_FORM;
+ label LABEL_END;
+ subtitle text = STRING_TOKEN(STR_NULL);
+
+ goto FORMID_SECURE_BOOT_OPTION_FORM,
+ prompt = STRING_TOKEN(STR_SAVE_AND_EXIT),
+ help = STRING_TOKEN(STR_SAVE_AND_EXIT),
+ flags = INTERACTIVE| RESET_REQUIRED,
+ key = KEY_VALUE_SAVE_AND_EXIT_PK;
+
+ goto FORMID_SECURE_BOOT_OPTION_FORM,
+ prompt = STRING_TOKEN(STR_NO_SAVE_AND_EXIT),
+ help = STRING_TOKEN(STR_NO_SAVE_AND_EXIT),
+ flags = INTERACTIVE,
+ key = KEY_VALUE_NO_SAVE_AND_EXIT_PK;
+
+ endform;
+
+ //
+ // ##5 Form: 'KEK Options'
+ //
+ form formid = FORMID_SECURE_BOOT_KEK_OPTION_FORM,
+ title = STRING_TOKEN(STR_SECURE_BOOT_KEK_OPTION);
+
+ //
+ // Display of 'Enroll KEK'
+ //
+ goto FORMID_ENROLL_KEK_FORM,
+ prompt = STRING_TOKEN(STR_ENROLL_KEK),
+ help = STRING_TOKEN(STR_ENROLL_KEK_HELP),
+ flags = INTERACTIVE;
+
+ subtitle text = STRING_TOKEN(STR_NULL);
+
+ //
+ // Display of 'Delete KEK'
+ //
+ goto FORMID_DELETE_KEK_FORM,
+ prompt = STRING_TOKEN(STR_DELETE_KEK),
+ help = STRING_TOKEN(STR_DELETE_KEK_HELP),
+ flags = INTERACTIVE,
+ key = KEY_DELETE_KEK;
+
+ subtitle text = STRING_TOKEN(STR_NULL);
+ endform;
+
+ //
+ // ##6 Form: 'Enroll KEK'
+ //
+ form formid = FORMID_ENROLL_KEK_FORM,
+ title = STRING_TOKEN(STR_ENROLL_KEK_TITLE);
+
+ subtitle text = STRING_TOKEN(STR_NULL);
+
+ goto FORMID_ENROLL_KEK_FORM,
+ prompt = STRING_TOKEN(STR_FORM_ENROLL_KEK_FROM_FILE_TITLE),
+ help = STRING_TOKEN(STR_FORM_ENROLL_KEK_FROM_FILE_TITLE_HELP),
+ flags = INTERACTIVE,
+ key = FORMID_ENROLL_KEK_FORM;
+
+ subtitle text = STRING_TOKEN(STR_NULL);
+ label FORMID_ENROLL_KEK_FORM;
+ label LABEL_END;
+ subtitle text = STRING_TOKEN(STR_NULL);
+
+ string varid = SECUREBOOT_CONFIGURATION.SignatureGuid,
+ prompt = STRING_TOKEN(STR_SECURE_BOOT_SIGNATURE_GUID),
+ help = STRING_TOKEN(STR_SECURE_BOOT_SIGNATURE_GUID_HELP),
+ flags = INTERACTIVE,
+ key = KEY_SECURE_BOOT_KEK_GUID,
+ minsize = SECURE_BOOT_GUID_SIZE,
+ maxsize = SECURE_BOOT_GUID_SIZE,
+ endstring;
+
+ subtitle text = STRING_TOKEN(STR_NULL);
+ subtitle text = STRING_TOKEN(STR_NULL);
+
+ goto FORMID_SECURE_BOOT_OPTION_FORM,
+ prompt = STRING_TOKEN(STR_SAVE_AND_EXIT),
+ help = STRING_TOKEN(STR_SAVE_AND_EXIT),
+ flags = INTERACTIVE,
+ key = KEY_VALUE_SAVE_AND_EXIT_KEK;
+
+ goto FORMID_SECURE_BOOT_OPTION_FORM,
+ prompt = STRING_TOKEN(STR_NO_SAVE_AND_EXIT),
+ help = STRING_TOKEN(STR_NO_SAVE_AND_EXIT),
+ flags = INTERACTIVE,
+ key = KEY_VALUE_NO_SAVE_AND_EXIT_KEK;
+
+ endform;
+
+ //
+ // ##7 Form: 'Delete KEK'
+ //
+ form formid = FORMID_DELETE_KEK_FORM,
+ title = STRING_TOKEN(STR_DELETE_KEK_TITLE);
+
+ label LABEL_KEK_DELETE;
+ label LABEL_END;
+
+ subtitle text = STRING_TOKEN(STR_NULL);
+
+ endform;
+
+ //
+ // ##8 Form: 'DB Options'
+ //
+ form formid = FORMID_SECURE_BOOT_DB_OPTION_FORM,
+ title = STRING_TOKEN(STR_SECURE_BOOT_DB_OPTION);
+
+ subtitle text = STRING_TOKEN(STR_NULL);
+
+ goto SECUREBOOT_ENROLL_SIGNATURE_TO_DB,
+ prompt = STRING_TOKEN (STR_SECURE_BOOT_ENROLL_SIGNATURE),
+ help = STRING_TOKEN (STR_SECURE_BOOT_ENROLL_SIGNATURE),
+ flags = 0;
+
+ subtitle text = STRING_TOKEN(STR_NULL);
+
+ goto SECUREBOOT_DELETE_SIGNATURE_FROM_DB,
+ prompt = STRING_TOKEN (STR_SECURE_BOOT_DELETE_SIGNATURE),
+ help = STRING_TOKEN (STR_SECURE_BOOT_DELETE_SIGNATURE),
+ flags = INTERACTIVE,
+ key = SECUREBOOT_DELETE_SIGNATURE_FROM_DB;
+
+ endform;
+
+ //
+ // ##9 Form: 'DBX Options'
+ //
+ form formid = FORMID_SECURE_BOOT_DBX_OPTION_FORM,
+ title = STRING_TOKEN(STR_SECURE_BOOT_DBX_OPTION);
+
+ subtitle text = STRING_TOKEN(STR_NULL);
+
+ goto SECUREBOOT_ENROLL_SIGNATURE_TO_DBX,
+ prompt = STRING_TOKEN (STR_SECURE_BOOT_ENROLL_SIGNATURE),
+ help = STRING_TOKEN (STR_SECURE_BOOT_ENROLL_SIGNATURE),
+ flags = 0;
+
+ subtitle text = STRING_TOKEN(STR_NULL);
+
+ goto SECUREBOOT_DELETE_SIGNATURE_FROM_DBX,
+ prompt = STRING_TOKEN (STR_SECURE_BOOT_DELETE_SIGNATURE),
+ help = STRING_TOKEN (STR_SECURE_BOOT_DELETE_SIGNATURE),
+ flags = INTERACTIVE,
+ key = SECUREBOOT_DELETE_SIGNATURE_FROM_DBX;
+
+ endform;
+
+ //
+ // ##9 Form: 'DBT Options'
+ //
+ form formid = FORMID_SECURE_BOOT_DBT_OPTION_FORM,
+ title = STRING_TOKEN(STR_SECURE_BOOT_DBT_OPTION);
+
+ subtitle text = STRING_TOKEN(STR_NULL);
+
+ goto SECUREBOOT_ENROLL_SIGNATURE_TO_DBT,
+ prompt = STRING_TOKEN (STR_SECURE_BOOT_ENROLL_SIGNATURE),
+ help = STRING_TOKEN (STR_SECURE_BOOT_ENROLL_SIGNATURE),
+ flags = 0;
+
+ subtitle text = STRING_TOKEN(STR_NULL);
+
+ goto SECUREBOOT_DELETE_SIGNATURE_FROM_DBT,
+ prompt = STRING_TOKEN (STR_SECURE_BOOT_DELETE_SIGNATURE),
+ help = STRING_TOKEN (STR_SECURE_BOOT_DELETE_SIGNATURE),
+ flags = INTERACTIVE,
+ key = SECUREBOOT_DELETE_SIGNATURE_FROM_DBT;
+
+ endform;
+
+ //
+ // Form: 'Delete Signature' for DB Options.
+ //
+ form formid = SECUREBOOT_DELETE_SIGNATURE_FROM_DB,
+ title = STRING_TOKEN(STR_SECURE_BOOT_DELETE_SIGNATURE);
+
+ label LABEL_DB_DELETE;
+ label LABEL_END;
+ subtitle text = STRING_TOKEN(STR_NULL);
+
+ endform;
+
+ //
+ // Form: 'Delete Signature' for DBX Options.
+ //
+ form formid = SECUREBOOT_DELETE_SIGNATURE_FROM_DBX,
+ title = STRING_TOKEN(STR_SECURE_BOOT_DELETE_SIGNATURE);
+
+ label LABEL_DBX_DELETE;
+ label LABEL_END;
+ subtitle text = STRING_TOKEN(STR_NULL);
+
+ endform;
+
+ //
+ // Form: 'Delete Signature' for DBT Options.
+ //
+ form formid = SECUREBOOT_DELETE_SIGNATURE_FROM_DBT,
+ title = STRING_TOKEN(STR_SECURE_BOOT_DELETE_SIGNATURE);
+
+ label LABEL_DBT_DELETE;
+ label LABEL_END;
+ subtitle text = STRING_TOKEN(STR_NULL);
+
+ endform;
+
+ //
+ // Form: 'Enroll Signature' for DB options.
+ //
+ form formid = SECUREBOOT_ENROLL_SIGNATURE_TO_DB,
+ title = STRING_TOKEN(STR_SECURE_BOOT_ENROLL_SIGNATURE);
+
+ subtitle text = STRING_TOKEN(STR_NULL);
+
+ goto SECUREBOOT_ENROLL_SIGNATURE_TO_DB,
+ prompt = STRING_TOKEN(STR_SECURE_BOOT_ADD_SIGNATURE_FILE),
+ help = STRING_TOKEN(STR_SECURE_BOOT_ADD_SIGNATURE_FILE),
+ flags = INTERACTIVE,
+ key = SECUREBOOT_ENROLL_SIGNATURE_TO_DB;
+
+ subtitle text = STRING_TOKEN(STR_NULL);
+ label SECUREBOOT_ENROLL_SIGNATURE_TO_DB;
+ label LABEL_END;
+ subtitle text = STRING_TOKEN(STR_NULL);
+
+ string varid = SECUREBOOT_CONFIGURATION.SignatureGuid,
+ prompt = STRING_TOKEN(STR_SECURE_BOOT_SIGNATURE_GUID),
+ help = STRING_TOKEN(STR_SECURE_BOOT_SIGNATURE_GUID_HELP),
+ flags = INTERACTIVE,
+ key = KEY_SECURE_BOOT_SIGNATURE_GUID_DB,
+ minsize = SECURE_BOOT_GUID_SIZE,
+ maxsize = SECURE_BOOT_GUID_SIZE,
+ endstring;
+
+ subtitle text = STRING_TOKEN(STR_NULL);
+ subtitle text = STRING_TOKEN(STR_NULL);
+
+ goto FORMID_SECURE_BOOT_OPTION_FORM,
+ prompt = STRING_TOKEN(STR_SAVE_AND_EXIT),
+ help = STRING_TOKEN(STR_SAVE_AND_EXIT),
+ flags = INTERACTIVE,
+ key = KEY_VALUE_SAVE_AND_EXIT_DB;
+
+ goto FORMID_SECURE_BOOT_OPTION_FORM,
+ prompt = STRING_TOKEN(STR_NO_SAVE_AND_EXIT),
+ help = STRING_TOKEN(STR_NO_SAVE_AND_EXIT),
+ flags = INTERACTIVE,
+ key = KEY_VALUE_NO_SAVE_AND_EXIT_DB;
+
+ endform;
+
+ //
+ // Form: 'Enroll Signature' for DBX options.
+ //
+ form formid = SECUREBOOT_ENROLL_SIGNATURE_TO_DBX,
+ title = STRING_TOKEN(STR_SECURE_BOOT_ENROLL_SIGNATURE);
+
+ subtitle text = STRING_TOKEN(STR_NULL);
+
+ goto SECUREBOOT_ENROLL_SIGNATURE_TO_DBX,
+ prompt = STRING_TOKEN(STR_SECURE_BOOT_ADD_SIGNATURE_FILE),
+ help = STRING_TOKEN(STR_SECURE_BOOT_ADD_SIGNATURE_FILE),
+ flags = INTERACTIVE,
+ key = SECUREBOOT_ENROLL_SIGNATURE_TO_DBX;
+
+ label SECUREBOOT_ENROLL_SIGNATURE_TO_DBX;
+ label LABEL_END;
+ subtitle text = STRING_TOKEN(STR_NULL);
+
+ grayoutif ideqval SECUREBOOT_CONFIGURATION.FileEnrollType == 3;
+ string varid = SECUREBOOT_CONFIGURATION.SignatureGuid,
+ prompt = STRING_TOKEN(STR_SECURE_BOOT_SIGNATURE_GUID),
+ help = STRING_TOKEN(STR_SECURE_BOOT_SIGNATURE_GUID_HELP),
+ flags = INTERACTIVE,
+ key = KEY_SECURE_BOOT_SIGNATURE_GUID_DBX,
+ minsize = SECURE_BOOT_GUID_SIZE,
+ maxsize = SECURE_BOOT_GUID_SIZE,
+ endstring;
+ endif;
+
+ disableif NOT ideqval SECUREBOOT_CONFIGURATION.FileEnrollType == 1;
+ oneof name = X509SignatureFormatInDbx,
+ varid = SECUREBOOT_CONFIGURATION.CertificateFormat,
+ prompt = STRING_TOKEN(STR_DBX_CERTIFICATE_FORMAT_PROMPT),
+ help = STRING_TOKEN(STR_DBX_CERTIFICATE_FORMAT_HELP),
+ option text = STRING_TOKEN(STR_DBX_CERTIFICATE_FORMAT_SHA256), value = 0x1, flags = DEFAULT;
+ option text = STRING_TOKEN(STR_DBX_CERTIFICATE_FORMAT_SHA384), value = 0x2, flags = 0;
+ option text = STRING_TOKEN(STR_DBX_CERTIFICATE_FORMAT_SHA512), value = 0x3, flags = 0;
+ option text = STRING_TOKEN(STR_DBX_CERTIFICATE_FORMAT_RAW), value = 0x4, flags = 0;
+ endoneof;
+ endif;
+
+ disableif NOT ideqval SECUREBOOT_CONFIGURATION.FileEnrollType == 2;
+ text
+ help = STRING_TOKEN(STR_DBX_PE_IMAGE_FORMAT_HELP), // Help string
+ text = STRING_TOKEN(STR_DBX_CERTIFICATE_FORMAT_PROMPT), // Prompt string
+ text = STRING_TOKEN(STR_DBX_PE_FORMAT_SHA256); // PE image type
+ endif;
+
+ disableif NOT ideqval SECUREBOOT_CONFIGURATION.FileEnrollType == 3;
+ text
+ help = STRING_TOKEN(STR_DBX_AUTH_2_FORMAT_HELP), // Help string
+ text = STRING_TOKEN(STR_DBX_CERTIFICATE_FORMAT_PROMPT), // Prompt string
+ text = STRING_TOKEN(STR_DBX_AUTH_2_FORMAT); // AUTH_2 image type
+ endif;
+
+ suppressif ideqval SECUREBOOT_CONFIGURATION.CertificateFormat == 4;
+ checkbox varid = SECUREBOOT_CONFIGURATION.AlwaysRevocation,
+ prompt = STRING_TOKEN(STR_ALWAYS_CERTIFICATE_REVOCATION_PROMPT),
+ help = STRING_TOKEN(STR_ALWAYS_CERTIFICATE_REVOCATION_HELP),
+ flags = INTERACTIVE,
+ endcheckbox;
+
+ suppressif ideqval SECUREBOOT_CONFIGURATION.AlwaysRevocation == 1;
+ date varid = SECUREBOOT_CONFIGURATION.RevocationDate,
+ prompt = STRING_TOKEN(STR_CERTIFICATE_REVOCATION_DATE_PROMPT),
+ help = STRING_TOKEN(STR_CERTIFICATE_REVOCATION_DATE_HELP),
+ flags = STORAGE_NORMAL,
+ enddate;
+
+ time varid = SECUREBOOT_CONFIGURATION.RevocationTime,
+ prompt = STRING_TOKEN(STR_CERTIFICATE_REVOCATION_TIME_PROMPT),
+ help = STRING_TOKEN(STR_CERTIFICATE_REVOCATION_TIME_HELP),
+ flags = STORAGE_NORMAL,
+ endtime;
+ endif;
+ endif;
+
+ subtitle text = STRING_TOKEN(STR_NULL);
+ subtitle text = STRING_TOKEN(STR_NULL);
+
+ goto FORMID_SECURE_BOOT_OPTION_FORM,
+ prompt = STRING_TOKEN(STR_SAVE_AND_EXIT),
+ help = STRING_TOKEN(STR_SAVE_AND_EXIT),
+ flags = INTERACTIVE,
+ key = KEY_VALUE_SAVE_AND_EXIT_DBX;
+
+ goto FORMID_SECURE_BOOT_OPTION_FORM,
+ prompt = STRING_TOKEN(STR_NO_SAVE_AND_EXIT),
+ help = STRING_TOKEN(STR_NO_SAVE_AND_EXIT),
+ flags = INTERACTIVE,
+ key = KEY_VALUE_NO_SAVE_AND_EXIT_DBX;
+
+ endform;
+
+ //
+ // Form: 'Enroll Signature' for DBT options.
+ //
+ form formid = SECUREBOOT_ENROLL_SIGNATURE_TO_DBT,
+ title = STRING_TOKEN(STR_SECURE_BOOT_ENROLL_SIGNATURE);
+
+ subtitle text = STRING_TOKEN(STR_NULL);
+
+ goto SECUREBOOT_ENROLL_SIGNATURE_TO_DBT,
+ prompt = STRING_TOKEN(STR_SECURE_BOOT_ADD_SIGNATURE_FILE),
+ help = STRING_TOKEN(STR_SECURE_BOOT_ADD_SIGNATURE_FILE),
+ flags = INTERACTIVE,
+ key = SECUREBOOT_ENROLL_SIGNATURE_TO_DBT;
+
+ subtitle text = STRING_TOKEN(STR_NULL);
+ label SECUREBOOT_ENROLL_SIGNATURE_TO_DBT;
+ label LABEL_END;
+ subtitle text = STRING_TOKEN(STR_NULL);
+
+ string varid = SECUREBOOT_CONFIGURATION.SignatureGuid,
+ prompt = STRING_TOKEN(STR_SECURE_BOOT_SIGNATURE_GUID),
+ help = STRING_TOKEN(STR_SECURE_BOOT_SIGNATURE_GUID_HELP),
+ flags = INTERACTIVE,
+ key = KEY_SECURE_BOOT_SIGNATURE_GUID_DBT,
+ minsize = SECURE_BOOT_GUID_SIZE,
+ maxsize = SECURE_BOOT_GUID_SIZE,
+ endstring;
+
+ subtitle text = STRING_TOKEN(STR_NULL);
+ subtitle text = STRING_TOKEN(STR_NULL);
+
+ goto FORMID_SECURE_BOOT_OPTION_FORM,
+ prompt = STRING_TOKEN(STR_SAVE_AND_EXIT),
+ help = STRING_TOKEN(STR_SAVE_AND_EXIT),
+ flags = INTERACTIVE,
+ key = KEY_VALUE_SAVE_AND_EXIT_DBT;
+
+ goto FORMID_SECURE_BOOT_OPTION_FORM,
+ prompt = STRING_TOKEN(STR_NO_SAVE_AND_EXIT),
+ help = STRING_TOKEN(STR_NO_SAVE_AND_EXIT),
+ flags = INTERACTIVE,
+ key = KEY_VALUE_NO_SAVE_AND_EXIT_DBT;
+
+ endform;
+
+endformset; \ No newline at end of file
diff --git a/Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDevicePath.c b/Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDevicePath.c
new file mode 100644
index 0000000000..28c4d4f8b6
--- /dev/null
+++ b/Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDevicePath.c
@@ -0,0 +1,38 @@
+/** @file
+ Internal function defines the default device path string for SecureBoot configuration module.
+
+Copyright (c) 2012 - 2013, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "SecureBootConfigImpl.h"
+
+
+/**
+ This function converts an input device structure to a Unicode string.
+
+ @param[in] DevPath A pointer to the device path structure.
+
+ @return A new allocated Unicode string that represents the device path.
+
+**/
+CHAR16 *
+EFIAPI
+DevicePathToStr (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevPath
+ )
+{
+ return ConvertDevicePathToText (
+ DevPath,
+ FALSE,
+ TRUE
+ );
+}
+
diff --git a/Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDriver.c b/Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDriver.c
new file mode 100644
index 0000000000..1d6c4ac6e8
--- /dev/null
+++ b/Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDriver.c
@@ -0,0 +1,133 @@
+/** @file
+ The module entry point for SecureBoot configuration module.
+
+Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "SecureBootConfigImpl.h"
+
+/**
+ The entry point for SecureBoot 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 get the SecureBootEnable variable.
+
+**/
+EFI_STATUS
+EFIAPI
+SecureBootConfigDriverEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ SECUREBOOT_CONFIG_PRIVATE_DATA *PrivateData;
+
+ //
+ // If already started, return.
+ //
+ Status = gBS->OpenProtocol (
+ ImageHandle,
+ &gEfiCallerIdGuid,
+ NULL,
+ ImageHandle,
+ ImageHandle,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+ if (!EFI_ERROR (Status)) {
+ return EFI_ALREADY_STARTED;
+ }
+
+ //
+ // Create a private data structure.
+ //
+ PrivateData = AllocateCopyPool (sizeof (SECUREBOOT_CONFIG_PRIVATE_DATA), &mSecureBootConfigPrivateDateTemplate);
+ if (PrivateData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Install SecureBoot configuration form
+ //
+ Status = InstallSecureBootConfigForm (PrivateData);
+ if (EFI_ERROR (Status)) {
+ goto ErrorExit;
+ }
+
+ //
+ // Install private GUID.
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &ImageHandle,
+ &gEfiCallerIdGuid,
+ PrivateData,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto ErrorExit;
+ }
+
+ return EFI_SUCCESS;
+
+ErrorExit:
+ if (PrivateData != NULL) {
+ UninstallSecureBootConfigForm (PrivateData);
+ }
+
+ return Status;
+}
+
+/**
+ Unload the SecureBoot configuration form.
+
+ @param[in] ImageHandle The driver's image handle.
+
+ @retval EFI_SUCCESS The SecureBoot configuration form is unloaded.
+ @retval Others Failed to unload the form.
+
+**/
+EFI_STATUS
+EFIAPI
+SecureBootConfigDriverUnload (
+ IN EFI_HANDLE ImageHandle
+ )
+{
+ EFI_STATUS Status;
+ SECUREBOOT_CONFIG_PRIVATE_DATA *PrivateData;
+
+ Status = gBS->HandleProtocol (
+ ImageHandle,
+ &gEfiCallerIdGuid,
+ (VOID **) &PrivateData
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ASSERT (PrivateData->Signature == SECUREBOOT_CONFIG_PRIVATE_DATA_SIGNATURE);
+
+ gBS->UninstallMultipleProtocolInterfaces (
+ &ImageHandle,
+ &gEfiCallerIdGuid,
+ PrivateData,
+ NULL
+ );
+
+ UninstallSecureBootConfigForm (PrivateData);
+
+ return EFI_SUCCESS;
+}
diff --git a/Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxe.inf b/Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxe.inf
new file mode 100644
index 0000000000..fa7c39d6e5
--- /dev/null
+++ b/Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxe.inf
@@ -0,0 +1,127 @@
+## @file
+# Provides the capbility to configure secure boot in a setup browser
+# By this module, user may change the content of DB, DBX, PK and KEK.
+#
+# Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SecureBootConfigDxe
+ MODULE_UNI_FILE = SecureBootConfigDxe.uni
+ FILE_GUID = F0E6A44F-7195-41c3-AC64-54F202CD0A21
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = SecureBootConfigDriverEntryPoint
+ UNLOAD_IMAGE = SecureBootConfigDriverUnload
+
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ SecureBootConfigDriver.c
+ SecureBootConfigImpl.c
+ SecureBootConfigFileExplorer.c
+ SecureBootConfigDevicePath.c
+ SecureBootConfigMisc.c
+ SecureBootConfigImpl.h
+ SecureBootConfig.vfr
+ SecureBootConfigStrings.uni
+ SecureBootConfigNvData.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ SecurityPkg/SecurityPkg.dec
+ CryptoPkg/CryptoPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ BaseCryptLib
+ MemoryAllocationLib
+ UefiLib
+ UefiBootServicesTableLib
+ UefiRuntimeServicesTableLib
+ UefiDriverEntryPoint
+ UefiHiiServicesLib
+ DebugLib
+ HiiLib
+ PlatformSecureLib
+ DevicePathLib
+ FileExplorerLib
+ PeCoffLib
+
+[Guids]
+ ## SOMETIMES_CONSUMES ## Variable:L"CustomMode"
+ ## SOMETIMES_PRODUCES ## Variable:L"CustomMode"
+ gEfiCustomModeEnableGuid
+
+ ## SOMETIMES_CONSUMES ## Variable:L"SecureBootEnable"
+ ## SOMETIMES_PRODUCES ## Variable:L"SecureBootEnable"
+ gEfiSecureBootEnableDisableGuid
+
+ ## SOMETIMES_CONSUMES ## GUID # Unique ID for the type of the signature.
+ ## SOMETIMES_PRODUCES ## GUID # Unique ID for the type of the signature.
+ gEfiCertRsa2048Guid
+
+ ## SOMETIMES_CONSUMES ## GUID # Unique ID for the type of the signature.
+ ## SOMETIMES_PRODUCES ## GUID # Unique ID for the type of the signature.
+ gEfiCertX509Guid
+
+ ## SOMETIMES_CONSUMES ## GUID # Unique ID for the type of the signature.
+ ## SOMETIMES_PRODUCES ## GUID # Unique ID for the type of the signature.
+ gEfiCertSha1Guid
+
+ ## SOMETIMES_CONSUMES ## GUID # Unique ID for the type of the signature.
+ ## SOMETIMES_PRODUCES ## GUID # Unique ID for the type of the signature.
+ gEfiCertSha256Guid
+
+ ## SOMETIMES_CONSUMES ## Variable:L"db"
+ ## SOMETIMES_PRODUCES ## Variable:L"db"
+ ## SOMETIMES_CONSUMES ## Variable:L"dbx"
+ ## SOMETIMES_PRODUCES ## Variable:L"dbx"
+ gEfiImageSecurityDatabaseGuid
+
+ ## SOMETIMES_CONSUMES ## Variable:L"SetupMode"
+ ## SOMETIMES_PRODUCES ## Variable:L"PK"
+ ## SOMETIMES_CONSUMES ## Variable:L"KEK"
+ ## SOMETIMES_PRODUCES ## Variable:L"KEK"
+ ## SOMETIMES_CONSUMES ## Variable:L"SecureBoot"
+ gEfiGlobalVariableGuid
+
+ gEfiIfrTianoGuid ## PRODUCES ## GUID # HII opcode
+ ## PRODUCES ## HII
+ ## CONSUMES ## HII
+ gSecureBootConfigFormSetGuid
+ gEfiCertPkcs7Guid ## SOMETIMES_PRODUCES ## GUID # Unique ID for the type of the certificate.
+ gEfiCertTypeRsa2048Sha256Guid ## SOMETIMES_CONSUMES ## GUID # Unique ID for the type of the certificate.
+ gEfiFileSystemVolumeLabelInfoIdGuid ## SOMETIMES_CONSUMES ## GUID # Indicate the information type
+ gEfiFileInfoGuid ## SOMETIMES_CONSUMES ## GUID # Indicate the information type
+
+ gEfiCertX509Sha256Guid ## SOMETIMES_PRODUCES ## GUID # Unique ID for the type of the certificate.
+ gEfiCertX509Sha384Guid ## SOMETIMES_PRODUCES ## GUID # Unique ID for the type of the certificate.
+ gEfiCertX509Sha512Guid ## SOMETIMES_PRODUCES ## GUID # Unique ID for the type of the certificate.
+
+[Protocols]
+ gEfiHiiConfigAccessProtocolGuid ## PRODUCES
+ gEfiDevicePathProtocolGuid ## PRODUCES
+ gEfiSimpleFileSystemProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiBlockIoProtocolGuid ## SOMETIMES_CONSUMES
+
+[Depex]
+ gEfiHiiConfigRoutingProtocolGuid AND
+ gEfiHiiDatabaseProtocolGuid AND
+ gEfiVariableArchProtocolGuid AND
+ gEfiVariableWriteArchProtocolGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ SecureBootConfigDxeExtra.uni
diff --git a/Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxe.uni b/Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxe.uni
new file mode 100644
index 0000000000..d0d2e5ad75
--- /dev/null
+++ b/Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxe.uni
@@ -0,0 +1,21 @@
+// /** @file
+// Provides the capbility to configure secure boot in a setup browser
+//
+// By this module, user may change the content of DB, DBX, PK and KEK.
+//
+// Copyright (c) 2011 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Provides the capability to configure secure boot in a setup browser"
+
+#string STR_MODULE_DESCRIPTION #language en-US "By this module, user may change the content of DB, DBX, PK and KEK."
+
diff --git a/Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxeExtra.uni b/Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxeExtra.uni
new file mode 100644
index 0000000000..2bc7f3d537
--- /dev/null
+++ b/Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxeExtra.uni
@@ -0,0 +1,19 @@
+// /** @file
+// SecureBootConfigDxe Localized Strings and Content
+//
+// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Secure Boot Config DXE"
+
+
diff --git a/Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigFileExplorer.c b/Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigFileExplorer.c
new file mode 100644
index 0000000000..1b6f888042
--- /dev/null
+++ b/Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigFileExplorer.c
@@ -0,0 +1,422 @@
+/** @file
+ Internal file explorer functions for SecureBoot configuration module.
+
+Copyright (c) 2012 - 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "SecureBootConfigImpl.h"
+
+VOID *mStartOpCodeHandle = NULL;
+VOID *mEndOpCodeHandle = NULL;
+EFI_IFR_GUID_LABEL *mStartLabel = NULL;
+EFI_IFR_GUID_LABEL *mEndLabel = NULL;
+
+/**
+ Refresh the global UpdateData structure.
+
+**/
+VOID
+RefreshUpdateData (
+ VOID
+ )
+{
+ //
+ // Free current updated date
+ //
+ if (mStartOpCodeHandle != NULL) {
+ HiiFreeOpCodeHandle (mStartOpCodeHandle);
+ }
+
+ //
+ // Create new OpCode Handle
+ //
+ mStartOpCodeHandle = HiiAllocateOpCodeHandle ();
+
+ //
+ // Create Hii Extend Label OpCode as the start opcode
+ //
+ mStartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (
+ mStartOpCodeHandle,
+ &gEfiIfrTianoGuid,
+ NULL,
+ sizeof (EFI_IFR_GUID_LABEL)
+ );
+ mStartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
+}
+
+/**
+ Clean up the dynamic opcode at label and form specified by both LabelId.
+
+ @param[in] LabelId It is both the Form ID and Label ID for opcode deletion.
+ @param[in] PrivateData Module private data.
+
+**/
+VOID
+CleanUpPage (
+ IN UINT16 LabelId,
+ IN SECUREBOOT_CONFIG_PRIVATE_DATA *PrivateData
+ )
+{
+ RefreshUpdateData ();
+
+ //
+ // Remove all op-codes from dynamic page
+ //
+ mStartLabel->Number = LabelId;
+ HiiUpdateForm (
+ PrivateData->HiiHandle,
+ &gSecureBootConfigFormSetGuid,
+ LabelId,
+ mStartOpCodeHandle, // Label LabelId
+ mEndOpCodeHandle // LABEL_END
+ );
+}
+
+/**
+ This function will open a file or directory referenced by DevicePath.
+
+ This function opens a file with the open mode according to the file path. The
+ Attributes is valid only for EFI_FILE_MODE_CREATE.
+
+ @param[in, out] FilePath On input, the device path to the file.
+ On output, the remaining device path.
+ @param[out] FileHandle Pointer to the file handle.
+ @param[in] OpenMode The mode to open the file with.
+ @param[in] Attributes The file's file attributes.
+
+ @retval EFI_SUCCESS The information was set.
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+ @retval EFI_UNSUPPORTED Could not open the file path.
+ @retval EFI_NOT_FOUND The specified file could not be found on the
+ device or the file system could not be found on
+ the device.
+ @retval EFI_NO_MEDIA The device has no medium.
+ @retval EFI_MEDIA_CHANGED The device has a different medium in it or the
+ medium is no longer supported.
+ @retval EFI_DEVICE_ERROR The device reported an error.
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.
+ @retval EFI_WRITE_PROTECTED The file or medium is write protected.
+ @retval EFI_ACCESS_DENIED The file was opened read only.
+ @retval EFI_OUT_OF_RESOURCES Not enough resources were available to open the
+ file.
+ @retval EFI_VOLUME_FULL The volume is full.
+**/
+EFI_STATUS
+EFIAPI
+OpenFileByDevicePath(
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **FilePath,
+ OUT EFI_FILE_HANDLE *FileHandle,
+ IN UINT64 OpenMode,
+ IN UINT64 Attributes
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *EfiSimpleFileSystemProtocol;
+ EFI_FILE_PROTOCOL *Handle1;
+ EFI_FILE_PROTOCOL *Handle2;
+ EFI_HANDLE DeviceHandle;
+
+ if ((FilePath == NULL || FileHandle == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = gBS->LocateDevicePath (
+ &gEfiSimpleFileSystemProtocolGuid,
+ FilePath,
+ &DeviceHandle
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->OpenProtocol(
+ DeviceHandle,
+ &gEfiSimpleFileSystemProtocolGuid,
+ (VOID**)&EfiSimpleFileSystemProtocol,
+ gImageHandle,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = EfiSimpleFileSystemProtocol->OpenVolume(EfiSimpleFileSystemProtocol, &Handle1);
+ if (EFI_ERROR (Status)) {
+ FileHandle = NULL;
+ return Status;
+ }
+
+ //
+ // go down directories one node at a time.
+ //
+ while (!IsDevicePathEnd (*FilePath)) {
+ //
+ // For file system access each node should be a file path component
+ //
+ if (DevicePathType (*FilePath) != MEDIA_DEVICE_PATH ||
+ DevicePathSubType (*FilePath) != MEDIA_FILEPATH_DP
+ ) {
+ FileHandle = NULL;
+ return (EFI_INVALID_PARAMETER);
+ }
+ //
+ // Open this file path node
+ //
+ Handle2 = Handle1;
+ Handle1 = NULL;
+
+ //
+ // Try to test opening an existing file
+ //
+ Status = Handle2->Open (
+ Handle2,
+ &Handle1,
+ ((FILEPATH_DEVICE_PATH*)*FilePath)->PathName,
+ OpenMode &~EFI_FILE_MODE_CREATE,
+ 0
+ );
+
+ //
+ // see if the error was that it needs to be created
+ //
+ if ((EFI_ERROR (Status)) && (OpenMode != (OpenMode &~EFI_FILE_MODE_CREATE))) {
+ Status = Handle2->Open (
+ Handle2,
+ &Handle1,
+ ((FILEPATH_DEVICE_PATH*)*FilePath)->PathName,
+ OpenMode,
+ Attributes
+ );
+ }
+ //
+ // Close the last node
+ //
+ Handle2->Close (Handle2);
+
+ if (EFI_ERROR(Status)) {
+ return (Status);
+ }
+
+ //
+ // Get the next node
+ //
+ *FilePath = NextDevicePathNode (*FilePath);
+ }
+
+ //
+ // This is a weak spot since if the undefined SHELL_FILE_HANDLE format changes this must change also!
+ //
+ *FileHandle = (VOID*)Handle1;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Extract filename from device path. The returned buffer is allocated using AllocateCopyPool.
+ The caller is responsible for freeing the allocated buffer using FreePool(). If return NULL
+ means not enough memory resource.
+
+ @param DevicePath Device path.
+
+ @retval NULL Not enough memory resourece for AllocateCopyPool.
+ @retval Other A new allocated string that represents the file name.
+
+**/
+CHAR16 *
+ExtractFileNameFromDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ CHAR16 *String;
+ CHAR16 *MatchString;
+ CHAR16 *LastMatch;
+ CHAR16 *FileName;
+ UINTN Length;
+
+ ASSERT(DevicePath != NULL);
+
+ String = DevicePathToStr(DevicePath);
+ MatchString = String;
+ LastMatch = String;
+ FileName = NULL;
+
+ while(MatchString != NULL){
+ LastMatch = MatchString + 1;
+ MatchString = StrStr(LastMatch,L"\\");
+ }
+
+ Length = StrLen(LastMatch);
+ FileName = AllocateCopyPool ((Length + 1) * sizeof(CHAR16), LastMatch);
+ if (FileName != NULL) {
+ *(FileName + Length) = 0;
+ }
+
+ FreePool(String);
+
+ return FileName;
+}
+
+
+/**
+ Update the form base on the selected file.
+
+ @param FilePath Point to the file path.
+ @param FormId The form need to display.
+
+ @retval TRUE Exit caller function.
+ @retval FALSE Not exit caller function.
+
+**/
+BOOLEAN
+UpdatePage(
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
+ IN EFI_FORM_ID FormId
+ )
+{
+ CHAR16 *FileName;
+ EFI_STRING_ID StringToken;
+
+ FileName = NULL;
+
+ if (FilePath != NULL) {
+ FileName = ExtractFileNameFromDevicePath(FilePath);
+ }
+ if (FileName == NULL) {
+ //
+ // FileName = NULL has two case:
+ // 1. FilePath == NULL, not select file.
+ // 2. FilePath != NULL, but ExtractFileNameFromDevicePath return NULL not enough memory resource.
+ // In these two case, no need to update the form, and exit the caller function.
+ //
+ return TRUE;
+ }
+ StringToken = HiiSetString (gSecureBootPrivateData->HiiHandle, 0, FileName, NULL);
+
+ gSecureBootPrivateData->FileContext->FileName = FileName;
+
+ OpenFileByDevicePath(
+ &FilePath,
+ &gSecureBootPrivateData->FileContext->FHandle,
+ EFI_FILE_MODE_READ,
+ 0
+ );
+ //
+ // Create Subtitle op-code for the display string of the option.
+ //
+ RefreshUpdateData ();
+ mStartLabel->Number = FormId;
+
+ HiiCreateSubTitleOpCode (
+ mStartOpCodeHandle,
+ StringToken,
+ 0,
+ 0,
+ 0
+ );
+
+ HiiUpdateForm (
+ gSecureBootPrivateData->HiiHandle,
+ &gSecureBootConfigFormSetGuid,
+ FormId,
+ mStartOpCodeHandle, // Label FormId
+ mEndOpCodeHandle // LABEL_END
+ );
+
+ return TRUE;
+}
+
+/**
+ Update the PK form base on the input file path info.
+
+ @param FilePath Point to the file path.
+
+ @retval TRUE Exit caller function.
+ @retval FALSE Not exit caller function.
+**/
+BOOLEAN
+EFIAPI
+UpdatePKFromFile (
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath
+ )
+{
+ return UpdatePage(FilePath, FORMID_ENROLL_PK_FORM);
+
+}
+
+/**
+ Update the KEK form base on the input file path info.
+
+ @param FilePath Point to the file path.
+
+ @retval TRUE Exit caller function.
+ @retval FALSE Not exit caller function.
+**/
+BOOLEAN
+EFIAPI
+UpdateKEKFromFile (
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath
+ )
+{
+ return UpdatePage(FilePath, FORMID_ENROLL_KEK_FORM);
+}
+
+/**
+ Update the DB form base on the input file path info.
+
+ @param FilePath Point to the file path.
+
+ @retval TRUE Exit caller function.
+ @retval FALSE Not exit caller function.
+**/
+BOOLEAN
+EFIAPI
+UpdateDBFromFile (
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath
+ )
+{
+ return UpdatePage(FilePath, SECUREBOOT_ENROLL_SIGNATURE_TO_DB);
+}
+
+/**
+ Update the DBX form base on the input file path info.
+
+ @param FilePath Point to the file path.
+
+ @retval TRUE Exit caller function.
+ @retval FALSE Not exit caller function.
+**/
+BOOLEAN
+EFIAPI
+UpdateDBXFromFile (
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath
+ )
+{
+ return UpdatePage(FilePath, SECUREBOOT_ENROLL_SIGNATURE_TO_DBX);
+}
+
+/**
+ Update the DBT form base on the input file path info.
+
+ @param FilePath Point to the file path.
+
+ @retval TRUE Exit caller function.
+ @retval FALSE Not exit caller function.
+**/
+BOOLEAN
+EFIAPI
+UpdateDBTFromFile (
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath
+ )
+{
+ return UpdatePage(FilePath, SECUREBOOT_ENROLL_SIGNATURE_TO_DBT);
+}
+
diff --git a/Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigImpl.c b/Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigImpl.c
new file mode 100644
index 0000000000..2eaf24633d
--- /dev/null
+++ b/Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigImpl.c
@@ -0,0 +1,4080 @@
+/** @file
+ HII Config Access protocol implementation of SecureBoot configuration module.
+
+Copyright (c) 2011 - 2017, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "SecureBootConfigImpl.h"
+
+CHAR16 mSecureBootStorageName[] = L"SECUREBOOT_CONFIGURATION";
+
+SECUREBOOT_CONFIG_PRIVATE_DATA mSecureBootConfigPrivateDateTemplate = {
+ SECUREBOOT_CONFIG_PRIVATE_DATA_SIGNATURE,
+ {
+ SecureBootExtractConfig,
+ SecureBootRouteConfig,
+ SecureBootCallback
+ }
+};
+
+HII_VENDOR_DEVICE_PATH mSecureBootHiiVendorDevicePath = {
+ {
+ {
+ HARDWARE_DEVICE_PATH,
+ HW_VENDOR_DP,
+ {
+ (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
+ (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
+ }
+ },
+ SECUREBOOT_CONFIG_FORM_SET_GUID
+ },
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ (UINT8) (END_DEVICE_PATH_LENGTH),
+ (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
+ }
+ }
+};
+
+
+BOOLEAN mIsEnterSecureBootForm = FALSE;
+
+//
+// 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"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, Sha384GetContextSize, Sha384Init, Sha384Update, Sha384Final},
+ { L"SHA512", 64, &mHashOidValue[40], 9, Sha512GetContextSize, Sha512Init, Sha512Update, Sha512Final}
+};
+
+//
+// Variable Definitions
+//
+UINT32 mPeCoffHeaderOffset = 0;
+WIN_CERTIFICATE *mCertificate = NULL;
+IMAGE_TYPE mImageType;
+UINT8 *mImageBase = NULL;
+UINTN mImageSize = 0;
+UINT8 mImageDigest[MAX_DIGEST_SIZE];
+UINTN mImageDigestSize;
+EFI_GUID mCertType;
+EFI_IMAGE_SECURITY_DATA_DIRECTORY *mSecDataDir = NULL;
+EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION mNtHeader;
+
+//
+// Possible DER-encoded certificate file suffixes, end with NULL pointer.
+//
+CHAR16* mDerEncodedSuffix[] = {
+ L".cer",
+ L".der",
+ L".crt",
+ NULL
+};
+CHAR16* mSupportX509Suffix = L"*.cer/der/crt";
+
+SECUREBOOT_CONFIG_PRIVATE_DATA *gSecureBootPrivateData = NULL;
+
+/**
+ This code cleans up enrolled file by closing file & free related resources attached to
+ enrolled file.
+
+ @param[in] FileContext FileContext cached in SecureBootConfig driver
+
+**/
+VOID
+CloseEnrolledFile(
+ IN SECUREBOOT_FILE_CONTEXT *FileContext
+)
+{
+ if (FileContext->FHandle != NULL) {
+ CloseFile (FileContext->FHandle);
+ FileContext->FHandle = NULL;
+ }
+
+ if (FileContext->FileName != NULL){
+ FreePool(FileContext->FileName);
+ FileContext->FileName = NULL;
+ }
+ FileContext->FileType = UNKNOWN_FILE_TYPE;
+
+}
+
+/**
+ This code checks if the FileSuffix is one of the possible DER-encoded certificate suffix.
+
+ @param[in] FileSuffix The suffix of the input certificate file
+
+ @retval TRUE It's a DER-encoded certificate.
+ @retval FALSE It's NOT a DER-encoded certificate.
+
+**/
+BOOLEAN
+IsDerEncodeCertificate (
+ IN CONST CHAR16 *FileSuffix
+)
+{
+ UINTN Index;
+ for (Index = 0; mDerEncodedSuffix[Index] != NULL; Index++) {
+ if (StrCmp (FileSuffix, mDerEncodedSuffix[Index]) == 0) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/**
+ This code checks if the file content complies with EFI_VARIABLE_AUTHENTICATION_2 format
+The function reads file content but won't open/close given FileHandle.
+
+ @param[in] FileHandle The FileHandle to be checked
+
+ @retval TRUE The content is EFI_VARIABLE_AUTHENTICATION_2 format.
+ @retval FALSE The content is NOT a EFI_VARIABLE_AUTHENTICATION_2 format.
+
+**/
+BOOLEAN
+IsAuthentication2Format (
+ IN EFI_FILE_HANDLE FileHandle
+)
+{
+ EFI_STATUS Status;
+ EFI_VARIABLE_AUTHENTICATION_2 *Auth2;
+ BOOLEAN IsAuth2Format;
+
+ IsAuth2Format = FALSE;
+
+ //
+ // Read the whole file content
+ //
+ Status = ReadFileContent(
+ FileHandle,
+ (VOID **) &mImageBase,
+ &mImageSize,
+ 0
+ );
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+
+ Auth2 = (EFI_VARIABLE_AUTHENTICATION_2 *)mImageBase;
+ if (Auth2->AuthInfo.Hdr.wCertificateType != WIN_CERT_TYPE_EFI_GUID) {
+ goto ON_EXIT;
+ }
+
+ if (CompareGuid(&gEfiCertPkcs7Guid, &Auth2->AuthInfo.CertType)) {
+ IsAuth2Format = TRUE;
+ }
+
+ON_EXIT:
+ //
+ // Do not close File. simply check file content
+ //
+ if (mImageBase != NULL) {
+ FreePool (mImageBase);
+ mImageBase = NULL;
+ }
+
+ return IsAuth2Format;
+}
+
+/**
+ Set Secure Boot option into variable space.
+
+ @param[in] VarValue The option of Secure Boot.
+
+ @retval EFI_SUCCESS The operation is finished successfully.
+ @retval Others Other errors as indicated.
+
+**/
+EFI_STATUS
+SaveSecureBootVariable (
+ IN UINT8 VarValue
+ )
+{
+ EFI_STATUS Status;
+
+ Status = gRT->SetVariable (
+ EFI_SECURE_BOOT_ENABLE_NAME,
+ &gEfiSecureBootEnableDisableGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ sizeof (UINT8),
+ &VarValue
+ );
+ return Status;
+}
+
+/**
+ Create a time based data payload by concatenating the EFI_VARIABLE_AUTHENTICATION_2
+ descriptor with the input data. NO authentication is required in this function.
+
+ @param[in, out] DataSize On input, the size of Data buffer in bytes.
+ On output, the size of data returned in Data
+ buffer in bytes.
+ @param[in, out] Data On input, Pointer to data buffer to be wrapped or
+ pointer to NULL to wrap an empty payload.
+ On output, Pointer to the new payload date buffer allocated from pool,
+ it's caller's responsibility to free the memory when finish using it.
+
+ @retval EFI_SUCCESS Create time based payload successfully.
+ @retval EFI_OUT_OF_RESOURCES There are not enough memory resourses to create time based payload.
+ @retval EFI_INVALID_PARAMETER The parameter is invalid.
+ @retval Others Unexpected error happens.
+
+**/
+EFI_STATUS
+CreateTimeBasedPayload (
+ IN OUT UINTN *DataSize,
+ IN OUT UINT8 **Data
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *NewData;
+ UINT8 *Payload;
+ UINTN PayloadSize;
+ EFI_VARIABLE_AUTHENTICATION_2 *DescriptorData;
+ UINTN DescriptorSize;
+ EFI_TIME Time;
+
+ if (Data == NULL || DataSize == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // In Setup mode or Custom mode, the variable does not need to be signed but the
+ // parameters to the SetVariable() call still need to be prepared as authenticated
+ // variable. So we create EFI_VARIABLE_AUTHENTICATED_2 descriptor without certificate
+ // data in it.
+ //
+ Payload = *Data;
+ PayloadSize = *DataSize;
+
+ DescriptorSize = OFFSET_OF (EFI_VARIABLE_AUTHENTICATION_2, AuthInfo) + OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData);
+ NewData = (UINT8*) AllocateZeroPool (DescriptorSize + PayloadSize);
+ if (NewData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if ((Payload != NULL) && (PayloadSize != 0)) {
+ CopyMem (NewData + DescriptorSize, Payload, PayloadSize);
+ }
+
+ DescriptorData = (EFI_VARIABLE_AUTHENTICATION_2 *) (NewData);
+
+ ZeroMem (&Time, sizeof (EFI_TIME));
+ Status = gRT->GetTime (&Time, NULL);
+ if (EFI_ERROR (Status)) {
+ FreePool(NewData);
+ return Status;
+ }
+ Time.Pad1 = 0;
+ Time.Nanosecond = 0;
+ Time.TimeZone = 0;
+ Time.Daylight = 0;
+ Time.Pad2 = 0;
+ CopyMem (&DescriptorData->TimeStamp, &Time, sizeof (EFI_TIME));
+
+ DescriptorData->AuthInfo.Hdr.dwLength = OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData);
+ DescriptorData->AuthInfo.Hdr.wRevision = 0x0200;
+ DescriptorData->AuthInfo.Hdr.wCertificateType = WIN_CERT_TYPE_EFI_GUID;
+ CopyGuid (&DescriptorData->AuthInfo.CertType, &gEfiCertPkcs7Guid);
+
+ if (Payload != NULL) {
+ FreePool(Payload);
+ }
+
+ *DataSize = DescriptorSize + PayloadSize;
+ *Data = NewData;
+ return EFI_SUCCESS;
+}
+
+/**
+ Internal helper function to delete a Variable given its name and GUID, NO authentication
+ required.
+
+ @param[in] VariableName Name of the Variable.
+ @param[in] VendorGuid GUID of the Variable.
+
+ @retval EFI_SUCCESS Variable deleted successfully.
+ @retval Others The driver failed to start the device.
+
+**/
+EFI_STATUS
+DeleteVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid
+ )
+{
+ EFI_STATUS Status;
+ VOID* Variable;
+ UINT8 *Data;
+ UINTN DataSize;
+ UINT32 Attr;
+
+ GetVariable2 (VariableName, VendorGuid, &Variable, NULL);
+ if (Variable == NULL) {
+ return EFI_SUCCESS;
+ }
+ FreePool (Variable);
+
+ Data = NULL;
+ DataSize = 0;
+ Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS
+ | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
+
+ Status = CreateTimeBasedPayload (&DataSize, &Data);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status));
+ return Status;
+ }
+
+ Status = gRT->SetVariable (
+ VariableName,
+ VendorGuid,
+ Attr,
+ DataSize,
+ Data
+ );
+ if (Data != NULL) {
+ FreePool (Data);
+ }
+ return Status;
+}
+
+/**
+
+ Set the platform secure boot mode into "Custom" or "Standard" mode.
+
+ @param[in] SecureBootMode New secure boot mode: STANDARD_SECURE_BOOT_MODE or
+ CUSTOM_SECURE_BOOT_MODE.
+
+ @return EFI_SUCCESS The platform has switched to the special mode successfully.
+ @return other Fail to operate the secure boot mode.
+
+**/
+EFI_STATUS
+SetSecureBootMode (
+ IN UINT8 SecureBootMode
+ )
+{
+ return gRT->SetVariable (
+ EFI_CUSTOM_MODE_NAME,
+ &gEfiCustomModeEnableGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ sizeof (UINT8),
+ &SecureBootMode
+ );
+}
+
+/**
+ Generate the PK signature list from the X509 Certificate storing file (.cer)
+
+ @param[in] X509File FileHandle of X509 Certificate storing file.
+ @param[out] PkCert Point to the data buffer to store the signature list.
+
+ @return EFI_UNSUPPORTED Unsupported Key Length.
+ @return EFI_OUT_OF_RESOURCES There are not enough memory resourses to form the signature list.
+
+**/
+EFI_STATUS
+CreatePkX509SignatureList (
+ IN EFI_FILE_HANDLE X509File,
+ OUT EFI_SIGNATURE_LIST **PkCert
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *X509Data;
+ UINTN X509DataSize;
+ EFI_SIGNATURE_DATA *PkCertData;
+
+ X509Data = NULL;
+ PkCertData = NULL;
+ X509DataSize = 0;
+
+ Status = ReadFileContent (X509File, (VOID**) &X509Data, &X509DataSize, 0);
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+ ASSERT (X509Data != NULL);
+
+ //
+ // Allocate space for PK certificate list and initialize it.
+ // Create PK database entry with SignatureHeaderSize equals 0.
+ //
+ *PkCert = (EFI_SIGNATURE_LIST*) AllocateZeroPool (
+ sizeof(EFI_SIGNATURE_LIST) + sizeof(EFI_SIGNATURE_DATA) - 1
+ + X509DataSize
+ );
+ if (*PkCert == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+
+ (*PkCert)->SignatureListSize = (UINT32) (sizeof(EFI_SIGNATURE_LIST)
+ + sizeof(EFI_SIGNATURE_DATA) - 1
+ + X509DataSize);
+ (*PkCert)->SignatureSize = (UINT32) (sizeof(EFI_SIGNATURE_DATA) - 1 + X509DataSize);
+ (*PkCert)->SignatureHeaderSize = 0;
+ CopyGuid (&(*PkCert)->SignatureType, &gEfiCertX509Guid);
+ PkCertData = (EFI_SIGNATURE_DATA*) ((UINTN)(*PkCert)
+ + sizeof(EFI_SIGNATURE_LIST)
+ + (*PkCert)->SignatureHeaderSize);
+ CopyGuid (&PkCertData->SignatureOwner, &gEfiGlobalVariableGuid);
+ //
+ // Fill the PK database with PKpub data from X509 certificate file.
+ //
+ CopyMem (&(PkCertData->SignatureData[0]), X509Data, X509DataSize);
+
+ON_EXIT:
+
+ if (X509Data != NULL) {
+ FreePool (X509Data);
+ }
+
+ if (EFI_ERROR(Status) && *PkCert != NULL) {
+ FreePool (*PkCert);
+ *PkCert = NULL;
+ }
+
+ return Status;
+}
+
+/**
+ Enroll new PK into the System without original PK's authentication.
+
+ The SignatureOwner GUID will be the same with PK's vendorguid.
+
+ @param[in] PrivateData The module's private data.
+
+ @retval EFI_SUCCESS New PK enrolled successfully.
+ @retval EFI_INVALID_PARAMETER The parameter is invalid.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources.
+
+**/
+EFI_STATUS
+EnrollPlatformKey (
+ IN SECUREBOOT_CONFIG_PRIVATE_DATA* Private
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Attr;
+ UINTN DataSize;
+ EFI_SIGNATURE_LIST *PkCert;
+ UINT16* FilePostFix;
+ UINTN NameLength;
+
+ if (Private->FileContext->FileName == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PkCert = NULL;
+
+ Status = SetSecureBootMode(CUSTOM_SECURE_BOOT_MODE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Parse the file's postfix. Only support DER encoded X.509 certificate files.
+ //
+ NameLength = StrLen (Private->FileContext->FileName);
+ if (NameLength <= 4) {
+ return EFI_INVALID_PARAMETER;
+ }
+ FilePostFix = Private->FileContext->FileName + NameLength - 4;
+ if (!IsDerEncodeCertificate(FilePostFix)) {
+ DEBUG ((EFI_D_ERROR, "Unsupported file type, only DER encoded certificate (%s) is supported.", mSupportX509Suffix));
+ return EFI_INVALID_PARAMETER;
+ }
+ DEBUG ((EFI_D_INFO, "FileName= %s\n", Private->FileContext->FileName));
+ DEBUG ((EFI_D_INFO, "FilePostFix = %s\n", FilePostFix));
+
+ //
+ // Prase the selected PK file and generature PK certificate list.
+ //
+ Status = CreatePkX509SignatureList (
+ Private->FileContext->FHandle,
+ &PkCert
+ );
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+ ASSERT (PkCert != NULL);
+
+ //
+ // Set Platform Key variable.
+ //
+ Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS
+ | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
+ DataSize = PkCert->SignatureListSize;
+ Status = CreateTimeBasedPayload (&DataSize, (UINT8**) &PkCert);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status));
+ goto ON_EXIT;
+ }
+
+ Status = gRT->SetVariable(
+ EFI_PLATFORM_KEY_NAME,
+ &gEfiGlobalVariableGuid,
+ Attr,
+ DataSize,
+ PkCert
+ );
+ if (EFI_ERROR (Status)) {
+ if (Status == EFI_OUT_OF_RESOURCES) {
+ DEBUG ((EFI_D_ERROR, "Enroll PK failed with out of resource.\n"));
+ }
+ goto ON_EXIT;
+ }
+
+ON_EXIT:
+
+ if (PkCert != NULL) {
+ FreePool(PkCert);
+ }
+
+ CloseEnrolledFile(Private->FileContext);
+
+ return Status;
+}
+
+/**
+ Remove the PK variable.
+
+ @retval EFI_SUCCESS Delete PK successfully.
+ @retval Others Could not allow to delete PK.
+
+**/
+EFI_STATUS
+DeletePlatformKey (
+ VOID
+)
+{
+ EFI_STATUS Status;
+
+ Status = SetSecureBootMode(CUSTOM_SECURE_BOOT_MODE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = DeleteVariable (
+ EFI_PLATFORM_KEY_NAME,
+ &gEfiGlobalVariableGuid
+ );
+ return Status;
+}
+
+/**
+ Enroll a new KEK item from public key storing file (*.pbk).
+
+ @param[in] PrivateData The module's private data.
+
+ @retval EFI_SUCCESS New KEK enrolled successfully.
+ @retval EFI_INVALID_PARAMETER The parameter is invalid.
+ @retval EFI_UNSUPPORTED Unsupported command.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources.
+
+**/
+EFI_STATUS
+EnrollRsa2048ToKek (
+ IN SECUREBOOT_CONFIG_PRIVATE_DATA *Private
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Attr;
+ UINTN DataSize;
+ EFI_SIGNATURE_LIST *KekSigList;
+ UINTN KeyBlobSize;
+ UINT8 *KeyBlob;
+ CPL_KEY_INFO *KeyInfo;
+ EFI_SIGNATURE_DATA *KEKSigData;
+ UINTN KekSigListSize;
+ UINT8 *KeyBuffer;
+ UINTN KeyLenInBytes;
+
+ Attr = 0;
+ DataSize = 0;
+ KeyBuffer = NULL;
+ KeyBlobSize = 0;
+ KeyBlob = NULL;
+ KeyInfo = NULL;
+ KEKSigData = NULL;
+ KekSigList = NULL;
+ KekSigListSize = 0;
+
+ //
+ // Form the KeKpub certificate list into EFI_SIGNATURE_LIST type.
+ // First, We have to parse out public key data from the pbk key file.
+ //
+ Status = ReadFileContent (
+ Private->FileContext->FHandle,
+ (VOID**) &KeyBlob,
+ &KeyBlobSize,
+ 0
+ );
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+ ASSERT (KeyBlob != NULL);
+ KeyInfo = (CPL_KEY_INFO *) KeyBlob;
+ if (KeyInfo->KeyLengthInBits / 8 != WIN_CERT_UEFI_RSA2048_SIZE) {
+ DEBUG ((DEBUG_ERROR, "Unsupported key length, Only RSA2048 is supported.\n"));
+ Status = EFI_UNSUPPORTED;
+ goto ON_EXIT;
+ }
+
+ //
+ // Convert the Public key to fix octet string format represented in RSA PKCS#1.
+ //
+ KeyLenInBytes = KeyInfo->KeyLengthInBits / 8;
+ KeyBuffer = AllocateZeroPool (KeyLenInBytes);
+ if (KeyBuffer == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+ Int2OctStr (
+ (UINTN*) (KeyBlob + sizeof (CPL_KEY_INFO)),
+ KeyLenInBytes / sizeof (UINTN),
+ KeyBuffer,
+ KeyLenInBytes
+ );
+ CopyMem(KeyBlob + sizeof(CPL_KEY_INFO), KeyBuffer, KeyLenInBytes);
+
+ //
+ // Form an new EFI_SIGNATURE_LIST.
+ //
+ KekSigListSize = sizeof(EFI_SIGNATURE_LIST)
+ + sizeof(EFI_SIGNATURE_DATA) - 1
+ + WIN_CERT_UEFI_RSA2048_SIZE;
+
+ KekSigList = (EFI_SIGNATURE_LIST*) AllocateZeroPool (KekSigListSize);
+ if (KekSigList == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+
+ KekSigList->SignatureListSize = sizeof(EFI_SIGNATURE_LIST)
+ + sizeof(EFI_SIGNATURE_DATA) - 1
+ + WIN_CERT_UEFI_RSA2048_SIZE;
+ KekSigList->SignatureHeaderSize = 0;
+ KekSigList->SignatureSize = sizeof(EFI_SIGNATURE_DATA) - 1 + WIN_CERT_UEFI_RSA2048_SIZE;
+ CopyGuid (&KekSigList->SignatureType, &gEfiCertRsa2048Guid);
+
+ KEKSigData = (EFI_SIGNATURE_DATA*)((UINT8*)KekSigList + sizeof(EFI_SIGNATURE_LIST));
+ CopyGuid (&KEKSigData->SignatureOwner, Private->SignatureGUID);
+ CopyMem (
+ KEKSigData->SignatureData,
+ KeyBlob + sizeof(CPL_KEY_INFO),
+ WIN_CERT_UEFI_RSA2048_SIZE
+ );
+
+ //
+ // Check if KEK entry has been already existed.
+ // If true, use EFI_VARIABLE_APPEND_WRITE attribute to append the
+ // new KEK to original variable.
+ //
+ Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS
+ | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
+ Status = CreateTimeBasedPayload (&KekSigListSize, (UINT8**) &KekSigList);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status));
+ goto ON_EXIT;
+ }
+
+ Status = gRT->GetVariable(
+ EFI_KEY_EXCHANGE_KEY_NAME,
+ &gEfiGlobalVariableGuid,
+ NULL,
+ &DataSize,
+ NULL
+ );
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ Attr |= EFI_VARIABLE_APPEND_WRITE;
+ } else if (Status != EFI_NOT_FOUND) {
+ goto ON_EXIT;
+ }
+
+ //
+ // Done. Now we have formed the correct KEKpub database item, just set it into variable storage,
+ //
+ Status = gRT->SetVariable(
+ EFI_KEY_EXCHANGE_KEY_NAME,
+ &gEfiGlobalVariableGuid,
+ Attr,
+ KekSigListSize,
+ KekSigList
+ );
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+
+ON_EXIT:
+
+ CloseEnrolledFile(Private->FileContext);
+
+ if (Private->SignatureGUID != NULL) {
+ FreePool (Private->SignatureGUID);
+ Private->SignatureGUID = NULL;
+ }
+
+ if (KeyBlob != NULL) {
+ FreePool (KeyBlob);
+ }
+ if (KeyBuffer != NULL) {
+ FreePool (KeyBuffer);
+ }
+ if (KekSigList != NULL) {
+ FreePool (KekSigList);
+ }
+
+ return Status;
+}
+
+/**
+ Enroll a new KEK item from X509 certificate file.
+
+ @param[in] PrivateData The module's private data.
+
+ @retval EFI_SUCCESS New X509 is enrolled successfully.
+ @retval EFI_INVALID_PARAMETER The parameter is invalid.
+ @retval EFI_UNSUPPORTED Unsupported command.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources.
+
+**/
+EFI_STATUS
+EnrollX509ToKek (
+ IN SECUREBOOT_CONFIG_PRIVATE_DATA *Private
+ )
+{
+ EFI_STATUS Status;
+ UINTN X509DataSize;
+ VOID *X509Data;
+ EFI_SIGNATURE_DATA *KEKSigData;
+ EFI_SIGNATURE_LIST *KekSigList;
+ UINTN DataSize;
+ UINTN KekSigListSize;
+ UINT32 Attr;
+
+ X509Data = NULL;
+ X509DataSize = 0;
+ KekSigList = NULL;
+ KekSigListSize = 0;
+ DataSize = 0;
+ KEKSigData = NULL;
+
+ Status = ReadFileContent (
+ Private->FileContext->FHandle,
+ &X509Data,
+ &X509DataSize,
+ 0
+ );
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+ ASSERT (X509Data != NULL);
+
+ KekSigListSize = sizeof(EFI_SIGNATURE_LIST) + sizeof(EFI_SIGNATURE_DATA) - 1 + X509DataSize;
+ KekSigList = (EFI_SIGNATURE_LIST*) AllocateZeroPool (KekSigListSize);
+ if (KekSigList == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+
+ //
+ // Fill Certificate Database parameters.
+ //
+ KekSigList->SignatureListSize = (UINT32) KekSigListSize;
+ KekSigList->SignatureHeaderSize = 0;
+ KekSigList->SignatureSize = (UINT32) (sizeof(EFI_SIGNATURE_DATA) - 1 + X509DataSize);
+ CopyGuid (&KekSigList->SignatureType, &gEfiCertX509Guid);
+
+ KEKSigData = (EFI_SIGNATURE_DATA*) ((UINT8*) KekSigList + sizeof (EFI_SIGNATURE_LIST));
+ CopyGuid (&KEKSigData->SignatureOwner, Private->SignatureGUID);
+ CopyMem (KEKSigData->SignatureData, X509Data, X509DataSize);
+
+ //
+ // Check if KEK been already existed.
+ // If true, use EFI_VARIABLE_APPEND_WRITE attribute to append the
+ // new kek to original variable
+ //
+ Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS
+ | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
+ Status = CreateTimeBasedPayload (&KekSigListSize, (UINT8**) &KekSigList);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status));
+ goto ON_EXIT;
+ }
+
+ Status = gRT->GetVariable(
+ EFI_KEY_EXCHANGE_KEY_NAME,
+ &gEfiGlobalVariableGuid,
+ NULL,
+ &DataSize,
+ NULL
+ );
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ Attr |= EFI_VARIABLE_APPEND_WRITE;
+ } else if (Status != EFI_NOT_FOUND) {
+ goto ON_EXIT;
+ }
+
+ Status = gRT->SetVariable(
+ EFI_KEY_EXCHANGE_KEY_NAME,
+ &gEfiGlobalVariableGuid,
+ Attr,
+ KekSigListSize,
+ KekSigList
+ );
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+
+ON_EXIT:
+
+ CloseEnrolledFile(Private->FileContext);
+
+ if (Private->SignatureGUID != NULL) {
+ FreePool (Private->SignatureGUID);
+ Private->SignatureGUID = NULL;
+ }
+
+ if (KekSigList != NULL) {
+ FreePool (KekSigList);
+ }
+
+ return Status;
+}
+
+/**
+ Enroll new KEK into the System without PK's authentication.
+ The SignatureOwner GUID will be Private->SignatureGUID.
+
+ @param[in] PrivateData The module's private data.
+
+ @retval EFI_SUCCESS New KEK enrolled successful.
+ @retval EFI_INVALID_PARAMETER The parameter is invalid.
+ @retval others Fail to enroll KEK data.
+
+**/
+EFI_STATUS
+EnrollKeyExchangeKey (
+ IN SECUREBOOT_CONFIG_PRIVATE_DATA *Private
+ )
+{
+ UINT16* FilePostFix;
+ EFI_STATUS Status;
+ UINTN NameLength;
+
+ if ((Private->FileContext->FHandle == NULL) || (Private->FileContext->FileName == NULL) || (Private->SignatureGUID == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = SetSecureBootMode(CUSTOM_SECURE_BOOT_MODE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Parse the file's postfix. Supports DER-encoded X509 certificate,
+ // and .pbk as RSA public key file.
+ //
+ NameLength = StrLen (Private->FileContext->FileName);
+ if (NameLength <= 4) {
+ return EFI_INVALID_PARAMETER;
+ }
+ FilePostFix = Private->FileContext->FileName + NameLength - 4;
+ if (IsDerEncodeCertificate(FilePostFix)) {
+ return EnrollX509ToKek (Private);
+ } else if (CompareMem (FilePostFix, L".pbk",4) == 0) {
+ return EnrollRsa2048ToKek (Private);
+ } else {
+ //
+ // File type is wrong, simply close it
+ //
+ CloseEnrolledFile(Private->FileContext);
+
+ return EFI_INVALID_PARAMETER;
+ }
+}
+
+/**
+ Enroll a new X509 certificate into Signature Database (DB or DBX or DBT) without
+ KEK's authentication.
+
+ @param[in] PrivateData The module's private data.
+ @param[in] VariableName Variable name of signature database, must be
+ EFI_IMAGE_SECURITY_DATABASE or EFI_IMAGE_SECURITY_DATABASE1.
+
+ @retval EFI_SUCCESS New X509 is enrolled successfully.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources.
+
+**/
+EFI_STATUS
+EnrollX509toSigDB (
+ IN SECUREBOOT_CONFIG_PRIVATE_DATA *Private,
+ IN CHAR16 *VariableName
+ )
+{
+ EFI_STATUS Status;
+ UINTN X509DataSize;
+ VOID *X509Data;
+ EFI_SIGNATURE_LIST *SigDBCert;
+ EFI_SIGNATURE_DATA *SigDBCertData;
+ VOID *Data;
+ UINTN DataSize;
+ UINTN SigDBSize;
+ UINT32 Attr;
+
+ X509DataSize = 0;
+ SigDBSize = 0;
+ DataSize = 0;
+ X509Data = NULL;
+ SigDBCert = NULL;
+ SigDBCertData = NULL;
+ Data = NULL;
+
+ Status = ReadFileContent (
+ Private->FileContext->FHandle,
+ &X509Data,
+ &X509DataSize,
+ 0
+ );
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+ ASSERT (X509Data != NULL);
+
+ SigDBSize = sizeof(EFI_SIGNATURE_LIST) + sizeof(EFI_SIGNATURE_DATA) - 1 + X509DataSize;
+
+ Data = AllocateZeroPool (SigDBSize);
+ if (Data == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+
+ //
+ // Fill Certificate Database parameters.
+ //
+ SigDBCert = (EFI_SIGNATURE_LIST*) Data;
+ SigDBCert->SignatureListSize = (UINT32) SigDBSize;
+ SigDBCert->SignatureHeaderSize = 0;
+ SigDBCert->SignatureSize = (UINT32) (sizeof(EFI_SIGNATURE_DATA) - 1 + X509DataSize);
+ CopyGuid (&SigDBCert->SignatureType, &gEfiCertX509Guid);
+
+ SigDBCertData = (EFI_SIGNATURE_DATA*) ((UINT8* ) SigDBCert + sizeof (EFI_SIGNATURE_LIST));
+ CopyGuid (&SigDBCertData->SignatureOwner, Private->SignatureGUID);
+ CopyMem ((UINT8* ) (SigDBCertData->SignatureData), X509Data, X509DataSize);
+
+ //
+ // Check if signature database entry has been already existed.
+ // If true, use EFI_VARIABLE_APPEND_WRITE attribute to append the
+ // new signature data to original variable
+ //
+ Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS
+ | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
+ Status = CreateTimeBasedPayload (&SigDBSize, (UINT8**) &Data);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status));
+ goto ON_EXIT;
+ }
+
+ Status = gRT->GetVariable(
+ VariableName,
+ &gEfiImageSecurityDatabaseGuid,
+ NULL,
+ &DataSize,
+ NULL
+ );
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ Attr |= EFI_VARIABLE_APPEND_WRITE;
+ } else if (Status != EFI_NOT_FOUND) {
+ goto ON_EXIT;
+ }
+
+ Status = gRT->SetVariable(
+ VariableName,
+ &gEfiImageSecurityDatabaseGuid,
+ Attr,
+ SigDBSize,
+ Data
+ );
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+
+ON_EXIT:
+
+ CloseEnrolledFile(Private->FileContext);
+
+ if (Private->SignatureGUID != NULL) {
+ FreePool (Private->SignatureGUID);
+ Private->SignatureGUID = NULL;
+ }
+
+ if (Data != NULL) {
+ FreePool (Data);
+ }
+
+ if (X509Data != NULL) {
+ FreePool (X509Data);
+ }
+
+ 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] 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 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);
+ if (Data == NULL) {
+ return FALSE;
+ }
+
+ 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 - sizeof (EFI_SIGNATURE_LIST) - 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, &gEfiCertX509Guid))) {
+ 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;
+}
+
+/**
+ Calculate the hash of a certificate data with the specified hash algorithm.
+
+ @param[in] CertData The certificate data to be hashed.
+ @param[in] CertSize The certificate size in bytes.
+ @param[in] HashAlg The specified hash algorithm.
+ @param[out] CertHash The output digest of the certificate
+
+ @retval TRUE Successfully got the hash of the CertData.
+ @retval FALSE Failed to get the hash of CertData.
+
+**/
+BOOLEAN
+CalculateCertHash (
+ IN UINT8 *CertData,
+ IN UINTN CertSize,
+ IN UINT32 HashAlg,
+ OUT UINT8 *CertHash
+ )
+{
+ BOOLEAN Status;
+ VOID *HashCtx;
+ UINTN CtxSize;
+ UINT8 *TBSCert;
+ UINTN TBSCertSize;
+
+ HashCtx = NULL;
+ Status = FALSE;
+
+ if (HashAlg >= HASHALG_MAX) {
+ return FALSE;
+ }
+
+ //
+ // Retrieve the TBSCertificate for Hash Calculation.
+ //
+ if (!X509GetTBSCert (CertData, CertSize, &TBSCert, &TBSCertSize)) {
+ return FALSE;
+ }
+
+ //
+ // 1. Initialize context of hash.
+ //
+ CtxSize = mHash[HashAlg].GetContextSize ();
+ HashCtx = AllocatePool (CtxSize);
+ ASSERT (HashCtx != NULL);
+
+ //
+ // 2. Initialize a hash context.
+ //
+ Status = mHash[HashAlg].HashInit (HashCtx);
+ if (!Status) {
+ goto Done;
+ }
+
+ //
+ // 3. Calculate the hash.
+ //
+ Status = mHash[HashAlg].HashUpdate (HashCtx, TBSCert, TBSCertSize);
+ if (!Status) {
+ goto Done;
+ }
+
+ //
+ // 4. Get the hash result.
+ //
+ ZeroMem (CertHash, mHash[HashAlg].DigestLength);
+ Status = mHash[HashAlg].HashFinal (HashCtx, CertHash);
+
+Done:
+ if (HashCtx != NULL) {
+ FreePool (HashCtx);
+ }
+
+ return Status;
+}
+
+/**
+ Check whether the hash of an X.509 certificate is in forbidden database (DBX).
+
+ @param[in] Certificate Pointer to X.509 Certificate that is searched for.
+ @param[in] CertSize Size of X.509 Certificate.
+
+ @return TRUE Found the certificate hash in the forbidden database.
+ @return FALSE Certificate hash is Not found in the forbidden database.
+
+**/
+BOOLEAN
+IsCertHashFoundInDbx (
+ IN UINT8 *Certificate,
+ IN UINTN CertSize
+ )
+{
+ BOOLEAN IsFound;
+ EFI_STATUS Status;
+ EFI_SIGNATURE_LIST *DbxList;
+ EFI_SIGNATURE_DATA *CertHash;
+ UINTN CertHashCount;
+ UINTN Index;
+ UINT32 HashAlg;
+ UINT8 CertDigest[MAX_DIGEST_SIZE];
+ UINT8 *DbxCertHash;
+ UINTN SiglistHeaderSize;
+ UINT8 *Data;
+ UINTN DataSize;
+
+ IsFound = FALSE;
+ HashAlg = HASHALG_MAX;
+ Data = NULL;
+
+ //
+ // Read signature database variable.
+ //
+ DataSize = 0;
+ Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, NULL);
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ return FALSE;
+ }
+
+ Data = (UINT8 *) AllocateZeroPool (DataSize);
+ if (Data == NULL) {
+ return FALSE;
+ }
+
+ Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, Data);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Check whether the certificate hash exists in the forbidden database.
+ //
+ DbxList = (EFI_SIGNATURE_LIST *) Data;
+ while ((DataSize > 0) && (DataSize >= DbxList->SignatureListSize)) {
+ //
+ // Determine Hash Algorithm of Certificate in the forbidden database.
+ //
+ if (CompareGuid (&DbxList->SignatureType, &gEfiCertX509Sha256Guid)) {
+ HashAlg = HASHALG_SHA256;
+ } else if (CompareGuid (&DbxList->SignatureType, &gEfiCertX509Sha384Guid)) {
+ HashAlg = HASHALG_SHA384;
+ } else if (CompareGuid (&DbxList->SignatureType, &gEfiCertX509Sha512Guid)) {
+ HashAlg = HASHALG_SHA512;
+ } else {
+ DataSize -= DbxList->SignatureListSize;
+ DbxList = (EFI_SIGNATURE_LIST *) ((UINT8 *) DbxList + DbxList->SignatureListSize);
+ continue;
+ }
+
+ //
+ // Calculate the hash value of current db certificate for comparision.
+ //
+ if (!CalculateCertHash (Certificate, CertSize, HashAlg, CertDigest)) {
+ goto Done;
+ }
+
+ SiglistHeaderSize = sizeof (EFI_SIGNATURE_LIST) + DbxList->SignatureHeaderSize;
+ CertHash = (EFI_SIGNATURE_DATA *) ((UINT8 *) DbxList + SiglistHeaderSize);
+ CertHashCount = (DbxList->SignatureListSize - SiglistHeaderSize) / DbxList->SignatureSize;
+ for (Index = 0; Index < CertHashCount; Index++) {
+ //
+ // Iterate each Signature Data Node within this CertList for verify.
+ //
+ DbxCertHash = CertHash->SignatureData;
+ if (CompareMem (DbxCertHash, CertDigest, mHash[HashAlg].DigestLength) == 0) {
+ //
+ // Hash of Certificate is found in forbidden database.
+ //
+ IsFound = TRUE;
+ goto Done;
+ }
+ CertHash = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertHash + DbxList->SignatureSize);
+ }
+
+ DataSize -= DbxList->SignatureListSize;
+ DbxList = (EFI_SIGNATURE_LIST *) ((UINT8 *) DbxList + DbxList->SignatureListSize);
+ }
+
+Done:
+ if (Data != NULL) {
+ FreePool (Data);
+ }
+
+ return IsFound;
+}
+
+/**
+ Check whether the signature list exists in given variable data.
+
+ It searches the signature list for the ceritificate hash by CertType.
+ If the signature list is found, get the offset of Database for the
+ next hash of a certificate.
+
+ @param[in] Database Variable data to save signature list.
+ @param[in] DatabaseSize Variable size.
+ @param[in] SignatureType The type of the signature.
+ @param[out] Offset The offset to save a new hash of certificate.
+
+ @return TRUE The signature list is found in the forbidden database.
+ @return FALSE The signature list is not found in the forbidden database.
+**/
+BOOLEAN
+GetSignaturelistOffset (
+ IN EFI_SIGNATURE_LIST *Database,
+ IN UINTN DatabaseSize,
+ IN EFI_GUID *SignatureType,
+ OUT UINTN *Offset
+ )
+{
+ EFI_SIGNATURE_LIST *SigList;
+ UINTN SiglistSize;
+
+ if ((Database == NULL) || (DatabaseSize == 0)) {
+ *Offset = 0;
+ return FALSE;
+ }
+
+ SigList = Database;
+ SiglistSize = DatabaseSize;
+ while ((SiglistSize > 0) && (SiglistSize >= SigList->SignatureListSize)) {
+ if (CompareGuid (&SigList->SignatureType, SignatureType)) {
+ *Offset = DatabaseSize - SiglistSize;
+ return TRUE;
+ }
+ SiglistSize -= SigList->SignatureListSize;
+ SigList = (EFI_SIGNATURE_LIST *) ((UINT8 *) SigList + SigList->SignatureListSize);
+ }
+ *Offset = 0;
+ return FALSE;
+}
+
+/**
+ Enroll a new X509 certificate hash into Signature Database (dbx) without
+ KEK's authentication.
+
+ @param[in] PrivateData The module's private data.
+ @param[in] HashAlg The hash algorithm to enroll the certificate.
+ @param[in] RevocationDate The revocation date of the certificate.
+ @param[in] RevocationTime The revocation time of the certificate.
+ @param[in] AlwaysRevocation Indicate whether the certificate is always revoked.
+
+ @retval EFI_SUCCESS New X509 is enrolled successfully.
+ @retval EFI_INVALID_PARAMETER The parameter is invalid.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources.
+
+**/
+EFI_STATUS
+EnrollX509HashtoSigDB (
+ IN SECUREBOOT_CONFIG_PRIVATE_DATA *Private,
+ IN UINT32 HashAlg,
+ IN EFI_HII_DATE *RevocationDate,
+ IN EFI_HII_TIME *RevocationTime,
+ IN BOOLEAN AlwaysRevocation
+ )
+{
+ EFI_STATUS Status;
+ UINTN X509DataSize;
+ VOID *X509Data;
+ EFI_SIGNATURE_LIST *SignatureList;
+ UINTN SignatureListSize;
+ UINT8 *Data;
+ UINT8 *NewData;
+ UINTN DataSize;
+ UINTN DbSize;
+ UINT32 Attr;
+ EFI_SIGNATURE_DATA *SignatureData;
+ UINTN SignatureSize;
+ EFI_GUID SignatureType;
+ UINTN Offset;
+ UINT8 CertHash[MAX_DIGEST_SIZE];
+ UINT16* FilePostFix;
+ UINTN NameLength;
+ EFI_TIME *Time;
+
+ X509DataSize = 0;
+ DbSize = 0;
+ X509Data = NULL;
+ SignatureData = NULL;
+ SignatureList = NULL;
+ Data = NULL;
+ NewData = NULL;
+
+ if ((Private->FileContext->FileName == NULL) || (Private->FileContext->FHandle == NULL) || (Private->SignatureGUID == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = SetSecureBootMode (CUSTOM_SECURE_BOOT_MODE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Parse the file's postfix.
+ //
+ NameLength = StrLen (Private->FileContext->FileName);
+ if (NameLength <= 4) {
+ return EFI_INVALID_PARAMETER;
+ }
+ FilePostFix = Private->FileContext->FileName + NameLength - 4;
+ if (!IsDerEncodeCertificate(FilePostFix)) {
+ //
+ // Only supports DER-encoded X509 certificate.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Get the certificate from file and calculate its hash.
+ //
+ Status = ReadFileContent (
+ Private->FileContext->FHandle,
+ &X509Data,
+ &X509DataSize,
+ 0
+ );
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+ ASSERT (X509Data != NULL);
+
+ if (!CalculateCertHash (X509Data, X509DataSize, HashAlg, CertHash)) {
+ goto ON_EXIT;
+ }
+
+ //
+ // Get the variable for enrollment.
+ //
+ DataSize = 0;
+ Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, NULL);
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ Data = (UINT8 *) AllocateZeroPool (DataSize);
+ if (Data == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, Data);
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+ }
+
+ //
+ // Allocate memory for Signature and fill the Signature
+ //
+ SignatureSize = sizeof(EFI_SIGNATURE_DATA) - 1 + sizeof (EFI_TIME) + mHash[HashAlg].DigestLength;
+ SignatureData = (EFI_SIGNATURE_DATA *) AllocateZeroPool (SignatureSize);
+ if (SignatureData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ CopyGuid (&SignatureData->SignatureOwner, Private->SignatureGUID);
+ CopyMem (SignatureData->SignatureData, CertHash, mHash[HashAlg].DigestLength);
+
+ //
+ // Fill the time.
+ //
+ if (!AlwaysRevocation) {
+ Time = (EFI_TIME *)(&SignatureData->SignatureData + mHash[HashAlg].DigestLength);
+ Time->Year = RevocationDate->Year;
+ Time->Month = RevocationDate->Month;
+ Time->Day = RevocationDate->Day;
+ Time->Hour = RevocationTime->Hour;
+ Time->Minute = RevocationTime->Minute;
+ Time->Second = RevocationTime->Second;
+ }
+
+ //
+ // Determine the GUID for certificate hash.
+ //
+ switch (HashAlg) {
+ case HASHALG_SHA256:
+ SignatureType = gEfiCertX509Sha256Guid;
+ break;
+ case HASHALG_SHA384:
+ SignatureType = gEfiCertX509Sha384Guid;
+ break;
+ case HASHALG_SHA512:
+ SignatureType = gEfiCertX509Sha512Guid;
+ break;
+ default:
+ return FALSE;
+ }
+
+ //
+ // Add signature into the new variable data buffer
+ //
+ if (GetSignaturelistOffset((EFI_SIGNATURE_LIST *)Data, DataSize, &SignatureType, &Offset)) {
+ //
+ // Add the signature to the found signaturelist.
+ //
+ DbSize = DataSize + SignatureSize;
+ NewData = AllocateZeroPool (DbSize);
+ if (NewData == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+
+ SignatureList = (EFI_SIGNATURE_LIST *)(Data + Offset);
+ SignatureListSize = (UINTN) ReadUnaligned32 ((UINT32 *)&SignatureList->SignatureListSize);
+ CopyMem (NewData, Data, Offset + SignatureListSize);
+
+ SignatureList = (EFI_SIGNATURE_LIST *)(NewData + Offset);
+ WriteUnaligned32 ((UINT32 *) &SignatureList->SignatureListSize, (UINT32)(SignatureListSize + SignatureSize));
+
+ Offset += SignatureListSize;
+ CopyMem (NewData + Offset, SignatureData, SignatureSize);
+ CopyMem (NewData + Offset + SignatureSize, Data + Offset, DataSize - Offset);
+
+ FreePool (Data);
+ Data = NewData;
+ DataSize = DbSize;
+ } else {
+ //
+ // Create a new signaturelist, and add the signature into the signaturelist.
+ //
+ DbSize = DataSize + sizeof(EFI_SIGNATURE_LIST) + SignatureSize;
+ NewData = AllocateZeroPool (DbSize);
+ if (NewData == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+ //
+ // Fill Certificate Database parameters.
+ //
+ SignatureList = (EFI_SIGNATURE_LIST*) (NewData + DataSize);
+ SignatureListSize = sizeof(EFI_SIGNATURE_LIST) + SignatureSize;
+ WriteUnaligned32 ((UINT32 *) &SignatureList->SignatureListSize, (UINT32) SignatureListSize);
+ WriteUnaligned32 ((UINT32 *) &SignatureList->SignatureSize, (UINT32) SignatureSize);
+ CopyGuid (&SignatureList->SignatureType, &SignatureType);
+ CopyMem ((UINT8* ) SignatureList + sizeof (EFI_SIGNATURE_LIST), SignatureData, SignatureSize);
+ if ((DataSize != 0) && (Data != NULL)) {
+ CopyMem (NewData, Data, DataSize);
+ FreePool (Data);
+ }
+ Data = NewData;
+ DataSize = DbSize;
+ }
+
+ Status = CreateTimeBasedPayload (&DataSize, (UINT8**) &Data);
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+
+ Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS
+ | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
+ Status = gRT->SetVariable(
+ EFI_IMAGE_SECURITY_DATABASE1,
+ &gEfiImageSecurityDatabaseGuid,
+ Attr,
+ DataSize,
+ Data
+ );
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+
+ON_EXIT:
+
+ CloseEnrolledFile(Private->FileContext);
+
+ if (Private->SignatureGUID != NULL) {
+ FreePool (Private->SignatureGUID);
+ Private->SignatureGUID = NULL;
+ }
+
+ if (Data != NULL) {
+ FreePool (Data);
+ }
+
+ if (SignatureData != NULL) {
+ FreePool (SignatureData);
+ }
+
+ if (X509Data != NULL) {
+ FreePool (X509Data);
+ }
+
+ return Status;
+}
+
+/**
+ Check whether a certificate from a file exists in dbx.
+
+ @param[in] PrivateData The module's private data.
+ @param[in] VariableName Variable name of signature database, must be
+ EFI_IMAGE_SECURITY_DATABASE1.
+
+ @retval TRUE The X509 certificate is found in dbx successfully.
+ @retval FALSE The X509 certificate is not found in dbx.
+**/
+BOOLEAN
+IsX509CertInDbx (
+ IN SECUREBOOT_CONFIG_PRIVATE_DATA *Private,
+ IN CHAR16 *VariableName
+ )
+{
+ EFI_STATUS Status;
+ UINTN X509DataSize;
+ VOID *X509Data;
+ BOOLEAN IsFound;
+
+ //
+ // Read the certificate from file
+ //
+ X509DataSize = 0;
+ X509Data = NULL;
+ Status = ReadFileContent (
+ Private->FileContext->FHandle,
+ &X509Data,
+ &X509DataSize,
+ 0
+ );
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ //
+ // Check the raw certificate.
+ //
+ IsFound = FALSE;
+ if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE1, X509Data, X509DataSize)) {
+ IsFound = TRUE;
+ goto ON_EXIT;
+ }
+
+ //
+ // Check the hash of certificate.
+ //
+ if (IsCertHashFoundInDbx (X509Data, X509DataSize)) {
+ IsFound = TRUE;
+ goto ON_EXIT;
+ }
+
+ON_EXIT:
+ if (X509Data != NULL) {
+ FreePool (X509Data);
+ }
+
+ return IsFound;
+}
+
+/**
+ Reads contents of a PE/COFF image in memory buffer.
+
+ Caution: This function may receive untrusted input.
+ PE/COFF image is external input, so this function will make sure the PE/COFF image content
+ read is within the image 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
+SecureBootConfigImageRead (
+ IN VOID *FileHandle,
+ IN UINTN FileOffset,
+ IN OUT UINTN *ReadSize,
+ OUT VOID *Buffer
+ )
+{
+ UINTN EndPosition;
+
+ if (FileHandle == NULL || ReadSize == NULL || Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (MAX_ADDRESS - FileOffset < *ReadSize) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ EndPosition = FileOffset + *ReadSize;
+ if (EndPosition > mImageSize) {
+ *ReadSize = (UINT32)(mImageSize - FileOffset);
+ }
+
+ if (FileOffset >= mImageSize) {
+ *ReadSize = 0;
+ }
+
+ CopyMem (Buffer, (UINT8 *)((UINTN) FileHandle + FileOffset), *ReadSize);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Load PE/COFF image information into internal buffer and check its validity.
+
+ @retval EFI_SUCCESS Successful
+ @retval EFI_UNSUPPORTED Invalid PE/COFF file
+ @retval EFI_ABORTED Serious error occurs, like file I/O error etc.
+
+**/
+EFI_STATUS
+LoadPeImage (
+ VOID
+ )
+{
+ EFI_IMAGE_DOS_HEADER *DosHdr;
+ EFI_IMAGE_NT_HEADERS32 *NtHeader32;
+ EFI_IMAGE_NT_HEADERS64 *NtHeader64;
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
+ EFI_STATUS Status;
+
+ NtHeader32 = NULL;
+ NtHeader64 = NULL;
+
+ ZeroMem (&ImageContext, sizeof (ImageContext));
+ ImageContext.Handle = (VOID *) mImageBase;
+ ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) SecureBootConfigImageRead;
+
+ //
+ // Get information about the image being loaded
+ //
+ Status = PeCoffLoaderGetImageInfo (&ImageContext);
+ if (EFI_ERROR (Status)) {
+ //
+ // The information can't be got from the invalid PeImage
+ //
+ DEBUG ((DEBUG_INFO, "SecureBootConfigDxe: PeImage invalid. \n"));
+ return Status;
+ }
+
+ //
+ // Read the Dos header
+ //
+ 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;
+ }
+
+ //
+ // Read PE header and check the signature validity and machine compatibility
+ //
+ NtHeader32 = (EFI_IMAGE_NT_HEADERS32*) (mImageBase + mPeCoffHeaderOffset);
+ if (NtHeader32->Signature != EFI_IMAGE_NT_SIGNATURE)
+ {
+ return EFI_UNSUPPORTED;
+ }
+
+ mNtHeader.Pe32 = NtHeader32;
+
+ //
+ // Check the architecture field of PE header and get the Certificate Data Directory data
+ // Note the size of FileHeader field is constant for both IA32 and X64 arch
+ //
+ if ((NtHeader32->FileHeader.Machine == EFI_IMAGE_MACHINE_IA32)
+ || (NtHeader32->FileHeader.Machine == EFI_IMAGE_MACHINE_EBC)
+ || (NtHeader32->FileHeader.Machine == EFI_IMAGE_MACHINE_ARMTHUMB_MIXED)) {
+ //
+ // 32-bits Architecture
+ //
+ mImageType = ImageType_IA32;
+ mSecDataDir = (EFI_IMAGE_SECURITY_DATA_DIRECTORY*) &(NtHeader32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]);
+ }
+ else if ((NtHeader32->FileHeader.Machine == EFI_IMAGE_MACHINE_IA64)
+ || (NtHeader32->FileHeader.Machine == EFI_IMAGE_MACHINE_X64)
+ || (NtHeader32->FileHeader.Machine == EFI_IMAGE_MACHINE_AARCH64)) {
+ //
+ // 64-bits Architecture
+ //
+ mImageType = ImageType_X64;
+ NtHeader64 = (EFI_IMAGE_NT_HEADERS64 *) (mImageBase + mPeCoffHeaderOffset);
+ mSecDataDir = (EFI_IMAGE_SECURITY_DATA_DIRECTORY*) &(NtHeader64->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]);
+ } else {
+ return EFI_UNSUPPORTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Calculate hash of Pe/Coff image based on the authenticode image hashing in
+ PE/COFF Specification 8.0 Appendix A
+
+ Notes: PE/COFF image has been checked by BasePeCoffLib PeCoffLoaderGetImageInfo() in
+ the function LoadPeImage ().
+
+ @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_SHA256) {
+ return FALSE;
+ }
+
+ //
+ // Initialize context of hash.
+ //
+ ZeroMem (mImageDigest, MAX_DIGEST_SIZE);
+
+ mImageDigestSize = SHA256_DIGEST_SIZE;
+ mCertType = gEfiCertSha256Guid;
+
+ 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
+ //
+ if (mNtHeader.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ //
+ // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value
+ // in the PE/COFF Header. If the MachineType is Itanium(IA64) and the
+ // Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
+ // then override the magic value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
+ //
+ Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;
+ } else {
+ //
+ // Get the magic value from the PE/COFF Optional Header
+ //
+ 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) (&mNtHeader.Pe32->OptionalHeader.CheckSum) - (UINTN) HashBase;
+ } else {
+ //
+ // Use PE32+ offset.
+ //
+ HashSize = (UINTN) (&mNtHeader.Pe32Plus->OptionalHeader.CheckSum) - (UINTN) 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) (&mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - (UINTN) HashBase;
+ } else {
+ //
+ // Use PE32+ offset.
+ //
+ HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);
+ HashSize = (UINTN) (&mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - (UINTN) 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) (&mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]) - (UINTN) mImageBase);
+ } else {
+ //
+ // Use PE32+ offset.
+ //
+ HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];
+ HashSize = mNtHeader.Pe32Plus->OptionalHeader.SizeOfHeaders - ((UINTN) (&mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]) - (UINTN) 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 calculate hash of
+ Pe/Coff image based on the authenticated 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->Offset);
+
+ 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.
+ // Fixed offset (+32) is calculated based on two bytes of length encoding.
+ //
+ if ((*(PkcsCertData->CertData + 1) & TWO_BYTE_ENCODE) != TWO_BYTE_ENCODE) {
+ //
+ // Only support two bytes of Long Form of Length Encoding.
+ //
+ continue;
+ }
+
+ //
+ 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;
+}
+
+/**
+ Enroll a new executable's signature into Signature Database.
+
+ @param[in] PrivateData The module's private data.
+ @param[in] VariableName Variable name of signature database, must be
+ EFI_IMAGE_SECURITY_DATABASE, EFI_IMAGE_SECURITY_DATABASE1
+ or EFI_IMAGE_SECURITY_DATABASE2.
+
+ @retval EFI_SUCCESS New signature is enrolled successfully.
+ @retval EFI_INVALID_PARAMETER The parameter is invalid.
+ @retval EFI_UNSUPPORTED Unsupported command.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources.
+
+**/
+EFI_STATUS
+EnrollAuthentication2Descriptor (
+ IN SECUREBOOT_CONFIG_PRIVATE_DATA *Private,
+ IN CHAR16 *VariableName
+ )
+{
+ EFI_STATUS Status;
+ VOID *Data;
+ UINTN DataSize;
+ UINT32 Attr;
+
+ Data = NULL;
+
+ //
+ // DBT only support DER-X509 Cert Enrollment
+ //
+ if (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE2) == 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Read the whole file content
+ //
+ Status = ReadFileContent(
+ Private->FileContext->FHandle,
+ (VOID **) &mImageBase,
+ &mImageSize,
+ 0
+ );
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+ ASSERT (mImageBase != NULL);
+
+ Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS
+ | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
+
+ //
+ // Check if SigDB variable has been already existed.
+ // If true, use EFI_VARIABLE_APPEND_WRITE attribute to append the
+ // new signature data to original variable
+ //
+ DataSize = 0;
+ Status = gRT->GetVariable(
+ VariableName,
+ &gEfiImageSecurityDatabaseGuid,
+ NULL,
+ &DataSize,
+ NULL
+ );
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ Attr |= EFI_VARIABLE_APPEND_WRITE;
+ } else if (Status != EFI_NOT_FOUND) {
+ goto ON_EXIT;
+ }
+
+ //
+ // Diretly set AUTHENTICATION_2 data to SetVariable
+ //
+ Status = gRT->SetVariable(
+ VariableName,
+ &gEfiImageSecurityDatabaseGuid,
+ Attr,
+ mImageSize,
+ mImageBase
+ );
+
+ DEBUG((DEBUG_INFO, "Enroll AUTH_2 data to Var:%s Status: %x\n", VariableName, Status));
+
+ON_EXIT:
+
+ CloseEnrolledFile(Private->FileContext);
+
+ if (Data != NULL) {
+ FreePool (Data);
+ }
+
+ if (mImageBase != NULL) {
+ FreePool (mImageBase);
+ mImageBase = NULL;
+ }
+
+ return Status;
+
+}
+
+
+/**
+ Enroll a new executable's signature into Signature Database.
+
+ @param[in] PrivateData The module's private data.
+ @param[in] VariableName Variable name of signature database, must be
+ EFI_IMAGE_SECURITY_DATABASE, EFI_IMAGE_SECURITY_DATABASE1
+ or EFI_IMAGE_SECURITY_DATABASE2.
+
+ @retval EFI_SUCCESS New signature is enrolled successfully.
+ @retval EFI_INVALID_PARAMETER The parameter is invalid.
+ @retval EFI_UNSUPPORTED Unsupported command.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources.
+
+**/
+EFI_STATUS
+EnrollImageSignatureToSigDB (
+ IN SECUREBOOT_CONFIG_PRIVATE_DATA *Private,
+ IN CHAR16 *VariableName
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIGNATURE_LIST *SigDBCert;
+ EFI_SIGNATURE_DATA *SigDBCertData;
+ VOID *Data;
+ UINTN DataSize;
+ UINTN SigDBSize;
+ UINT32 Attr;
+ WIN_CERTIFICATE_UEFI_GUID *GuidCertData;
+
+ Data = NULL;
+ GuidCertData = NULL;
+
+ if (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE2) == 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Form the SigDB certificate list.
+ // Format the data item into EFI_SIGNATURE_LIST type.
+ //
+ // We need to parse executable's signature data from specified signed executable file.
+ // In current implementation, we simply trust the pass-in signed executable file.
+ // In reality, it's OS's responsibility to verify the signed executable file.
+ //
+
+ //
+ // Read the whole file content
+ //
+ Status = ReadFileContent(
+ Private->FileContext->FHandle,
+ (VOID **) &mImageBase,
+ &mImageSize,
+ 0
+ );
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+ ASSERT (mImageBase != NULL);
+
+ Status = LoadPeImage ();
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+
+ if (mSecDataDir->SizeOfCert == 0) {
+ if (!HashPeImage (HASHALG_SHA256)) {
+ Status = EFI_SECURITY_VIOLATION;
+ goto ON_EXIT;
+ }
+ } else {
+
+ //
+ // Read the certificate data
+ //
+ mCertificate = (WIN_CERTIFICATE *)(mImageBase + mSecDataDir->Offset);
+
+ if (mCertificate->wCertificateType == WIN_CERT_TYPE_EFI_GUID) {
+ GuidCertData = (WIN_CERTIFICATE_UEFI_GUID*) mCertificate;
+ if (CompareMem (&GuidCertData->CertType, &gEfiCertTypeRsa2048Sha256Guid, sizeof(EFI_GUID)) != 0) {
+ Status = EFI_ABORTED;
+ goto ON_EXIT;
+ }
+
+ if (!HashPeImage (HASHALG_SHA256)) {
+ Status = EFI_ABORTED;
+ goto ON_EXIT;;
+ }
+
+ } else if (mCertificate->wCertificateType == WIN_CERT_TYPE_PKCS_SIGNED_DATA) {
+
+ Status = HashPeImageByType ();
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;;
+ }
+ } else {
+ Status = EFI_ABORTED;
+ goto ON_EXIT;
+ }
+ }
+
+ //
+ // Create a new SigDB entry.
+ //
+ SigDBSize = sizeof(EFI_SIGNATURE_LIST)
+ + sizeof(EFI_SIGNATURE_DATA) - 1
+ + (UINT32) mImageDigestSize;
+
+ Data = (UINT8*) AllocateZeroPool (SigDBSize);
+ if (Data == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+
+ //
+ // Adjust the Certificate Database parameters.
+ //
+ SigDBCert = (EFI_SIGNATURE_LIST*) Data;
+ SigDBCert->SignatureListSize = (UINT32) SigDBSize;
+ SigDBCert->SignatureHeaderSize = 0;
+ SigDBCert->SignatureSize = sizeof(EFI_SIGNATURE_DATA) - 1 + (UINT32) mImageDigestSize;
+ CopyGuid (&SigDBCert->SignatureType, &mCertType);
+
+ SigDBCertData = (EFI_SIGNATURE_DATA*)((UINT8*)SigDBCert + sizeof(EFI_SIGNATURE_LIST));
+ CopyGuid (&SigDBCertData->SignatureOwner, Private->SignatureGUID);
+ CopyMem (SigDBCertData->SignatureData, mImageDigest, mImageDigestSize);
+
+ Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS
+ | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
+ Status = CreateTimeBasedPayload (&SigDBSize, (UINT8**) &Data);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status));
+ goto ON_EXIT;
+ }
+
+ //
+ // Check if SigDB variable has been already existed.
+ // If true, use EFI_VARIABLE_APPEND_WRITE attribute to append the
+ // new signature data to original variable
+ //
+ DataSize = 0;
+ Status = gRT->GetVariable(
+ VariableName,
+ &gEfiImageSecurityDatabaseGuid,
+ NULL,
+ &DataSize,
+ NULL
+ );
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ Attr |= EFI_VARIABLE_APPEND_WRITE;
+ } else if (Status != EFI_NOT_FOUND) {
+ goto ON_EXIT;
+ }
+
+ //
+ // Enroll the variable.
+ //
+ Status = gRT->SetVariable(
+ VariableName,
+ &gEfiImageSecurityDatabaseGuid,
+ Attr,
+ SigDBSize,
+ Data
+ );
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+
+ON_EXIT:
+
+ CloseEnrolledFile(Private->FileContext);
+
+ if (Private->SignatureGUID != NULL) {
+ FreePool (Private->SignatureGUID);
+ Private->SignatureGUID = NULL;
+ }
+
+ if (Data != NULL) {
+ FreePool (Data);
+ }
+
+ if (mImageBase != NULL) {
+ FreePool (mImageBase);
+ mImageBase = NULL;
+ }
+
+ return Status;
+}
+
+/**
+ Enroll signature into DB/DBX/DBT without KEK's authentication.
+ The SignatureOwner GUID will be Private->SignatureGUID.
+
+ @param[in] PrivateData The module's private data.
+ @param[in] VariableName Variable name of signature database, must be
+ EFI_IMAGE_SECURITY_DATABASE or EFI_IMAGE_SECURITY_DATABASE1.
+
+ @retval EFI_SUCCESS New signature enrolled successfully.
+ @retval EFI_INVALID_PARAMETER The parameter is invalid.
+ @retval others Fail to enroll signature data.
+
+**/
+EFI_STATUS
+EnrollSignatureDatabase (
+ IN SECUREBOOT_CONFIG_PRIVATE_DATA *Private,
+ IN CHAR16 *VariableName
+ )
+{
+ UINT16* FilePostFix;
+ EFI_STATUS Status;
+ UINTN NameLength;
+
+ if ((Private->FileContext->FileName == NULL) || (Private->FileContext->FHandle == NULL) || (Private->SignatureGUID == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = SetSecureBootMode (CUSTOM_SECURE_BOOT_MODE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Parse the file's postfix.
+ //
+ NameLength = StrLen (Private->FileContext->FileName);
+ if (NameLength <= 4) {
+ return EFI_INVALID_PARAMETER;
+ }
+ FilePostFix = Private->FileContext->FileName + NameLength - 4;
+ if (IsDerEncodeCertificate (FilePostFix)) {
+ //
+ // Supports DER-encoded X509 certificate.
+ //
+ return EnrollX509toSigDB (Private, VariableName);
+ } else if (IsAuthentication2Format(Private->FileContext->FHandle)){
+ return EnrollAuthentication2Descriptor(Private, VariableName);
+ } else {
+ return EnrollImageSignatureToSigDB (Private, VariableName);
+ }
+}
+
+/**
+ List all signatures in specified signature database (e.g. KEK/DB/DBX/DBT)
+ by GUID in the page for user to select and delete as needed.
+
+ @param[in] PrivateData Module's private data.
+ @param[in] VariableName The variable name of the vendor's signature database.
+ @param[in] VendorGuid A unique identifier for the vendor.
+ @param[in] LabelNumber Label number to insert opcodes.
+ @param[in] FormId Form ID of current page.
+ @param[in] QuestionIdBase Base question id of the signature list.
+
+ @retval EFI_SUCCESS Success to update the signature list page
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate required resources.
+
+**/
+EFI_STATUS
+UpdateDeletePage (
+ IN SECUREBOOT_CONFIG_PRIVATE_DATA *PrivateData,
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT16 LabelNumber,
+ IN EFI_FORM_ID FormId,
+ IN EFI_QUESTION_ID QuestionIdBase
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Index;
+ UINTN CertCount;
+ UINTN GuidIndex;
+ VOID *StartOpCodeHandle;
+ VOID *EndOpCodeHandle;
+ EFI_IFR_GUID_LABEL *StartLabel;
+ EFI_IFR_GUID_LABEL *EndLabel;
+ UINTN DataSize;
+ UINT8 *Data;
+ EFI_SIGNATURE_LIST *CertList;
+ EFI_SIGNATURE_DATA *Cert;
+ UINT32 ItemDataSize;
+ CHAR16 *GuidStr;
+ EFI_STRING_ID GuidID;
+ EFI_STRING_ID Help;
+
+ Data = NULL;
+ CertList = NULL;
+ Cert = NULL;
+ GuidStr = NULL;
+ StartOpCodeHandle = NULL;
+ EndOpCodeHandle = NULL;
+
+ //
+ // Initialize the container for dynamic opcodes.
+ //
+ StartOpCodeHandle = HiiAllocateOpCodeHandle ();
+ if (StartOpCodeHandle == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+
+ EndOpCodeHandle = HiiAllocateOpCodeHandle ();
+ if (EndOpCodeHandle == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+
+ //
+ // 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 = LabelNumber;
+
+ 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;
+
+ //
+ // Read Variable.
+ //
+ DataSize = 0;
+ Status = gRT->GetVariable (VariableName, VendorGuid, NULL, &DataSize, Data);
+ if (EFI_ERROR (Status) && Status != EFI_BUFFER_TOO_SMALL) {
+ goto ON_EXIT;
+ }
+
+ Data = (UINT8 *) AllocateZeroPool (DataSize);
+ if (Data == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+
+ Status = gRT->GetVariable (VariableName, VendorGuid, NULL, &DataSize, Data);
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+
+ GuidStr = AllocateZeroPool (100);
+ if (GuidStr == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+
+ //
+ // Enumerate all KEK pub data.
+ //
+ ItemDataSize = (UINT32) DataSize;
+ CertList = (EFI_SIGNATURE_LIST *) Data;
+ GuidIndex = 0;
+
+ while ((ItemDataSize > 0) && (ItemDataSize >= CertList->SignatureListSize)) {
+
+ if (CompareGuid (&CertList->SignatureType, &gEfiCertRsa2048Guid)) {
+ Help = STRING_TOKEN (STR_CERT_TYPE_RSA2048_SHA256_GUID);
+ } else if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {
+ Help = STRING_TOKEN (STR_CERT_TYPE_PCKS7_GUID);
+ } else if (CompareGuid (&CertList->SignatureType, &gEfiCertSha1Guid)) {
+ Help = STRING_TOKEN (STR_CERT_TYPE_SHA1_GUID);
+ } else if (CompareGuid (&CertList->SignatureType, &gEfiCertSha256Guid)) {
+ Help = STRING_TOKEN (STR_CERT_TYPE_SHA256_GUID);
+ } else if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Sha256Guid)) {
+ Help = STRING_TOKEN (STR_CERT_TYPE_X509_SHA256_GUID);
+ } else if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Sha384Guid)) {
+ Help = STRING_TOKEN (STR_CERT_TYPE_X509_SHA384_GUID);
+ } else if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Sha512Guid)) {
+ Help = STRING_TOKEN (STR_CERT_TYPE_X509_SHA512_GUID);
+ } else {
+ //
+ // The signature type is not supported in current implementation.
+ //
+ ItemDataSize -= CertList->SignatureListSize;
+ CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
+ continue;
+ }
+
+ CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
+ for (Index = 0; Index < CertCount; Index++) {
+ Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList
+ + sizeof (EFI_SIGNATURE_LIST)
+ + CertList->SignatureHeaderSize
+ + Index * CertList->SignatureSize);
+ //
+ // Display GUID and help
+ //
+ GuidToString (&Cert->SignatureOwner, GuidStr, 100);
+ GuidID = HiiSetString (PrivateData->HiiHandle, 0, GuidStr, NULL);
+ HiiCreateCheckBoxOpCode (
+ StartOpCodeHandle,
+ (EFI_QUESTION_ID) (QuestionIdBase + GuidIndex++),
+ 0,
+ 0,
+ GuidID,
+ Help,
+ EFI_IFR_FLAG_CALLBACK,
+ 0,
+ NULL
+ );
+ }
+
+ ItemDataSize -= CertList->SignatureListSize;
+ CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
+ }
+
+ON_EXIT:
+ HiiUpdateForm (
+ PrivateData->HiiHandle,
+ &gSecureBootConfigFormSetGuid,
+ FormId,
+ StartOpCodeHandle,
+ EndOpCodeHandle
+ );
+
+ if (StartOpCodeHandle != NULL) {
+ HiiFreeOpCodeHandle (StartOpCodeHandle);
+ }
+
+ if (EndOpCodeHandle != NULL) {
+ HiiFreeOpCodeHandle (EndOpCodeHandle);
+ }
+
+ if (Data != NULL) {
+ FreePool (Data);
+ }
+
+ if (GuidStr != NULL) {
+ FreePool (GuidStr);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Delete a KEK entry from KEK database.
+
+ @param[in] PrivateData Module's private data.
+ @param[in] QuestionId Question id of the KEK item to delete.
+
+ @retval EFI_SUCCESS Delete kek item successfully.
+ @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources.
+
+**/
+EFI_STATUS
+DeleteKeyExchangeKey (
+ IN SECUREBOOT_CONFIG_PRIVATE_DATA *PrivateData,
+ IN EFI_QUESTION_ID QuestionId
+ )
+{
+ EFI_STATUS Status;
+ UINTN DataSize;
+ UINT8 *Data;
+ UINT8 *OldData;
+ UINT32 Attr;
+ UINT32 Index;
+ EFI_SIGNATURE_LIST *CertList;
+ EFI_SIGNATURE_LIST *NewCertList;
+ EFI_SIGNATURE_DATA *Cert;
+ UINTN CertCount;
+ UINT32 Offset;
+ BOOLEAN IsKEKItemFound;
+ UINT32 KekDataSize;
+ UINTN DeleteKekIndex;
+ UINTN GuidIndex;
+
+ Data = NULL;
+ OldData = NULL;
+ CertList = NULL;
+ Cert = NULL;
+ Attr = 0;
+ DeleteKekIndex = QuestionId - OPTION_DEL_KEK_QUESTION_ID;
+
+ Status = SetSecureBootMode(CUSTOM_SECURE_BOOT_MODE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Get original KEK variable.
+ //
+ DataSize = 0;
+ Status = gRT->GetVariable (EFI_KEY_EXCHANGE_KEY_NAME, &gEfiGlobalVariableGuid, NULL, &DataSize, NULL);
+ if (EFI_ERROR(Status) && Status != EFI_BUFFER_TOO_SMALL) {
+ goto ON_EXIT;
+ }
+
+ OldData = (UINT8*)AllocateZeroPool(DataSize);
+ if (OldData == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+
+ Status = gRT->GetVariable (EFI_KEY_EXCHANGE_KEY_NAME, &gEfiGlobalVariableGuid, &Attr, &DataSize, OldData);
+ if (EFI_ERROR(Status)) {
+ goto ON_EXIT;
+ }
+
+ //
+ // Allocate space for new variable.
+ //
+ Data = (UINT8*) AllocateZeroPool (DataSize);
+ if (Data == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+
+ //
+ // Enumerate all KEK pub data and erasing the target item.
+ //
+ IsKEKItemFound = FALSE;
+ KekDataSize = (UINT32) DataSize;
+ CertList = (EFI_SIGNATURE_LIST *) OldData;
+ Offset = 0;
+ GuidIndex = 0;
+ while ((KekDataSize > 0) && (KekDataSize >= CertList->SignatureListSize)) {
+ if (CompareGuid (&CertList->SignatureType, &gEfiCertRsa2048Guid) ||
+ CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {
+ CopyMem (Data + Offset, CertList, (sizeof(EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize));
+ NewCertList = (EFI_SIGNATURE_LIST *)(Data + Offset);
+ Offset += (sizeof(EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
+ 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++) {
+ if (GuidIndex == DeleteKekIndex ) {
+ //
+ // Find it! Skip it!
+ //
+ NewCertList->SignatureListSize -= CertList->SignatureSize;
+ IsKEKItemFound = TRUE;
+ } else {
+ //
+ // This item doesn't match. Copy it to the Data buffer.
+ //
+ CopyMem (Data + Offset, Cert, CertList->SignatureSize);
+ Offset += CertList->SignatureSize;
+ }
+ GuidIndex++;
+ Cert = (EFI_SIGNATURE_DATA *) ((UINT8*) Cert + CertList->SignatureSize);
+ }
+ } else {
+ //
+ // This List doesn't match. Copy it to the Data buffer.
+ //
+ CopyMem (Data + Offset, CertList, CertList->SignatureListSize);
+ Offset += CertList->SignatureListSize;
+ }
+
+ KekDataSize -= CertList->SignatureListSize;
+ CertList = (EFI_SIGNATURE_LIST*) ((UINT8*) CertList + CertList->SignatureListSize);
+ }
+
+ if (!IsKEKItemFound) {
+ //
+ // Doesn't find the Kek Item!
+ //
+ Status = EFI_NOT_FOUND;
+ goto ON_EXIT;
+ }
+
+ //
+ // Delete the Signature header if there is no signature in the list.
+ //
+ KekDataSize = Offset;
+ CertList = (EFI_SIGNATURE_LIST*) Data;
+ Offset = 0;
+ ZeroMem (OldData, KekDataSize);
+ while ((KekDataSize > 0) && (KekDataSize >= CertList->SignatureListSize)) {
+ CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
+ DEBUG ((DEBUG_INFO, " CertCount = %x\n", CertCount));
+ if (CertCount != 0) {
+ CopyMem (OldData + Offset, CertList, CertList->SignatureListSize);
+ Offset += CertList->SignatureListSize;
+ }
+ KekDataSize -= CertList->SignatureListSize;
+ CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
+ }
+
+ DataSize = Offset;
+ if ((Attr & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {
+ Status = CreateTimeBasedPayload (&DataSize, &OldData);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status));
+ goto ON_EXIT;
+ }
+ }
+
+ Status = gRT->SetVariable(
+ EFI_KEY_EXCHANGE_KEY_NAME,
+ &gEfiGlobalVariableGuid,
+ Attr,
+ DataSize,
+ OldData
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Failed to set variable, Status = %r\n", Status));
+ goto ON_EXIT;
+ }
+
+ON_EXIT:
+ if (Data != NULL) {
+ FreePool(Data);
+ }
+
+ if (OldData != NULL) {
+ FreePool(OldData);
+ }
+
+ return UpdateDeletePage (
+ PrivateData,
+ EFI_KEY_EXCHANGE_KEY_NAME,
+ &gEfiGlobalVariableGuid,
+ LABEL_KEK_DELETE,
+ FORMID_DELETE_KEK_FORM,
+ OPTION_DEL_KEK_QUESTION_ID
+ );
+}
+
+/**
+ Delete a signature entry from siganture database.
+
+ @param[in] PrivateData Module's private data.
+ @param[in] VariableName The variable name of the vendor's signature database.
+ @param[in] VendorGuid A unique identifier for the vendor.
+ @param[in] LabelNumber Label number to insert opcodes.
+ @param[in] FormId Form ID of current page.
+ @param[in] QuestionIdBase Base question id of the signature list.
+ @param[in] DeleteIndex Signature index to delete.
+
+ @retval EFI_SUCCESS Delete siganture successfully.
+ @retval EFI_NOT_FOUND Can't find the signature item,
+ @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources.
+**/
+EFI_STATUS
+DeleteSignature (
+ IN SECUREBOOT_CONFIG_PRIVATE_DATA *PrivateData,
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT16 LabelNumber,
+ IN EFI_FORM_ID FormId,
+ IN EFI_QUESTION_ID QuestionIdBase,
+ IN UINTN DeleteIndex
+ )
+{
+ EFI_STATUS Status;
+ UINTN DataSize;
+ UINT8 *Data;
+ UINT8 *OldData;
+ UINT32 Attr;
+ UINT32 Index;
+ EFI_SIGNATURE_LIST *CertList;
+ EFI_SIGNATURE_LIST *NewCertList;
+ EFI_SIGNATURE_DATA *Cert;
+ UINTN CertCount;
+ UINT32 Offset;
+ BOOLEAN IsItemFound;
+ UINT32 ItemDataSize;
+ UINTN GuidIndex;
+
+ Data = NULL;
+ OldData = NULL;
+ CertList = NULL;
+ Cert = NULL;
+ Attr = 0;
+
+ Status = SetSecureBootMode(CUSTOM_SECURE_BOOT_MODE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Get original signature list data.
+ //
+ DataSize = 0;
+ Status = gRT->GetVariable (VariableName, VendorGuid, NULL, &DataSize, NULL);
+ if (EFI_ERROR (Status) && Status != EFI_BUFFER_TOO_SMALL) {
+ goto ON_EXIT;
+ }
+
+ OldData = (UINT8 *) AllocateZeroPool (DataSize);
+ if (OldData == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+
+ Status = gRT->GetVariable (VariableName, VendorGuid, &Attr, &DataSize, OldData);
+ if (EFI_ERROR(Status)) {
+ goto ON_EXIT;
+ }
+
+ //
+ // Allocate space for new variable.
+ //
+ Data = (UINT8*) AllocateZeroPool (DataSize);
+ if (Data == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ON_EXIT;
+ }
+
+ //
+ // Enumerate all signature data and erasing the target item.
+ //
+ IsItemFound = FALSE;
+ ItemDataSize = (UINT32) DataSize;
+ CertList = (EFI_SIGNATURE_LIST *) OldData;
+ Offset = 0;
+ GuidIndex = 0;
+ while ((ItemDataSize > 0) && (ItemDataSize >= CertList->SignatureListSize)) {
+ if (CompareGuid (&CertList->SignatureType, &gEfiCertRsa2048Guid) ||
+ CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid) ||
+ CompareGuid (&CertList->SignatureType, &gEfiCertSha1Guid) ||
+ CompareGuid (&CertList->SignatureType, &gEfiCertSha256Guid) ||
+ CompareGuid (&CertList->SignatureType, &gEfiCertX509Sha256Guid) ||
+ CompareGuid (&CertList->SignatureType, &gEfiCertX509Sha384Guid) ||
+ CompareGuid (&CertList->SignatureType, &gEfiCertX509Sha512Guid)
+ ) {
+ //
+ // Copy EFI_SIGNATURE_LIST header then calculate the signature count in this list.
+ //
+ CopyMem (Data + Offset, CertList, (sizeof(EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize));
+ NewCertList = (EFI_SIGNATURE_LIST*) (Data + Offset);
+ Offset += (sizeof(EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
+ 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++) {
+ if (GuidIndex == DeleteIndex) {
+ //
+ // Find it! Skip it!
+ //
+ NewCertList->SignatureListSize -= CertList->SignatureSize;
+ IsItemFound = TRUE;
+ } else {
+ //
+ // This item doesn't match. Copy it to the Data buffer.
+ //
+ CopyMem (Data + Offset, (UINT8*)(Cert), CertList->SignatureSize);
+ Offset += CertList->SignatureSize;
+ }
+ GuidIndex++;
+ Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);
+ }
+ } else {
+ //
+ // This List doesn't match. Just copy it to the Data buffer.
+ //
+ CopyMem (Data + Offset, (UINT8*)(CertList), CertList->SignatureListSize);
+ Offset += CertList->SignatureListSize;
+ }
+
+ ItemDataSize -= CertList->SignatureListSize;
+ CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
+ }
+
+ if (!IsItemFound) {
+ //
+ // Doesn't find the signature Item!
+ //
+ Status = EFI_NOT_FOUND;
+ goto ON_EXIT;
+ }
+
+ //
+ // Delete the EFI_SIGNATURE_LIST header if there is no signature in the list.
+ //
+ ItemDataSize = Offset;
+ CertList = (EFI_SIGNATURE_LIST *) Data;
+ Offset = 0;
+ ZeroMem (OldData, ItemDataSize);
+ while ((ItemDataSize > 0) && (ItemDataSize >= CertList->SignatureListSize)) {
+ CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
+ DEBUG ((DEBUG_INFO, " CertCount = %x\n", CertCount));
+ if (CertCount != 0) {
+ CopyMem (OldData + Offset, (UINT8*)(CertList), CertList->SignatureListSize);
+ Offset += CertList->SignatureListSize;
+ }
+ ItemDataSize -= CertList->SignatureListSize;
+ CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
+ }
+
+ DataSize = Offset;
+ if ((Attr & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {
+ Status = CreateTimeBasedPayload (&DataSize, &OldData);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status));
+ goto ON_EXIT;
+ }
+ }
+
+ Status = gRT->SetVariable(
+ VariableName,
+ VendorGuid,
+ Attr,
+ DataSize,
+ OldData
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Failed to set variable, Status = %r\n", Status));
+ goto ON_EXIT;
+ }
+
+ON_EXIT:
+ if (Data != NULL) {
+ FreePool(Data);
+ }
+
+ if (OldData != NULL) {
+ FreePool(OldData);
+ }
+
+ return UpdateDeletePage (
+ PrivateData,
+ VariableName,
+ VendorGuid,
+ LabelNumber,
+ FormId,
+ QuestionIdBase
+ );
+}
+
+/**
+
+ Update SecureBoot strings based on new Secure Boot Mode State. String includes STR_SECURE_BOOT_STATE_CONTENT
+ and STR_CUR_SECURE_BOOT_MODE_CONTENT.
+
+ @param[in] PrivateData Module's private data.
+
+ @return EFI_SUCCESS Update secure boot strings successfully.
+ @return other Fail to update secure boot strings.
+
+**/
+EFI_STATUS
+UpdateSecureBootString(
+ IN SECUREBOOT_CONFIG_PRIVATE_DATA *Private
+ )
+{
+ UINT8 *SecureBoot;
+
+ SecureBoot = NULL;
+
+ //
+ // Get current secure boot state.
+ //
+ GetVariable2 (EFI_SECURE_BOOT_MODE_NAME, &gEfiGlobalVariableGuid, (VOID**)&SecureBoot, NULL);
+ if (SecureBoot == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (*SecureBoot == SECURE_BOOT_MODE_ENABLE) {
+ HiiSetString (Private->HiiHandle, STRING_TOKEN (STR_SECURE_BOOT_STATE_CONTENT), L"Enabled", NULL);
+ } else {
+ HiiSetString (Private->HiiHandle, STRING_TOKEN (STR_SECURE_BOOT_STATE_CONTENT), L"Disabled", NULL);
+ }
+
+ FreePool(SecureBoot);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function extracts configuration from variable.
+
+ @param[in] Private Point to SecureBoot configuration driver private data.
+ @param[in, out] ConfigData Point to SecureBoot configuration private data.
+
+**/
+VOID
+SecureBootExtractConfigFromVariable (
+ IN SECUREBOOT_CONFIG_PRIVATE_DATA *Private,
+ IN OUT SECUREBOOT_CONFIGURATION *ConfigData
+ )
+{
+ UINT8 *SecureBootEnable;
+ UINT8 *SetupMode;
+ UINT8 *SecureBootMode;
+ EFI_TIME CurrTime;
+
+ SecureBootEnable = NULL;
+ SetupMode = NULL;
+ SecureBootMode = NULL;
+
+ //
+ // Initilize the Date and Time using system time.
+ //
+ ConfigData->CertificateFormat = HASHALG_RAW;
+ ConfigData->AlwaysRevocation = TRUE;
+ gRT->GetTime (&CurrTime, NULL);
+ ConfigData->RevocationDate.Year = CurrTime.Year;
+ ConfigData->RevocationDate.Month = CurrTime.Month;
+ ConfigData->RevocationDate.Day = CurrTime.Day;
+ ConfigData->RevocationTime.Hour = CurrTime.Hour;
+ ConfigData->RevocationTime.Minute = CurrTime.Minute;
+ ConfigData->RevocationTime.Second = 0;
+ if (Private->FileContext->FHandle != NULL) {
+ ConfigData->FileEnrollType = Private->FileContext->FileType;
+ } else {
+ ConfigData->FileEnrollType = UNKNOWN_FILE_TYPE;
+ }
+
+ //
+ // If it is Physical Presence User, set the PhysicalPresent to true.
+ //
+ if (UserPhysicalPresent()) {
+ ConfigData->PhysicalPresent = TRUE;
+ } else {
+ ConfigData->PhysicalPresent = FALSE;
+ }
+
+ //
+ // If there is no PK then the Delete Pk button will be gray.
+ //
+ GetVariable2 (EFI_SETUP_MODE_NAME, &gEfiGlobalVariableGuid, (VOID**)&SetupMode, NULL);
+ if (SetupMode == NULL || (*SetupMode) == SETUP_MODE) {
+ ConfigData->HasPk = FALSE;
+ } else {
+ ConfigData->HasPk = TRUE;
+ }
+
+ //
+ // Check SecureBootEnable & Pk status, fix the inconsistence.
+ // If the SecureBootEnable Variable doesn't exist, hide the SecureBoot Enable/Disable
+ // Checkbox.
+ //
+ ConfigData->AttemptSecureBoot = FALSE;
+ GetVariable2 (EFI_SECURE_BOOT_ENABLE_NAME, &gEfiSecureBootEnableDisableGuid, (VOID**)&SecureBootEnable, NULL);
+
+ //
+ // Fix Pk, SecureBootEnable inconsistence
+ //
+ if ((SetupMode != NULL) && (*SetupMode) == USER_MODE) {
+ ConfigData->HideSecureBoot = FALSE;
+ if ((SecureBootEnable != NULL) && (*SecureBootEnable == SECURE_BOOT_ENABLE)) {
+ ConfigData->AttemptSecureBoot = TRUE;
+ }
+ } else {
+ ConfigData->HideSecureBoot = TRUE;
+ }
+
+ //
+ // Get the SecureBootMode from CustomMode variable.
+ //
+ GetVariable2 (EFI_CUSTOM_MODE_NAME, &gEfiCustomModeEnableGuid, (VOID**)&SecureBootMode, NULL);
+ if (SecureBootMode == NULL) {
+ ConfigData->SecureBootMode = STANDARD_SECURE_BOOT_MODE;
+ } else {
+ ConfigData->SecureBootMode = *(SecureBootMode);
+ }
+
+ if (SecureBootEnable != NULL) {
+ FreePool (SecureBootEnable);
+ }
+ if (SetupMode != NULL) {
+ FreePool (SetupMode);
+ }
+ if (SecureBootMode != NULL) {
+ FreePool (SecureBootMode);
+ }
+}
+
+/**
+ This function allows a caller to extract the current configuration for one
+ or more named elements from the target driver.
+
+ @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param[in] Request A null-terminated Unicode string in
+ <ConfigRequest> format.
+ @param[out] Progress On return, points to a character in the Request
+ string. Points to the string's null terminator if
+ request was successful. Points to the most recent
+ '&' before the first failing name/value pair (or
+ the beginning of the string if the failure is in
+ the first name/value pair) if the request was not
+ successful.
+ @param[out] Results A null-terminated Unicode string in
+ <ConfigAltResp> format which has all values filled
+ in for the names in the Request string. String to
+ be allocated by the called function.
+
+ @retval EFI_SUCCESS The Results is filled with the requested values.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results.
+ @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name.
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in this
+ driver.
+
+**/
+EFI_STATUS
+EFIAPI
+SecureBootExtractConfig (
+ 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;
+ UINTN Size;
+ SECUREBOOT_CONFIGURATION Configuration;
+ EFI_STRING ConfigRequest;
+ EFI_STRING ConfigRequestHdr;
+ SECUREBOOT_CONFIG_PRIVATE_DATA *PrivateData;
+ BOOLEAN AllocatedRequest;
+
+ if (Progress == NULL || Results == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ AllocatedRequest = FALSE;
+ ConfigRequestHdr = NULL;
+ ConfigRequest = NULL;
+ Size = 0;
+
+ ZeroMem (&Configuration, sizeof (Configuration));
+ PrivateData = SECUREBOOT_CONFIG_PRIVATE_FROM_THIS (This);
+ *Progress = Request;
+
+ if ((Request != NULL) && !HiiIsConfigHdrMatch (Request, &gSecureBootConfigFormSetGuid, mSecureBootStorageName)) {
+ return EFI_NOT_FOUND;
+ }
+
+ ZeroMem(&Configuration, sizeof(SECUREBOOT_CONFIGURATION));
+
+ //
+ // Get Configuration from Variable.
+ //
+ SecureBootExtractConfigFromVariable (PrivateData, &Configuration);
+
+ BufferSize = sizeof (SECUREBOOT_CONFIGURATION);
+ ConfigRequest = Request;
+ if ((Request == NULL) || (StrStr (Request, L"OFFSET") == NULL)) {
+ //
+ // Request is set to NULL or OFFSET is NULL, construct full request string.
+ //
+ // Allocate and fill a buffer large enough to hold the <ConfigHdr> template
+ // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator
+ //
+ ConfigRequestHdr = HiiConstructConfigHdr (&gSecureBootConfigFormSetGuid, mSecureBootStorageName, 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);
+ ConfigRequestHdr = NULL;
+ }
+
+ 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 <ConfigResp>
+ 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
+SecureBootRouteConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Configuration,
+ OUT EFI_STRING *Progress
+ )
+{
+ SECUREBOOT_CONFIGURATION IfrNvData;
+ UINTN BufferSize;
+ SECUREBOOT_CONFIG_PRIVATE_DATA *PrivateData;
+ EFI_STATUS Status;
+
+ if (Configuration == NULL || Progress == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *Progress = Configuration;
+ if (!HiiIsConfigHdrMatch (Configuration, &gSecureBootConfigFormSetGuid, mSecureBootStorageName)) {
+ return EFI_NOT_FOUND;
+ }
+
+ PrivateData = SECUREBOOT_CONFIG_PRIVATE_FROM_THIS (This);
+
+ //
+ // Get Configuration from Variable.
+ //
+ SecureBootExtractConfigFromVariable (PrivateData, &IfrNvData);
+
+ //
+ // Map the Configuration to the configuration block.
+ //
+ BufferSize = sizeof (SECUREBOOT_CONFIGURATION);
+ Status = gHiiConfigRouting->ConfigToBlock (
+ gHiiConfigRouting,
+ Configuration,
+ (UINT8 *)&IfrNvData,
+ &BufferSize,
+ Progress
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Store Buffer Storage back to EFI variable if needed
+ //
+ if (!IfrNvData.HideSecureBoot) {
+ Status = SaveSecureBootVariable (IfrNvData.AttemptSecureBoot);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ *Progress = Configuration + StrLen (Configuration);
+ return EFI_SUCCESS;
+}
+
+/**
+ This function is called to provide results data to the driver.
+
+ @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
+SecureBootCallback (
+ 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_INPUT_KEY Key;
+ EFI_STATUS Status;
+ RETURN_STATUS RStatus;
+ SECUREBOOT_CONFIG_PRIVATE_DATA *Private;
+ UINTN BufferSize;
+ SECUREBOOT_CONFIGURATION *IfrNvData;
+ UINT16 LabelId;
+ UINT8 *SecureBootEnable;
+ UINT8 *Pk;
+ UINT8 *SecureBootMode;
+ UINT8 *SetupMode;
+ CHAR16 PromptString[100];
+ EFI_DEVICE_PATH_PROTOCOL *File;
+ UINTN NameLength;
+ UINT16 *FilePostFix;
+ SECUREBOOT_CONFIG_PRIVATE_DATA *PrivateData;
+
+ Status = EFI_SUCCESS;
+ SecureBootEnable = NULL;
+ SecureBootMode = NULL;
+ SetupMode = NULL;
+ File = NULL;
+
+ if ((This == NULL) || (Value == NULL) || (ActionRequest == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = SECUREBOOT_CONFIG_PRIVATE_FROM_THIS (This);
+
+ gSecureBootPrivateData = Private;
+
+ //
+ // Retrieve uncommitted data from Browser
+ //
+ BufferSize = sizeof (SECUREBOOT_CONFIGURATION);
+ IfrNvData = AllocateZeroPool (BufferSize);
+ if (IfrNvData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ HiiGetBrowserData (&gSecureBootConfigFormSetGuid, mSecureBootStorageName, BufferSize, (UINT8 *) IfrNvData);
+
+ if (Action == EFI_BROWSER_ACTION_FORM_OPEN) {
+ if (QuestionId == KEY_SECURE_BOOT_MODE) {
+ //
+ // Update secure boot strings when opening this form
+ //
+ Status = UpdateSecureBootString(Private);
+ SecureBootExtractConfigFromVariable (Private, IfrNvData);
+ mIsEnterSecureBootForm = TRUE;
+ } else {
+ //
+ // When entering SecureBoot OPTION Form
+ // always close opened file & free resource
+ //
+ if ((QuestionId == KEY_SECURE_BOOT_PK_OPTION) ||
+ (QuestionId == KEY_SECURE_BOOT_KEK_OPTION) ||
+ (QuestionId == KEY_SECURE_BOOT_DB_OPTION) ||
+ (QuestionId == KEY_SECURE_BOOT_DBX_OPTION) ||
+ (QuestionId == KEY_SECURE_BOOT_DBT_OPTION)) {
+ CloseEnrolledFile(Private->FileContext);
+ }
+ }
+ goto EXIT;
+ }
+
+ if (Action == EFI_BROWSER_ACTION_RETRIEVE) {
+ Status = EFI_UNSUPPORTED;
+ if (QuestionId == KEY_SECURE_BOOT_MODE) {
+ if (mIsEnterSecureBootForm) {
+ Value->u8 = SECURE_BOOT_MODE_STANDARD;
+ Status = EFI_SUCCESS;
+ }
+ }
+ goto EXIT;
+ }
+
+ if ((Action != EFI_BROWSER_ACTION_CHANGED) &&
+ (Action != EFI_BROWSER_ACTION_CHANGING) &&
+ (Action != EFI_BROWSER_ACTION_FORM_CLOSE) &&
+ (Action != EFI_BROWSER_ACTION_DEFAULT_STANDARD)) {
+ Status = EFI_UNSUPPORTED;
+ goto EXIT;
+ }
+
+ if (Action == EFI_BROWSER_ACTION_CHANGING) {
+
+ switch (QuestionId) {
+ case KEY_SECURE_BOOT_ENABLE:
+ GetVariable2 (EFI_SECURE_BOOT_ENABLE_NAME, &gEfiSecureBootEnableDisableGuid, (VOID**)&SecureBootEnable, NULL);
+ if (NULL != SecureBootEnable) {
+ FreePool (SecureBootEnable);
+ if (EFI_ERROR (SaveSecureBootVariable (Value->u8))) {
+ CreatePopUp (
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
+ &Key,
+ L"Only Physical Presence User could disable secure boot!",
+ NULL
+ );
+ Status = EFI_UNSUPPORTED;
+ } else {
+ CreatePopUp (
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
+ &Key,
+ L"Configuration changed, please reset the platform to take effect!",
+ NULL
+ );
+ }
+ }
+ break;
+
+ case KEY_SECURE_BOOT_KEK_OPTION:
+ case KEY_SECURE_BOOT_DB_OPTION:
+ case KEY_SECURE_BOOT_DBX_OPTION:
+ case KEY_SECURE_BOOT_DBT_OPTION:
+ PrivateData = SECUREBOOT_CONFIG_PRIVATE_FROM_THIS (This);
+ //
+ // Clear Signature GUID.
+ //
+ ZeroMem (IfrNvData->SignatureGuid, sizeof (IfrNvData->SignatureGuid));
+ if (Private->SignatureGUID == NULL) {
+ Private->SignatureGUID = (EFI_GUID *) AllocateZeroPool (sizeof (EFI_GUID));
+ if (Private->SignatureGUID == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ //
+ // Cleanup VFRData once leaving PK/KEK/DB/DBX/DBT enroll/delete page
+ //
+ SecureBootExtractConfigFromVariable (PrivateData, IfrNvData);
+
+ if (QuestionId == KEY_SECURE_BOOT_DB_OPTION) {
+ LabelId = SECUREBOOT_ENROLL_SIGNATURE_TO_DB;
+ } else if (QuestionId == KEY_SECURE_BOOT_DBX_OPTION) {
+ LabelId = SECUREBOOT_ENROLL_SIGNATURE_TO_DBX;
+ } else if (QuestionId == KEY_SECURE_BOOT_DBT_OPTION) {
+ LabelId = SECUREBOOT_ENROLL_SIGNATURE_TO_DBT;
+ } else {
+ LabelId = FORMID_ENROLL_KEK_FORM;
+ }
+
+ //
+ // Refresh selected file.
+ //
+ CleanUpPage (LabelId, Private);
+ break;
+ case KEY_SECURE_BOOT_PK_OPTION:
+ LabelId = FORMID_ENROLL_PK_FORM;
+ //
+ // Refresh selected file.
+ //
+ CleanUpPage (LabelId, Private);
+ break;
+
+ case FORMID_ENROLL_PK_FORM:
+ ChooseFile (NULL, NULL, UpdatePKFromFile, &File);
+ break;
+
+ case FORMID_ENROLL_KEK_FORM:
+ ChooseFile (NULL, NULL, UpdateKEKFromFile, &File);
+ break;
+
+ case SECUREBOOT_ENROLL_SIGNATURE_TO_DB:
+ ChooseFile (NULL, NULL, UpdateDBFromFile, &File);
+ break;
+
+ case SECUREBOOT_ENROLL_SIGNATURE_TO_DBX:
+ ChooseFile (NULL, NULL, UpdateDBXFromFile, &File);
+
+ if (Private->FileContext->FHandle != NULL) {
+ //
+ // Parse the file's postfix.
+ //
+ NameLength = StrLen (Private->FileContext->FileName);
+ if (NameLength <= 4) {
+ return FALSE;
+ }
+ FilePostFix = Private->FileContext->FileName + NameLength - 4;
+
+ if (IsDerEncodeCertificate (FilePostFix)) {
+ //
+ // Supports DER-encoded X509 certificate.
+ //
+ IfrNvData->FileEnrollType = X509_CERT_FILE_TYPE;
+ } else if (IsAuthentication2Format(Private->FileContext->FHandle)){
+ IfrNvData->FileEnrollType = AUTHENTICATION_2_FILE_TYPE;
+ } else {
+ IfrNvData->FileEnrollType = PE_IMAGE_FILE_TYPE;
+ }
+ Private->FileContext->FileType = IfrNvData->FileEnrollType;
+
+ //
+ // Clean up Certificate Format if File type is not X509 DER
+ //
+ if (IfrNvData->FileEnrollType != X509_CERT_FILE_TYPE) {
+ IfrNvData->CertificateFormat = HASHALG_RAW;
+ }
+ DEBUG((DEBUG_ERROR, "IfrNvData->FileEnrollType %d\n", Private->FileContext->FileType));
+ }
+
+ break;
+
+ case SECUREBOOT_ENROLL_SIGNATURE_TO_DBT:
+ ChooseFile (NULL, NULL, UpdateDBTFromFile, &File);
+ break;
+
+ case KEY_SECURE_BOOT_DELETE_PK:
+ if (Value->u8) {
+ CreatePopUp (
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
+ &Key,
+ L"Are you sure you want to delete PK? Secure boot will be disabled!",
+ L"Press 'Y' to delete PK and exit, 'N' to discard change and return",
+ NULL
+ );
+ if (Key.UnicodeChar == 'y' || Key.UnicodeChar == 'Y') {
+ Status = DeletePlatformKey ();
+ if (EFI_ERROR (Status)) {
+ CreatePopUp (
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
+ &Key,
+ L"Only Physical Presence User could delete PK in custom mode!",
+ NULL
+ );
+ }
+ }
+ }
+ break;
+
+ case KEY_DELETE_KEK:
+ UpdateDeletePage (
+ Private,
+ EFI_KEY_EXCHANGE_KEY_NAME,
+ &gEfiGlobalVariableGuid,
+ LABEL_KEK_DELETE,
+ FORMID_DELETE_KEK_FORM,
+ OPTION_DEL_KEK_QUESTION_ID
+ );
+ break;
+
+ case SECUREBOOT_DELETE_SIGNATURE_FROM_DB:
+ UpdateDeletePage (
+ Private,
+ EFI_IMAGE_SECURITY_DATABASE,
+ &gEfiImageSecurityDatabaseGuid,
+ LABEL_DB_DELETE,
+ SECUREBOOT_DELETE_SIGNATURE_FROM_DB,
+ OPTION_DEL_DB_QUESTION_ID
+ );
+ break;
+
+ case SECUREBOOT_DELETE_SIGNATURE_FROM_DBX:
+ UpdateDeletePage (
+ Private,
+ EFI_IMAGE_SECURITY_DATABASE1,
+ &gEfiImageSecurityDatabaseGuid,
+ LABEL_DBX_DELETE,
+ SECUREBOOT_DELETE_SIGNATURE_FROM_DBX,
+ OPTION_DEL_DBX_QUESTION_ID
+ );
+
+ break;
+
+ case SECUREBOOT_DELETE_SIGNATURE_FROM_DBT:
+ UpdateDeletePage (
+ Private,
+ EFI_IMAGE_SECURITY_DATABASE2,
+ &gEfiImageSecurityDatabaseGuid,
+ LABEL_DBT_DELETE,
+ SECUREBOOT_DELETE_SIGNATURE_FROM_DBT,
+ OPTION_DEL_DBT_QUESTION_ID
+ );
+
+ break;
+
+ case KEY_VALUE_SAVE_AND_EXIT_KEK:
+ Status = EnrollKeyExchangeKey (Private);
+ if (EFI_ERROR (Status)) {
+ CreatePopUp (
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
+ &Key,
+ L"ERROR: Unsupported file type!",
+ L"Only supports DER-encoded X509 certificate",
+ NULL
+ );
+ }
+ break;
+
+ case KEY_VALUE_SAVE_AND_EXIT_DB:
+ Status = EnrollSignatureDatabase (Private, EFI_IMAGE_SECURITY_DATABASE);
+ if (EFI_ERROR (Status)) {
+ CreatePopUp (
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
+ &Key,
+ L"ERROR: Unsupported file type!",
+ L"Only supports DER-encoded X509 certificate and executable EFI image",
+ NULL
+ );
+ }
+ break;
+
+ case KEY_VALUE_SAVE_AND_EXIT_DBX:
+ if (IsX509CertInDbx (Private, EFI_IMAGE_SECURITY_DATABASE1)) {
+ CreatePopUp (
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
+ &Key,
+ L"Enrollment failed! Same certificate had already been in the dbx!",
+ NULL
+ );
+
+ //
+ // Cert already exists in DBX. Close opened file before exit.
+ //
+ CloseEnrolledFile(Private->FileContext);
+ break;
+ }
+
+ if ((IfrNvData != NULL) && (IfrNvData->CertificateFormat < HASHALG_MAX)) {
+ Status = EnrollX509HashtoSigDB (
+ Private,
+ IfrNvData->CertificateFormat,
+ &IfrNvData->RevocationDate,
+ &IfrNvData->RevocationTime,
+ IfrNvData->AlwaysRevocation
+ );
+ IfrNvData->CertificateFormat = HASHALG_RAW;
+ } else {
+ Status = EnrollSignatureDatabase (Private, EFI_IMAGE_SECURITY_DATABASE1);
+ }
+ if (EFI_ERROR (Status)) {
+ CreatePopUp (
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
+ &Key,
+ L"ERROR: Unsupported file type!",
+ L"Only supports DER-encoded X509 certificate, AUTH_2 format data & executable EFI image",
+ NULL
+ );
+ }
+ break;
+
+ case KEY_VALUE_SAVE_AND_EXIT_DBT:
+ Status = EnrollSignatureDatabase (Private, EFI_IMAGE_SECURITY_DATABASE2);
+ if (EFI_ERROR (Status)) {
+ CreatePopUp (
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
+ &Key,
+ L"ERROR: Unsupported file type!",
+ L"Only supports DER-encoded X509 certificate.",
+ NULL
+ );
+ }
+ break;
+ case KEY_VALUE_SAVE_AND_EXIT_PK:
+ Status = EnrollPlatformKey (Private);
+ if (EFI_ERROR (Status)) {
+ UnicodeSPrint (
+ PromptString,
+ sizeof (PromptString),
+ L"Only DER encoded certificate file (%s) is supported.",
+ mSupportX509Suffix
+ );
+ CreatePopUp (
+ EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
+ &Key,
+ L"ERROR: Unsupported file type!",
+ PromptString,
+ NULL
+ );
+ }
+ break;
+ default:
+ if ((QuestionId >= OPTION_DEL_KEK_QUESTION_ID) &&
+ (QuestionId < (OPTION_DEL_KEK_QUESTION_ID + OPTION_CONFIG_RANGE))) {
+ DeleteKeyExchangeKey (Private, QuestionId);
+ } else if ((QuestionId >= OPTION_DEL_DB_QUESTION_ID) &&
+ (QuestionId < (OPTION_DEL_DB_QUESTION_ID + OPTION_CONFIG_RANGE))) {
+ DeleteSignature (
+ Private,
+ EFI_IMAGE_SECURITY_DATABASE,
+ &gEfiImageSecurityDatabaseGuid,
+ LABEL_DB_DELETE,
+ SECUREBOOT_DELETE_SIGNATURE_FROM_DB,
+ OPTION_DEL_DB_QUESTION_ID,
+ QuestionId - OPTION_DEL_DB_QUESTION_ID
+ );
+ } else if ((QuestionId >= OPTION_DEL_DBX_QUESTION_ID) &&
+ (QuestionId < (OPTION_DEL_DBX_QUESTION_ID + OPTION_CONFIG_RANGE))) {
+ DeleteSignature (
+ Private,
+ EFI_IMAGE_SECURITY_DATABASE1,
+ &gEfiImageSecurityDatabaseGuid,
+ LABEL_DBX_DELETE,
+ SECUREBOOT_DELETE_SIGNATURE_FROM_DBX,
+ OPTION_DEL_DBX_QUESTION_ID,
+ QuestionId - OPTION_DEL_DBX_QUESTION_ID
+ );
+ } else if ((QuestionId >= OPTION_DEL_DBT_QUESTION_ID) &&
+ (QuestionId < (OPTION_DEL_DBT_QUESTION_ID + OPTION_CONFIG_RANGE))) {
+ DeleteSignature (
+ Private,
+ EFI_IMAGE_SECURITY_DATABASE2,
+ &gEfiImageSecurityDatabaseGuid,
+ LABEL_DBT_DELETE,
+ SECUREBOOT_DELETE_SIGNATURE_FROM_DBT,
+ OPTION_DEL_DBT_QUESTION_ID,
+ QuestionId - OPTION_DEL_DBT_QUESTION_ID
+ );
+ }
+ break;
+
+ case KEY_VALUE_NO_SAVE_AND_EXIT_PK:
+ case KEY_VALUE_NO_SAVE_AND_EXIT_KEK:
+ case KEY_VALUE_NO_SAVE_AND_EXIT_DB:
+ case KEY_VALUE_NO_SAVE_AND_EXIT_DBX:
+ case KEY_VALUE_NO_SAVE_AND_EXIT_DBT:
+ CloseEnrolledFile(Private->FileContext);
+
+ if (Private->SignatureGUID != NULL) {
+ FreePool (Private->SignatureGUID);
+ Private->SignatureGUID = NULL;
+ }
+ break;
+ }
+ } else if (Action == EFI_BROWSER_ACTION_CHANGED) {
+ switch (QuestionId) {
+ case KEY_SECURE_BOOT_ENABLE:
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;
+ break;
+ case KEY_SECURE_BOOT_MODE:
+ mIsEnterSecureBootForm = FALSE;
+ break;
+ case KEY_SECURE_BOOT_KEK_GUID:
+ case KEY_SECURE_BOOT_SIGNATURE_GUID_DB:
+ case KEY_SECURE_BOOT_SIGNATURE_GUID_DBX:
+ case KEY_SECURE_BOOT_SIGNATURE_GUID_DBT:
+ ASSERT (Private->SignatureGUID != NULL);
+ RStatus = StrToGuid (IfrNvData->SignatureGuid, Private->SignatureGUID);
+ if (RETURN_ERROR (RStatus) || (IfrNvData->SignatureGuid[GUID_STRING_LENGTH] != L'\0')) {
+ Status = EFI_INVALID_PARAMETER;
+ break;
+ }
+
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;
+ break;
+ case KEY_SECURE_BOOT_DELETE_PK:
+ GetVariable2 (EFI_SETUP_MODE_NAME, &gEfiGlobalVariableGuid, (VOID**)&SetupMode, NULL);
+ if (SetupMode == NULL || (*SetupMode) == SETUP_MODE) {
+ IfrNvData->DeletePk = TRUE;
+ IfrNvData->HasPk = FALSE;
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT;
+ } else {
+ IfrNvData->DeletePk = FALSE;
+ IfrNvData->HasPk = TRUE;
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;
+ }
+ if (SetupMode != NULL) {
+ FreePool (SetupMode);
+ }
+ break;
+ default:
+ break;
+ }
+ } else if (Action == EFI_BROWSER_ACTION_DEFAULT_STANDARD) {
+ if (QuestionId == KEY_HIDE_SECURE_BOOT) {
+ GetVariable2 (EFI_PLATFORM_KEY_NAME, &gEfiGlobalVariableGuid, (VOID**)&Pk, NULL);
+ if (Pk == NULL) {
+ IfrNvData->HideSecureBoot = TRUE;
+ } else {
+ FreePool (Pk);
+ IfrNvData->HideSecureBoot = FALSE;
+ }
+ Value->b = IfrNvData->HideSecureBoot;
+ }
+ } else if (Action == EFI_BROWSER_ACTION_FORM_CLOSE) {
+ //
+ // Force the platform back to Standard Mode once user leave the setup screen.
+ //
+ GetVariable2 (EFI_CUSTOM_MODE_NAME, &gEfiCustomModeEnableGuid, (VOID**)&SecureBootMode, NULL);
+ if (NULL != SecureBootMode && *SecureBootMode == CUSTOM_SECURE_BOOT_MODE) {
+ IfrNvData->SecureBootMode = STANDARD_SECURE_BOOT_MODE;
+ SetSecureBootMode(STANDARD_SECURE_BOOT_MODE);
+ }
+ if (SecureBootMode != NULL) {
+ FreePool (SecureBootMode);
+ }
+ }
+
+EXIT:
+
+ if (!EFI_ERROR (Status)) {
+ BufferSize = sizeof (SECUREBOOT_CONFIGURATION);
+ HiiSetBrowserData (&gSecureBootConfigFormSetGuid, mSecureBootStorageName, BufferSize, (UINT8*) IfrNvData, NULL);
+ }
+
+ FreePool (IfrNvData);
+
+ if (File != NULL){
+ FreePool(File);
+ File = NULL;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function publish the SecureBoot configuration Form.
+
+ @param[in, out] PrivateData Points to SecureBoot configuration private data.
+
+ @retval EFI_SUCCESS HII Form is installed successfully.
+ @retval EFI_OUT_OF_RESOURCES Not enough resource for HII Form installation.
+ @retval Others Other errors as indicated.
+
+**/
+EFI_STATUS
+InstallSecureBootConfigForm (
+ IN OUT SECUREBOOT_CONFIG_PRIVATE_DATA *PrivateData
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_HANDLE HiiHandle;
+ EFI_HANDLE DriverHandle;
+ EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
+
+ DriverHandle = NULL;
+ ConfigAccess = &PrivateData->ConfigAccess;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &DriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mSecureBootHiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ ConfigAccess,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ PrivateData->DriverHandle = DriverHandle;
+
+ //
+ // Publish the HII package list
+ //
+ HiiHandle = HiiAddPackages (
+ &gSecureBootConfigFormSetGuid,
+ DriverHandle,
+ SecureBootConfigDxeStrings,
+ SecureBootConfigBin,
+ NULL
+ );
+ if (HiiHandle == NULL) {
+ gBS->UninstallMultipleProtocolInterfaces (
+ DriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mSecureBootHiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ ConfigAccess,
+ NULL
+ );
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ PrivateData->HiiHandle = HiiHandle;
+
+ PrivateData->FileContext = AllocateZeroPool (sizeof (SECUREBOOT_FILE_CONTEXT));
+
+ if (PrivateData->FileContext == NULL) {
+ UninstallSecureBootConfigForm (PrivateData);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Init OpCode Handle and Allocate space for creation of Buffer
+ //
+ mStartOpCodeHandle = HiiAllocateOpCodeHandle ();
+ if (mStartOpCodeHandle == NULL) {
+ UninstallSecureBootConfigForm (PrivateData);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ mEndOpCodeHandle = HiiAllocateOpCodeHandle ();
+ if (mEndOpCodeHandle == NULL) {
+ UninstallSecureBootConfigForm (PrivateData);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Create Hii Extend Label OpCode as the start opcode
+ //
+ mStartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (
+ mStartOpCodeHandle,
+ &gEfiIfrTianoGuid,
+ NULL,
+ sizeof (EFI_IFR_GUID_LABEL)
+ );
+ mStartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
+
+ //
+ // Create Hii Extend Label OpCode as the end opcode
+ //
+ mEndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (
+ mEndOpCodeHandle,
+ &gEfiIfrTianoGuid,
+ NULL,
+ sizeof (EFI_IFR_GUID_LABEL)
+ );
+ mEndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
+ mEndLabel->Number = LABEL_END;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function removes SecureBoot configuration Form.
+
+ @param[in, out] PrivateData Points to SecureBoot configuration private data.
+
+**/
+VOID
+UninstallSecureBootConfigForm (
+ IN OUT SECUREBOOT_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,
+ &mSecureBootHiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ &PrivateData->ConfigAccess,
+ NULL
+ );
+ PrivateData->DriverHandle = NULL;
+ }
+
+ if (PrivateData->SignatureGUID != NULL) {
+ FreePool (PrivateData->SignatureGUID);
+ }
+
+ if (PrivateData->FileContext != NULL) {
+ FreePool (PrivateData->FileContext);
+ }
+
+ FreePool (PrivateData);
+
+ if (mStartOpCodeHandle != NULL) {
+ HiiFreeOpCodeHandle (mStartOpCodeHandle);
+ }
+
+ if (mEndOpCodeHandle != NULL) {
+ HiiFreeOpCodeHandle (mEndOpCodeHandle);
+ }
+}
diff --git a/Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigImpl.h b/Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigImpl.h
new file mode 100644
index 0000000000..75b18f121c
--- /dev/null
+++ b/Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigImpl.h
@@ -0,0 +1,567 @@
+/** @file
+ The header file of HII Config Access protocol implementation of SecureBoot
+ configuration module.
+
+Copyright (c) 2011 - 2017, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __SECUREBOOT_CONFIG_IMPL_H__
+#define __SECUREBOOT_CONFIG_IMPL_H__
+
+#include <Uefi.h>
+
+#include <Protocol/HiiConfigAccess.h>
+#include <Protocol/HiiConfigRouting.h>
+#include <Protocol/SimpleFileSystem.h>
+#include <Protocol/BlockIo.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/DebugPort.h>
+#include <Protocol/LoadFile.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiHiiServicesLib.h>
+#include <Library/UefiLib.h>
+#include <Library/HiiLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/PrintLib.h>
+#include <Library/PlatformSecureLib.h>
+#include <Library/BaseCryptLib.h>
+#include <Library/FileExplorerLib.h>
+#include <Library/PeCoffLib.h>
+
+#include <Guid/MdeModuleHii.h>
+#include <Guid/AuthenticatedVariableFormat.h>
+#include <Guid/FileSystemVolumeLabelInfo.h>
+#include <Guid/ImageAuthentication.h>
+#include <Guid/FileInfo.h>
+#include <Guid/WinCertificate.h>
+
+#include "SecureBootConfigNvData.h"
+
+//
+// Tool generated IFR binary data and String package data
+//
+extern UINT8 SecureBootConfigBin[];
+extern UINT8 SecureBootConfigDxeStrings[];
+
+//
+// Shared IFR form update data
+//
+extern VOID *mStartOpCodeHandle;
+extern VOID *mEndOpCodeHandle;
+extern EFI_IFR_GUID_LABEL *mStartLabel;
+extern EFI_IFR_GUID_LABEL *mEndLabel;
+
+#define MAX_CHAR 480
+#define TWO_BYTE_ENCODE 0x82
+
+
+//
+// SHA-256 digest size in bytes
+//
+#define SHA256_DIGEST_SIZE 32
+//
+// SHA-384 digest size in bytes
+//
+#define SHA384_DIGEST_SIZE 48
+//
+// SHA-512 digest size in bytes
+//
+#define SHA512_DIGEST_SIZE 64
+
+//
+// Set max digest size as SHA512 Output (64 bytes) by far
+//
+#define MAX_DIGEST_SIZE SHA512_DIGEST_SIZE
+
+#define WIN_CERT_UEFI_RSA2048_SIZE 256
+
+//
+// Support hash types
+//
+#define HASHALG_SHA224 0x00000000
+#define HASHALG_SHA256 0x00000001
+#define HASHALG_SHA384 0x00000002
+#define HASHALG_SHA512 0x00000003
+#define HASHALG_RAW 0x00000004
+#define HASHALG_MAX 0x00000004
+
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Head;
+ UINTN MenuNumber;
+} SECUREBOOT_MENU_OPTION;
+
+typedef struct {
+ EFI_FILE_HANDLE FHandle;
+ UINT16 *FileName;
+ UINT8 FileType;
+} SECUREBOOT_FILE_CONTEXT;
+
+
+//
+// We define another format of 5th directory entry: security directory
+//
+typedef struct {
+ UINT32 Offset; // Offset of certificate
+ UINT32 SizeOfCert; // size of certificate appended
+} EFI_IMAGE_SECURITY_DATA_DIRECTORY;
+
+typedef enum{
+ ImageType_IA32,
+ ImageType_X64
+} IMAGE_TYPE;
+
+///
+/// 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;
+
+ SECUREBOOT_FILE_CONTEXT *FileContext;
+
+ EFI_GUID *SignatureGUID;
+} SECUREBOOT_CONFIG_PRIVATE_DATA;
+
+extern SECUREBOOT_CONFIG_PRIVATE_DATA mSecureBootConfigPrivateDateTemplate;
+extern SECUREBOOT_CONFIG_PRIVATE_DATA *gSecureBootPrivateData;
+
+#define SECUREBOOT_CONFIG_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('S', 'E', 'C', 'B')
+#define SECUREBOOT_CONFIG_PRIVATE_FROM_THIS(a) CR (a, SECUREBOOT_CONFIG_PRIVATE_DATA, ConfigAccess, SECUREBOOT_CONFIG_PRIVATE_DATA_SIGNATURE)
+
+//
+// Cryptograhpic Key Information
+//
+#pragma pack(1)
+typedef struct _CPL_KEY_INFO {
+ UINT32 KeyLengthInBits; // Key Length In Bits
+ UINT32 BlockSize; // Operation Block Size in Bytes
+ UINT32 CipherBlockSize; // Output Cipher Block Size in Bytes
+ UINT32 KeyType; // Key Type
+ UINT32 CipherMode; // Cipher Mode for Symmetric Algorithm
+ UINT32 Flags; // Additional Key Property Flags
+} CPL_KEY_INFO;
+#pragma pack()
+
+
+/**
+ 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
+EFI_STATUS
+(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 (16 bytes).
+
+ @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 {
+ CHAR16 *Name; ///< Name for Hash Algorithm
+ UINTN DigestLength; ///< Digest Length
+ UINT8 *OidValue; ///< Hash Algorithm OID ASN.1 Value
+ UINTN OidLength; ///< Length of Hash OID Value
+ HASH_GET_CONTEXT_SIZE GetContextSize; ///< Pointer to Hash GetContentSize function
+ HASH_INIT HashInit; ///< Pointer to Hash Init function
+ HASH_UPDATE HashUpdate; ///< Pointer to Hash Update function
+ HASH_FINAL HashFinal; ///< Pointer to Hash Final function
+} HASH_TABLE;
+
+typedef struct {
+ WIN_CERTIFICATE Hdr;
+ UINT8 CertData[1];
+} WIN_CERTIFICATE_EFI_PKCS;
+
+
+/**
+ This function publish the SecureBoot configuration Form.
+
+ @param[in, out] PrivateData Points to SecureBoot configuration private data.
+
+ @retval EFI_SUCCESS HII Form is installed successfully.
+ @retval EFI_OUT_OF_RESOURCES Not enough resource for HII Form installation.
+ @retval Others Other errors as indicated.
+
+**/
+EFI_STATUS
+InstallSecureBootConfigForm (
+ IN OUT SECUREBOOT_CONFIG_PRIVATE_DATA *PrivateData
+ );
+
+
+/**
+ This function removes SecureBoot configuration Form.
+
+ @param[in, out] PrivateData Points to SecureBoot configuration private data.
+
+**/
+VOID
+UninstallSecureBootConfigForm (
+ IN OUT SECUREBOOT_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
+ <ConfigRequest> format.
+ @param[out] Progress On return, points to a character in the Request
+ string. Points to the string's null terminator if
+ request was successful. Points to the most recent
+ '&' before the first failing name/value pair (or
+ the beginning of the string if the failure is in
+ the first name/value pair) if the request was not
+ successful.
+ @param[out] Results A null-terminated Unicode string in
+ <ConfigAltResp> format which has all values filled
+ in for the names in the Request string. String to
+ be allocated by the called function.
+
+ @retval EFI_SUCCESS The Results is filled with the requested values.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results.
+ @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name.
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in this
+ driver.
+
+**/
+EFI_STATUS
+EFIAPI
+SecureBootExtractConfig (
+ 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 <ConfigResp>
+ 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
+SecureBootRouteConfig (
+ 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
+SecureBootCallback (
+ 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
+ );
+
+
+/**
+ This function converts an input device structure to a Unicode string.
+
+ @param[in] DevPath A pointer to the device path structure.
+
+ @return A new allocated Unicode string that represents the device path.
+
+**/
+CHAR16 *
+EFIAPI
+DevicePathToStr (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevPath
+ );
+
+
+/**
+ Clean up the dynamic opcode at label and form specified by both LabelId.
+
+ @param[in] LabelId It is both the Form ID and Label ID for opcode deletion.
+ @param[in] PrivateData Module private data.
+
+**/
+VOID
+CleanUpPage (
+ IN UINT16 LabelId,
+ IN SECUREBOOT_CONFIG_PRIVATE_DATA *PrivateData
+ );
+
+
+/**
+ Read file content into BufferPtr, the size of the allocate buffer
+ is *FileSize plus AddtionAllocateSize.
+
+ @param[in] FileHandle The file to be read.
+ @param[in, out] BufferPtr Pointers to the pointer of allocated buffer.
+ @param[out] FileSize Size of input file
+ @param[in] AddtionAllocateSize Addtion size the buffer need to be allocated.
+ In case the buffer need to contain others besides the file content.
+
+ @retval EFI_SUCCESS The file was read into the buffer.
+ @retval EFI_INVALID_PARAMETER A parameter was invalid.
+ @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
+ @retval others Unexpected error.
+
+**/
+EFI_STATUS
+ReadFileContent (
+ IN EFI_FILE_HANDLE FileHandle,
+ IN OUT VOID **BufferPtr,
+ OUT UINTN *FileSize,
+ IN UINTN AddtionAllocateSize
+ );
+
+
+/**
+ Close an open file handle.
+
+ @param[in] FileHandle The file handle to close.
+
+**/
+VOID
+CloseFile (
+ IN EFI_FILE_HANDLE FileHandle
+ );
+
+
+/**
+ Converts a nonnegative integer to an octet string of a specified length.
+
+ @param[in] Integer Pointer to the nonnegative integer to be converted
+ @param[in] IntSizeInWords Length of integer buffer in words
+ @param[out] OctetString Converted octet string of the specified length
+ @param[in] OSSizeInBytes Intended length of resulting octet string in bytes
+
+Returns:
+
+ @retval EFI_SUCCESS Data conversion successfully
+ @retval EFI_BUFFER_TOOL_SMALL Buffer is too small for output string
+
+**/
+EFI_STATUS
+EFIAPI
+Int2OctStr (
+ IN CONST UINTN *Integer,
+ IN UINTN IntSizeInWords,
+ OUT UINT8 *OctetString,
+ IN UINTN OSSizeInBytes
+ );
+
+/**
+ Worker function that prints an EFI_GUID into specified Buffer.
+
+ @param[in] Guid Pointer to GUID to print.
+ @param[in] Buffer Buffer to print Guid into.
+ @param[in] BufferSize Size of Buffer.
+
+ @retval Number of characters printed.
+
+**/
+UINTN
+GuidToString (
+ IN EFI_GUID *Guid,
+ IN CHAR16 *Buffer,
+ IN UINTN BufferSize
+ );
+
+/**
+ Update the PK form base on the input file path info.
+
+ @param FilePath Point to the file path.
+
+ @retval TRUE Exit caller function.
+ @retval FALSE Not exit caller function.
+**/
+BOOLEAN
+EFIAPI
+UpdatePKFromFile (
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath
+ );
+
+/**
+ Update the KEK form base on the input file path info.
+
+ @param FilePath Point to the file path.
+
+ @retval TRUE Exit caller function.
+ @retval FALSE Not exit caller function.
+**/
+BOOLEAN
+EFIAPI
+UpdateKEKFromFile (
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath
+ );
+
+/**
+ Update the DB form base on the input file path info.
+
+ @param FilePath Point to the file path.
+
+ @retval TRUE Exit caller function.
+ @retval FALSE Not exit caller function.
+**/
+BOOLEAN
+EFIAPI
+UpdateDBFromFile (
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath
+ );
+
+/**
+ Update the DBX form base on the input file path info.
+
+ @param FilePath Point to the file path.
+
+ @retval TRUE Exit caller function.
+ @retval FALSE Not exit caller function.
+**/
+BOOLEAN
+EFIAPI
+UpdateDBXFromFile (
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath
+ );
+
+/**
+ Update the DBT form base on the input file path info.
+
+ @param FilePath Point to the file path.
+
+ @retval TRUE Exit caller function.
+ @retval FALSE Not exit caller function.
+**/
+BOOLEAN
+EFIAPI
+UpdateDBTFromFile (
+ IN EFI_DEVICE_PATH_PROTOCOL *FilePath
+ );
+
+#endif
diff --git a/Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigMisc.c b/Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigMisc.c
new file mode 100644
index 0000000000..038707ca83
--- /dev/null
+++ b/Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigMisc.c
@@ -0,0 +1,195 @@
+/** @file
+ Helper functions for SecureBoot configuration module.
+
+Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "SecureBootConfigImpl.h"
+
+/**
+ Read file content into BufferPtr, the size of the allocate buffer
+ is *FileSize plus AddtionAllocateSize.
+
+ @param[in] FileHandle The file to be read.
+ @param[in, out] BufferPtr Pointers to the pointer of allocated buffer.
+ @param[out] FileSize Size of input file
+ @param[in] AddtionAllocateSize Addtion size the buffer need to be allocated.
+ In case the buffer need to contain others besides the file content.
+
+ @retval EFI_SUCCESS The file was read into the buffer.
+ @retval EFI_INVALID_PARAMETER A parameter was invalid.
+ @retval EFI_OUT_OF_RESOURCES A memory allocation failed.
+ @retval others Unexpected error.
+
+**/
+EFI_STATUS
+ReadFileContent (
+ IN EFI_FILE_HANDLE FileHandle,
+ IN OUT VOID **BufferPtr,
+ OUT UINTN *FileSize,
+ IN UINTN AddtionAllocateSize
+ )
+
+{
+ UINTN BufferSize;
+ UINT64 SourceFileSize;
+ VOID *Buffer;
+ EFI_STATUS Status;
+
+ if ((FileHandle == NULL) || (FileSize == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Buffer = NULL;
+
+ //
+ // Get the file size
+ //
+ Status = FileHandle->SetPosition (FileHandle, (UINT64) -1);
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+
+ Status = FileHandle->GetPosition (FileHandle, &SourceFileSize);
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+
+ Status = FileHandle->SetPosition (FileHandle, 0);
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+
+ BufferSize = (UINTN) SourceFileSize + AddtionAllocateSize;
+ Buffer = AllocateZeroPool(BufferSize);
+ if (Buffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ BufferSize = (UINTN) SourceFileSize;
+ *FileSize = BufferSize;
+
+ Status = FileHandle->Read (FileHandle, &BufferSize, Buffer);
+ if (EFI_ERROR (Status) || BufferSize != *FileSize) {
+ FreePool (Buffer);
+ Buffer = NULL;
+ Status = EFI_BAD_BUFFER_SIZE;
+ goto ON_EXIT;
+ }
+
+ON_EXIT:
+
+ *BufferPtr = Buffer;
+ return Status;
+}
+
+/**
+ Close an open file handle.
+
+ @param[in] FileHandle The file handle to close.
+
+**/
+VOID
+CloseFile (
+ IN EFI_FILE_HANDLE FileHandle
+ )
+{
+ if (FileHandle != NULL) {
+ FileHandle->Close (FileHandle);
+ }
+}
+
+/**
+ Convert a nonnegative integer to an octet string of a specified length.
+
+ @param[in] Integer Pointer to the nonnegative integer to be converted
+ @param[in] IntSizeInWords Length of integer buffer in words
+ @param[out] OctetString Converted octet string of the specified length
+ @param[in] OSSizeInBytes Intended length of resulting octet string in bytes
+
+Returns:
+
+ @retval EFI_SUCCESS Data conversion successfully
+ @retval EFI_BUFFER_TOOL_SMALL Buffer is too small for output string
+
+**/
+EFI_STATUS
+EFIAPI
+Int2OctStr (
+ IN CONST UINTN *Integer,
+ IN UINTN IntSizeInWords,
+ OUT UINT8 *OctetString,
+ IN UINTN OSSizeInBytes
+ )
+{
+ CONST UINT8 *Ptr1;
+ UINT8 *Ptr2;
+
+ for (Ptr1 = (CONST UINT8 *)Integer, Ptr2 = OctetString + OSSizeInBytes - 1;
+ Ptr1 < (UINT8 *)(Integer + IntSizeInWords) && Ptr2 >= OctetString;
+ Ptr1++, Ptr2--) {
+ *Ptr2 = *Ptr1;
+ }
+
+ for (; Ptr1 < (CONST UINT8 *)(Integer + IntSizeInWords) && *Ptr1 == 0; Ptr1++);
+
+ if (Ptr1 < (CONST UINT8 *)(Integer + IntSizeInWords)) {
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ if (Ptr2 >= OctetString) {
+ ZeroMem (OctetString, Ptr2 - OctetString + 1);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Worker function that prints an EFI_GUID into specified Buffer.
+
+ @param[in] Guid Pointer to GUID to print.
+ @param[in] Buffer Buffer to print Guid into.
+ @param[in] BufferSize Size of Buffer.
+
+ @retval Number of characters printed.
+
+**/
+UINTN
+GuidToString (
+ IN EFI_GUID *Guid,
+ IN CHAR16 *Buffer,
+ IN UINTN BufferSize
+ )
+{
+ UINTN Size;
+
+ Size = UnicodeSPrint (
+ Buffer,
+ BufferSize,
+ L"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+ (UINTN)Guid->Data1,
+ (UINTN)Guid->Data2,
+ (UINTN)Guid->Data3,
+ (UINTN)Guid->Data4[0],
+ (UINTN)Guid->Data4[1],
+ (UINTN)Guid->Data4[2],
+ (UINTN)Guid->Data4[3],
+ (UINTN)Guid->Data4[4],
+ (UINTN)Guid->Data4[5],
+ (UINTN)Guid->Data4[6],
+ (UINTN)Guid->Data4[7]
+ );
+
+ //
+ // SPrint will null terminate the string. The -1 skips the null
+ //
+ return Size - 1;
+}
diff --git a/Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigNvData.h b/Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigNvData.h
new file mode 100644
index 0000000000..6b69f92b26
--- /dev/null
+++ b/Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigNvData.h
@@ -0,0 +1,133 @@
+/** @file
+ Header file for NV data structure definition.
+
+Copyright (c) 2011 - 2017, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __SECUREBOOT_CONFIG_NV_DATA_H__
+#define __SECUREBOOT_CONFIG_NV_DATA_H__
+
+#include <Guid/HiiPlatformSetupFormset.h>
+#include <Guid/SecureBootConfigHii.h>
+
+//
+// Used by VFR for form or button identification
+//
+#define SECUREBOOT_CONFIGURATION_VARSTORE_ID 0x0001
+#define SECUREBOOT_CONFIGURATION_FORM_ID 0x01
+#define FORMID_SECURE_BOOT_OPTION_FORM 0x02
+#define FORMID_SECURE_BOOT_PK_OPTION_FORM 0x03
+#define FORMID_SECURE_BOOT_KEK_OPTION_FORM 0x04
+#define FORMID_SECURE_BOOT_DB_OPTION_FORM 0x05
+#define FORMID_SECURE_BOOT_DBX_OPTION_FORM 0x06
+#define FORMID_ENROLL_PK_FORM 0x07
+#define SECUREBOOT_ADD_PK_FILE_FORM_ID 0x08
+#define FORMID_ENROLL_KEK_FORM 0x09
+#define FORMID_DELETE_KEK_FORM 0x0a
+#define SECUREBOOT_ENROLL_SIGNATURE_TO_DB 0x0b
+#define SECUREBOOT_DELETE_SIGNATURE_FROM_DB 0x0c
+#define SECUREBOOT_ENROLL_SIGNATURE_TO_DBX 0x0d
+#define SECUREBOOT_DELETE_SIGNATURE_FROM_DBX 0x0e
+#define FORMID_SECURE_BOOT_DBT_OPTION_FORM 0x14
+#define SECUREBOOT_ENROLL_SIGNATURE_TO_DBT 0x15
+#define SECUREBOOT_DELETE_SIGNATURE_FROM_DBT 0x16
+
+#define SECURE_BOOT_MODE_CUSTOM 0x01
+#define SECURE_BOOT_MODE_STANDARD 0x00
+
+#define KEY_SECURE_BOOT_ENABLE 0x1000
+#define KEY_SECURE_BOOT_MODE 0x1001
+#define KEY_VALUE_SAVE_AND_EXIT_DB 0x1002
+#define KEY_VALUE_NO_SAVE_AND_EXIT_DB 0x1003
+#define KEY_VALUE_SAVE_AND_EXIT_PK 0x1004
+#define KEY_VALUE_NO_SAVE_AND_EXIT_PK 0x1005
+#define KEY_VALUE_SAVE_AND_EXIT_KEK 0x1008
+#define KEY_VALUE_NO_SAVE_AND_EXIT_KEK 0x1009
+#define KEY_VALUE_SAVE_AND_EXIT_DBX 0x100a
+#define KEY_VALUE_NO_SAVE_AND_EXIT_DBX 0x100b
+#define KEY_HIDE_SECURE_BOOT 0x100c
+#define KEY_VALUE_SAVE_AND_EXIT_DBT 0x100d
+#define KEY_VALUE_NO_SAVE_AND_EXIT_DBT 0x100e
+
+#define KEY_SECURE_BOOT_OPTION 0x1100
+#define KEY_SECURE_BOOT_PK_OPTION 0x1101
+#define KEY_SECURE_BOOT_KEK_OPTION 0x1102
+#define KEY_SECURE_BOOT_DB_OPTION 0x1103
+#define KEY_SECURE_BOOT_DBX_OPTION 0x1104
+#define KEY_SECURE_BOOT_DELETE_PK 0x1105
+#define KEY_ENROLL_PK 0x1106
+#define KEY_ENROLL_KEK 0x1107
+#define KEY_DELETE_KEK 0x1108
+#define KEY_SECURE_BOOT_KEK_GUID 0x110a
+#define KEY_SECURE_BOOT_SIGNATURE_GUID_DB 0x110b
+#define KEY_SECURE_BOOT_SIGNATURE_GUID_DBX 0x110c
+#define KEY_SECURE_BOOT_DBT_OPTION 0x110d
+#define KEY_SECURE_BOOT_SIGNATURE_GUID_DBT 0x110e
+
+#define LABEL_KEK_DELETE 0x1200
+#define LABEL_DB_DELETE 0x1201
+#define LABEL_DBX_DELETE 0x1202
+#define LABEL_DBT_DELETE 0x1203
+#define LABEL_END 0xffff
+
+
+#define SECURE_BOOT_MAX_ATTEMPTS_NUM 255
+
+#define CONFIG_OPTION_OFFSET 0x2000
+
+#define OPTION_CONFIG_QUESTION_ID 0x2000
+#define OPTION_CONFIG_RANGE 0x1000
+
+//
+// Question ID 0x2000 ~ 0x2FFF is for KEK
+//
+#define OPTION_DEL_KEK_QUESTION_ID 0x2000
+//
+// Question ID 0x3000 ~ 0x3FFF is for DB
+//
+#define OPTION_DEL_DB_QUESTION_ID 0x3000
+//
+// Question ID 0x4000 ~ 0x4FFF is for DBX
+//
+#define OPTION_DEL_DBX_QUESTION_ID 0x4000
+
+//
+// Question ID 0x5000 ~ 0x5FFF is for DBT
+//
+#define OPTION_DEL_DBT_QUESTION_ID 0x5000
+
+#define SECURE_BOOT_GUID_SIZE 36
+#define SECURE_BOOT_GUID_STORAGE_SIZE 37
+
+#define UNKNOWN_FILE_TYPE 0
+#define X509_CERT_FILE_TYPE 1
+#define PE_IMAGE_FILE_TYPE 2
+#define AUTHENTICATION_2_FILE_TYPE 3
+
+//
+// Nv Data structure referenced by IFR
+//
+typedef struct {
+ BOOLEAN AttemptSecureBoot; // Attempt to enable/disable Secure Boot
+ BOOLEAN HideSecureBoot; // Hiden Attempt Secure Boot
+ CHAR16 SignatureGuid[SECURE_BOOT_GUID_STORAGE_SIZE];
+ BOOLEAN PhysicalPresent; // If a Physical Present User
+ UINT8 SecureBootMode; // Secure Boot Mode: Standard Or Custom
+ BOOLEAN DeletePk;
+ BOOLEAN HasPk; // If Pk is existed it is true
+ BOOLEAN AlwaysRevocation; // If the certificate is always revoked. Revocation time is hidden
+ UINT8 CertificateFormat; // The type of the certificate
+ EFI_HII_DATE RevocationDate; // The revocation date of the certificate
+ EFI_HII_TIME RevocationTime; // The revocation time of the certificate
+ UINT8 FileEnrollType; // File type of sigunature enroll
+} SECUREBOOT_CONFIGURATION;
+
+#endif
diff --git a/Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigStrings.uni b/Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigStrings.uni
new file mode 100644
index 0000000000..320cc79c47
--- /dev/null
+++ b/Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigStrings.uni
@@ -0,0 +1,116 @@
+/** @file
+ String definitions for Secure Boot Configuration form.
+
+Copyright (c) 2011 - 2017, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#langdef en-US "English"
+
+#string STR_SECUREBOOT_TITLE #language en-US "Secure Boot Configuration"
+#string STR_SECUREBOOT_HELP #language en-US "Press <Enter> to select Secure Boot options."
+
+#string STR_NULL #language en-US ""
+#string STR_DBX_SUBTITLE_TEXT #language en-US ""
+
+#string STR_SECURE_BOOT_STATE_PROMPT #language en-US "Current Secure Boot State"
+#string STR_SECURE_BOOT_STATE_HELP #language en-US "Current Secure Boot state: enabled or disabled."
+#string STR_SECURE_BOOT_STATE_CONTENT #language en-US " "
+
+#string STR_SECURE_BOOT_PROMPT #language en-US "Attempt Secure Boot"
+#string STR_SECURE_BOOT_HELP #language en-US "Enable/Disable the Secure Boot feature after platform reset"
+
+#string STR_SECURE_BOOT_ENROLL_SIGNATURE #language en-US "Enroll Signature"
+#string STR_SECURE_BOOT_DELETE_SIGNATURE #language en-US "Delete Signature"
+
+#string STR_SECURE_BOOT_SIGNATURE_GUID #language en-US "Signature GUID"
+#string STR_SECURE_BOOT_SIGNATURE_GUID_HELP #language en-US "Input digit character in 11111111-2222-3333-4444-1234567890ab format."
+#string STR_SECURE_BOOT_ADD_SIGNATURE_FILE #language en-US "Enroll Signature Using File"
+
+#string STR_DBX_CERTIFICATE_FORMAT_PROMPT #language en-US "Signature Format"
+#string STR_DBX_CERTIFICATE_FORMAT_HELP #language en-US "X509 DER-Cert enrolled. Select different option to enroll it into DBX."
+#string STR_DBX_CERTIFICATE_FORMAT_SHA256 #language en-US "X509 CERT SHA256"
+#string STR_DBX_CERTIFICATE_FORMAT_SHA384 #language en-US "X509 CERT SHA384"
+#string STR_DBX_CERTIFICATE_FORMAT_SHA512 #language en-US "X509 CERT SHA512"
+#string STR_DBX_CERTIFICATE_FORMAT_RAW #language en-US "X509 CERT"
+
+#string STR_DBX_PE_IMAGE_FORMAT_HELP #language en-US "PE image enrolled. Use SHA256 hash to enroll it into DBX"
+#string STR_DBX_PE_FORMAT_SHA256 #language en-US "PE Image SHA256"
+
+#string STR_DBX_AUTH_2_FORMAT_HELP #language en-US "VARIABLE_AUTHENICATION_2 binary enrolled. Use raw binary to enroll it into DBX"
+#string STR_DBX_AUTH_2_FORMAT #language en-US "VARIABLE_AUTHENICATION_2"
+
+#string STR_CERTIFICATE_REVOCATION_TIME_PROMPT #language en-US " Revocation Time"
+#string STR_CERTIFICATE_REVOCATION_TIME_HELP #language en-US "Input the revocation time of the certificate"
+#string STR_CERTIFICATE_REVOCATION_DATE_PROMPT #language en-US " Revocation Date"
+#string STR_CERTIFICATE_REVOCATION_DATE_HELP #language en-US "Input the revocation date of the certificate"
+
+#string STR_ALWAYS_CERTIFICATE_REVOCATION_PROMPT #language en-US "Always Revocation"
+#string STR_ALWAYS_CERTIFICATE_REVOCATION_HELP #language en-US "Indicate whether the certificate is always revoked."
+
+
+#string STR_SAVE_SIGNATURE_FILE #language en-US "Save Signature File"
+
+#string STR_SAVE_AND_EXIT #language en-US "Commit Changes and Exit"
+#string STR_NO_SAVE_AND_EXIT #language en-US "Discard Changes and Exit"
+
+#string STR_FILE_EXPLORER_TITLE #language en-US "File Explorer"
+
+#string STR_SECURE_BOOT_MODE_PROMPT #language en-US "Secure Boot Mode"
+#string STR_SECURE_BOOT_MODE_HELP #language en-US "Secure Boot Mode: Custom Mode or Standard Mode"
+
+#string STR_STANDARD_MODE #language en-US "Standard Mode"
+#string STR_CUSTOM_MODE #language en-US "Custom Mode"
+
+#string STR_SECURE_BOOT_OPTION #language en-US "Custom Secure Boot Options"
+#string STR_SECURE_BOOT_OPTION_HELP #language en-US "Enter into Custom Secure Boot Options Form"
+
+#string STR_SECURE_BOOT_OPTION_TITLE #language en-US "Custom Secure Boot Options"
+
+#string STR_SECURE_BOOT_PK_OPTION #language en-US "PK Options"
+#string STR_SECURE_BOOT_PK_OPTION_HELP #language en-US "Enroll/Delete PK"
+#string STR_SECURE_BOOT_KEK_OPTION #language en-US "KEK Options"
+#string STR_SECURE_BOOT_KEK_OPTION_HELP #language en-US "Enroll/Delete KEK"
+#string STR_SECURE_BOOT_DB_OPTION #language en-US "DB Options"
+#string STR_SECURE_BOOT_DB_OPTION_HELP #language en-US "Enroll/Delete Signature"
+#string STR_SECURE_BOOT_DBX_OPTION #language en-US "DBX Options"
+#string STR_SECURE_BOOT_DBX_OPTION_HELP #language en-US "Enroll/Delete DBX"
+#string STR_SECURE_BOOT_DBT_OPTION #language en-US "DBT Options"
+#string STR_SECURE_BOOT_DBT_OPTION_HELP #language en-US "Enroll/Delete DBT"
+
+#string STR_ENROLL_PK #language en-US "Enroll PK"
+#string STR_ENROLL_PK_HELP #language en-US "Enter into Enroll PK Form"
+#string STR_SAVE_PK_FILE #language en-US "Save PK file"
+#string STR_SECURE_BOOT_ENROLL_PK_FILE #language en-US "Enroll PK Using File"
+
+#string STR_DELETE_PK #language en-US "Delete Pk"
+#string STR_DELETE_PK_HELP #language en-US "Choose to Delete PK, Otherwise keep the PK"
+
+#string STR_ENROLL_PK_TITLE #language en-US "Enroll PK"
+
+#string STR_ENROLL_KEK #language en-US "Enroll KEK"
+#string STR_ENROLL_KEK_HELP #language en-US "Enter into Enroll KEK Form"
+
+#string STR_DELETE_KEK #language en-US "Delete KEK"
+#string STR_DELETE_KEK_HELP #language en-US "Enter into Delete KEK Form"
+
+#string STR_ENROLL_KEK_TITLE #language en-US "Enroll KEK"
+#string STR_DELETE_KEK_TITLE #language en-US "Delete KEK"
+
+#string STR_FORM_ENROLL_KEK_FROM_FILE_TITLE #language en-US "Enroll KEK using File"
+#string STR_FORM_ENROLL_KEK_FROM_FILE_TITLE_HELP #language en-US "Read the public key of KEK from file"
+#string STR_FILE_EXPLORER_TITLE #language en-US "File Explorer"
+#string STR_CERT_TYPE_RSA2048_SHA256_GUID #language en-US "RSA2048_SHA256_GUID"
+#string STR_CERT_TYPE_PCKS7_GUID #language en-US "PKCS7_GUID"
+#string STR_CERT_TYPE_SHA1_GUID #language en-US "SHA1_GUID"
+#string STR_CERT_TYPE_SHA256_GUID #language en-US "SHA256_GUID"
+#string STR_CERT_TYPE_X509_SHA256_GUID #language en-US "X509_SHA256_GUID"
+#string STR_CERT_TYPE_X509_SHA384_GUID #language en-US "X509_SHA384_GUID"
+#string STR_CERT_TYPE_X509_SHA512_GUID #language en-US "X509_SHA512_GUID"