summaryrefslogtreecommitdiff
path: root/Core
diff options
context:
space:
mode:
authorGuo Mang <mang.guo@intel.com>2016-12-22 15:59:41 +0800
committerGuo Mang <mang.guo@intel.com>2016-12-26 19:14:42 +0800
commit08b9f4f8ea456e32f3286eb59aaa87f7f42c16d3 (patch)
tree872165e45101d77030f2b088b4631d9821f89cf7 /Core
parent1760cf81e4b1847c6823ea3514a78dd120e19b6e (diff)
downloadedk2-platforms-08b9f4f8ea456e32f3286eb59aaa87f7f42c16d3.tar.xz
SecurityPkg: Move to new location
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Guo Mang <mang.guo@intel.com>
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.unibin0 -> 2254 bytes
-rw-r--r--Core/SecurityPkg/Application/RngTest/RngTestExtra.unibin0 -> 1390 bytes
-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.unibin0 -> 1708 bytes
-rw-r--r--Core/SecurityPkg/Hash2DxeCrypto/Hash2DxeCryptoExtra.unibin0 -> 1348 bytes
-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.h47
-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.h160
-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.h141
-rw-r--r--Core/SecurityPkg/Include/Library/Tpm12DeviceLib.h54
-rw-r--r--Core/SecurityPkg/Include/Library/Tpm2CommandLib.h974
-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.c2548
-rw-r--r--Core/SecurityPkg/Library/AuthVariableLib/AuthServiceInternal.h427
-rw-r--r--Core/SecurityPkg/Library/AuthVariableLib/AuthVariableLib.c464
-rw-r--r--Core/SecurityPkg/Library/AuthVariableLib/AuthVariableLib.inf90
-rw-r--r--Core/SecurityPkg/Library/AuthVariableLib/AuthVariableLib.unibin0 -> 1670 bytes
-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.unibin0 -> 2430 bytes
-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.unibin0 -> 1836 bytes
-rw-r--r--Core/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c1967
-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.unibin0 -> 2868 bytes
-rw-r--r--Core/SecurityPkg/Library/DxeImageVerificationLib/Measurement.c322
-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.unibin0 -> 2768 bytes
-rw-r--r--Core/SecurityPkg/Library/DxeTcg2PhysicalPresenceLib/DxeTcg2PhysicalPresenceLib.c1250
-rw-r--r--Core/SecurityPkg/Library/DxeTcg2PhysicalPresenceLib/DxeTcg2PhysicalPresenceLib.inf69
-rw-r--r--Core/SecurityPkg/Library/DxeTcg2PhysicalPresenceLib/DxeTcg2PhysicalPresenceLib.unibin0 -> 2938 bytes
-rw-r--r--Core/SecurityPkg/Library/DxeTcg2PhysicalPresenceLib/PhysicalPresenceStrings.unibin0 -> 10998 bytes
-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.unibin0 -> 3126 bytes
-rw-r--r--Core/SecurityPkg/Library/DxeTcgPhysicalPresenceLib/PhysicalPresenceStrings.unibin0 -> 8314 bytes
-rw-r--r--Core/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c702
-rw-r--r--Core/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.inf68
-rw-r--r--Core/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.unibin0 -> 3196 bytes
-rw-r--r--Core/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c1012
-rw-r--r--Core/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.inf68
-rw-r--r--Core/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.unibin0 -> 3196 bytes
-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.unibin0 -> 2102 bytes
-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.unibin0 -> 2938 bytes
-rw-r--r--Core/SecurityPkg/Library/DxeTrEEPhysicalPresenceLib/PhysicalPresenceStrings.unibin0 -> 3712 bytes
-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.unibin0 -> 1814 bytes
-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.unibin0 -> 1822 bytes
-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.c238
-rw-r--r--Core/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterDxe.inf53
-rw-r--r--Core/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterDxe.unibin0 -> 2326 bytes
-rw-r--r--Core/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterPei.c305
-rw-r--r--Core/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterPei.inf54
-rw-r--r--Core/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterPei.unibin0 -> 2312 bytes
-rw-r--r--Core/SecurityPkg/Library/HashLibTpm2/HashLibTpm2.c341
-rw-r--r--Core/SecurityPkg/Library/HashLibTpm2/HashLibTpm2.inf49
-rw-r--r--Core/SecurityPkg/Library/HashLibTpm2/HashLibTpm2.unibin0 -> 1958 bytes
-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.unibin0 -> 2768 bytes
-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.unibin0 -> 1754 bytes
-rw-r--r--Core/SecurityPkg/Library/PlatformSecureLibNull/PlatformSecureLibNull.c42
-rw-r--r--Core/SecurityPkg/Library/PlatformSecureLibNull/PlatformSecureLibNull.inf39
-rw-r--r--Core/SecurityPkg/Library/PlatformSecureLibNull/PlatformSecureLibNull.unibin0 -> 3056 bytes
-rw-r--r--Core/SecurityPkg/Library/SmmTcg2PhysicalPresenceLib/SmmTcg2PhysicalPresenceLib.c315
-rw-r--r--Core/SecurityPkg/Library/SmmTcg2PhysicalPresenceLib/SmmTcg2PhysicalPresenceLib.inf56
-rw-r--r--Core/SecurityPkg/Library/SmmTcg2PhysicalPresenceLib/SmmTcg2PhysicalPresenceLib.unibin0 -> 2706 bytes
-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.unibin0 -> 1810 bytes
-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.unibin0 -> 1810 bytes
-rw-r--r--Core/SecurityPkg/Library/TcgStorageCoreLib/TcgStorageCore.c1650
-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.inf47
-rw-r--r--Core/SecurityPkg/Library/Tpm12CommandLib/Tpm12CommandLib.unibin0 -> 1744 bytes
-rw-r--r--Core/SecurityPkg/Library/Tpm12CommandLib/Tpm12NvStorage.c255
-rw-r--r--Core/SecurityPkg/Library/Tpm12CommandLib/Tpm12Ownership.c72
-rw-r--r--Core/SecurityPkg/Library/Tpm12CommandLib/Tpm12Startup.c127
-rw-r--r--Core/SecurityPkg/Library/Tpm12DeviceLibDTpm/Tpm12DeviceLibDTpm.inf48
-rw-r--r--Core/SecurityPkg/Library/Tpm12DeviceLibDTpm/Tpm12DeviceLibDTpm.unibin0 -> 2214 bytes
-rw-r--r--Core/SecurityPkg/Library/Tpm12DeviceLibDTpm/Tpm12Tis.c530
-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.unibin0 -> 1966 bytes
-rw-r--r--Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2Capability.c741
-rw-r--r--Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2CommandLib.inf54
-rw-r--r--Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2CommandLib.unibin0 -> 1744 bytes
-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.c166
-rw-r--r--Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2Hierarchy.c803
-rw-r--r--Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2Integrity.c537
-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/Tpm2Sequences.c508
-rw-r--r--Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2Session.c169
-rw-r--r--Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2Startup.c123
-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.unibin0 -> 2418 bytes
-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.unibin0 -> 2370 bytes
-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.unibin0 -> 2550 bytes
-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.unibin0 -> 2550 bytes
-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.unibin0 -> 1970 bytes
-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.unibin0 -> 1970 bytes
-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.unibin0 -> 1958 bytes
-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.unibin0 -> 1816 bytes
-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.unibin0 -> 2254 bytes
-rw-r--r--Core/SecurityPkg/Pkcs7Verify/Pkcs7VerifyDxe/Pkcs7VerifyDxeExtra.unibin0 -> 1342 bytes
-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.unibin0 -> 2736 bytes
-rw-r--r--Core/SecurityPkg/RandomNumberGenerator/RngDxe/RngDxeExtra.unibin0 -> 1336 bytes
-rw-r--r--Core/SecurityPkg/SecurityPkg.dec437
-rw-r--r--Core/SecurityPkg/SecurityPkg.dsc327
-rw-r--r--Core/SecurityPkg/SecurityPkg.unibin0 -> 41964 bytes
-rw-r--r--Core/SecurityPkg/SecurityPkgExtra.unibin0 -> 1346 bytes
-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.unibin0 -> 1808 bytes
-rw-r--r--Core/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMorExtra.unibin0 -> 1352 bytes
-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.unibin0 -> 1964 bytes
-rw-r--r--Core/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLockExtra.unibin0 -> 1356 bytes
-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.c1103
-rw-r--r--Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalDriver.h413
-rw-r--r--Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalDriverPrivate.h102
-rw-r--r--Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalHii.c1377
-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.uni91
-rw-r--r--Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalHiiFormValues.h120
-rw-r--r--Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalHiiPrivate.h266
-rw-r--r--Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalPasswordDxe.inf81
-rw-r--r--Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalPasswordForm.vfr327
-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.c2157
-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.c1092
-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.unibin0 -> 2262 bytes
-rw-r--r--Core/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePeiExtra.unibin0 -> 1354 bytes
-rw-r--r--Core/SecurityPkg/Tcg/Tcg2Config/Tcg2Config.vfr209
-rw-r--r--Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDriver.c281
-rw-r--r--Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDxe.inf89
-rw-r--r--Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDxe.unibin0 -> 2124 bytes
-rw-r--r--Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDxeExtra.unibin0 -> 1382 bytes
-rw-r--r--Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigImpl.c875
-rw-r--r--Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigImpl.h197
-rw-r--r--Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigNvData.h114
-rw-r--r--Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPei.inf78
-rw-r--r--Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPei.unibin0 -> 2206 bytes
-rw-r--r--Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPeiExtra.unibin0 -> 1382 bytes
-rw-r--r--Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPeim.c159
-rw-r--r--Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigStrings.unibin0 -> 15732 bytes
-rw-r--r--Core/SecurityPkg/Tcg/Tcg2Config/TpmDetection.c130
-rw-r--r--Core/SecurityPkg/Tcg/Tcg2Dxe/MeasureBootPeCoff.c427
-rw-r--r--Core/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c2593
-rw-r--r--Core/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.inf111
-rw-r--r--Core/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.unibin0 -> 2320 bytes
-rw-r--r--Core/SecurityPkg/Tcg/Tcg2Dxe/Tcg2DxeExtra.unibin0 -> 1334 bytes
-rw-r--r--Core/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.c997
-rw-r--r--Core/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.inf91
-rw-r--r--Core/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.unibin0 -> 1876 bytes
-rw-r--r--Core/SecurityPkg/Tcg/Tcg2Pei/Tcg2PeiExtra.unibin0 -> 1342 bytes
-rw-r--r--Core/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.c509
-rw-r--r--Core/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.h96
-rw-r--r--Core/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.inf83
-rw-r--r--Core/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.unibin0 -> 3270 bytes
-rw-r--r--Core/SecurityPkg/Tcg/Tcg2Smm/Tcg2SmmExtra.unibin0 -> 1342 bytes
-rw-r--r--Core/SecurityPkg/Tcg/Tcg2Smm/Tpm.asl359
-rw-r--r--Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfig.vfr74
-rw-r--r--Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDriver.c150
-rw-r--r--Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDxe.inf83
-rw-r--r--Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDxe.unibin0 -> 1886 bytes
-rw-r--r--Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDxeExtra.unibin0 -> 1378 bytes
-rw-r--r--Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigImpl.c502
-rw-r--r--Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigImpl.h193
-rw-r--r--Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigNvData.h39
-rw-r--r--Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigStrings.unibin0 -> 4642 bytes
-rw-r--r--Core/SecurityPkg/Tcg/TcgDxe/TcgDxe.c1399
-rw-r--r--Core/SecurityPkg/Tcg/TcgDxe/TcgDxe.inf85
-rw-r--r--Core/SecurityPkg/Tcg/TcgDxe/TcgDxe.unibin0 -> 1830 bytes
-rw-r--r--Core/SecurityPkg/Tcg/TcgDxe/TcgDxeExtra.unibin0 -> 1352 bytes
-rw-r--r--Core/SecurityPkg/Tcg/TcgDxe/TisDxe.c448
-rw-r--r--Core/SecurityPkg/Tcg/TcgDxe/TpmComm.c170
-rw-r--r--Core/SecurityPkg/Tcg/TcgDxe/TpmComm.h99
-rw-r--r--Core/SecurityPkg/Tcg/TcgPei/TcgPei.c832
-rw-r--r--Core/SecurityPkg/Tcg/TcgPei/TcgPei.inf94
-rw-r--r--Core/SecurityPkg/Tcg/TcgPei/TcgPei.unibin0 -> 2214 bytes
-rw-r--r--Core/SecurityPkg/Tcg/TcgPei/TcgPeiExtra.unibin0 -> 1352 bytes
-rw-r--r--Core/SecurityPkg/Tcg/TcgPei/TisPei.c160
-rw-r--r--Core/SecurityPkg/Tcg/TcgPei/TpmComm.c274
-rw-r--r--Core/SecurityPkg/Tcg/TcgPei/TpmComm.h163
-rw-r--r--Core/SecurityPkg/Tcg/TcgSmm/TcgSmm.c465
-rw-r--r--Core/SecurityPkg/Tcg/TcgSmm/TcgSmm.h104
-rw-r--r--Core/SecurityPkg/Tcg/TcgSmm/TcgSmm.inf83
-rw-r--r--Core/SecurityPkg/Tcg/TcgSmm/TcgSmm.unibin0 -> 3132 bytes
-rw-r--r--Core/SecurityPkg/Tcg/TcgSmm/TcgSmmExtra.unibin0 -> 1352 bytes
-rw-r--r--Core/SecurityPkg/Tcg/TcgSmm/Tpm.asl355
-rw-r--r--Core/SecurityPkg/Tcg/TrEEConfig/TpmDetection.c130
-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.unibin0 -> 2138 bytes
-rw-r--r--Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigDxeExtra.unibin0 -> 1394 bytes
-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.inf78
-rw-r--r--Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigPei.unibin0 -> 2220 bytes
-rw-r--r--Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigPeiExtra.unibin0 -> 1408 bytes
-rw-r--r--Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigPeim.c159
-rw-r--r--Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigStrings.unibin0 -> 4070 bytes
-rw-r--r--Core/SecurityPkg/Tcg/TrEEDxe/MeasureBootPeCoff.c427
-rw-r--r--Core/SecurityPkg/Tcg/TrEEDxe/TrEEDxe.c1912
-rw-r--r--Core/SecurityPkg/Tcg/TrEEDxe/TrEEDxe.inf104
-rw-r--r--Core/SecurityPkg/Tcg/TrEEDxe/TrEEDxe.unibin0 -> 2334 bytes
-rw-r--r--Core/SecurityPkg/Tcg/TrEEDxe/TrEEDxeExtra.unibin0 -> 1342 bytes
-rw-r--r--Core/SecurityPkg/Tcg/TrEEPei/TrEEPei.c725
-rw-r--r--Core/SecurityPkg/Tcg/TrEEPei/TrEEPei.inf86
-rw-r--r--Core/SecurityPkg/Tcg/TrEEPei/TrEEPei.unibin0 -> 1890 bytes
-rw-r--r--Core/SecurityPkg/Tcg/TrEEPei/TrEEPeiExtra.unibin0 -> 1354 bytes
-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.unibin0 -> 3284 bytes
-rw-r--r--Core/SecurityPkg/Tcg/TrEESmm/TrEESmmExtra.unibin0 -> 1354 bytes
-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.unibin0 -> 1842 bytes
-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.unibin0 -> 1372 bytes
-rw-r--r--Core/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderStrings.unibin0 -> 5128 bytes
-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.unibin0 -> 2306 bytes
-rw-r--r--Core/SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProviderDxe.inf70
-rw-r--r--Core/SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProviderExtra.unibin0 -> 1362 bytes
-rw-r--r--Core/SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProviderStrings.unibin0 -> 3556 bytes
-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.unibin0 -> 1766 bytes
-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.unibin0 -> 1354 bytes
-rw-r--r--Core/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManagerStrings.unibin0 -> 2696 bytes
-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.unibin0 -> 2042 bytes
-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.unibin0 -> 1350 bytes
-rw-r--r--Core/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManagerStrings.unibin0 -> 21532 bytes
-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.unibin0 -> 2322 bytes
-rw-r--r--Core/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/EsalVariableDxeSalExtra.unibin0 -> 1372 bytes
-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.vfr611
-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.inf126
-rw-r--r--Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxe.unibin0 -> 1892 bytes
-rw-r--r--Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxeExtra.unibin0 -> 1356 bytes
-rw-r--r--Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigFileExplorer.c1234
-rw-r--r--Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigImpl.c3833
-rw-r--r--Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigImpl.h625
-rw-r--r--Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigMisc.c334
-rw-r--r--Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigNvData.h136
-rw-r--r--Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigStrings.unibin0 -> 13090 bytes
384 files changed, 99519 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..75ceda1047
--- /dev/null
+++ b/Core/SecurityPkg/Application/RngTest/RngTest.uni
Binary files differ
diff --git a/Core/SecurityPkg/Application/RngTest/RngTestExtra.uni b/Core/SecurityPkg/Application/RngTest/RngTestExtra.uni
new file mode 100644
index 0000000000..2206a0b76a
--- /dev/null
+++ b/Core/SecurityPkg/Application/RngTest/RngTestExtra.uni
Binary files differ
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..ba2fe6a2c4
--- /dev/null
+++ b/Core/SecurityPkg/Hash2DxeCrypto/Driver.c
@@ -0,0 +1,242 @@
+/** @file
+ This is service binding for Hash 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.
+
+**/
+
+#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 availabe 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..a145858fa0
--- /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, Intel Corporation. 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 availabe 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..ab34de7351
--- /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 intialized 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..087cee683c
--- /dev/null
+++ b/Core/SecurityPkg/Hash2DxeCrypto/Hash2DxeCrypto.uni
Binary files differ
diff --git a/Core/SecurityPkg/Hash2DxeCrypto/Hash2DxeCryptoExtra.uni b/Core/SecurityPkg/Hash2DxeCrypto/Hash2DxeCryptoExtra.uni
new file mode 100644
index 0000000000..123b0b460a
--- /dev/null
+++ b/Core/SecurityPkg/Hash2DxeCrypto/Hash2DxeCryptoExtra.uni
Binary files differ
diff --git a/Core/SecurityPkg/Include/Guid/AuthenticatedVariableFormat.h b/Core/SecurityPkg/Include/Guid/AuthenticatedVariableFormat.h
new file mode 100644
index 0000000000..1f007cfc73
--- /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 - 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 __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..1082807c36
--- /dev/null
+++ b/Core/SecurityPkg/Include/Guid/TcgEventHob.h
@@ -0,0 +1,47 @@
+/** @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 - 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_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;
+
+#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..b85756961e
--- /dev/null
+++ b/Core/SecurityPkg/Include/Library/HashLib.h
@@ -0,0 +1,169 @@
+/** @file
+ Ihis 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, Intel Corporation. All rights reserved. <BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+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..ce45f17454
--- /dev/null
+++ b/Core/SecurityPkg/Include/Library/Tcg2PhysicalPresenceLib.h
@@ -0,0 +1,160 @@
+/** @file
+ Ihis library is intended to be used by BDS modules.
+ This library will execute TPM2 request.
+
+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_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
+
+//
+// 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)
+
+/**
+ 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] 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..2434750f9f
--- /dev/null
+++ b/Core/SecurityPkg/Include/Library/Tcg2PpVendorLib.h
@@ -0,0 +1,129 @@
+/** @file
+ Ihis 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, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+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..3ef9d0a442
--- /dev/null
+++ b/Core/SecurityPkg/Include/Library/TcgPhysicalPresenceLib.h
@@ -0,0 +1,54 @@
+/** @file
+ Ihis library is intended to be used by BDS modules.
+ This library will lock TPM after executing TPM request.
+
+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 _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..fd8c2e7cfb
--- /dev/null
+++ b/Core/SecurityPkg/Include/Library/TcgPpVendorLib.h
@@ -0,0 +1,159 @@
+/** @file
+ Ihis 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, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+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 Sumbit TPM Request to Pre-OS Environment
+// and Sumbit 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..108affc422
--- /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 funciton 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..037a1f34bc
--- /dev/null
+++ b/Core/SecurityPkg/Include/Library/Tpm12CommandLib.h
@@ -0,0 +1,141 @@
+/** @file
+ This library is used by other modules to send TPM12 command.
+
+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 _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
+ );
+
+#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..c4915496dd
--- /dev/null
+++ b/Core/SecurityPkg/Include/Library/Tpm2CommandLib.h
@@ -0,0 +1,974 @@
+/** @file
+ This library is used by other modules to send TPM2 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.
+
+**/
+
+#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
+ );
+
+/**
+ 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 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
+ );
+
+//
+// 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
+ );
+
+#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..9bca341bb5
--- /dev/null
+++ b/Core/SecurityPkg/Include/Library/TpmCommLib.h
@@ -0,0 +1,287 @@
+/** @file
+ Ihis library is only intended to be used by TPM modules.
+ It provides basic TPM Interface Specification (TIS) and Command functions.
+
+Copyright (c) 2005 - 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 _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..7c0484d7a2
--- /dev/null
+++ b/Core/SecurityPkg/Include/Library/TrEEPhysicalPresenceLib.h
@@ -0,0 +1,57 @@
+/** @file
+ Ihis library is intended to be used by BDS modules.
+ This library will execute TPM2 request.
+
+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.
+
+**/
+
+#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..80c1babeae
--- /dev/null
+++ b/Core/SecurityPkg/Include/Library/TrEEPpVendorLib.h
@@ -0,0 +1,164 @@
+/** @file
+ Ihis 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, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+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 Sumbit TPM Request to Pre-OS Environment
+// and Sumbit 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..88d09b0d33
--- /dev/null
+++ b/Core/SecurityPkg/Include/Ppi/FirmwareVolumeInfoMeasurementExcluded.h
@@ -0,0 +1,37 @@
+/** @file
+ Ihis PPI means a FV does not need to be extended to PCR by TCG modules.
+
+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 __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..1f9ba15384
--- /dev/null
+++ b/Core/SecurityPkg/Library/AuthVariableLib/AuthService.c
@@ -0,0 +1,2548 @@
+/** @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 - 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 "AuthServiceInternal.h"
+
+//
+// Public Exponent of RSA Key.
+//
+CONST UINT8 mRsaE[] = { 0x01, 0x00, 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;
+ }
+
+ 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 OPTIONAL
+ )
+{
+ 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);
+ }
+
+ 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".
+
+ The data format of "certdb":
+ //
+ // 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".
+ @param[in] DataSize Size of variable "certdb".
+ @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".
+
+ @param[in] VariableName Name of authenticated Variable.
+ @param[in] VendorGuid Vendor GUID 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" or matching certs.
+ @retval EFI_SUCCESS Get signer's certificates successfully.
+
+**/
+EFI_STATUS
+GetCertsFromDb (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ OUT UINT8 **CertData,
+ OUT UINT32 *CertDataSize
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *Data;
+ UINTN DataSize;
+ UINT32 CertOffset;
+
+ if ((VariableName == NULL) || (VendorGuid == NULL) || (CertData == NULL) || (CertDataSize == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Get 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;
+ }
+
+ 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".
+
+ @param[in] VariableName Name of authenticated Variable.
+ @param[in] VendorGuid Vendor GUID of authenticated Variable.
+
+ @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
+ @retval EFI_NOT_FOUND Fail to find "certdb" 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
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *Data;
+ UINTN DataSize;
+ UINT32 VarAttr;
+ UINT32 CertNodeOffset;
+ UINT32 CertNodeSize;
+ UINT8 *NewCertDb;
+ UINT32 NewCertDbSize;
+
+ if ((VariableName == NULL) || (VendorGuid == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Get 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;
+ }
+
+ if (DataSize == sizeof (UINT32)) {
+ //
+ // There is no certs in certdb.
+ //
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Get corresponding cert node from certdb.
+ //
+ 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".
+ //
+ 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".
+ //
+ VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
+ Status = AuthServiceInternalUpdateVariable (
+ EFI_CERT_DB_NAME,
+ &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".
+
+ @param[in] VariableName Name of authenticated Variable.
+ @param[in] VendorGuid Vendor GUID 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"
+
+**/
+EFI_STATUS
+InsertCertsToDb (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ 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;
+
+ if ((VariableName == NULL) || (VendorGuid == NULL) || (CertData == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Get 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;
+ }
+
+ //
+ // Find whether matching cert node already exists in "certdb".
+ // 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".
+ //
+ 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".
+ //
+ VarAttr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
+ Status = AuthServiceInternalUpdateVariable (
+ EFI_CERT_DB_NAME,
+ &gEfiCertDbGuid,
+ NewCertDb,
+ NewCertDbSize,
+ VarAttr
+ );
+
+ return Status;
+}
+
+/**
+ 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
+ )
+{
+ UINT32 Offset;
+ AUTH_CERT_DB_DATA *Ptr;
+ UINT32 NameSize;
+ UINT32 NodeSize;
+ CHAR16 *VariableName;
+ EFI_STATUS Status;
+ BOOLEAN CertCleaned;
+ UINT8 *Data;
+ UINTN DataSize;
+ UINT8 *AuthVarData;
+ UINTN AuthVarDataSize;
+ EFI_GUID AuthVarGuid;
+
+ 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);
+ //
+ // Check whether VendorGuid matches.
+ //
+ 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
+ //
+ Status = AuthServiceInternalFindVariable (
+ VariableName,
+ &AuthVarGuid,
+ (VOID **) &AuthVarData,
+ &AuthVarDataSize
+ );
+
+ if (EFI_ERROR(Status)) {
+ Status = DeleteCertsFromDb(VariableName, &AuthVarGuid);
+ 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));
+
+ //
+ // 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 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, &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, 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);
+ }
+
+ 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..add05c21cc
--- /dev/null
+++ b/Core/SecurityPkg/Library/AuthVariableLib/AuthServiceInternal.h
@@ -0,0 +1,427 @@
+/** @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 - 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 _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>
+
+///
+/// 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 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"
+
+#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".
+
+ @param[in] VariableName Name of authenticated Variable.
+ @param[in] VendorGuid Vendor GUID of authenticated Variable.
+
+ @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
+ @retval EFI_NOT_FOUND Fail to find "certdb" 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
+ );
+
+/**
+ 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 OPTIONAL
+ );
+
+/**
+ 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..00ec1710fc
--- /dev/null
+++ b/Core/SecurityPkg/Library/AuthVariableLib/AuthVariableLib.c
@@ -0,0 +1,464 @@
+/** @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, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+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
+ }
+ },
+};
+
+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.
+ //
+ mMaxCertDbSize = (UINT32) (mAuthVarLibContextIn->MaxAuthVariableSize - sizeof (EFI_CERT_DB_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_INFO, "Clean up CertDB fail! Status %x\n", 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 = sizeof (mAuthVarEntry) / sizeof (mAuthVarEntry[0]);
+ 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 = sizeof (mAuthVarAddressPointer) / sizeof (mAuthVarAddressPointer[0]);
+
+ 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..3709f7baae
--- /dev/null
+++ b/Core/SecurityPkg/Library/AuthVariableLib/AuthVariableLib.inf
@@ -0,0 +1,90 @@
+## @file
+# 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.
+#
+##
+
+[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"
+ ## PRODUCES ## Variable:L"certdb"
+ 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..2f72288eea
--- /dev/null
+++ b/Core/SecurityPkg/Library/AuthVariableLib/AuthVariableLib.uni
Binary files differ
diff --git a/Core/SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.c b/Core/SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.c
new file mode 100644
index 0000000000..142b5469af
--- /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 TURE The DevicePath is in the specified List.
+ @retval FALSE The DevicePath is not in the specified List.
+
+**/
+BOOLEAN
+IsDevicePathInList (
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ IN UINT32 AccessType
+ )
+{
+ EFI_STATUS Status;
+ EFI_USER_INFO_ACCESS_CONTROL *Access;
+ EFI_DEVICE_PATH_PROTOCOL *Path;
+ UINTN OffSet;
+
+ Status = GetAccessControl (&Access, AccessType);
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ OffSet = 0;
+ while (OffSet < Access->Size - sizeof (EFI_USER_INFO_ACCESS_CONTROL)) {
+ Path = (EFI_DEVICE_PATH_PROTOCOL*)((UINT8*)(Access + 1) + OffSet);
+ if (CheckDevicePath (Path, DevicePath)) {
+ //
+ // The device path is found in list.
+ //
+ FreePool (Access);
+ return TRUE;
+ }
+ OffSet += GetDevicePathSize (Path);
+ }
+
+ FreePool (Access);
+ return FALSE;
+}
+
+
+/**
+ Check whether the image pointed to by DevicePath is permitted to load.
+
+ @param[in] DevicePath Points to device path
+
+ @retval TURE The image pointed by DevicePath is permitted to load.
+ @retval FALSE The image pointed by DevicePath is forbidden to load.
+
+**/
+BOOLEAN
+VerifyDevicePath (
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ if (IsDevicePathInList (DevicePath, EFI_USER_INFO_ACCESS_PERMIT_LOAD)) {
+ //
+ // This access control overrides any restrictions put in place by the
+ // EFI_USER_INFO_ACCESS_FORBID_LOAD record.
+ //
+ return TRUE;
+ }
+
+ if (IsDevicePathInList (DevicePath, EFI_USER_INFO_ACCESS_FORBID_LOAD)) {
+ //
+ // The device path is found in the forbidden list.
+ //
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/**
+ Check the image pointed by DevicePath is a boot option or not.
+
+ @param[in] DevicePath Points to device path.
+
+ @retval TURE The image pointed by DevicePath is a boot option.
+ @retval FALSE The image pointed by DevicePath is not a boot option.
+
+**/
+BOOLEAN
+IsBootOption (
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ EFI_STATUS Status;
+ UINT16 *BootOrderList;
+ UINTN BootOrderListSize;
+ UINTN Index;
+ CHAR16 StrTemp[20];
+ UINT8 *OptionBuffer;
+ UINT8 *OptionPtr;
+ EFI_DEVICE_PATH_PROTOCOL *OptionDevicePath;
+
+ //
+ // Get BootOrder
+ //
+ BootOrderListSize = 0;
+ BootOrderList = NULL;
+ Status = gRT->GetVariable (
+ L"BootOrder",
+ &gEfiGlobalVariableGuid,
+ NULL,
+ &BootOrderListSize,
+ NULL
+ );
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ BootOrderList = AllocateZeroPool (BootOrderListSize);
+ ASSERT (BootOrderList != NULL);
+ Status = gRT->GetVariable (
+ L"BootOrder",
+ &gEfiGlobalVariableGuid,
+ NULL,
+ &BootOrderListSize,
+ BootOrderList
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+ //
+ // No Boot option
+ //
+ return FALSE;
+ }
+
+ OptionBuffer = NULL;
+ for (Index = 0; Index < BootOrderListSize / sizeof (UINT16); Index++) {
+ //
+ // Try to find the DevicePath in BootOption
+ //
+ UnicodeSPrint (StrTemp, sizeof (StrTemp), L"Boot%04x", Index);
+ 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..cd6c777b28
--- /dev/null
+++ b/Core/SecurityPkg/Library/DxeDeferImageLoadLib/DxeDeferImageLoadLib.uni
Binary files differ
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..b570d01a55
--- /dev/null
+++ b/Core/SecurityPkg/Library/DxeImageAuthenticationStatusLib/DxeImageAuthenticationStatusLib.uni
Binary files differ
diff --git a/Core/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c b/Core/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c
new file mode 100644
index 0000000000..c0c4a9093b
--- /dev/null
+++ b/Core/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.c
@@ -0,0 +1,1967 @@
+/** @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 - 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 "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}
+};
+
+/**
+ 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;
+ }
+
+ 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) ((UINT8 *) (&mNtHeader.Pe32->OptionalHeader.CheckSum) - HashBase);
+ NumberOfRvaAndSizes = mNtHeader.Pe32->OptionalHeader.NumberOfRvaAndSizes;
+ } else if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
+ //
+ // Use PE32+ offset.
+ //
+ HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32Plus->OptionalHeader.CheckSum) - 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 - mImageBase);
+ } else {
+ //
+ // Use PE32+ offset.
+ //
+ HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);
+ HashSize = mNtHeader.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - 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) ((UINT8 *) (&mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase);
+ } else {
+ //
+ // Use PE32+ offset.
+ //
+ HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);
+ HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase);
+ }
+
+ 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 - mImageBase);
+ } else {
+ //
+ // Use PE32+ offset.
+ //
+ HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];
+ HashSize = mNtHeader.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - 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;
+
+ ImageExeInfoTable = NULL;
+ NewImageExeInfoTable = NULL;
+ ImageExeInfoEntry = NULL;
+ NameStringLen = 0;
+
+ 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);
+ 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);
+
+ if (Name != NULL) {
+ CopyMem ((UINT8 *) ImageExeInfoEntry + sizeof (EFI_IMAGE_EXECUTION_ACTION) + sizeof (UINT32), Name, NameStringLen);
+ } else {
+ ZeroMem ((UINT8 *) ImageExeInfoEntry + sizeof (EFI_IMAGE_EXECUTION_ACTION) + sizeof (UINT32), sizeof (CHAR16));
+ }
+ CopyMem (
+ (UINT8 *) ImageExeInfoEntry + sizeof (EFI_IMAGE_EXECUTION_ACTION) + sizeof (UINT32) + NameStringLen,
+ DevicePath,
+ DevicePathSize
+ );
+ if (Signature != NULL) {
+ CopyMem (
+ (UINT8 *) ImageExeInfoEntry + sizeof (EFI_IMAGE_EXECUTION_ACTION) + sizeof (UINT32) + 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;
+ 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) {
+ SecureBootHook (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, CertList->SignatureSize, CertData);
+ 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;
+ }
+ 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 *Cert;
+ UINTN DataSize;
+ UINT8 *Data;
+ UINT8 *RootCert;
+ UINTN RootCertSize;
+ UINTN Index;
+ UINTN CertCount;
+ UINTN DbxDataSize;
+ UINT8 *DbxData;
+ EFI_TIME RevocationTime;
+
+ Data = NULL;
+ CertList = NULL;
+ Cert = 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)) {
+ 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);
+
+ //
+ // 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 image can be trusted.
+ //
+ VerifyStatus = PassTimestampCheck (AuthData, AuthDataSize, &RevocationTime);
+ }
+
+ goto Done;
+ }
+
+ Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);
+ }
+ }
+
+ DataSize -= CertList->SignatureListSize;
+ CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
+ }
+ }
+
+Done:
+ if (VerifyStatus) {
+ SecureBootHook (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid, CertList->SignatureSize, Cert);
+ }
+
+ 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.
+ //
+ 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
+ //
+ 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.
+ //
+ 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)) {
+ goto Done;
+ }
+
+ if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE1, mImageDigest, &mCertType, mImageDigestSize)) {
+ //
+ // Image Hash is in forbidden database (DBX).
+ //
+ 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.
+ //
+ 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;
+ VerifyStatus = EFI_ACCESS_DENIED;
+ break;
+ } else if (EFI_ERROR (VerifyStatus)) {
+ if (IsSignatureFoundInDatabase (EFI_IMAGE_SECURITY_DATABASE, mImageDigest, &mCertType, mImageDigestSize)) {
+ VerifyStatus = EFI_SUCCESS;
+ }
+ }
+ }
+
+ 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..b09ef8afd3
--- /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 \ No newline at end of file
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..b7b0ca8808
--- /dev/null
+++ b/Core/SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.uni
Binary files differ
diff --git a/Core/SecurityPkg/Library/DxeImageVerificationLib/Measurement.c b/Core/SecurityPkg/Library/DxeImageVerificationLib/Measurement.c
new file mode 100644
index 0000000000..1dc29895f3
--- /dev/null
+++ b/Core/SecurityPkg/Library/DxeImageVerificationLib/Measurement.c
@@ -0,0 +1,322 @@
+/** @file
+ Measure TrEE required variable.
+
+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 <PiDxe.h>
+#include <Guid/ImageAuthentication.h>
+#include <IndustryStandard/UefiTcgPlatform.h>
+#include <Protocol/TrEEProtocol.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;
+ EFI_VARIABLE_DATA_TREE *VarLog;
+ UINT32 VarLogSize;
+
+ //
+ // The EFI_VARIABLE_DATA_TREE.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 = (EFI_VARIABLE_DATA_TREE *) 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..5f5d242d6e
--- /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 successull 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..9345cc552e
--- /dev/null
+++ b/Core/SecurityPkg/Library/DxeRsa2048Sha256GuidedSectionExtractLib/DxeRsa2048Sha256GuidedSectionExtractLib.uni
Binary files differ
diff --git a/Core/SecurityPkg/Library/DxeTcg2PhysicalPresenceLib/DxeTcg2PhysicalPresenceLib.c b/Core/SecurityPkg/Library/DxeTcg2PhysicalPresenceLib/DxeTcg2PhysicalPresenceLib.c
new file mode 100644
index 0000000000..e34fd8da25
--- /dev/null
+++ b/Core/SecurityPkg/Library/DxeTcg2PhysicalPresenceLib/DxeTcg2PhysicalPresenceLib.c
@@ -0,0 +1,1250 @@
+/** @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;
+}
+
+/**
+ 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
+Tpm2CommandAllocPcr (
+ 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 ((EFI_TCG2_BOOT_HASH_ALG_SHA1 & SupportedPCRBanks) != 0) {
+ PcrAllocation.pcrSelections[PcrAllocation.count].hash = TPM_ALG_SHA1;
+ PcrAllocation.pcrSelections[PcrAllocation.count].sizeofSelect = PCR_SELECT_MAX;
+ if ((EFI_TCG2_BOOT_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 ((EFI_TCG2_BOOT_HASH_ALG_SHA256 & SupportedPCRBanks) != 0) {
+ PcrAllocation.pcrSelections[PcrAllocation.count].hash = TPM_ALG_SHA256;
+ PcrAllocation.pcrSelections[PcrAllocation.count].sizeofSelect = PCR_SELECT_MAX;
+ if ((EFI_TCG2_BOOT_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 ((EFI_TCG2_BOOT_HASH_ALG_SHA384 & SupportedPCRBanks) != 0) {
+ PcrAllocation.pcrSelections[PcrAllocation.count].hash = TPM_ALG_SHA384;
+ PcrAllocation.pcrSelections[PcrAllocation.count].sizeofSelect = PCR_SELECT_MAX;
+ if ((EFI_TCG2_BOOT_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 ((EFI_TCG2_BOOT_HASH_ALG_SHA512 & SupportedPCRBanks) != 0) {
+ PcrAllocation.pcrSelections[PcrAllocation.count].hash = TPM_ALG_SHA512;
+ PcrAllocation.pcrSelections[PcrAllocation.count].sizeofSelect = PCR_SELECT_MAX;
+ if ((EFI_TCG2_BOOT_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 ((EFI_TCG2_BOOT_HASH_ALG_SM3_256 & SupportedPCRBanks) != 0) {
+ PcrAllocation.pcrSelections[PcrAllocation.count].hash = TPM_ALG_SM3_256;
+ PcrAllocation.pcrSelections[PcrAllocation.count].sizeofSelect = PCR_SELECT_MAX;
+ if ((EFI_TCG2_BOOT_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, "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;
+}
+
+/**
+ 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_PROTOCOL *Tcg2Protocol;
+ EFI_TCG2_BOOT_SERVICE_CAPABILITY ProtocolCapability;
+
+ Status = gBS->LocateProtocol (&gEfiTcg2ProtocolGuid, NULL, (VOID **) &Tcg2Protocol);
+ ASSERT_EFI_ERROR (Status);
+
+ ProtocolCapability.Size = sizeof(ProtocolCapability);
+ Status = Tcg2Protocol->GetCapability (
+ Tcg2Protocol,
+ &ProtocolCapability
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ 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 = Tpm2CommandAllocPcr (PlatformAuth, ProtocolCapability.HashAlgorithmBitmap, 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 = Tpm2CommandAllocPcr (PlatformAuth, ProtocolCapability.HashAlgorithmBitmap, ProtocolCapability.HashAlgorithmBitmap);
+ if (EFI_ERROR (Status)) {
+ return TCG_PP_OPERATION_RESPONSE_BIOS_FAILURE;
+ } else {
+ 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;
+
+ 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);
+
+ TmpStr2 = NULL;
+ CautionKey = FALSE;
+ NoPpiInfo = FALSE;
+ BufSize = CONFIRM_BUFFER_SIZE;
+ ConfirmText = AllocateZeroPool (BufSize);
+ ASSERT (ConfirmText != 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:
+ 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;
+
+
+ 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);
+
+ 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
+ )
+{
+ BOOLEAN IsRequestValid;
+
+ *RequestConfirmed = 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;
+
+ 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] TcgPpData Point to the physical presence NV variable.
+ @param[in] Flags The physical presence interface flags.
+**/
+VOID
+Tcg2ExecutePendingTpmRequest (
+ IN TPM2B_AUTH *PlatformAuth, OPTIONAL
+ IN EFI_TCG2_PHYSICAL_PRESENCE *TcgPpData,
+ IN 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) {
+ 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;
+
+ 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;
+ EFI_TCG2_PROTOCOL *Tcg2Protocol;
+ EDKII_VARIABLE_LOCK_PROTOCOL *VariableLockProtocol;
+ EFI_TCG2_PHYSICAL_PRESENCE_FLAGS PpiFlags;
+
+ Status = gBS->LocateProtocol (&gEfiTcg2ProtocolGuid, NULL, (VOID **) &Tcg2Protocol);
+ if (EFI_ERROR (Status)) {
+ return ;
+ }
+
+ //
+ // Check S4 resume
+ //
+ if (GetBootModeHob () == BOOT_ON_S4_RESUME) {
+ DEBUG ((EFI_D_INFO, "S4 Resume, Skip TPM PP process!\n"));
+ return ;
+ }
+
+ mTcg2PpStringPackHandle = HiiAddPackages (&gEfiTcg2PhysicalPresenceGuid, gImageHandle, DxeTcg2PhysicalPresenceLibStrings, NULL);
+ ASSERT (mTcg2PpStringPackHandle != NULL);
+
+ //
+ // 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 = TCG2_BIOS_TPM_MANAGEMENT_FLAG_DEFAULT;
+ 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 ((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,
+ 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);
+ }
+ }
+
+ //
+ // 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_PROTOCOL *Tcg2Protocol;
+ EFI_TCG2_PHYSICAL_PRESENCE_FLAGS PpiFlags;
+
+ Status = gBS->LocateProtocol (&gEfiTcg2ProtocolGuid, NULL, (VOID **) &Tcg2Protocol);
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ //
+ // 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_VENDOR_SPECIFIC_OPERATION) ) {
+ //
+ // This command requires UI to prompt user for Auth data.
+ //
+ 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;
+ }
+ return Tcg2PpVendorLibSubmitRequestToPreOSFunction (OperationRequest, Flags.PPFlags, RequestParameter);
+ }
+
+ return TCG_PP_SUBMIT_REQUEST_TO_PREOS_SUCCESS;
+}
diff --git a/Core/SecurityPkg/Library/DxeTcg2PhysicalPresenceLib/DxeTcg2PhysicalPresenceLib.inf b/Core/SecurityPkg/Library/DxeTcg2PhysicalPresenceLib/DxeTcg2PhysicalPresenceLib.inf
new file mode 100644
index 0000000000..bad4fe41b1
--- /dev/null
+++ b/Core/SecurityPkg/Library/DxeTcg2PhysicalPresenceLib/DxeTcg2PhysicalPresenceLib.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 = 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 ## CONSUMES
+ gEdkiiVariableLockProtocolGuid ## CONSUMES
+
+[Guids]
+ ## 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..9794792d70
--- /dev/null
+++ b/Core/SecurityPkg/Library/DxeTcg2PhysicalPresenceLib/DxeTcg2PhysicalPresenceLib.uni
Binary files differ
diff --git a/Core/SecurityPkg/Library/DxeTcg2PhysicalPresenceLib/PhysicalPresenceStrings.uni b/Core/SecurityPkg/Library/DxeTcg2PhysicalPresenceLib/PhysicalPresenceStrings.uni
new file mode 100644
index 0000000000..30f21a36c0
--- /dev/null
+++ b/Core/SecurityPkg/Library/DxeTcg2PhysicalPresenceLib/PhysicalPresenceStrings.uni
Binary files differ
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..b48b887ad3
--- /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 ## CONSUMES
+ gEdkiiVariableLockProtocolGuid ## CONSUMES
+
+[Guids]
+ ## 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..dee12cc7ee
--- /dev/null
+++ b/Core/SecurityPkg/Library/DxeTcgPhysicalPresenceLib/DxeTcgPhysicalPresenceLib.uni
Binary files differ
diff --git a/Core/SecurityPkg/Library/DxeTcgPhysicalPresenceLib/PhysicalPresenceStrings.uni b/Core/SecurityPkg/Library/DxeTcgPhysicalPresenceLib/PhysicalPresenceStrings.uni
new file mode 100644
index 0000000000..cfa1989245
--- /dev/null
+++ b/Core/SecurityPkg/Library/DxeTcgPhysicalPresenceLib/PhysicalPresenceStrings.uni
Binary files differ
diff --git a/Core/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c b/Core/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.c
new file mode 100644
index 0000000000..26bf6fb000
--- /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 - 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/Tcg2Protocol.h>
+#include <Protocol/BlockIo.h>
+#include <Protocol/DiskIo.h>
+#include <Protocol/DevicePathToText.h>
+#include <Protocol/FirmwareVolumeBlock.h>
+
+#include <Guid/MeasuredFvHob.h>
+#include <Guid/ZeroGuid.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 (!CompareGuid (&PartitionEntry->PartitionTypeGUID, &gZeroGuid)) {
+ 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 (!CompareGuid (&PartitionEntry->PartitionTypeGUID, &gZeroGuid)) {
+ 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_INFO, "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..1296c977b4
--- /dev/null
+++ b/Core/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.inf
@@ -0,0 +1,68 @@
+## @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 - 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 = 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
+ gZeroGuid ## SOMETIMES_CONSUMES ## GUID
+
+[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..fabe3d7276
--- /dev/null
+++ b/Core/SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.uni
Binary files differ
diff --git a/Core/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c b/Core/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c
new file mode 100644
index 0000000000..8ab60d871d
--- /dev/null
+++ b/Core/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.c
@@ -0,0 +1,1012 @@
+/** @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 - 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/TcgService.h>
+#include <Protocol/BlockIo.h>
+#include <Protocol/DiskIo.h>
+#include <Protocol/FirmwareVolumeBlock.h>
+
+#include <Guid/MeasuredFvHob.h>
+#include <Guid/ZeroGuid.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 (!CompareGuid (&PartitionEntry->PartitionTypeGUID, &gZeroGuid)) {
+ 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 (!CompareGuid (&PartitionEntry->PartitionTypeGUID, &gZeroGuid)) {
+ 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) ((UINT8 *)(&Hdr.Pe32->OptionalHeader.CheckSum) - HashBase);
+ } else {
+ //
+ // Use PE32+ offset
+ //
+ NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
+ HashSize = (UINTN) ((UINT8 *)(&Hdr.Pe32Plus->OptionalHeader.CheckSum) - 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) ((UINT8 *)(&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase);
+ } else {
+ //
+ // Use PE32+ offset
+ //
+ HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);
+ HashSize = (UINTN) ((UINT8 *)(&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase);
+ }
+
+ 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..0d58eec9b5
--- /dev/null
+++ b/Core/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.inf
@@ -0,0 +1,68 @@
+## @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 - 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 = 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
+ gZeroGuid ## SOMETIMES_CONSUMES ## GUID
+
+[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..6e16ee203f
--- /dev/null
+++ b/Core/SecurityPkg/Library/DxeTpmMeasureBootLib/DxeTpmMeasureBootLib.uni
Binary files differ
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..2f37078f83
--- /dev/null
+++ b/Core/SecurityPkg/Library/DxeTpmMeasurementLib/DxeTpmMeasurementLib.uni
Binary files differ
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..06122269aa
--- /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 ## CONSUMES
+ gEdkiiVariableLockProtocolGuid ## CONSUMES
+
+[Guids]
+ ## 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..9794792d70
--- /dev/null
+++ b/Core/SecurityPkg/Library/DxeTrEEPhysicalPresenceLib/DxeTrEEPhysicalPresenceLib.uni
Binary files differ
diff --git a/Core/SecurityPkg/Library/DxeTrEEPhysicalPresenceLib/PhysicalPresenceStrings.uni b/Core/SecurityPkg/Library/DxeTrEEPhysicalPresenceLib/PhysicalPresenceStrings.uni
new file mode 100644
index 0000000000..99e2a2fd94
--- /dev/null
+++ b/Core/SecurityPkg/Library/DxeTrEEPhysicalPresenceLib/PhysicalPresenceStrings.uni
Binary files differ
diff --git a/Core/SecurityPkg/Library/HashInstanceLibSha1/HashInstanceLibSha1.c b/Core/SecurityPkg/Library/HashInstanceLibSha1/HashInstanceLibSha1.c
new file mode 100644
index 0000000000..a42c60d9ba
--- /dev/null
+++ b/Core/SecurityPkg/Library/HashInstanceLibSha1/HashInstanceLibSha1.c
@@ -0,0 +1,155 @@
+/** @file
+ Ihis library is BaseCrypto SHA1 hash instance.
+ It can be registered to BaseCrypto router, to serve as hash engine.
+
+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 <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..18043e5c64
--- /dev/null
+++ b/Core/SecurityPkg/Library/HashInstanceLibSha1/HashInstanceLibSha1.uni
Binary files differ
diff --git a/Core/SecurityPkg/Library/HashInstanceLibSha256/HashInstanceLibSha256.c b/Core/SecurityPkg/Library/HashInstanceLibSha256/HashInstanceLibSha256.c
new file mode 100644
index 0000000000..abc97b4473
--- /dev/null
+++ b/Core/SecurityPkg/Library/HashInstanceLibSha256/HashInstanceLibSha256.c
@@ -0,0 +1,155 @@
+/** @file
+ Ihis library is BaseCrypto SHA256 hash instance.
+ It can be registered to BaseCrypto router, to serve as hash engine.
+
+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 <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..1f8ab2e75f
--- /dev/null
+++ b/Core/SecurityPkg/Library/HashInstanceLibSha256/HashInstanceLibSha256.uni
Binary files differ
diff --git a/Core/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterCommon.c b/Core/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterCommon.c
new file mode 100644
index 0000000000..7fb5f3d1f8
--- /dev/null
+++ b/Core/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterCommon.c
@@ -0,0 +1,77 @@
+/** @file
+ Ihis is BaseCrypto router support function.
+
+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 <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..f0ea3ca212
--- /dev/null
+++ b/Core/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterCommon.h
@@ -0,0 +1,44 @@
+/** @file
+ Ihis is BaseCrypto router support function 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 _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..4f3c8dfa7c
--- /dev/null
+++ b/Core/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterDxe.c
@@ -0,0 +1,238 @@
+/** @file
+ Ihis 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 - 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 <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;
+
+/**
+ 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;
+ }
+
+ 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;
+ }
+
+ 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;
+ }
+
+ 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;
+ }
+
+ 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;
+ UINT32 BiosSupportedHashMask;
+ 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;
+ }
+ BiosSupportedHashMask = PcdGet32 (PcdTcg2HashAlgorithmBitmap);
+ Status = PcdSet32S (PcdTcg2HashAlgorithmBitmap, BiosSupportedHashMask | HashMask);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Check duplication
+ //
+ for (Index = 0; Index < mHashInterfaceCount; Index++) {
+ if (CompareGuid (&mHashInterface[Index].HashGuid, &HashInterface->HashGuid)) {
+ return EFI_ALREADY_STARTED;
+ }
+ }
+
+ CopyMem (&mHashInterface[mHashInterfaceCount], HashInterface, sizeof(*HashInterface));
+ mHashInterfaceCount ++;
+
+ return EFI_SUCCESS;
+} \ No newline at end of file
diff --git a/Core/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterDxe.inf b/Core/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterDxe.inf
new file mode 100644
index 0000000000..7c38ea6bc2
--- /dev/null
+++ b/Core/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterDxe.inf
@@ -0,0 +1,53 @@
+## @file
+# Provides hash service by registered hash handler
+#
+# Ihis 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 - 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 = 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
+
+#
+# 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
+ gEfiSecurityPkgTokenSpaceGuid.PcdTcg2HashAlgorithmBitmap ## CONSUMES
+
diff --git a/Core/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterDxe.uni b/Core/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterDxe.uni
new file mode 100644
index 0000000000..06b7a2f859
--- /dev/null
+++ b/Core/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterDxe.uni
Binary files differ
diff --git a/Core/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterPei.c b/Core/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterPei.c
new file mode 100644
index 0000000000..c3d487958b
--- /dev/null
+++ b/Core/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterPei.c
@@ -0,0 +1,305 @@
+/** @file
+ Ihis 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 - 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 <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 "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 {
+ UINTN HashInterfaceCount;
+ HASH_INTERFACE HashInterface[HASH_COUNT];
+} HASH_INTERFACE_HOB;
+
+/**
+ This function get hash interface.
+
+ @retval hash interface.
+**/
+HASH_INTERFACE_HOB *
+InternalGetHashInterface (
+ VOID
+ )
+{
+ EFI_HOB_GUID_TYPE *Hob;
+
+ Hob = GetFirstGuidHob (&mHashLibPeiRouterGuid);
+ if (Hob == NULL) {
+ return NULL;
+ }
+ return (HASH_INTERFACE_HOB *)(Hob + 1);
+}
+
+/**
+ 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 = InternalGetHashInterface ();
+ if (HashInterfaceHob == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (HashInterfaceHob->HashInterfaceCount == 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ 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 = InternalGetHashInterface ();
+ if (HashInterfaceHob == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (HashInterfaceHob->HashInterfaceCount == 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ 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 = InternalGetHashInterface ();
+ if (HashInterfaceHob == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (HashInterfaceHob->HashInterfaceCount == 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ 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 = InternalGetHashInterface ();
+ if (HashInterfaceHob == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (HashInterfaceHob->HashInterfaceCount == 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ 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;
+ HASH_INTERFACE_HOB LocalHashInterfaceHob;
+ UINT32 HashMask;
+ UINT32 BiosSupportedHashMask;
+ EFI_STATUS Status;
+
+ //
+ // Check allow
+ //
+ HashMask = Tpm2GetHashMaskFromAlgo (&HashInterface->HashGuid);
+ if ((HashMask & PcdGet32 (PcdTpm2HashMask)) == 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ HashInterfaceHob = InternalGetHashInterface ();
+ if (HashInterfaceHob == NULL) {
+ ZeroMem (&LocalHashInterfaceHob, sizeof(LocalHashInterfaceHob));
+ HashInterfaceHob = BuildGuidDataHob (&mHashLibPeiRouterGuid, &LocalHashInterfaceHob, sizeof(LocalHashInterfaceHob));
+ if (HashInterfaceHob == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ if (HashInterfaceHob->HashInterfaceCount >= HASH_COUNT) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ BiosSupportedHashMask = PcdGet32 (PcdTcg2HashAlgorithmBitmap);
+ Status = PcdSet32S (PcdTcg2HashAlgorithmBitmap, BiosSupportedHashMask | HashMask);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Check duplication
+ //
+ for (Index = 0; Index < HashInterfaceHob->HashInterfaceCount; Index++) {
+ if (CompareGuid (&HashInterfaceHob->HashInterface[Index].HashGuid, &HashInterface->HashGuid)) {
+ //
+ // In PEI phase, there will be shadow driver dispatched again.
+ //
+ DEBUG ((EFI_D_INFO, "RegisterHashInterfaceLib - Override\n"));
+ CopyMem (&HashInterfaceHob->HashInterface[Index], HashInterface, sizeof(*HashInterface));
+ return EFI_SUCCESS;
+ }
+ }
+
+ CopyMem (&HashInterfaceHob->HashInterface[HashInterfaceHob->HashInterfaceCount], HashInterface, sizeof(*HashInterface));
+ HashInterfaceHob->HashInterfaceCount ++;
+
+ return EFI_SUCCESS;
+} \ No newline at end of file
diff --git a/Core/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterPei.inf b/Core/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterPei.inf
new file mode 100644
index 0000000000..c1a699fd0f
--- /dev/null
+++ b/Core/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterPei.inf
@@ -0,0 +1,54 @@
+## @file
+# Provides hash service by registered hash handler
+#
+# Ihis 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 - 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 = HashLibBaseCryptoRouterPei
+ MODULE_UNI_FILE = HashLibBaseCryptoRouterPei.uni
+ FILE_GUID = DDCBCFBA-8EEB-488a-96D6-097831A6E50B
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = HashLib|PEIM
+
+#
+# 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
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ Tpm2CommandLib
+ MemoryAllocationLib
+ PcdLib
+ HobLib
+
+[Pcd]
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpm2HashMask ## CONSUMES
+ gEfiSecurityPkgTokenSpaceGuid.PcdTcg2HashAlgorithmBitmap ## CONSUMES
+
diff --git a/Core/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterPei.uni b/Core/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterPei.uni
new file mode 100644
index 0000000000..8d2c0ed01e
--- /dev/null
+++ b/Core/SecurityPkg/Library/HashLibBaseCryptoRouter/HashLibBaseCryptoRouterPei.uni
Binary files differ
diff --git a/Core/SecurityPkg/Library/HashLibTpm2/HashLibTpm2.c b/Core/SecurityPkg/Library/HashLibTpm2/HashLibTpm2.c
new file mode 100644
index 0000000000..379f2f7e7e
--- /dev/null
+++ b/Core/SecurityPkg/Library/HashLibTpm2/HashLibTpm2.c
@@ -0,0 +1,341 @@
+/** @file
+ Ihis library uses TPM2 device to calculation hash.
+
+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 <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_INFO, "\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_INFO, "\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_INFO, "\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_INFO, "\n Tpm2EventSequenceComplete Success \n"));
+ } else {
+ Status = Tpm2SequenceComplete (
+ SequenceHandle,
+ &HashBuffer,
+ &Result
+ );
+ if (EFI_ERROR(Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+ DEBUG((EFI_D_INFO, "\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_INFO, "\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..7d107e054a
--- /dev/null
+++ b/Core/SecurityPkg/Library/HashLibTpm2/HashLibTpm2.uni
Binary files differ
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..473370300a
--- /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 successull 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..9345cc552e
--- /dev/null
+++ b/Core/SecurityPkg/Library/PeiRsa2048Sha256GuidedSectionExtractLib/PeiRsa2048Sha256GuidedSectionExtractLib.uni
Binary files differ
diff --git a/Core/SecurityPkg/Library/PeiTcg2PhysicalPresenceLib/PeiTcg2PhysicalPresenceLib.c b/Core/SecurityPkg/Library/PeiTcg2PhysicalPresenceLib/PeiTcg2PhysicalPresenceLib.c
new file mode 100644
index 0000000000..81fe1b4d2c
--- /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, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+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;
+ }
+ 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..d4492f6909
--- /dev/null
+++ b/Core/SecurityPkg/Library/PeiTcg2PhysicalPresenceLib/PeiTcg2PhysicalPresenceLib.uni
Binary files differ
diff --git a/Core/SecurityPkg/Library/PlatformSecureLibNull/PlatformSecureLibNull.c b/Core/SecurityPkg/Library/PlatformSecureLibNull/PlatformSecureLibNull.c
new file mode 100644
index 0000000000..1450ac44ab
--- /dev/null
+++ b/Core/SecurityPkg/Library/PlatformSecureLibNull/PlatformSecureLibNull.c
@@ -0,0 +1,42 @@
+/** @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 - 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.
+
+**/
+
+/**
+
+ 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 TRUE;
+}
diff --git a/Core/SecurityPkg/Library/PlatformSecureLibNull/PlatformSecureLibNull.inf b/Core/SecurityPkg/Library/PlatformSecureLibNull/PlatformSecureLibNull.inf
new file mode 100644
index 0000000000..7a5229d039
--- /dev/null
+++ b/Core/SecurityPkg/Library/PlatformSecureLibNull/PlatformSecureLibNull.inf
@@ -0,0 +1,39 @@
+## @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.
+#
+##
+
+[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
+
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ PlatformSecureLibNull.c
+
+[Packages]
+ MdePkg/MdePkg.dec
diff --git a/Core/SecurityPkg/Library/PlatformSecureLibNull/PlatformSecureLibNull.uni b/Core/SecurityPkg/Library/PlatformSecureLibNull/PlatformSecureLibNull.uni
new file mode 100644
index 0000000000..3274e8f6a0
--- /dev/null
+++ b/Core/SecurityPkg/Library/PlatformSecureLibNull/PlatformSecureLibNull.uni
Binary files differ
diff --git a/Core/SecurityPkg/Library/SmmTcg2PhysicalPresenceLib/SmmTcg2PhysicalPresenceLib.c b/Core/SecurityPkg/Library/SmmTcg2PhysicalPresenceLib/SmmTcg2PhysicalPresenceLib.c
new file mode 100644
index 0000000000..081ec6c00c
--- /dev/null
+++ b/Core/SecurityPkg/Library/SmmTcg2PhysicalPresenceLib/SmmTcg2PhysicalPresenceLib.c
@@ -0,0 +1,315 @@
+/** @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/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] 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 = 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_SUBMIT_REQUEST_TO_PREOS_GENERAL_FAILURE;
+ }
+
+ if ((OperationRequest > TCG2_PHYSICAL_PRESENCE_NO_ACTION_MAX) &&
+ (OperationRequest < TCG2_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION) ) {
+ //
+ // This command requires UI to prompt user for Auth data.
+ //
+ 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 = 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));
+ 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 = mTcg2PpSmmVariable->SmmGetVariable (
+ TCG2_PHYSICAL_PRESENCE_FLAGS_VARIABLE,
+ &gEfiTcg2PhysicalPresenceGuid,
+ NULL,
+ &DataSize,
+ &Flags
+ );
+ if (EFI_ERROR (Status)) {
+ Flags.PPFlags = TCG2_BIOS_TPM_MANAGEMENT_FLAG_DEFAULT;
+ }
+ return Tcg2PpVendorLibSubmitRequestToPreOSFunction (OperationRequest, Flags.PPFlags, RequestParameter);
+ }
+
+ return TCG_PP_SUBMIT_REQUEST_TO_PREOS_SUCCESS;
+}
+
+/**
+ 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;
+
+ 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 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
+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..a351dcbaf2
--- /dev/null
+++ b/Core/SecurityPkg/Library/SmmTcg2PhysicalPresenceLib/SmmTcg2PhysicalPresenceLib.inf
@@ -0,0 +1,56 @@
+## @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
+
+[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..c0a7809719
--- /dev/null
+++ b/Core/SecurityPkg/Library/SmmTcg2PhysicalPresenceLib/SmmTcg2PhysicalPresenceLib.uni
Binary files differ
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..905a89f766
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tcg2PpVendorLibNull/Tcg2PpVendorLibNull.uni
Binary files differ
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..e840a3d959
--- /dev/null
+++ b/Core/SecurityPkg/Library/TcgPpVendorLibNull/TcgPpVendorLibNull.uni
Binary files differ
diff --git a/Core/SecurityPkg/Library/TcgStorageCoreLib/TcgStorageCore.c b/Core/SecurityPkg/Library/TcgStorageCoreLib/TcgStorageCore.c
new file mode 100644
index 0000000000..e333b55352
--- /dev/null
+++ b/Core/SecurityPkg/Library/TcgStorageCoreLib/TcgStorageCore.c
@@ -0,0 +1,1650 @@
+/** @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;
+ }
+
+ 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..30808cd835
--- /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 TURE 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..cc8d5ef3f0
--- /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"));
+ //
+ // TODO do we want to 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 funciton 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..4f0c3848e1
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm12CommandLib/Tpm12CommandLib.inf
@@ -0,0 +1,47 @@
+## @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.
+#
+##
+
+[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
+
+[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..1a3f9cc1e7
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm12CommandLib/Tpm12CommandLib.uni
Binary files differ
diff --git a/Core/SecurityPkg/Library/Tpm12CommandLib/Tpm12NvStorage.c b/Core/SecurityPkg/Library/Tpm12CommandLib/Tpm12NvStorage.c
new file mode 100644
index 0000000000..d644d33846
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm12CommandLib/Tpm12NvStorage.c
@@ -0,0 +1,255 @@
+/** @file
+ Implement TPM1.2 NV storage related command.
+
+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 <Uefi.h>
+#include <IndustryStandard/Tpm12.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/BaseLib.h>
+#include <Library/Tpm12DeviceLib.h>
+#include <Library/Tpm12CommandLib.h>
+#include <Library/DebugLib.h>
+
+//
+// Max TPM command/reponse length
+//
+#define TPMCMDBUFLENGTH 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_RSP_COMMAND_HDR Hdr;
+} TPM_RSP_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[TPMCMDBUFLENGTH];
+} TPM_RSP_NV_READ_VALUE;
+
+typedef struct {
+ TPM_RQU_COMMAND_HDR Hdr;
+ TPM_NV_INDEX NvIndex;
+ UINT32 Offset;
+ UINT32 DataSize;
+ UINT8 Data[TPMCMDBUFLENGTH];
+} TPM_CMD_NV_WRITE_VALUE;
+
+typedef struct {
+ TPM_RSP_COMMAND_HDR Hdr;
+} TPM_RSP_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;
+ UINT32 TpmRecvSize;
+ UINT32 TpmSendSize;
+ TPM_CMD_NV_DEFINE_SPACE SendBuffer;
+ TPM_RSP_NV_DEFINE_SPACE RecvBuffer;
+ UINT32 ReturnCode;
+
+ //
+ // send Tpm command TPM_ORD_NV_DefineSpace
+ //
+ TpmRecvSize = sizeof (TPM_RSP_NV_DEFINE_SPACE);
+ TpmSendSize = sizeof (TPM_CMD_NV_DEFINE_SPACE);
+ SendBuffer.Hdr.tag = SwapBytes16 (TPM_TAG_RQU_COMMAND);
+ SendBuffer.Hdr.paramSize = SwapBytes32 (sizeof(TPM_CMD_NV_DEFINE_SPACE));
+ SendBuffer.Hdr.ordinal = SwapBytes32 (TPM_ORD_NV_DefineSpace);
+ SendBuffer.PubInfo.tag = SwapBytes16 (PubInfo->tag);
+ SendBuffer.PubInfo.nvIndex = SwapBytes32 (PubInfo->nvIndex);
+ SendBuffer.PubInfo.pcrInfoRead.pcrSelection.sizeOfSelect = SwapBytes16 (PubInfo->pcrInfoRead.pcrSelection.sizeOfSelect);
+ SendBuffer.PubInfo.pcrInfoRead.pcrSelection.pcrSelect[0] = PubInfo->pcrInfoRead.pcrSelection.pcrSelect[0];
+ SendBuffer.PubInfo.pcrInfoRead.pcrSelection.pcrSelect[1] = PubInfo->pcrInfoRead.pcrSelection.pcrSelect[1];
+ SendBuffer.PubInfo.pcrInfoRead.pcrSelection.pcrSelect[2] = PubInfo->pcrInfoRead.pcrSelection.pcrSelect[2];
+ SendBuffer.PubInfo.pcrInfoRead.localityAtRelease = PubInfo->pcrInfoRead.localityAtRelease;
+ CopyMem (&SendBuffer.PubInfo.pcrInfoRead.digestAtRelease, &PubInfo->pcrInfoRead.digestAtRelease, sizeof(PubInfo->pcrInfoRead.digestAtRelease));
+ SendBuffer.PubInfo.pcrInfoWrite.pcrSelection.sizeOfSelect = SwapBytes16 (PubInfo->pcrInfoWrite.pcrSelection.sizeOfSelect);
+ SendBuffer.PubInfo.pcrInfoWrite.pcrSelection.pcrSelect[0] = PubInfo->pcrInfoWrite.pcrSelection.pcrSelect[0];
+ SendBuffer.PubInfo.pcrInfoWrite.pcrSelection.pcrSelect[1] = PubInfo->pcrInfoWrite.pcrSelection.pcrSelect[1];
+ SendBuffer.PubInfo.pcrInfoWrite.pcrSelection.pcrSelect[2] = PubInfo->pcrInfoWrite.pcrSelection.pcrSelect[2];
+ SendBuffer.PubInfo.pcrInfoWrite.localityAtRelease = PubInfo->pcrInfoWrite.localityAtRelease;
+ CopyMem (&SendBuffer.PubInfo.pcrInfoWrite.digestAtRelease, &PubInfo->pcrInfoWrite.digestAtRelease, sizeof(PubInfo->pcrInfoWrite.digestAtRelease));
+ SendBuffer.PubInfo.permission.tag = SwapBytes16 (PubInfo->permission.tag);
+ SendBuffer.PubInfo.permission.attributes = SwapBytes32 (PubInfo->permission.attributes);
+ SendBuffer.PubInfo.bReadSTClear = PubInfo->bReadSTClear;
+ SendBuffer.PubInfo.bWriteSTClear = PubInfo->bWriteSTClear;
+ SendBuffer.PubInfo.bWriteDefine = PubInfo->bWriteDefine;
+ SendBuffer.PubInfo.dataSize = SwapBytes32 (PubInfo->dataSize);
+ CopyMem (&SendBuffer.EncAuth, EncAuth, sizeof(*EncAuth));
+
+ Status = Tpm12SubmitCommand (TpmSendSize, (UINT8 *)&SendBuffer, &TpmRecvSize, (UINT8 *)&RecvBuffer);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ ReturnCode = SwapBytes32(RecvBuffer.Hdr.returnCode);
+ DEBUG ((DEBUG_INFO, "Tpm12NvDefineSpace - ReturnCode = %x\n", ReturnCode));
+ switch (ReturnCode) {
+ case TPM_SUCCESS:
+ break;
+ default:
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ 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;
+ UINT32 TpmRecvSize;
+ UINT32 TpmSendSize;
+ TPM_CMD_NV_READ_VALUE SendBuffer;
+ TPM_RSP_NV_READ_VALUE RecvBuffer;
+ UINT32 ReturnCode;
+
+ //
+ // send Tpm command TPM_ORD_NV_ReadValue
+ //
+ TpmRecvSize = sizeof (TPM_RSP_NV_READ_VALUE);
+ TpmSendSize = sizeof (TPM_CMD_NV_READ_VALUE);
+ SendBuffer.Hdr.tag = SwapBytes16 (TPM_TAG_RQU_COMMAND);
+ SendBuffer.Hdr.paramSize = SwapBytes32 (sizeof(TPM_CMD_NV_READ_VALUE));
+ SendBuffer.Hdr.ordinal = SwapBytes32 (TPM_ORD_NV_ReadValue);
+ SendBuffer.NvIndex = SwapBytes32 (NvIndex);
+ SendBuffer.Offset = SwapBytes32 (Offset);
+ SendBuffer.DataSize = SwapBytes32 (*DataSize);
+
+ Status = Tpm12SubmitCommand (TpmSendSize, (UINT8 *)&SendBuffer, &TpmRecvSize, (UINT8 *)&RecvBuffer);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ ReturnCode = SwapBytes32(RecvBuffer.Hdr.returnCode);
+ DEBUG ((DEBUG_INFO, "Tpm12NvReadValue - ReturnCode = %x\n", ReturnCode));
+ switch (ReturnCode) {
+ case TPM_SUCCESS:
+ break;
+ default:
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Return the response
+ //
+ *DataSize = SwapBytes32(RecvBuffer.DataSize);
+ CopyMem (Data, &RecvBuffer.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;
+ UINT32 TpmRecvSize;
+ UINT32 TpmSendSize;
+ TPM_CMD_NV_WRITE_VALUE SendBuffer;
+ TPM_RSP_NV_WRITE_VALUE RecvBuffer;
+ UINT32 ReturnCode;
+
+ if (DataSize > sizeof(SendBuffer.Data)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // send Tpm command TPM_ORD_NV_WriteValue
+ //
+ TpmRecvSize = sizeof (TPM_RSP_NV_WRITE_VALUE);
+ TpmSendSize = sizeof (TPM_CMD_NV_WRITE_VALUE) - sizeof(SendBuffer.Data) + DataSize;
+ SendBuffer.Hdr.tag = SwapBytes16 (TPM_TAG_RQU_COMMAND);
+ SendBuffer.Hdr.paramSize = SwapBytes32 (sizeof(TPM_CMD_NV_WRITE_VALUE) - sizeof(SendBuffer.Data) + DataSize);
+ SendBuffer.Hdr.ordinal = SwapBytes32 (TPM_ORD_NV_WriteValue);
+ SendBuffer.NvIndex = SwapBytes32 (NvIndex);
+ SendBuffer.Offset = SwapBytes32 (Offset);
+ SendBuffer.DataSize = SwapBytes32 (DataSize);
+ CopyMem (SendBuffer.Data, Data, DataSize);
+
+ Status = Tpm12SubmitCommand (TpmSendSize, (UINT8 *)&SendBuffer, &TpmRecvSize, (UINT8 *)&RecvBuffer);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ ReturnCode = SwapBytes32(RecvBuffer.Hdr.returnCode);
+ DEBUG ((DEBUG_INFO, "Tpm12NvWritedValue - ReturnCode = %x\n", ReturnCode));
+ switch (ReturnCode) {
+ case TPM_SUCCESS:
+ break;
+ default:
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Core/SecurityPkg/Library/Tpm12CommandLib/Tpm12Ownership.c b/Core/SecurityPkg/Library/Tpm12CommandLib/Tpm12Ownership.c
new file mode 100644
index 0000000000..5ca1323c30
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm12CommandLib/Tpm12Ownership.c
@@ -0,0 +1,72 @@
+/** @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 <Uefi.h>
+#include <IndustryStandard/Tpm12.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/BaseLib.h>
+#include <Library/Tpm12DeviceLib.h>
+
+#pragma pack(1)
+
+typedef struct {
+ TPM_RQU_COMMAND_HDR Hdr;
+} TPM_CMD_FORCE_CLEAR;
+
+typedef struct {
+ TPM_RSP_COMMAND_HDR Hdr;
+} TPM_RSP_FORCE_CLEAR;
+
+#pragma pack()
+
+/**
+ 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;
+ UINT32 TpmRecvSize;
+ UINT32 TpmSendSize;
+ TPM_CMD_FORCE_CLEAR SendBuffer;
+ TPM_RSP_FORCE_CLEAR RecvBuffer;
+ UINT32 ReturnCode;
+
+ //
+ // send Tpm command TPM_ORD_ForceClear
+ //
+ TpmRecvSize = sizeof (TPM_RSP_FORCE_CLEAR);
+ TpmSendSize = sizeof (TPM_CMD_FORCE_CLEAR);
+ SendBuffer.Hdr.tag = SwapBytes16 (TPM_TAG_RQU_COMMAND);
+ SendBuffer.Hdr.paramSize = SwapBytes32 (TpmSendSize);
+ SendBuffer.Hdr.ordinal = SwapBytes32 (TPM_ORD_ForceClear);
+
+ Status = Tpm12SubmitCommand (TpmSendSize, (UINT8 *)&SendBuffer, &TpmRecvSize, (UINT8 *)&RecvBuffer);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ ReturnCode = SwapBytes32(RecvBuffer.Hdr.returnCode);
+ switch (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/Tpm12Startup.c b/Core/SecurityPkg/Library/Tpm12CommandLib/Tpm12Startup.c
new file mode 100644
index 0000000000..afbe02e382
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm12CommandLib/Tpm12Startup.c
@@ -0,0 +1,127 @@
+/** @file
+ Implement TPM1.2 Startup 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 <Uefi.h>
+#include <IndustryStandard/Tpm12.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/BaseLib.h>
+#include <Library/Tpm12DeviceLib.h>
+
+#pragma pack(1)
+
+typedef struct {
+ TPM_RQU_COMMAND_HDR Hdr;
+ TPM_STARTUP_TYPE TpmSt;
+} TPM_CMD_START_UP;
+
+typedef struct {
+ TPM_RSP_COMMAND_HDR Hdr;
+} TPM_RSP_START_UP;
+
+typedef struct {
+ TPM_RQU_COMMAND_HDR Hdr;
+} TPM_CMD_SAVE_STATE;
+
+typedef struct {
+ TPM_RSP_COMMAND_HDR Hdr;
+} TPM_RSP_SAVE_STATE;
+
+#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;
+ UINT32 TpmRecvSize;
+ UINT32 TpmSendSize;
+ TPM_CMD_START_UP SendBuffer;
+ TPM_RSP_START_UP RecvBuffer;
+ UINT32 ReturnCode;
+
+ //
+ // send Tpm command TPM_ORD_Startup
+ //
+ TpmRecvSize = sizeof (TPM_RSP_START_UP);
+ TpmSendSize = sizeof (TPM_CMD_START_UP);
+ SendBuffer.Hdr.tag = SwapBytes16 (TPM_TAG_RQU_COMMAND);
+ SendBuffer.Hdr.paramSize = SwapBytes32 (TpmSendSize);
+ SendBuffer.Hdr.ordinal = SwapBytes32 (TPM_ORD_Startup);
+ SendBuffer.TpmSt = SwapBytes16 (TpmSt);
+
+ Status = Tpm12SubmitCommand (TpmSendSize, (UINT8 *)&SendBuffer, &TpmRecvSize, (UINT8 *)&RecvBuffer);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ ReturnCode = SwapBytes32(RecvBuffer.Hdr.returnCode);
+ switch (ReturnCode) {
+ case TPM_SUCCESS:
+ case TPM_INVALID_POSTINIT:
+ // In warm reset, TPM may response TPM_INVALID_POSTINIT
+ 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;
+ UINT32 TpmRecvSize;
+ UINT32 TpmSendSize;
+ TPM_CMD_SAVE_STATE SendBuffer;
+ TPM_RSP_SAVE_STATE RecvBuffer;
+ UINT32 ReturnCode;
+
+ //
+ // send Tpm command TPM_ORD_SaveState
+ //
+ TpmRecvSize = sizeof (TPM_RSP_SAVE_STATE);
+ TpmSendSize = sizeof (TPM_CMD_SAVE_STATE);
+ SendBuffer.Hdr.tag = SwapBytes16 (TPM_TAG_RQU_COMMAND);
+ SendBuffer.Hdr.paramSize = SwapBytes32 (TpmSendSize);
+ SendBuffer.Hdr.ordinal = SwapBytes32 (TPM_ORD_SaveState);
+
+ Status = Tpm12SubmitCommand (TpmSendSize, (UINT8 *)&SendBuffer, &TpmRecvSize, (UINT8 *)&RecvBuffer);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ ReturnCode = SwapBytes32(RecvBuffer.Hdr.returnCode);
+ switch (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..17d0fcae2e
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm12DeviceLibDTpm/Tpm12DeviceLibDTpm.uni
Binary files differ
diff --git a/Core/SecurityPkg/Library/Tpm12DeviceLibDTpm/Tpm12Tis.c b/Core/SecurityPkg/Library/Tpm12DeviceLibDTpm/Tpm12Tis.c
new file mode 100644
index 0000000000..3d88030d25
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm12DeviceLibDTpm/Tpm12Tis.c
@@ -0,0 +1,530 @@
+/** @file
+ TIS (TPM Interface Specification) functions used by TPM1.2.
+
+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 <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);
+}
+
+/**
+ 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;
+
+ DEBUG_CODE (
+ UINTN DebugSize;
+
+ DEBUG ((EFI_D_INFO, "Tpm12TisTpmCommand Send - "));
+ if (SizeIn > 0x100) {
+ DebugSize = 0x40;
+ } else {
+ DebugSize = SizeIn;
+ }
+ for (Index = 0; Index < DebugSize; Index++) {
+ DEBUG ((EFI_D_INFO, "%02x ", BufferIn[Index]));
+ }
+ if (DebugSize != SizeIn) {
+ DEBUG ((EFI_D_INFO, "...... "));
+ for (Index = SizeIn - 0x20; Index < SizeIn; Index++) {
+ DEBUG ((EFI_D_INFO, "%02x ", BufferIn[Index]));
+ }
+ }
+ DEBUG ((EFI_D_INFO, "\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_INFO, "Tpm12TisTpmCommand ReceiveHeader - "));
+ for (Index = 0; Index < sizeof (TPM_RSP_COMMAND_HDR); Index++) {
+ DEBUG ((EFI_D_INFO, "%02x ", BufferOut[Index]));
+ }
+ DEBUG ((EFI_D_INFO, "\n"));
+ );
+ //
+ // Check the reponse data header (tag,parasize and returncode )
+ //
+ CopyMem (&Data16, BufferOut, sizeof (UINT16));
+ if (SwapBytes16 (Data16) != TPM_TAG_RSP_COMMAND) {
+ DEBUG ((EFI_D_ERROR, "TPM12: TPM_ST_RSP error - %x\n", TPM_TAG_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 = Tpm12TisPcReadBurstCount (TisReg, &BurstCount);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+ }
+Exit:
+ DEBUG_CODE (
+ DEBUG ((EFI_D_INFO, "Tpm12TisTpmCommand Receive - "));
+ for (Index = 0; Index < TpmOutSize; Index++) {
+ DEBUG ((EFI_D_INFO, "%02x ", BufferOut[Index]));
+ }
+ DEBUG ((EFI_D_INFO, "\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
+ )
+{
+ return Tpm12TisTpmCommand (
+ (TIS_PC_REGISTERS_PTR) (UINTN) PcdGet64 (PcdTpmBaseAddress),
+ InputParameterBlock,
+ InputParameterBlockSize,
+ OutputParameterBlock,
+ OutputParameterBlockSize
+ );
+}
+
+/**
+ 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
+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..6b793bf6be
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm12DeviceLibTcg/Tpm12DeviceLibTcg.c
@@ -0,0 +1,108 @@
+/** @file
+ Ihis library is TPM12 TCG protocol lib.
+
+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/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..f34d363e37
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm12DeviceLibTcg/Tpm12DeviceLibTcg.uni
Binary files differ
diff --git a/Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2Capability.c b/Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2Capability.c
new file mode 100644
index 0000000000..0fe2c367d2
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2Capability.c
@@ -0,0 +1,741 @@
+/** @file
+ Implement TPM2 Capability 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;
+ 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 = SwapBytes32 (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 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..740af3f72b
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2CommandLib.inf
@@ -0,0 +1,54 @@
+## @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.
+#
+##
+
+[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
+ 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..12ccaa4db0
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2CommandLib.uni
Binary files differ
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..5e24290f7c
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2Help.c
@@ -0,0 +1,166 @@
+/** @file
+ Implement TPM2 help.
+
+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 <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;
+} INTERNAL_HASH_INFO;
+
+STATIC INTERNAL_HASH_INFO mHashInfo[] = {
+ {TPM_ALG_SHA1, SHA1_DIGEST_SIZE},
+ {TPM_ALG_SHA256, SHA256_DIGEST_SIZE},
+ {TPM_ALG_SM3_256, SM3_256_DIGEST_SIZE},
+ {TPM_ALG_SHA384, SHA384_DIGEST_SIZE},
+ {TPM_ALG_SHA512, SHA512_DIGEST_SIZE},
+};
+
+/**
+ 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;
+}
+
+/**
+ 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 - (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
+ )
+{
+ 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 - (UINT8 *)AuthSessionIn);
+}
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..fa4318dd5f
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2Integrity.c
@@ -0,0 +1,537 @@
+/** @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;
+}
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/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..f67043b84b
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm2CommandLib/Tpm2Startup.c
@@ -0,0 +1,123 @@
+/** @file
+ Implement TPM2 Startup 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_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:
+ case TPM_RC_INITIALIZE:
+ // TPM_RC_INITIALIZE can be returned if Tpm2Startup is not required.
+ 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..7d10dbbe47
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2DeviceLibDTpm.c
@@ -0,0 +1,116 @@
+/** @file
+ Ihis library is TPM2 DTPM device lib.
+ Choosing this library means platform uses and only uses DTPM device as TPM2 engine.
+
+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 <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..807ba8bdfd
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2DeviceLibDTpm.uni
Binary files differ
diff --git a/Core/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2InstanceLibDTpm.c b/Core/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2InstanceLibDTpm.c
new file mode 100644
index 0000000000..a50d266b8e
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2InstanceLibDTpm.c
@@ -0,0 +1,98 @@
+/** @file
+ Ihis 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..3319d778c7
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm2DeviceLibDTpm/Tpm2InstanceLibDTpm.uni
Binary files differ
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..bee8bb35fd
--- /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_INFO, "Tpm2TisTpmCommand Send - "));
+ if (SizeIn > 0x100) {
+ DebugSize = 0x40;
+ } else {
+ DebugSize = SizeIn;
+ }
+ for (Index = 0; Index < DebugSize; Index++) {
+ DEBUG ((EFI_D_INFO, "%02x ", BufferIn[Index]));
+ }
+ if (DebugSize != SizeIn) {
+ DEBUG ((EFI_D_INFO, "...... "));
+ for (Index = SizeIn - 0x20; Index < SizeIn; Index++) {
+ DEBUG ((EFI_D_INFO, "%02x ", BufferIn[Index]));
+ }
+ }
+ DEBUG ((EFI_D_INFO, "\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_INFO, "Tpm2TisTpmCommand ReceiveHeader - "));
+ for (Index = 0; Index < sizeof (TPM2_RESPONSE_HEADER); Index++) {
+ DEBUG ((EFI_D_INFO, "%02x ", BufferOut[Index]));
+ }
+ DEBUG ((EFI_D_INFO, "\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_INFO, "Tpm2TisTpmCommand Receive - "));
+ for (Index = 0; Index < TpmOutSize; Index++) {
+ DEBUG ((EFI_D_INFO, "%02x ", BufferOut[Index]));
+ }
+ DEBUG ((EFI_D_INFO, "\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..5e1501edae
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm2DeviceLibRouter/Tpm2DeviceLibRouterDxe.c
@@ -0,0 +1,98 @@
+/** @file
+ Ihis 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, Intel Corporation. All rights reserved. <BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+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 ((EFI_D_ERROR, "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..b69e2a768d
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm2DeviceLibRouter/Tpm2DeviceLibRouterDxe.inf
@@ -0,0 +1,47 @@
+## @file
+# Provides TPM 2.0 TIS functions
+#
+# Ihis 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 - 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 = 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..9b270b0d46
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm2DeviceLibRouter/Tpm2DeviceLibRouterDxe.uni
Binary files differ
diff --git a/Core/SecurityPkg/Library/Tpm2DeviceLibRouter/Tpm2DeviceLibRouterPei.c b/Core/SecurityPkg/Library/Tpm2DeviceLibRouter/Tpm2DeviceLibRouterPei.c
new file mode 100644
index 0000000000..8e75140123
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm2DeviceLibRouter/Tpm2DeviceLibRouterPei.c
@@ -0,0 +1,143 @@
+/** @file
+ Ihis 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 - 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 <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 ((EFI_D_ERROR, "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..b1a850f6ca
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm2DeviceLibRouter/Tpm2DeviceLibRouterPei.inf
@@ -0,0 +1,49 @@
+## @file
+# Provides TPM 2.0 TIS functions
+#
+# Ihis 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 - 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 = 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..9b270b0d46
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm2DeviceLibRouter/Tpm2DeviceLibRouterPei.uni
Binary files differ
diff --git a/Core/SecurityPkg/Library/Tpm2DeviceLibTcg2/Tpm2DeviceLibTcg2.c b/Core/SecurityPkg/Library/Tpm2DeviceLibTcg2/Tpm2DeviceLibTcg2.c
new file mode 100644
index 0000000000..e1a92c31f4
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm2DeviceLibTcg2/Tpm2DeviceLibTcg2.c
@@ -0,0 +1,125 @@
+/** @file
+ Ihis library is TPM2 TCG2 protocol lib.
+
+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 <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..27e390d8e8
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm2DeviceLibTcg2/Tpm2DeviceLibTcg2.uni
Binary files differ
diff --git a/Core/SecurityPkg/Library/Tpm2DeviceLibTrEE/Tpm2DeviceLibTrEE.c b/Core/SecurityPkg/Library/Tpm2DeviceLibTrEE/Tpm2DeviceLibTrEE.c
new file mode 100644
index 0000000000..53963b743b
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm2DeviceLibTrEE/Tpm2DeviceLibTrEE.c
@@ -0,0 +1,125 @@
+/** @file
+ Ihis library is TPM2 TREE protocol lib.
+
+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 <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..6eb05d059f
--- /dev/null
+++ b/Core/SecurityPkg/Library/Tpm2DeviceLibTrEE/Tpm2DeviceLibTrEE.uni
Binary files differ
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..00596a1c49
--- /dev/null
+++ b/Core/SecurityPkg/Library/TpmCommLib/TpmCommLib.uni
Binary files differ
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..7e6ef74fd3
--- /dev/null
+++ b/Core/SecurityPkg/Library/TrEEPpVendorLibNull/TrEEPpVendorLibNull.uni
Binary files differ
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..42d6e07c8c
--- /dev/null
+++ b/Core/SecurityPkg/Pkcs7Verify/Pkcs7VerifyDxe/Pkcs7VerifyDxe.uni
Binary files differ
diff --git a/Core/SecurityPkg/Pkcs7Verify/Pkcs7VerifyDxe/Pkcs7VerifyDxeExtra.uni b/Core/SecurityPkg/Pkcs7Verify/Pkcs7VerifyDxe/Pkcs7VerifyDxeExtra.uni
new file mode 100644
index 0000000000..2ce097b15e
--- /dev/null
+++ b/Core/SecurityPkg/Pkcs7Verify/Pkcs7VerifyDxe/Pkcs7VerifyDxeExtra.uni
Binary files differ
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..802e63ab3c
--- /dev/null
+++ b/Core/SecurityPkg/RandomNumberGenerator/RngDxe/RngDxe.uni
Binary files differ
diff --git a/Core/SecurityPkg/RandomNumberGenerator/RngDxe/RngDxeExtra.uni b/Core/SecurityPkg/RandomNumberGenerator/RngDxe/RngDxeExtra.uni
new file mode 100644
index 0000000000..4b25b3bb53
--- /dev/null
+++ b/Core/SecurityPkg/RandomNumberGenerator/RngDxe/RngDxeExtra.uni
Binary files differ
diff --git a/Core/SecurityPkg/SecurityPkg.dec b/Core/SecurityPkg/SecurityPkg.dec
new file mode 100644
index 0000000000..b4eabc4886
--- /dev/null
+++ b/Core/SecurityPkg/SecurityPkg.dec
@@ -0,0 +1,437 @@
+## @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 - 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.
+#
+##
+
+[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" 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 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
+
+ ## Null-terminated string of the Version of Physical Presence interface supported by platform.
+ # @Prompt Version of Physical Presence interface supported by platform.
+ gEfiSecurityPkgTokenSpaceGuid.PcdTcgPhysicalPresenceInterfaceVer|"1.3"|VOID*|0x00000008
+
+[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
+ #
+ # @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
+
+ ## 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
+
+[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.
+ # @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..49306981cf
--- /dev/null
+++ b/Core/SecurityPkg/SecurityPkg.dsc
@@ -0,0 +1,327 @@
+## @file
+# Security Module Package for All Architectures.
+#
+# Copyright (c) 2009 - 2015, 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
+ 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
+ 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
+
+[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
+
+[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
+
+[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/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
+
diff --git a/Core/SecurityPkg/SecurityPkg.uni b/Core/SecurityPkg/SecurityPkg.uni
new file mode 100644
index 0000000000..8995d11da6
--- /dev/null
+++ b/Core/SecurityPkg/SecurityPkg.uni
Binary files differ
diff --git a/Core/SecurityPkg/SecurityPkgExtra.uni b/Core/SecurityPkg/SecurityPkgExtra.uni
new file mode 100644
index 0000000000..81af19e246
--- /dev/null
+++ b/Core/SecurityPkg/SecurityPkgExtra.uni
Binary files differ
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..d5a7da8343
--- /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 gEfiTrEEProtocolGuid )
+
+[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..d9d947299f
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.uni
Binary files differ
diff --git a/Core/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMorExtra.uni b/Core/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMorExtra.uni
new file mode 100644
index 0000000000..acf6ca8b25
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMorExtra.uni
Binary files differ
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..2e549379cf
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLock.uni
Binary files differ
diff --git a/Core/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLockExtra.uni b/Core/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLockExtra.uni
new file mode 100644
index 0000000000..ea7896b273
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLockExtra.uni
Binary files differ
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..61fd1b7e1d
--- /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 gEfiTrEEProtocolGuid )
+
+[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..9bf1ced3cc
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalDriver.c
@@ -0,0 +1,1103 @@
+/** @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);
+
+ 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 hanlder private Data
+
+**/
+VOID
+EFIAPI
+ReadyToBootCallback (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ OPAL_DRIVER_DEVICE* Itr;
+ TCG_RESULT Result;
+ OPAL_EXTRA_INFO_VAR OpalExtraInfo;
+ UINTN DataSize;
+ OPAL_SESSION Session;
+
+ gBS->CloseEvent (Event);
+
+ DataSize = sizeof (OPAL_EXTRA_INFO_VAR);
+ Status = gRT->GetVariable (
+ OPAL_EXTRA_INFO_VAR_NAME,
+ &gOpalExtraInfoVariableGuid,
+ NULL,
+ &DataSize,
+ &OpalExtraInfo
+ );
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ if (OpalExtraInfo.EnableBlockSid == TRUE) {
+ //
+ // 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..213c139e01
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalDriver.h
@@ -0,0 +1,413 @@
+/** @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 <Guid/OpalPasswordExtraInfoVariable.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>
+
+#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..c10163ef3c
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalHii.c
@@ -0,0 +1,1377 @@
+/** @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[];
+
+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
+ )
+{
+ EFI_STATUS Status;
+ OPAL_EXTRA_INFO_VAR OpalExtraInfo;
+ UINTN DataSize;
+
+ gHiiConfiguration.NumDisks = GetDeviceCount();
+
+ DataSize = sizeof (OPAL_EXTRA_INFO_VAR);
+ Status = gRT->GetVariable (
+ OPAL_EXTRA_INFO_VAR_NAME,
+ &gOpalExtraInfoVariableGuid,
+ NULL,
+ &DataSize,
+ &OpalExtraInfo
+ );
+ if (!EFI_ERROR (Status)) {
+ gHiiConfiguration.EnableBlockSid = OpalExtraInfo.EnableBlockSid;
+ }
+}
+
+/**
+ 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;
+
+ 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);
+ }
+ } else if (Action == EFI_BROWSER_ACTION_CHANGED) {
+ switch (HiiKeyId) {
+ case HII_KEY_ID_ENTER_PSID:
+ HiiPsidRevert();
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;
+ return EFI_SUCCESS;
+
+ case HII_KEY_ID_BLOCKSID:
+ HiiSetBlockSid(Value->b);
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;
+ return EFI_SUCCESS;
+ }
+ }
+
+ 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.
+
+ @retval EFI_SUCCESS Do the required action success.
+
+**/
+EFI_STATUS
+HiiPsidRevert(
+ VOID
+ )
+{
+ CHAR8 Response[DEFAULT_RESPONSE_SIZE];
+ TCG_PSID Psid;
+ OPAL_DISK *OpalDisk;
+ TCG_RESULT Ret;
+ OPAL_SESSION Session;
+ UINT8 TmpBuf[PSID_CHARACTER_STRING_END_LENGTH];
+
+ Ret = TcgResultFailure;
+
+ OpalHiiGetBrowserData();
+
+ ZeroMem (TmpBuf, sizeof (TmpBuf));
+ UnicodeStrToAsciiStrS (gHiiConfiguration.Psid, (CHAR8*)TmpBuf, PSID_CHARACTER_STRING_END_LENGTH);
+ CopyMem (Psid.Psid, TmpBuf, PSID_CHARACTER_LENGTH);
+
+ 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);
+ }
+
+ 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;
+ }
+ PassLength = (UINT32) StrLen (UniStr);
+ if (PassLength >= sizeof(Password)) {
+ HiiSetFormString(STRING_TOKEN(STR_ACTION_STATUS), "Password too long");
+ gBS->FreePool(UniStr);
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ UnicodeStrToAsciiStrS (UniStr, Password, sizeof (Password));
+ gBS->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);
+ }
+
+ OpalHiiSetBrowserData ();
+
+ return Status;
+}
+
+/**
+ Update block sid info.
+
+ @param Enable Enable/disable BlockSid.
+
+ @retval EFI_SUCCESS Do the required action success.
+ @retval Others Other error occur.
+
+**/
+EFI_STATUS
+HiiSetBlockSid (
+ BOOLEAN Enable
+ )
+{
+ EFI_STATUS Status;
+ OPAL_EXTRA_INFO_VAR OpalExtraInfo;
+ UINTN DataSize;
+
+ Status = EFI_SUCCESS;
+
+ OpalExtraInfo.EnableBlockSid = Enable;
+ DataSize = sizeof (OPAL_EXTRA_INFO_VAR);
+ Status = gRT->SetVariable (
+ OPAL_EXTRA_INFO_VAR_NAME,
+ &gOpalExtraInfoVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ DataSize,
+ &OpalExtraInfo
+ );
+
+ 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);
+ }
+
+ 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);
+ }
+
+ //
+ // 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..754dbf776b
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalHiiFormStrings.uni
@@ -0,0 +1,91 @@
+// /** @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 "Enable BlockSID"
+#string STR_ENABLED #language en-US "Enabled"
+#string STR_DISABLED #language en-US "Disabled"
+
+#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 "Enable to send BlockSID command"
+
+///////////////////////////////// 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..bb086bd35f
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalHiiPrivate.h
@@ -0,0 +1,266 @@
+/** @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 Enable Enable/disable BlockSid.
+
+ @retval EFI_SUCCESS Do the required action success.
+ @retval Others Other error occur.
+
+**/
+EFI_STATUS
+HiiSetBlockSid (
+ BOOLEAN Enable
+ );
+
+/**
+ Reverts the Opal disk to factory default.
+
+ @retval EFI_SUCCESS Do the required action success.
+
+**/
+EFI_STATUS
+HiiPsidRevert(
+ VOID
+ );
+
+/**
+ 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..703c1b6039
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalPasswordDxe.inf
@@ -0,0 +1,81 @@
+## @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
+
+[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..88cc2a1c4e
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalPasswordForm.vfr
@@ -0,0 +1,327 @@
+/** @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);
+
+ 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_DISABLED), value = 0, flags = DEFAULT | MANUFACTURING | RESET_REQUIRED;
+ option text = STRING_TOKEN(STR_ENABLED), value = 1, 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..3826698709
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalNvmeMode.c
@@ -0,0 +1,2157 @@
+/** @file
+ Provide functions to initialize NVME controller and perform NVME 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 "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) (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;
+
+ 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..47b570f343
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalPasswordSmm.c
@@ -0,0 +1,1092 @@
+/** @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;
+}
+
+
+/**
+ 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_DISK_AND_PASSWORD_INFO *PciDev;
+ OPAL_HC_PCI_REGISTER_SAVE *HcRegisterSaveListPtr;
+ UINTN Count;
+ OPAL_SMM_DEVICE *SmmDev;
+
+ Data = 0;
+ Status = EFI_SUCCESS;
+
+ mOpalDeviceList = OpalSupportGetOpalDeviceList();
+
+ for (Entry = mOpalDeviceList->ForwardLink; Entry != mOpalDeviceList; 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;
+
+ InsertHeadList (&mSmmDeviceList, &SmmDev->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;
+ }
+ }
+ }
+
+ if (!IsListEmpty (mOpalDeviceList)) {
+ 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..a5a62954a0
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePei.uni
Binary files differ
diff --git a/Core/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePeiExtra.uni b/Core/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePeiExtra.uni
new file mode 100644
index 0000000000..88241f98f5
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePeiExtra.uni
Binary files differ
diff --git a/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2Config.vfr b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2Config.vfr
new file mode 100644
index 0000000000..a72f8246d1
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2Config.vfr
@@ -0,0 +1,209 @@
+/** @file
+ VFR file used by the TCG2 configuration component.
+
+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 "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;
+
+ 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;
+ 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);
+
+ 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;
+
+ option text = STRING_TOKEN(STR_TCG2_ENABLE_BLOCK_SID), value = TCG2_PHYSICAL_PRESENCE_ENABLE_BLOCK_SID, flags = RESET_REQUIRED;
+ option text = STRING_TOKEN(STR_TCG2_DISABLE_BLOCK_SID), value = TCG2_PHYSICAL_PRESENCE_DISABLE_BLOCK_SID, 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,
+ 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,
+ 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,
+ 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,
+ 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,
+ 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..968670f04d
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDriver.c
@@ -0,0 +1,281 @@
+/** @file
+ The module entry point for Tcg2 configuration module.
+
+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 "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 ;
+}
+
+/**
+ 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;
+ }
+
+ 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..dd2247b957
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDxe.inf
@@ -0,0 +1,89 @@
+## @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 - 2106, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# 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 ## CONSUMES
+ gEfiTcg2ProtocolGuid ## CONSUMES
+
+[Pcd]
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpmInstanceGuid ## CONSUMES
+ gEfiSecurityPkgTokenSpaceGuid.PcdTcg2HashAlgorithmBitmap ## CONSUMES
+ gEfiSecurityPkgTokenSpaceGuid.PcdTpmBaseAddress ## 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..a5b2040b49
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDxe.uni
Binary files differ
diff --git a/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDxeExtra.uni b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDxeExtra.uni
new file mode 100644
index 0000000000..c2571d74be
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDxeExtra.uni
Binary files differ
diff --git a/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigImpl.c b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigImpl.c
new file mode 100644
index 0000000000..db38bd45a3
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigImpl.c
@@ -0,0 +1,875 @@
+/** @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 - 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 "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;
+}
+
+/**
+ 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_INPUT_KEY Key;
+
+ if ((This == NULL) || (Value == NULL) || (ActionRequest == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Action == EFI_BROWSER_ACTION_CHANGING) {
+ if (QuestionId == KEY_TPM_DEVICE_INTERFACE) {
+ EFI_STATUS Status;
+ 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)) {
+ SaveTcg2PCRBanksRequest (QuestionId - KEY_TPM2_PCR_BANKS_REQUEST_0, Value->b);
+ }
+ }
+
+ 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");
+ }
+}
+
+/**
+ Check if buffer is all zero.
+
+ @param[in] Buffer Buffer to be checked.
+ @param[in] BufferSize Size of buffer to be checked.
+
+ @retval TRUE Buffer is all zero.
+ @retval FALSE Buffer is not all zero.
+**/
+BOOLEAN
+IsZeroBuffer (
+ IN VOID *Buffer,
+ IN UINTN BufferSize
+ )
+{
+ UINT8 *BufferData;
+ UINTN Index;
+
+ BufferData = Buffer;
+ for (Index = 0; Index < BufferSize; Index++) {
+ if (BufferData[Index] != 0) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+/**
+ 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..1b9a8452e0
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigImpl.h
@@ -0,0 +1,197 @@
+/** @file
+ The header file of HII Config Access protocol implementation of 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.
+
+**/
+
+#ifndef __TCG2_CONFIG_IMPL_H__
+#define __TCG2_CONFIG_IMPL_H__
+
+#include <Uefi.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)
+
+
+/**
+ 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..20eaa508fa
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigNvData.h
@@ -0,0 +1,114 @@
+/** @file
+ Header file for NV data structure definition.
+
+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_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_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 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 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
+
+//
+// Nv Data structure referenced by IFR, TPM device user desired
+//
+typedef struct {
+ UINT8 TpmDevice;
+} TCG2_CONFIGURATION;
+
+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 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..cd6a92da1c
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPei.inf
@@ -0,0 +1,78 @@
+## @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.
+#
+##
+
+[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
+ IoLib
+ 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..c3095564a2
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPei.uni
Binary files differ
diff --git a/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPeiExtra.uni b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPeiExtra.uni
new file mode 100644
index 0000000000..c2571d74be
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPeiExtra.uni
Binary files differ
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..e99fe96880
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigStrings.uni
Binary files differ
diff --git a/Core/SecurityPkg/Tcg/Tcg2Config/TpmDetection.c b/Core/SecurityPkg/Tcg/Tcg2Config/TpmDetection.c
new file mode 100644
index 0000000000..33f3a21d87
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Tcg2Config/TpmDetection.c
@@ -0,0 +1,130 @@
+/** @file
+ TPM1.2/dTPM2.0 auto detection.
+
+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 <Ppi/ReadOnlyVariable2.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/IoLib.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 return if dTPM (1.2 or 2.0) present.
+
+ @retval TRUE dTPM present
+ @retval FALSE dTPM not present
+**/
+BOOLEAN
+IsDtpmPresent (
+ VOID
+ )
+{
+ UINT8 RegRead;
+
+ RegRead = MmioRead8 ((UINTN)PcdGet64 (PcdTpmBaseAddress));
+ if (RegRead == 0xFF) {
+ DEBUG ((EFI_D_ERROR, "DetectTpmDevice: Dtpm not present\n"));
+ return FALSE;
+ } else {
+ DEBUG ((EFI_D_INFO, "DetectTpmDevice: Dtpm present\n"));
+ return TRUE;
+ }
+}
+
+/**
+ 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"));
+ if (!IsDtpmPresent ()) {
+ // dTPM not available
+ return TPM_DEVICE_NULL;
+ }
+
+ // 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)) {
+ return TPM_DEVICE_2_0_DTPM;
+ }
+
+ 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..de55ed9923
--- /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 - 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 <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) ((UINT8 *)(&Hdr.Pe32->OptionalHeader.CheckSum) - HashBase);
+ } else {
+ //
+ // Use PE32+ offset
+ //
+ NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
+ HashSize = (UINTN) ((UINT8 *)(&Hdr.Pe32Plus->OptionalHeader.CheckSum) - 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) ((UINT8 *)(&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase);
+ } else {
+ //
+ // Use PE32+ offset
+ //
+ HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);
+ HashSize = (UINTN) ((UINT8 *)(&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase);
+ }
+
+ 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..8f9e4c95f8
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c
@@ -0,0 +1,2593 @@
+/** @file
+ This module implements Tcg2 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.
+
+**/
+
+#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 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"));
+ }
+}
+
+/**
+ Check if buffer is all zero.
+
+ @param[in] Buffer Buffer to be checked.
+ @param[in] BufferSize Size of buffer to be checked.
+
+ @retval TRUE Buffer is all zero.
+ @retval FALSE Buffer is not all zero.
+**/
+BOOLEAN
+IsZeroBuffer (
+ IN VOID *Buffer,
+ IN UINTN BufferSize
+ )
+{
+ UINT8 *BufferData;
+ UINTN Index;
+
+ BufferData = Buffer;
+ for (Index = 0; Index < BufferSize; Index++) {
+ if (BufferData[Index] != 0) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+/**
+ 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 ((EFI_D_INFO, "Tcg2GetCapability ...\n"));
+
+ if ((This == NULL) || (ProtocolCapability == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ DEBUG ((EFI_D_INFO, "Size - 0x%x\n", ProtocolCapability->Size));
+ DEBUG ((EFI_D_INFO, " 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 ((EFI_D_INFO, "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->LastEvent - (UINTN)mTcgDxeData.FinalEventsTable[Index]));
+ }
+ }
+
+ return Status;
+}
+
+/**
+ This function get digest from digest list.
+
+ @param HashAlg digest algorithm
+ @param DigestList digest list
+ @param Digest digest
+
+ @retval EFI_SUCCESS Sha1Digest is found and returned.
+ @retval EFI_NOT_FOUND Sha1Digest is not found.
+**/
+EFI_STATUS
+Tpm2GetDigestFromDigestList (
+ IN TPMI_ALG_HASH HashAlg,
+ IN TPML_DIGEST_VALUES *DigestList,
+ IN 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;
+}
+
+/**
+ Get TPML_DIGEST_VALUES data size.
+
+ @param[in] DigestList TPML_DIGEST_VALUES data.
+
+ @return TPML_DIGEST_VALUES data size.
+**/
+UINT32
+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;
+}
+
+/**
+ 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;
+}
+
+/**
+ Return if hash alg is supported in TPM PCR bank.
+
+ @param HashAlg Hash algorithm to be checked.
+
+ @retval TRUE Hash algorithm is supported.
+ @retval FALSE Hash algorithm is not supported.
+**/
+BOOLEAN
+IsHashAlgSupportedInPcrBank (
+ IN TPMI_ALG_HASH HashAlg
+ )
+{
+ switch (HashAlg) {
+ case TPM_ALG_SHA1:
+ if ((mTcgDxeData.BsCap.ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SHA1) != 0) {
+ return TRUE;
+ }
+ break;
+ case TPM_ALG_SHA256:
+ if ((mTcgDxeData.BsCap.ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SHA256) != 0) {
+ return TRUE;
+ }
+ break;
+ case TPM_ALG_SHA384:
+ if ((mTcgDxeData.BsCap.ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SHA384) != 0) {
+ return TRUE;
+ }
+ break;
+ case TPM_ALG_SHA512:
+ if ((mTcgDxeData.BsCap.ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SHA512) != 0) {
+ return TRUE;
+ }
+ break;
+ case TPM_ALG_SM3_256:
+ if ((mTcgDxeData.BsCap.ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SM3_256) != 0) {
+ return TRUE;
+ }
+ break;
+ }
+
+ return FALSE;
+}
+
+/**
+ Copy TPML_DIGEST_VALUES into a buffer
+
+ @param[in,out] Buffer Buffer to hold TPML_DIGEST_VALUES.
+ @param[in] DigestList TPML_DIGEST_VALUES to be copied.
+
+ @return The end of buffer to hold TPML_DIGEST_VALUES.
+**/
+VOID *
+CopyDigestListToBuffer (
+ IN OUT VOID *Buffer,
+ IN TPML_DIGEST_VALUES *DigestList
+ )
+{
+ UINTN Index;
+ UINT16 DigestSize;
+
+ CopyMem (Buffer, &DigestList->count, sizeof(DigestList->count));
+ Buffer = (UINT8 *)Buffer + sizeof(DigestList->count);
+ for (Index = 0; Index < DigestList->count; Index++) {
+ if (!IsHashAlgSupportedInPcrBank (DigestList->digests[Index].hashAlg)) {
+ 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;
+ }
+
+ 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;
+
+ 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 = Tpm2GetDigestFromDigestList (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;
+ DigestBuffer = CopyDigestListToBuffer (DigestBuffer, DigestList);
+ CopyMem (DigestBuffer, &NewEventHdr->EventSize, sizeof(NewEventHdr->EventSize));
+ DigestBuffer = DigestBuffer + sizeof(NewEventHdr->EventSize);
+
+ //
+ // Enter critical region
+ //
+ OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
+ Status = TcgDxeLogEvent (
+ mTcg2EventInfo[Index].LogFormat,
+ &TcgPcrEvent2,
+ sizeof(TcgPcrEvent2.PCRIndex) + sizeof(TcgPcrEvent2.EventType) + GetDigestListSize (DigestList) + 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 ((EFI_D_INFO, "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 ((EFI_D_INFO, "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;
+ UINT32 DigestListBinSize;
+ UINT32 EventSize;
+ TCG_EfiSpecIDEventStruct *TcgEfiSpecIdEventStruct;
+ UINT8 TempBuf[sizeof(TCG_EfiSpecIDEventStruct) + (HASH_COUNT * sizeof(TCG_EfiSpecIdEventAlgorithmSize)) + sizeof(UINT8)];
+ TCG_PCR_EVENT_HDR FirstPcrEvent;
+ TCG_EfiSpecIdEventAlgorithmSize *DigestSize;
+ TCG_EfiSpecIdEventAlgorithmSize *TempDigestSize;
+ UINT8 *VendorInfoSize;
+ UINT32 NumberOfAlgorithms;
+
+ 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;
+ Lasa = (EFI_PHYSICAL_ADDRESS) (SIZE_4GB - 1);
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ 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;
+
+ //
+ // FirstPcrEvent
+ //
+ FirstPcrEvent.PCRIndex = 0;
+ FirstPcrEvent.EventType = EV_NO_ACTION;
+ ZeroMem (&FirstPcrEvent.Digest, sizeof(FirstPcrEvent.Digest));
+ FirstPcrEvent.EventSize = (UINT32)GetTcgEfiSpecIdEventStructSize (TcgEfiSpecIdEventStruct);
+
+ //
+ // Record
+ //
+ Status = TcgDxeLogEvent (
+ mTcg2EventInfo[Index].LogFormat,
+ &FirstPcrEvent,
+ sizeof(FirstPcrEvent),
+ (UINT8 *)TcgEfiSpecIdEventStruct,
+ FirstPcrEvent.EventSize
+ );
+ }
+ }
+ }
+
+ //
+ // 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) {
+ Lasa = (EFI_PHYSICAL_ADDRESS) (SIZE_4GB - 1);
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ 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 = GET_GUID_HOB_DATA (GuidHob.Guid);
+ 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:
+ DigestListBinSize = GetDigestListBinSize ((UINT8 *)TcgEvent + sizeof(TCG_PCRINDEX) + sizeof(TCG_EVENTTYPE));
+ CopyMem (&EventSize, (UINT8 *)TcgEvent + sizeof(TCG_PCRINDEX) + sizeof(TCG_EVENTTYPE) + DigestListBinSize, sizeof(UINT32));
+ Status = TcgDxeLogEvent (
+ mTcg2EventInfo[Index].LogFormat,
+ TcgEvent,
+ sizeof(TCG_PCRINDEX) + sizeof(TCG_EVENTTYPE) + DigestListBinSize + sizeof(UINT32),
+ (UINT8 *)TcgEvent + sizeof(TCG_PCRINDEX) + sizeof(TCG_EVENTTYPE) + DigestListBinSize + sizeof(UINT32),
+ 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, "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 = (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
+ );
+ }
+
+ if (EventType == EV_EFI_VARIABLE_DRIVER_CONFIG) {
+ //
+ // Digest is the event data (EFI_VARIABLE_DATA)
+ //
+ Status = TcgDxeHashLogExtendEvent (
+ 0,
+ (UINT8*)VarLog,
+ TcgEvent.EventSize,
+ &TcgEvent,
+ (UINT8*)VarLog
+ );
+ } else {
+ 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[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", "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 (
+ EFI_CALLING_EFI_APPLICATION
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "%s 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, "%s not Measured. Error!\n", EFI_RETURNING_FROM_EFI_APPLICATOIN));
+ }
+ }
+
+ 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 (
+ EFI_EXIT_BOOT_SERVICES_INVOCATION
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "%s 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, "%s 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, "%s 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;
+ TPML_PCR_SELECTION Pcrs;
+ UINTN Index;
+ EFI_TCG2_EVENT_ALGORITHM_BITMAP TpmHashAlgorithmBitmap;
+ UINT32 ActivePCRBanks;
+ UINT32 NumberOfPCRBanks;
+
+ mImageHandle = ImageHandle;
+
+ if (CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceNoneGuid) ||
+ CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceTpm12Guid)){
+ DEBUG ((EFI_D_ERROR, "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 = Tpm2GetCapabilityPcrs (&Pcrs);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Tpm2GetCapabilityPcrs fail!\n"));
+ TpmHashAlgorithmBitmap = EFI_TCG2_BOOT_HASH_ALG_SHA1;
+ ActivePCRBanks = EFI_TCG2_BOOT_HASH_ALG_SHA1;
+ } else {
+ DEBUG ((EFI_D_INFO, "Tpm2GetCapabilityPcrs Count - %08x\n", Pcrs.count));
+ TpmHashAlgorithmBitmap = 0;
+ ActivePCRBanks = 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 |= EFI_TCG2_BOOT_HASH_ALG_SHA1;
+ if (!IsZeroBuffer (Pcrs.pcrSelections[Index].pcrSelect, Pcrs.pcrSelections[Index].sizeofSelect)) {
+ ActivePCRBanks |= EFI_TCG2_BOOT_HASH_ALG_SHA1;
+ }
+ break;
+ case TPM_ALG_SHA256:
+ TpmHashAlgorithmBitmap |= EFI_TCG2_BOOT_HASH_ALG_SHA256;
+ if (!IsZeroBuffer (Pcrs.pcrSelections[Index].pcrSelect, Pcrs.pcrSelections[Index].sizeofSelect)) {
+ ActivePCRBanks |= EFI_TCG2_BOOT_HASH_ALG_SHA256;
+ }
+ break;
+ case TPM_ALG_SHA384:
+ TpmHashAlgorithmBitmap |= EFI_TCG2_BOOT_HASH_ALG_SHA384;
+ if (!IsZeroBuffer (Pcrs.pcrSelections[Index].pcrSelect, Pcrs.pcrSelections[Index].sizeofSelect)) {
+ ActivePCRBanks |= EFI_TCG2_BOOT_HASH_ALG_SHA384;
+ }
+ break;
+ case TPM_ALG_SHA512:
+ TpmHashAlgorithmBitmap |= EFI_TCG2_BOOT_HASH_ALG_SHA512;
+ if (!IsZeroBuffer (Pcrs.pcrSelections[Index].pcrSelect, Pcrs.pcrSelections[Index].sizeofSelect)) {
+ ActivePCRBanks |= EFI_TCG2_BOOT_HASH_ALG_SHA512;
+ }
+ break;
+ case TPM_ALG_SM3_256:
+ TpmHashAlgorithmBitmap |= EFI_TCG2_BOOT_HASH_ALG_SM3_256;
+ if (!IsZeroBuffer (Pcrs.pcrSelections[Index].pcrSelect, Pcrs.pcrSelections[Index].sizeofSelect)) {
+ ActivePCRBanks |= EFI_TCG2_BOOT_HASH_ALG_SM3_256;
+ }
+ break;
+ }
+ }
+ }
+ 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..6b4c15ffdd
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.inf
@@ -0,0 +1,111 @@
+## @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 - 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 = 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
+
+[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..8fd8b2a367
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.uni
Binary files differ
diff --git a/Core/SecurityPkg/Tcg/Tcg2Dxe/Tcg2DxeExtra.uni b/Core/SecurityPkg/Tcg/Tcg2Dxe/Tcg2DxeExtra.uni
new file mode 100644
index 0000000000..dbc52510eb
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Tcg2Dxe/Tcg2DxeExtra.uni
Binary files differ
diff --git a/Core/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.c b/Core/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.c
new file mode 100644
index 0000000000..63045f1c59
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.c
@@ -0,0 +1,997 @@
+/** @file
+ Initialize TPM2 device and measure FVs before handing off control to DXE.
+
+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 <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/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;
+
+/**
+ This function get digest from digest list.
+
+ @param HashAlg digest algorithm
+ @param DigestList digest list
+ @param Digest digest
+
+ @retval EFI_SUCCESS Sha1Digest is found and returned.
+ @retval EFI_NOT_FOUND Sha1Digest is not found.
+**/
+EFI_STATUS
+Tpm2GetDigestFromDigestList (
+ IN TPMI_ALG_HASH HashAlg,
+ IN TPML_DIGEST_VALUES *DigestList,
+ IN 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;
+}
+
+/**
+ 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;
+}
+
+/**
+ Check if buffer is all zero.
+
+ @param[in] Buffer Buffer to be checked.
+ @param[in] BufferSize Size of buffer to be checked.
+
+ @retval TRUE Buffer is all zero.
+ @retval FALSE Buffer is not all zero.
+**/
+BOOLEAN
+IsZeroBuffer (
+ IN VOID *Buffer,
+ IN UINTN BufferSize
+ )
+{
+ UINT8 *BufferData;
+ UINTN Index;
+
+ BufferData = Buffer;
+ for (Index = 0; Index < BufferSize; Index++) {
+ if (BufferData[Index] != 0) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+/**
+ Get TPML_DIGEST_VALUES data size.
+
+ @param[in] DigestList TPML_DIGEST_VALUES data.
+
+ @return TPML_DIGEST_VALUES data size.
+**/
+UINT32
+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;
+}
+
+/**
+ Return if hash alg is supported in TPM PCR bank.
+
+ @param HashAlg Hash algorithm to be checked.
+
+ @retval TRUE Hash algorithm is supported.
+ @retval FALSE Hash algorithm is not supported.
+**/
+BOOLEAN
+IsHashAlgSupportedInPcrBank (
+ IN TPMI_ALG_HASH HashAlg
+ )
+{
+ UINT32 ActivePcrBanks;
+
+ ActivePcrBanks = PcdGet32 (PcdTpm2HashMask);
+ switch (HashAlg) {
+ case TPM_ALG_SHA1:
+ if ((ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SHA1) != 0) {
+ return TRUE;
+ }
+ break;
+ case TPM_ALG_SHA256:
+ if ((ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SHA256) != 0) {
+ return TRUE;
+ }
+ break;
+ case TPM_ALG_SHA384:
+ if ((ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SHA384) != 0) {
+ return TRUE;
+ }
+ break;
+ case TPM_ALG_SHA512:
+ if ((ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SHA512) != 0) {
+ return TRUE;
+ }
+ break;
+ case TPM_ALG_SM3_256:
+ if ((ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SM3_256) != 0) {
+ return TRUE;
+ }
+ break;
+ }
+
+ return FALSE;
+}
+
+/**
+ Copy TPML_DIGEST_VALUES into a buffer
+
+ @param[in,out] Buffer Buffer to hold TPML_DIGEST_VALUES.
+ @param[in] DigestList TPML_DIGEST_VALUES to be copied.
+
+ @return The end of buffer to hold TPML_DIGEST_VALUES.
+**/
+VOID *
+CopyDigestListToBuffer (
+ IN OUT VOID *Buffer,
+ IN TPML_DIGEST_VALUES *DigestList
+ )
+{
+ UINTN Index;
+ UINT16 DigestSize;
+
+ CopyMem (Buffer, &DigestList->count, sizeof(DigestList->count));
+ Buffer = (UINT8 *)Buffer + sizeof(DigestList->count);
+ for (Index = 0; Index < DigestList->count; Index++) {
+ if (!IsHashAlgSupportedInPcrBank (DigestList->digests[Index].hashAlg)) {
+ 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;
+ }
+
+ return Buffer;
+}
+
+/**
+ Set Tpm2HashMask PCD value accroding to TPM2 PCR bank.
+**/
+VOID
+SetTpm2HashMask (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINT32 ActivePcrBanks;
+ TPML_PCR_SELECTION Pcrs;
+ UINTN Index;
+
+ DEBUG ((EFI_D_ERROR, "SetTpm2HashMask!\n"));
+
+ Status = Tpm2GetCapabilityPcrs (&Pcrs);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Tpm2GetCapabilityPcrs fail!\n"));
+ ActivePcrBanks = EFI_TCG2_BOOT_HASH_ALG_SHA1;
+ } else {
+ DEBUG ((EFI_D_INFO, "Tpm2GetCapabilityPcrs Count - %08x\n", Pcrs.count));
+ ActivePcrBanks = 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:
+ if (!IsZeroBuffer (Pcrs.pcrSelections[Index].pcrSelect, Pcrs.pcrSelections[Index].sizeofSelect)) {
+ ActivePcrBanks |= EFI_TCG2_BOOT_HASH_ALG_SHA1;
+ }
+ break;
+ case TPM_ALG_SHA256:
+ if (!IsZeroBuffer (Pcrs.pcrSelections[Index].pcrSelect, Pcrs.pcrSelections[Index].sizeofSelect)) {
+ ActivePcrBanks |= EFI_TCG2_BOOT_HASH_ALG_SHA256;
+ }
+ break;
+ case TPM_ALG_SHA384:
+ if (!IsZeroBuffer (Pcrs.pcrSelections[Index].pcrSelect, Pcrs.pcrSelections[Index].sizeofSelect)) {
+ ActivePcrBanks |= EFI_TCG2_BOOT_HASH_ALG_SHA384;
+ }
+ break;
+ case TPM_ALG_SHA512:
+ if (!IsZeroBuffer (Pcrs.pcrSelections[Index].pcrSelect, Pcrs.pcrSelections[Index].sizeofSelect)) {
+ ActivePcrBanks |= EFI_TCG2_BOOT_HASH_ALG_SHA512;
+ }
+ break;
+ case TPM_ALG_SM3_256:
+ if (!IsZeroBuffer (Pcrs.pcrSelections[Index].pcrSelect, Pcrs.pcrSelections[Index].sizeofSelect)) {
+ ActivePcrBanks |= EFI_TCG2_BOOT_HASH_ALG_SM3_256;
+ }
+ break;
+ }
+ }
+ }
+ Status = PcdSet32S (PcdTpm2HashMask, ActivePcrBanks);
+ 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 = Tpm2GetDigestFromDigestList (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:
+ 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);
+ 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 < FixedPcdGet32 (PcdPeiCoreMaxFvSupported));
+ if (mMeasuredBaseFvIndex < FixedPcdGet32 (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 < FixedPcdGet32 (PcdPeiCoreMaxFvSupported));
+ if (mMeasuredChildFvIndex < FixedPcdGet32 (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 ((EFI_D_ERROR, "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.
+ //
+ SetTpm2HashMask ();
+
+ 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..007ce918ed
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.inf
@@ -0,0 +1,91 @@
+## @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.
+#
+##
+
+[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
+
+[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..5a226bcce4
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.uni
Binary files differ
diff --git a/Core/SecurityPkg/Tcg/Tcg2Pei/Tcg2PeiExtra.uni b/Core/SecurityPkg/Tcg/Tcg2Pei/Tcg2PeiExtra.uni
new file mode 100644
index 0000000000..426fc77392
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Tcg2Pei/Tcg2PeiExtra.uni
Binary files differ
diff --git a/Core/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.c b/Core/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.c
new file mode 100644
index 0000000000..19d9b489fe
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.c
@@ -0,0 +1,509 @@
+/** @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 - 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 "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, // 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
+ )
+{
+ UINT32 MostRecentRequest;
+ UINT32 Response;
+
+ 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)) {
+ mTcgNvs->PhysicalPresence.ReturnCode = Tcg2PhysicalPresenceLibSubmitRequestToPreOSFunction (
+ mTcgNvs->PhysicalPresence.Request,
+ mTcgNvs->PhysicalPresence.RequestParameter
+ );
+ } else if (mTcgNvs->PhysicalPresence.Parameter == TCG_ACPI_FUNCTION_GET_USER_CONFIRMATION_STATUS_FOR_REQUEST) {
+ mTcgNvs->PhysicalPresence.ReturnCode = Tcg2PhysicalPresenceLibGetUserConfirmationStatusFunction (mTcgNvs->PhysicalPresence.Request);
+ }
+
+ 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;
+}
+
+/**
+ 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);
+
+ //
+ // 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;
+
+ //
+ // 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..fa77c9a89c
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.h
@@ -0,0 +1,96 @@
+/** @file
+ The header file for Tcg2 SMM 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.
+
+**/
+
+#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/Tpm2DeviceLib.h>
+#include <Library/Tcg2PhysicalPresenceLib.h>
+#include <Library/IoLib.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;
+} 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
+
+#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..0de4fcee04
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.inf
@@ -0,0 +1,83 @@
+## @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 - 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 = 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
+ Tpm2DeviceLib
+ 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
+
+[Depex]
+ gEfiAcpiTableProtocolGuid AND
+ gEfiSmmSwDispatch2ProtocolGuid AND
+ gEfiSmmVariableProtocolGuid
+
+[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..3d9dcac18a
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.uni
Binary files differ
diff --git a/Core/SecurityPkg/Tcg/Tcg2Smm/Tcg2SmmExtra.uni b/Core/SecurityPkg/Tcg/Tcg2Smm/Tcg2SmmExtra.uni
new file mode 100644
index 0000000000..173c4ebb70
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Tcg2Smm/Tcg2SmmExtra.uni
Binary files differ
diff --git a/Core/SecurityPkg/Tcg/Tcg2Smm/Tpm.asl b/Core/SecurityPkg/Tcg/Tcg2Smm/Tpm.asl
new file mode 100644
index 0000000000..e1060fcb54
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/Tcg2Smm/Tpm.asl
@@ -0,0 +1,359 @@
+/** @file
+ The TPM2 definition block in ACPI table for TCG2 physical presence
+ and MemoryClear.
+
+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.
+
+**/
+
+DefinitionBlock (
+ "Tpm.aml",
+ "SSDT",
+ 2,
+ "INTEL ",
+ "Tpm2Tabl",
+ 0x1000
+ )
+{
+ Scope (\_SB)
+ {
+ Device (TPM)
+ {
+ //
+ // TCG2
+ //
+ 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 (ReadOnly, 0xfed40000, 0x5000)
+ })
+
+ //
+ // Operational region for Smi port access
+ //
+ OperationRegion (SMIP, SystemIO, 0xB2, 1)
+ Field (SMIP, ByteAcc, NoLock, Preserve)
+ {
+ IOB2, 8
+ }
+
+ //
+ // Operational region for TPM access
+ //
+ OperationRegion (TPMR, SystemMemory, 0xfed40000, 0x5000)
+ Field (TPMR, AnyAcc, NoLock, Preserve)
+ {
+ ACC0, 8,
+ }
+
+ //
+ // Operational region for TPM support, TPM Physical Presence and TPM Memory Clear
+ // Region Offset 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
+ }
+
+ 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 (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)), 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/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..787251828f
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDriver.c
@@ -0,0 +1,150 @@
+/** @file
+ The module entry point for Tcg configuration module.
+
+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.
+
+**/
+
+#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 = TisPcRequestUseTpm ((TIS_TPM_HANDLE) (UINTN) TPM_BASE_ADDRESS);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "TPM not detected!\n"));
+ return Status;
+ }
+
+ Status = gBS->LocateProtocol (&gEfiTcgProtocolGuid, NULL, (VOID **) &TcgProtocol);
+ if (EFI_ERROR (Status)) {
+ TcgProtocol = NULL;
+ }
+
+ Status = gBS->OpenProtocol (
+ ImageHandle,
+ &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->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..bd655c8870
--- /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 - 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 = 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
+ TpmCommLib
+
+[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..5359046fed
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDxe.uni
Binary files differ
diff --git a/Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDxeExtra.uni b/Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDxeExtra.uni
new file mode 100644
index 0000000000..93475b2b64
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDxeExtra.uni
Binary files differ
diff --git a/Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigImpl.c b/Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigImpl.c
new file mode 100644
index 0000000000..c2e3b34a25
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigImpl.c
@@ -0,0 +1,502 @@
+/** @file
+ HII Config Access protocol implementation of TCG configuration module.
+
+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.
+
+**/
+
+#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;
+ UINTN BufferSize;
+ TCG_CONFIGURATION Configuration;
+ TCG_CONFIG_PRIVATE_DATA *PrivateData;
+ EFI_STRING ConfigRequestHdr;
+ EFI_STRING ConfigRequest;
+ BOOLEAN AllocatedRequest;
+ UINTN Size;
+ BOOLEAN TpmEnable;
+ BOOLEAN TpmActivate;
+ CHAR16 State[32];
+
+ if (Progress == NULL || Results == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *Progress = Request;
+ if ((Request != NULL) && !HiiIsConfigHdrMatch (Request, &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()
+ //
+ ZeroMem (&Configuration, sizeof (TCG_CONFIGURATION));
+
+ Configuration.TpmOperation = PHYSICAL_PRESENCE_ENABLE;
+
+ //
+ // Display current TPM state.
+ //
+ if (PrivateData->TcgProtocol != NULL) {
+ Status = GetTpmState (PrivateData->TcgProtocol, &TpmEnable, &TpmActivate);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ UnicodeSPrint (
+ State,
+ sizeof (State),
+ L"%s, and %s",
+ TpmEnable ? L"Enabled" : L"Disabled",
+ TpmActivate ? L"Activated" : L"Deactivated"
+ );
+ Configuration.TpmEnable = TpmEnable;
+ Configuration.TpmActivate = TpmActivate;
+
+ HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_TPM_STATE_CONTENT), State, NULL);
+ }
+
+ BufferSize = sizeof (Configuration);
+ ConfigRequest = Request;
+ if ((Request == NULL) || (StrStr (Request, L"OFFSET") == NULL)) {
+ //
+ // Request has no request element, construct full request string.
+ // Allocate and fill a buffer large enough to hold the <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, (UINT64) BufferSize);
+ FreePool (ConfigRequestHdr);
+ }
+
+ Status = gHiiConfigRouting->BlockToConfig (
+ gHiiConfigRouting,
+ ConfigRequest,
+ (UINT8 *) &Configuration,
+ BufferSize,
+ Results,
+ Progress
+ );
+ //
+ // Free the allocated config request string.
+ //
+ if (AllocatedRequest) {
+ FreePool (ConfigRequest);
+ }
+ //
+ // Set Progress string to the original request string.
+ //
+ if (Request == NULL) {
+ *Progress = NULL;
+ } else if (StrStr (Request, L"OFFSET") == NULL) {
+ *Progress = Request + StrLen (Request);
+ }
+
+ return Status;
+}
+
+/**
+ This function processes the results of changes in configuration.
+
+ @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param[in] Configuration A null-terminated Unicode string in <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
+ )
+{
+ if ((This == NULL) || (Value == NULL) || (ActionRequest == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ 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;
+ }
+
+ FreePool (PrivateData);
+}
diff --git a/Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigImpl.h b/Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigImpl.h
new file mode 100644
index 0000000000..ecc6a6d855
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigImpl.h
@@ -0,0 +1,193 @@
+/** @file
+ The header file of HII Config Access protocol implementation of TCG
+ configuration module.
+
+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_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/TpmCommLib.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;
+
+ 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..6010b80c7d
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigStrings.uni
Binary files differ
diff --git a/Core/SecurityPkg/Tcg/TcgDxe/TcgDxe.c b/Core/SecurityPkg/Tcg/TcgDxe/TcgDxe.c
new file mode 100644
index 0000000000..e1bf6c6989
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TcgDxe/TcgDxe.c
@@ -0,0 +1,1399 @@
+/** @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 - 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 <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/TpmCommLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiLib.h>
+#include <Library/ReportStatusCodeLib.h>
+
+#include "TpmComm.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;
+ TIS_TPM_HANDLE TpmHandle;
+} TCG_DXE_DATA;
+
+
+
+EFI_TCG_CLIENT_ACPI_TABLE mTcgClientAcpiTemplate = {
+ {
+ EFI_ACPI_3_0_TRUSTED_COMPUTING_PLATFORM_ALLIANCE_CAPABILITIES_TABLE_SIGNATURE,
+ sizeof (mTcgClientAcpiTemplate),
+ 0x02 //Revision
+ //
+ // Compiler initializes the remaining bytes to 0
+ // These fields should be filled in in production
+ //
+ },
+ 0, // 0 for PC Client Platform Class
+ 0, // Log Area Max Length
+ (EFI_PHYSICAL_ADDRESS) (SIZE_4GB - 1) // Log Area Start Address
+};
+
+//
+// The following EFI_TCG_SERVER_ACPI_TABLE default setting is just one example,
+// the TPM device connectes to LPC, and also defined the ACPI _UID as 0xFF,
+// this _UID can be changed and should match with the _UID setting of the TPM
+// ACPI device object
+//
+EFI_TCG_SERVER_ACPI_TABLE mTcgServerAcpiTemplate = {
+ {
+ EFI_ACPI_3_0_TRUSTED_COMPUTING_PLATFORM_ALLIANCE_CAPABILITIES_TABLE_SIGNATURE,
+ sizeof (mTcgServerAcpiTemplate),
+ 0x02 //Revision
+ //
+ // Compiler initializes the remaining bytes to 0
+ // These fields should be filled in in production
+ //
+ },
+ 1, // 1 for Server Platform Class
+ 0, // Reserved
+ 0, // Log Area Max Length
+ (EFI_PHYSICAL_ADDRESS) (SIZE_4GB - 1), // Log Area Start Address
+ 0x0100, // TCG Specification revision 1.0
+ 2, // Device Flags
+ 0, // Interrupt Flags
+ 0, // GPE
+ {0}, // Reserved 3 bytes
+ 0, // Global System Interrupt
+ {
+ EFI_ACPI_3_0_SYSTEM_MEMORY,
+ 0,
+ 0,
+ EFI_ACPI_3_0_BYTE,
+ TPM_BASE_ADDRESS // Base Address
+ },
+ 0, // Reserved
+ {0}, // Configuration Address
+ 0xFF, // ACPI _UID value of the device, can be changed for different platforms
+ 0, // ACPI _UID value of the device, can be changed for different platforms
+ 0, // ACPI _UID value of the device, can be changed for different platforms
+ 0 // ACPI _UID value of the device, can be changed for different platforms
+};
+
+UINTN mBootAttempts = 0;
+CHAR16 mBootVarName[] = L"BootOrder";
+
+/**
+ 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;
+}
+
+/**
+ 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] 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
+ )
+{
+ TCG_DXE_DATA *TcgData;
+
+ if (TpmInputParameterBlock == NULL ||
+ TpmOutputParameterBlock == NULL ||
+ TpmInputParameterBlockSize == 0 ||
+ TpmOutputParameterBlockSize == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ TcgData = TCG_DXE_DATA_FROM_THIS (This);
+
+ return TisPcExecute (
+ TcgData->TpmHandle,
+ "%r%/%r",
+ TpmInputParameterBlock,
+ (UINTN) TpmInputParameterBlockSize,
+ TpmOutputParameterBlock,
+ (UINTN) TpmOutputParameterBlockSize
+ );
+}
+
+/**
+ Do a hash operation on a data buffer, extend a specific TPM PCR with the hash result,
+ and add an entry to the Event Log.
+
+ @param[in] TcgData TCG_DXE_DATA structure.
+ @param[in] HashData Physical address of the start of the data buffer
+ to be hashed, extended, and logged.
+ @param[in] HashDataLen The length, in bytes, of the buffer referenced by HashData
+ @param[in, out] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR data structure.
+ @param[in] NewEventData Pointer to the new event data.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+
+**/
+EFI_STATUS
+EFIAPI
+TcgDxeHashLogExtendEventI (
+ IN TCG_DXE_DATA *TcgData,
+ IN UINT8 *HashData,
+ IN UINT64 HashDataLen,
+ IN OUT TCG_PCR_EVENT_HDR *NewEventHdr,
+ IN UINT8 *NewEventData
+ )
+{
+ EFI_STATUS Status;
+
+ if (!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 = TpmCommExtend (
+ TcgData->TpmHandle,
+ &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,
+ 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, "%s 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 ((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, "%s 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;
+
+ 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, "%s 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, "%s 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, "%s 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 VFlags;
+
+ Status = TpmCommGetFlags (
+ mTcgDxeData.TpmHandle,
+ TPM_CAP_FLAG_VOLATILE,
+ &VFlags,
+ sizeof (VFlags)
+ );
+ if (!EFI_ERROR (Status)) {
+ *TPMDeactivatedFlag = VFlags.deactivated;
+ }
+
+ return Status;
+}
+
+/**
+ The driver's entry point.
+
+ It publishes EFI TCG Protocol.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The entry point is executed successfully.
+ @retval other Some error occurs when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+DriverEntry (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_EVENT Event;
+ VOID *Registration;
+
+ 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;
+ }
+
+ mTcgDxeData.TpmHandle = (TIS_TPM_HANDLE)(UINTN)TPM_BASE_ADDRESS;
+ Status = TisPcRequestUseTpm (mTcgDxeData.TpmHandle);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "TPM not detected!\n"));
+ return Status;
+ }
+
+ Status = GetTpmStatus (&mTcgDxeData.BsCap.TPMDeactivatedFlag);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ EFI_D_ERROR,
+ "Line %d in file " __FILE__ ":\n "
+ "DriverEntry: TPM not working properly\n",
+ __LINE__
+ ));
+ return Status;
+ }
+
+ Status = gBS->InstallProtocolInterface (
+ &ImageHandle,
+ &gEfiTcgProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &mTcgDxeData.TcgProtocol
+ );
+ 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..e5409dfefd
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TcgDxe/TcgDxe.inf
@@ -0,0 +1,85 @@
+## @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
+ TisDxe.c
+ TpmComm.c
+ TpmComm.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+ MemoryAllocationLib
+ BaseLib
+ UefiBootServicesTableLib
+ HobLib
+ UefiDriverEntryPoint
+ UefiRuntimeServicesTableLib
+ BaseMemoryLib
+ DebugLib
+ TpmCommLib
+ PrintLib
+ UefiLib
+ PcdLib
+ ReportStatusCodeLib
+
+[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
+ 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..d54b5efc21
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TcgDxe/TcgDxe.uni
Binary files differ
diff --git a/Core/SecurityPkg/Tcg/TcgDxe/TcgDxeExtra.uni b/Core/SecurityPkg/Tcg/TcgDxe/TcgDxeExtra.uni
new file mode 100644
index 0000000000..b258469ace
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TcgDxe/TcgDxeExtra.uni
Binary files differ
diff --git a/Core/SecurityPkg/Tcg/TcgDxe/TisDxe.c b/Core/SecurityPkg/Tcg/TcgDxe/TisDxe.c
new file mode 100644
index 0000000000..e7e0f9e405
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TcgDxe/TisDxe.c
@@ -0,0 +1,448 @@
+/** @file
+ TIS (TPM Interface Specification) functions used by TPM Dxe driver.
+
+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 <IndustryStandard/Tpm12.h>
+#include <Library/TimerLib.h>
+#include <Library/TpmCommLib.h>
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+
+STATIC UINT8 TpmCommandBuf[TPMCMDBUFLENGTH];
+
+/**
+ Send command to TPM for execution.
+
+ @param[in] TisReg TPM register space base address.
+ @param[in] TpmBuffer Buffer for TPM command data.
+ @param[in] DataLength TPM command data length.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_TIMEOUT The register can't run into the expected status in time.
+
+**/
+EFI_STATUS
+TisPcSend (
+ IN TIS_PC_REGISTERS_PTR TisReg,
+ IN UINT8 *TpmBuffer,
+ IN UINT32 DataLength
+ )
+{
+ UINT16 BurstCount;
+ UINT32 Index;
+ EFI_STATUS Status;
+
+ Status = TisPcPrepareCommand (TisReg);
+ if (EFI_ERROR (Status)){
+ DEBUG ((DEBUG_ERROR, "The Tpm not ready!\n"));
+ return Status;
+ }
+ Index = 0;
+ while (Index < DataLength) {
+ Status = TisPcReadBurstCount (TisReg, &BurstCount);
+ if (EFI_ERROR (Status)) {
+ return EFI_TIMEOUT;
+ }
+ for (; BurstCount > 0 && Index < DataLength; BurstCount--) {
+ MmioWrite8 ((UINTN) &TisReg->DataFifo, *(TpmBuffer + Index));
+ Index++;
+ }
+ }
+ //
+ // Ensure the Tpm status STS_EXPECT change from 1 to 0
+ //
+ Status = TisPcWaitRegisterBits (
+ &TisReg->Status,
+ (UINT8) TIS_PC_VALID,
+ TIS_PC_STS_EXPECT,
+ TIS_TIMEOUT_C
+ );
+ return Status;
+}
+
+/**
+ Receive response data of last command from TPM.
+
+ @param[in] TisReg TPM register space base address.
+ @param[out] TpmBuffer Buffer for response data.
+ @param[out] RespSize Response data length.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_TIMEOUT The register can't run into the expected status in time.
+ @retval EFI_DEVICE_ERROR Unexpected device status.
+ @retval EFI_BUFFER_TOO_SMALL Response data is too long.
+
+**/
+EFI_STATUS
+TisPcReceive (
+ IN TIS_PC_REGISTERS_PTR TisReg,
+ OUT UINT8 *TpmBuffer,
+ OUT UINT32 *RespSize
+ )
+{
+ EFI_STATUS Status;
+ UINT16 BurstCount;
+ UINT32 Index;
+ UINT32 ResponseSize;
+ UINT32 Data32;
+
+ //
+ // Wait for the command completion
+ //
+ Status = TisPcWaitRegisterBits (
+ &TisReg->Status,
+ (UINT8) (TIS_PC_VALID | TIS_PC_STS_DATA),
+ 0,
+ TIS_TIMEOUT_B
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_TIMEOUT;
+ }
+ //
+ // Read the response data header and check it
+ //
+ Index = 0;
+ BurstCount = 0;
+ while (Index < sizeof (TPM_RSP_COMMAND_HDR)) {
+ Status = TisPcReadBurstCount (TisReg, &BurstCount);
+ if (EFI_ERROR (Status)) {
+ return EFI_TIMEOUT;
+ }
+ for (; BurstCount > 0 ; BurstCount--) {
+ *(TpmBuffer + Index) = MmioRead8 ((UINTN) &TisReg->DataFifo);
+ Index++;
+ if (Index == sizeof (TPM_RSP_COMMAND_HDR))
+ break;
+ }
+ }
+ //
+ // Check the reponse data header (tag,parasize and returncode )
+ //
+ CopyMem (&Data32, (TpmBuffer + 2), sizeof (UINT32));
+ ResponseSize = SwapBytes32 (Data32);
+ *RespSize = ResponseSize;
+ if (ResponseSize == sizeof (TPM_RSP_COMMAND_HDR)) {
+ return EFI_SUCCESS;
+ }
+ if (ResponseSize < sizeof (TPM_RSP_COMMAND_HDR)) {
+ return EFI_DEVICE_ERROR;
+ }
+ if (ResponseSize > TPMCMDBUFLENGTH) {
+ return EFI_BUFFER_TOO_SMALL;
+ }
+ //
+ // Continue reading the remaining data
+ //
+ while (Index < ResponseSize) {
+ for (; BurstCount > 0 ; BurstCount--) {
+ *(TpmBuffer + Index) = MmioRead8 ((UINTN) &TisReg->DataFifo);
+ Index++;
+ if (Index == ResponseSize) {
+ return EFI_SUCCESS;
+ }
+ }
+ Status = TisPcReadBurstCount (TisReg, &BurstCount);
+ if (EFI_ERROR (Status) && (Index < ResponseSize)) {
+ return EFI_DEVICE_ERROR;
+ }
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Format TPM command data according to the format control character.
+
+ @param[in] FmtChar Format control character.
+ @param[in, out] ap List of arguments.
+ @param[in] TpmBuffer Buffer for TPM command data.
+ @param[out] DataLength TPM command data length.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid format control character.
+ @retval EFI_BUFFER_TOO_SMALL Buffer too small for command data.
+
+**/
+EFI_STATUS
+TisPcSendV (
+ IN UINT8 FmtChar,
+ IN OUT VA_LIST *ap,
+ UINT8 *TpmBuffer,
+ UINT32 *DataLength
+ )
+{
+ UINT8 DataByte;
+ UINT16 DataWord;
+ UINT32 DataDword;
+ TPM_RQU_COMMAND_HDR TpmCmdHdr;
+ TPM_RQU_COMMAND_HDR *TpmCmdPtr;
+ UINTN Size;
+ UINT8 *Raw;
+
+ switch (FmtChar) {
+
+ case 'b':
+ DataByte = VA_ARG (*ap, UINT8);
+ Raw = &DataByte;
+ Size = sizeof (DataByte);
+ break;
+
+ case 'w':
+ DataWord = VA_ARG (*ap, UINT16);
+ DataWord = SwapBytes16 (DataWord);
+ Raw = (UINT8*)&DataWord;
+ Size = sizeof (DataWord);
+ break;
+
+ case 'd':
+ DataDword = VA_ARG (*ap, UINT32);
+ DataDword = SwapBytes32 (DataDword);
+ Raw = (UINT8*)&DataDword;
+ Size = sizeof (DataDword);
+ break;
+
+ case 'h':
+ TpmCmdPtr = VA_ARG (*ap, TPM_RQU_COMMAND_HDR*);
+ TpmCmdHdr.tag = SwapBytes16 (TpmCmdPtr->tag);
+ TpmCmdHdr.paramSize = SwapBytes32 (TpmCmdPtr->paramSize);
+ TpmCmdHdr.ordinal = SwapBytes32 (TpmCmdPtr->ordinal);
+ Raw = (UINT8*) &TpmCmdHdr;
+ Size = sizeof (TpmCmdHdr);
+ break;
+
+ case 'r':
+ Raw = VA_ARG (*ap, UINT8*);
+ Size = VA_ARG (*ap, UINTN);
+ break;
+
+ case '\0':
+ return EFI_INVALID_PARAMETER;
+
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check input to avoid overflow.
+ //
+ if ((UINT32) (~0)- *DataLength < (UINT32)Size) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if(*DataLength + (UINT32) Size > TPMCMDBUFLENGTH) {
+ return EFI_BUFFER_TOO_SMALL;
+ }
+ CopyMem (TpmBuffer + *DataLength, Raw, Size);
+ *DataLength += (UINT32) Size;
+ return EFI_SUCCESS;
+}
+
+/**
+ Format reponse data according to the format control character.
+
+ @param[in] FmtChar Format control character.
+ @param[in, out] ap List of arguments.
+ @param[out] TpmBuffer Buffer for reponse data.
+ @param[in, out] DataIndex Data offset in reponse data buffer.
+ @param[in] RespSize Response data length.
+ @param[out] DataFinished Reach the end of Response data.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_INVALID_PARAMETER Invalid format control character.
+ @retval EFI_BUFFER_TOO_SMALL Buffer too small for command data.
+
+**/
+EFI_STATUS
+TisPcReceiveV (
+ IN UINT8 FmtChar,
+ IN OUT VA_LIST *ap,
+ OUT UINT8 *TpmBuffer,
+ IN OUT UINT32 *DataIndex,
+ IN UINT32 RespSize,
+ OUT BOOLEAN *DataFinished
+ )
+{
+ UINT8 *Raw;
+ TPM_RSP_COMMAND_HDR *TpmRspPtr;
+ UINTN Size;
+
+ Raw = VA_ARG (*ap, UINT8*);
+ switch (FmtChar) {
+
+ case 'b':
+ Size = sizeof (UINT8);
+ break;
+
+ case 'w':
+ Size = sizeof (UINT16);
+ break;
+
+ case 'd':
+ Size = sizeof (UINT32);
+ break;
+
+ case 'h':
+ Size = sizeof (*TpmRspPtr);
+ break;
+
+ case 'r':
+ Size = VA_ARG (*ap, UINTN);
+ //
+ // If overflowed, which means Size is big enough for Response data.
+ // skip this check. Copy the whole data
+ //
+ if ((UINT32) (~0)- *DataIndex >= (UINT32)Size) {
+ if(*DataIndex + (UINT32) Size <= RespSize) {
+ break;
+ }
+ }
+
+ *DataFinished = TRUE;
+ if (*DataIndex >= RespSize) {
+ return EFI_SUCCESS;
+ }
+ CopyMem (Raw, TpmBuffer + *DataIndex, RespSize - *DataIndex);
+ *DataIndex += RespSize - *DataIndex;
+ return EFI_SUCCESS;
+
+ case '\0':
+ return EFI_INVALID_PARAMETER;
+
+ default:
+ return EFI_WARN_UNKNOWN_GLYPH;
+ }
+
+ if(*DataIndex + (UINT32) Size > RespSize) {
+ *DataFinished = TRUE;
+ return EFI_SUCCESS;
+ }
+
+ if( *DataIndex + (UINT32) Size > TPMCMDBUFLENGTH )
+ return EFI_BUFFER_TOO_SMALL;
+
+ CopyMem (Raw, TpmBuffer + *DataIndex, Size);
+ *DataIndex += (UINT32) Size;
+
+ switch (FmtChar) {
+
+ case 'w':
+ *(UINT16*)Raw = SwapBytes16 (*(UINT16*) Raw);
+ break;
+
+ case 'd':
+ *(UINT32*)Raw = SwapBytes32 (*(UINT32*) Raw);
+ break;
+
+ case 'h':
+ TpmRspPtr = (TPM_RSP_COMMAND_HDR*) Raw;
+ TpmRspPtr->tag = SwapBytes16 (TpmRspPtr->tag);
+ TpmRspPtr->paramSize = SwapBytes32 (TpmRspPtr->paramSize);
+ TpmRspPtr->returnCode = SwapBytes32 (TpmRspPtr->returnCode);
+ break;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Send formatted command to TPM for execution and return formatted data from response.
+
+ @param[in] TisReg TPM Handle.
+ @param[in] Fmt Format control string.
+ @param[in] ... The variable argument list.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_TIMEOUT The register can't run into the expected status in time.
+
+**/
+EFI_STATUS
+EFIAPI
+TisPcExecute (
+ IN TIS_TPM_HANDLE TisReg,
+ IN CONST CHAR8 *Fmt,
+ ...
+ )
+{
+ EFI_STATUS Status;
+ VA_LIST Ap;
+ UINT32 BufSize;
+ UINT32 ResponseSize;
+ BOOLEAN DataFinished;
+
+ VA_START (Ap, Fmt);
+
+ //
+ // Put the formatted command to the TpmCommandBuf
+ //
+ BufSize = 0;
+ while (*Fmt != '\0') {
+ if (*Fmt == '%') Fmt++;
+ if (*Fmt == '/') break;
+ Status = TisPcSendV (*Fmt, &Ap, TpmCommandBuf, &BufSize);
+ if (EFI_ERROR( Status )) {
+ goto Error;
+ }
+ Fmt++;
+ }
+ //
+ // Send the command to TPM
+ //
+ Status = TisPcSend (TisReg, TpmCommandBuf, BufSize);
+ if (EFI_ERROR (Status)) {
+ //
+ // Ensure the TPM state change from "Reception" to "Idle/Ready"
+ //
+ MmioWrite8 ((UINTN) &(((TIS_PC_REGISTERS_PTR) TisReg)->Status), TIS_PC_STS_READY);
+ goto Error;
+ }
+
+ MmioWrite8 ((UINTN) &(((TIS_PC_REGISTERS_PTR) TisReg)->Status), TIS_PC_STS_GO);
+ Fmt++;
+ //
+ // Receive the response data from TPM
+ //
+ ZeroMem (TpmCommandBuf, TPMCMDBUFLENGTH);
+ Status = TisPcReceive (TisReg, TpmCommandBuf, &ResponseSize);
+ //
+ // Ensure the TPM state change from "Execution" or "Completion" to "Idle/Ready"
+ //
+ MmioWrite8 ((UINTN) &(((TIS_PC_REGISTERS_PTR) TisReg)->Status), TIS_PC_STS_READY);
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+
+ //
+ // Get the formatted data from the TpmCommandBuf.
+ //
+ BufSize =0;
+ DataFinished = FALSE;
+ while (*Fmt != '\0') {
+ if (*Fmt == '%') {
+ Fmt++;
+ }
+ Status = TisPcReceiveV (*Fmt, &Ap, TpmCommandBuf, &BufSize, ResponseSize, &DataFinished);
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ if (DataFinished) {
+ VA_END (Ap);
+ return EFI_SUCCESS;
+ }
+ Fmt++;
+ }
+
+Error:
+ VA_END (Ap);
+ return Status;
+}
+
diff --git a/Core/SecurityPkg/Tcg/TcgDxe/TpmComm.c b/Core/SecurityPkg/Tcg/TcgDxe/TpmComm.c
new file mode 100644
index 0000000000..96732fad5d
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TcgDxe/TpmComm.c
@@ -0,0 +1,170 @@
+/** @file
+ Utility functions used by TPM Dxe driver.
+
+Copyright (c) 2005 - 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/Tpm12.h>
+#include <IndustryStandard/UefiTcgPlatform.h>
+#include <Library/TpmCommLib.h>
+#include <Library/BaseMemoryLib.h>
+
+#include "TpmComm.h"
+
+/**
+ Extend a TPM PCR.
+
+ @param[in] TpmHandle TPM handle.
+ @param[in] DigestToExtend The 160 bit value representing the event to be recorded.
+ @param[in] PcrIndex The PCR to be updated.
+ @param[out] NewPcrValue New PCR value after extend.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+
+**/
+EFI_STATUS
+TpmCommExtend (
+ IN TIS_TPM_HANDLE TpmHandle,
+ IN TPM_DIGEST *DigestToExtend,
+ IN TPM_PCRINDEX PcrIndex,
+ OUT TPM_DIGEST *NewPcrValue
+ )
+{
+ EFI_STATUS Status;
+ TPM_DIGEST NewValue;
+ TPM_RQU_COMMAND_HDR CmdHdr;
+ TPM_RSP_COMMAND_HDR RspHdr;
+
+ if (NewPcrValue == NULL) {
+ NewPcrValue = &NewValue;
+ }
+
+ CmdHdr.tag = TPM_TAG_RQU_COMMAND;
+ CmdHdr.paramSize =
+ sizeof (CmdHdr) + sizeof (PcrIndex) + sizeof (*DigestToExtend);
+ CmdHdr.ordinal = TPM_ORD_Extend;
+ Status = TisPcExecute (
+ TpmHandle,
+ "%h%d%r%/%h%r",
+ &CmdHdr,
+ PcrIndex,
+ DigestToExtend,
+ (UINTN)sizeof (*DigestToExtend),
+ &RspHdr,
+ NewPcrValue,
+ (UINTN)sizeof (*NewPcrValue)
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ if (RspHdr.returnCode != 0) {
+ return EFI_DEVICE_ERROR;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Get TPM capability flags.
+
+ @param[in] TpmHandle TPM handle.
+ @param[in] FlagSubcap Flag subcap.
+ @param[out] FlagBuffer Pointer to the buffer for returned flag structure.
+ @param[in] FlagSize Size of the buffer.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+
+**/
+EFI_STATUS
+TpmCommGetFlags (
+ IN TIS_TPM_HANDLE TpmHandle,
+ IN UINT32 FlagSubcap,
+ OUT VOID *FlagBuffer,
+ IN UINTN FlagSize
+ )
+{
+ EFI_STATUS Status;
+ TPM_RQU_COMMAND_HDR CmdHdr;
+ TPM_RSP_COMMAND_HDR RspHdr;
+ UINT32 Size;
+
+ CmdHdr.tag = TPM_TAG_RQU_COMMAND;
+ CmdHdr.paramSize = sizeof (CmdHdr) + sizeof (UINT32) * 3;
+ CmdHdr.ordinal = TPM_ORD_GetCapability;
+
+ Status = TisPcExecute (
+ TpmHandle,
+ "%h%d%d%d%/%h%d%r",
+ &CmdHdr,
+ TPM_CAP_FLAG,
+ sizeof (FlagSubcap),
+ FlagSubcap,
+ &RspHdr,
+ &Size,
+ FlagBuffer,
+ FlagSize
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ if (RspHdr.returnCode != 0) {
+ return EFI_DEVICE_ERROR;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Add a new entry to the Event Log.
+
+ @param[in, out] EventLogPtr Pointer to the Event Log data.
+ @param[in, out] LogSize Size of the Event Log.
+ @param[in] MaxSize Maximum size of the Event Log.
+ @param[in] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR data structure.
+ @param[in] NewEventData Pointer to the new event data.
+
+ @retval EFI_SUCCESS The new event log entry was added.
+ @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.
+
+**/
+EFI_STATUS
+TpmCommLogEvent (
+ IN OUT UINT8 **EventLogPtr,
+ IN OUT UINTN *LogSize,
+ IN UINTN MaxSize,
+ IN TCG_PCR_EVENT_HDR *NewEventHdr,
+ IN UINT8 *NewEventData
+ )
+{
+ UINTN NewLogSize;
+
+ //
+ // Prevent Event Overflow
+ //
+ if (NewEventHdr->EventSize > (UINTN)(~0) - 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;
+}
diff --git a/Core/SecurityPkg/Tcg/TcgDxe/TpmComm.h b/Core/SecurityPkg/Tcg/TcgDxe/TpmComm.h
new file mode 100644
index 0000000000..763ad76d62
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TcgDxe/TpmComm.h
@@ -0,0 +1,99 @@
+/** @file
+ Definitions and function prototypes used by TPM DXE driver.
+
+Copyright (c) 2005 - 2010, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _TPM_COMM_H_
+#define _TPM_COMM_H_
+
+/**
+ Add a new entry to the Event Log.
+
+ @param[in, out] EventLogPtr Pointer to the Event Log data.
+ @param[in, out] LogSize Size of the Event Log.
+ @param[in] MaxSize Maximum size of the Event Log.
+ @param[in] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR data structure.
+ @param[in] NewEventData Pointer to the new event data.
+
+ @retval EFI_SUCCESS The new event log entry was added.
+ @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.
+
+**/
+EFI_STATUS
+TpmCommLogEvent (
+ IN OUT UINT8 **EventLogPtr,
+ IN OUT UINTN *LogSize,
+ IN UINTN MaxSize,
+ IN TCG_PCR_EVENT_HDR *NewEventHdr,
+ IN UINT8 *NewEventData
+ );
+
+/**
+ Extend a TPM PCR.
+
+ @param[in] TpmHandle TPM handle.
+ @param[in] DigestToExtend The 160 bit value representing the event to be recorded.
+ @param[in] PcrIndex The PCR to be updated.
+ @param[out] NewPcrValue New PCR value after extend.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+
+**/
+EFI_STATUS
+TpmCommExtend (
+ IN TIS_TPM_HANDLE TpmHandle,
+ IN TPM_DIGEST *DigestToExtend,
+ IN TPM_PCRINDEX PcrIndex,
+ OUT TPM_DIGEST *NewPcrValue
+ );
+
+/**
+ Get TPM capability flags.
+
+ @param[in] TpmHandle TPM handle.
+ @param[in] FlagSubcap Flag subcap.
+ @param[out] FlagBuffer Pointer to the buffer for returned flag structure.
+ @param[in] FlagSize Size of the buffer.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+
+**/
+EFI_STATUS
+TpmCommGetFlags (
+ IN TIS_TPM_HANDLE TpmHandle,
+ IN UINT32 FlagSubcap,
+ OUT VOID *Buffer,
+ IN UINTN Size
+ );
+
+/**
+ Send formatted command to TPM for execution and return formatted data from response.
+
+ @param[in] TisReg TPM Handle.
+ @param[in] Fmt Format control string.
+ @param[in] ... The variable argument list.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_TIMEOUT The register can't run into the expected status in time.
+
+**/
+EFI_STATUS
+EFIAPI
+TisPcExecute (
+ IN TIS_TPM_HANDLE TisReg,
+ IN CONST CHAR8 *Fmt,
+ ...
+ );
+
+#endif // _TPM_COMM_H_
diff --git a/Core/SecurityPkg/Tcg/TcgPei/TcgPei.c b/Core/SecurityPkg/Tcg/TcgPei/TcgPei.c
new file mode 100644
index 0000000000..419eacf37d
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TcgPei/TcgPei.c
@@ -0,0 +1,832 @@
+/** @file
+ Initialize TPM device and measure FVs before handing off control to DXE.
+
+Copyright (c) 2005 - 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 <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/TpmCommLib.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 "TpmComm.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;
+}
+
+/**
+ Do a hash operation on a data buffer, extend a specific TPM PCR with the hash result,
+ and build a GUIDed HOB recording the event which will be passed to the DXE phase and
+ added into the Event Log.
+
+ @param[in] PeiServices Describes the list of possible PEI Services.
+ @param[in] HashData Physical address of the start of the data buffer
+ to be hashed, extended, and logged.
+ @param[in] HashDataLen The length, in bytes, of the buffer referenced by HashData.
+ @param[in] TpmHandle TPM handle.
+ @param[in] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR data structure.
+ @param[in] NewEventData Pointer to the new event data.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+
+**/
+EFI_STATUS
+HashLogExtendEvent (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN UINT8 *HashData,
+ IN UINTN HashDataLen,
+ IN TIS_TPM_HANDLE TpmHandle,
+ IN TCG_PCR_EVENT_HDR *NewEventHdr,
+ IN UINT8 *NewEventData
+ )
+{
+ EFI_STATUS Status;
+ VOID *HobData;
+
+ 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 = TpmCommExtend (
+ PeiServices,
+ TpmHandle,
+ &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.
+ @param[in] TpmHandle TPM handle.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+
+**/
+EFI_STATUS
+EFIAPI
+MeasureCRTMVersion (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN TIS_TPM_HANDLE TpmHandle
+ )
+{
+ TCG_PCR_EVENT_HDR TcgEventHdr;
+
+ //
+ // 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,
+ TpmHandle,
+ &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;
+ TIS_TPM_HANDLE TpmHandle;
+
+ TpmHandle = (TIS_TPM_HANDLE) (UINTN) TPM_BASE_ADDRESS;
+
+ //
+ // 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,
+ TpmHandle,
+ &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.
+ @param[in] TpmHandle TPM handle.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+
+**/
+EFI_STATUS
+EFIAPI
+MeasureMainBios (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN TIS_TPM_HANDLE TpmHandle
+ )
+{
+ EFI_STATUS Status;
+ UINT32 FvInstances;
+ EFI_PEI_FV_HANDLE VolumeHandle;
+ EFI_FV_INFO VolumeInfo;
+ EFI_PEI_FIRMWARE_VOLUME_PPI *FvPpi;
+
+ FvInstances = 0;
+ while (TRUE) {
+ //
+ // Traverse all firmware volume instances of Static Core Root of Trust for Measurement
+ // (S-CRTM), this firmware volume measure policy can be modified/enhanced by special
+ // platform for special CRTM TPM measuring.
+ //
+ Status = PeiServicesFfsFindNextVolume (FvInstances, &VolumeHandle);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ //
+ // Measure and record the firmware volume that is dispatched by PeiCore
+ //
+ Status = PeiServicesFfsGetVolumeInfo (VolumeHandle, &VolumeInfo);
+ ASSERT_EFI_ERROR (Status);
+ //
+ // Locate the corresponding FV_PPI according to founded FV's format guid
+ //
+ Status = PeiServicesLocatePpi (
+ &VolumeInfo.FvFormat,
+ 0,
+ NULL,
+ (VOID**)&FvPpi
+ );
+ if (!EFI_ERROR (Status)) {
+ MeasureFvImage ((EFI_PHYSICAL_ADDRESS) (UINTN) VolumeInfo.FvStart, VolumeInfo.FvSize);
+ }
+
+ FvInstances++;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Measure and record the Firmware Volum Information once FvInfoPPI install.
+
+ @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param[in] NotifyDescriptor Address of the notification descriptor data structure.
+ @param[in] Ppi Address of the PPI that was installed.
+
+ @retval EFI_SUCCESS The FV Info is measured and recorded to TPM.
+ @return Others Fail to measure FV.
+
+**/
+EFI_STATUS
+EFIAPI
+FirmwareVolmeInfoPpiNotifyCallback (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *Ppi
+ )
+{
+ EFI_PEI_FIRMWARE_VOLUME_INFO_PPI *Fv;
+ EFI_STATUS Status;
+ EFI_PEI_FIRMWARE_VOLUME_PPI *FvPpi;
+ 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;
+ PEI_LOCK_PHYSICAL_PRESENCE_PPI *LockPhysicalPresencePpi;
+ BOOLEAN LifetimeLock;
+ BOOLEAN CmdEnable;
+ TIS_TPM_HANDLE TpmHandle;
+ TPM_PHYSICAL_PRESENCE PhysicalPresenceValue;
+
+ TpmHandle = (TIS_TPM_HANDLE) (UINTN) TPM_BASE_ADDRESS;
+
+ Status = TpmCommGetCapability (PeiServices, TpmHandle, NULL, &LifetimeLock, &CmdEnable);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // 1. Set physicalPresenceLifetimeLock, physicalPresenceHWEnable and physicalPresenceCMDEnable bit by PCDs.
+ //
+ if (PcdGetBool (PcdPhysicalPresenceLifetimeLock) && !LifetimeLock) {
+ //
+ // Lock TPM LifetimeLock is required, and LifetimeLock is not locked yet.
+ //
+ PhysicalPresenceValue = TPM_PHYSICAL_PRESENCE_LIFETIME_LOCK;
+
+ if (PcdGetBool (PcdPhysicalPresenceCmdEnable)) {
+ PhysicalPresenceValue |= TPM_PHYSICAL_PRESENCE_CMD_ENABLE;
+ CmdEnable = TRUE;
+ } else {
+ PhysicalPresenceValue |= TPM_PHYSICAL_PRESENCE_CMD_DISABLE;
+ CmdEnable = FALSE;
+ }
+
+ if (PcdGetBool (PcdPhysicalPresenceHwEnable)) {
+ PhysicalPresenceValue |= TPM_PHYSICAL_PRESENCE_HW_ENABLE;
+ } else {
+ PhysicalPresenceValue |= TPM_PHYSICAL_PRESENCE_HW_DISABLE;
+ }
+
+ Status = TpmCommPhysicalPresence (
+ PeiServices,
+ TpmHandle,
+ 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 (!CmdEnable) {
+ if (LifetimeLock) {
+ //
+ // physicalPresenceCMDEnable is locked, can't change.
+ //
+ return EFI_ABORTED;
+ }
+
+ //
+ // Enable physical presence command
+ // It is necessary in order to lock physical presence
+ //
+ Status = TpmCommPhysicalPresence (
+ PeiServices,
+ TpmHandle,
+ TPM_PHYSICAL_PRESENCE_CMD_ENABLE
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // Lock physical presence
+ //
+ Status = TpmCommPhysicalPresence (
+ PeiServices,
+ TpmHandle,
+ TPM_PHYSICAL_PRESENCE_LOCK
+ );
+ return Status;
+}
+
+/**
+ Check if TPM chip is activeated or not.
+
+ @param[in] PeiServices Describes the list of possible PEI Services.
+ @param[in] TpmHandle TPM handle.
+
+ @retval TRUE TPM is activated.
+ @retval FALSE TPM is deactivated.
+
+**/
+BOOLEAN
+EFIAPI
+IsTpmUsable (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN TIS_TPM_HANDLE TpmHandle
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN Deactivated;
+
+ Status = TpmCommGetCapability (PeiServices, TpmHandle, &Deactivated, NULL, NULL);
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+ return (BOOLEAN)(!Deactivated);
+}
+
+/**
+ Do measurement after memory is ready.
+
+ @param[in] PeiServices Describes the list of possible PEI Services.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+
+**/
+EFI_STATUS
+EFIAPI
+PeimEntryMP (
+ IN EFI_PEI_SERVICES **PeiServices
+ )
+{
+ EFI_STATUS Status;
+ TIS_TPM_HANDLE TpmHandle;
+
+ 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);
+
+ TpmHandle = (TIS_TPM_HANDLE)(UINTN)TPM_BASE_ADDRESS;
+ Status = TisPcRequestUseTpm ((TIS_PC_REGISTERS_PTR)TpmHandle);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (IsTpmUsable (PeiServices, TpmHandle)) {
+ if (PcdGet8 (PcdTpmScrtmPolicy) == 1) {
+ Status = MeasureCRTMVersion (PeiServices, TpmHandle);
+ }
+
+ Status = MeasureMainBios (PeiServices, TpmHandle);
+ }
+
+ //
+ // Post callbacks:
+ // 1). for the FvInfoPpi services to measure and record
+ // the additional Fvs to TPM
+ // 2). for the OperatorPresencePpi service to determine whether to
+ // lock the TPM
+ //
+ Status = PeiServicesNotifyPpi (&mNotifyList[0]);
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
+/**
+ Entry point of this module.
+
+ @param[in] FileHandle Handle of the file being invoked.
+ @param[in] PeiServices Describes the list of possible PEI Services.
+
+ @return Status.
+
+**/
+EFI_STATUS
+EFIAPI
+PeimEntryMA (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS Status2;
+ EFI_BOOT_MODE BootMode;
+ TIS_TPM_HANDLE TpmHandle;
+
+ 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) {
+ TpmHandle = (TIS_TPM_HANDLE)(UINTN)TPM_BASE_ADDRESS;
+ Status = TisPcRequestUseTpm ((TIS_PC_REGISTERS_PTR)TpmHandle);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "TPM not detected!\n"));
+ goto Done;
+ }
+
+ if (PcdGet8 (PcdTpmInitializationPolicy) == 1) {
+ Status = TpmCommStartup ((EFI_PEI_SERVICES**)PeiServices, TpmHandle, BootMode);
+ 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 = TpmCommContinueSelfTest ((EFI_PEI_SERVICES**)PeiServices, TpmHandle);
+ 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..56f87c2e1b
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TcgPei/TcgPei.inf
@@ -0,0 +1,94 @@
+## @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 - 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 = 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
+ TisPei.c
+ TpmComm.c
+ TpmComm.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ SecurityPkg/SecurityPkg.dec
+
+[LibraryClasses]
+ HobLib
+ PeimEntryPoint
+ PeiServicesLib
+ BaseMemoryLib
+ DebugLib
+ TpmCommLib
+ TimerLib
+ IoLib
+ PeiServicesTablePointerLib
+ BaseLib
+ PcdLib
+ MemoryAllocationLib
+ ReportStatusCodeLib
+
+[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..7486e26d77
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TcgPei/TcgPei.uni
Binary files differ
diff --git a/Core/SecurityPkg/Tcg/TcgPei/TcgPeiExtra.uni b/Core/SecurityPkg/Tcg/TcgPei/TcgPeiExtra.uni
new file mode 100644
index 0000000000..0145366afb
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TcgPei/TcgPeiExtra.uni
Binary files differ
diff --git a/Core/SecurityPkg/Tcg/TcgPei/TisPei.c b/Core/SecurityPkg/Tcg/TcgPei/TisPei.c
new file mode 100644
index 0000000000..97d9628bda
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TcgPei/TisPei.c
@@ -0,0 +1,160 @@
+/** @file
+ TIS (TPM Interface Specification) functions used by TPM PEI driver.
+
+Copyright (c) 2005 - 2011, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+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/Tpm12.h>
+#include <IndustryStandard/UefiTcgPlatform.h>
+#include <Library/TpmCommLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseLib.h>
+#include <Library/IoLib.h>
+#include <Library/BaseMemoryLib.h>
+
+/**
+ Send a command to TPM for execution and return response data.
+
+ @param[in] PeiServices Describes the list of possible PEI Services.
+ @param[in] TisReg TPM register space base address.
+ @param[in] BufferIn Buffer for command data.
+ @param[in] SizeIn Size of command data.
+ @param[in, out] BufferOut Buffer for response data.
+ @param[in, out] SizeOut Size of response data.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_TIMEOUT The register can't run into the expected status in time.
+ @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+
+**/
+EFI_STATUS
+TisTpmCommand (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN TIS_PC_REGISTERS_PTR TisReg,
+ IN UINT8 *BufferIn,
+ IN UINT32 SizeIn,
+ IN OUT UINT8 *BufferOut,
+ IN OUT UINT32 *SizeOut
+ )
+{
+ EFI_STATUS Status;
+ UINT16 BurstCount;
+ UINT32 Index;
+ UINT32 TpmOutSize;
+ UINT16 Data16;
+ UINT32 Data32;
+
+ Status = TisPcPrepareCommand (TisReg);
+ if (EFI_ERROR (Status)){
+ DEBUG ((DEBUG_ERROR, "Tpm is not ready for command!\n"));
+ return Status;
+ }
+ //
+ // Send the command data to Tpm
+ //
+ Index = 0;
+ while (Index < SizeIn) {
+ Status = TisPcReadBurstCount (TisReg, &BurstCount);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_TIMEOUT;
+ goto Exit;
+ }
+ for (; BurstCount > 0 && Index < SizeIn; BurstCount--) {
+ MmioWrite8((UINTN)&TisReg->DataFifo, *(BufferIn + Index));
+ Index++;
+ }
+ }
+ //
+ // Check the Tpm status STS_EXPECT change from 1 to 0
+ //
+ Status = TisPcWaitRegisterBits (
+ &TisReg->Status,
+ (UINT8) TIS_PC_VALID,
+ TIS_PC_STS_EXPECT,
+ TIS_TIMEOUT_C
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "The send buffer too small!\n"));
+ Status = EFI_BUFFER_TOO_SMALL;
+ goto Exit;
+ }
+ //
+ // Executed the TPM command and waiting for the response data ready
+ //
+ MmioWrite8((UINTN)&TisReg->Status, TIS_PC_STS_GO);
+ Status = TisPcWaitRegisterBits (
+ &TisReg->Status,
+ (UINT8) (TIS_PC_VALID | TIS_PC_STS_DATA),
+ 0,
+ TIS_TIMEOUT_B
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Wait for Tpm response data time out!!\n"));
+ Status = EFI_TIMEOUT;
+ goto Exit;
+ }
+ //
+ // Get response data header
+ //
+ Index = 0;
+ BurstCount = 0;
+ while (Index < sizeof (TPM_RSP_COMMAND_HDR)) {
+ Status = TisPcReadBurstCount (TisReg, &BurstCount);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_TIMEOUT;
+ goto Exit;
+ }
+ for (; BurstCount > 0; BurstCount--) {
+ *(BufferOut + Index) = MmioRead8 ((UINTN)&TisReg->DataFifo);
+ Index++;
+ if (Index == sizeof (TPM_RSP_COMMAND_HDR)) break;
+ }
+ }
+ //
+ // Check the reponse data header (tag,parasize and returncode )
+ //
+ CopyMem (&Data16, BufferOut, sizeof (UINT16));
+ if (SwapBytes16 (Data16) != TPM_TAG_RSP_COMMAND ) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ CopyMem (&Data32, (BufferOut + 2), sizeof (UINT32));
+ TpmOutSize = SwapBytes32 (Data32);
+ if (*SizeOut < TpmOutSize) {
+ Status = EFI_BUFFER_TOO_SMALL;
+ goto Exit;
+ }
+ *SizeOut = TpmOutSize;
+ //
+ // Continue reading the remaining data
+ //
+ while ( Index < TpmOutSize ) {
+ for (; BurstCount > 0; BurstCount--) {
+ *(BufferOut + Index) = MmioRead8 ((UINTN)&TisReg->DataFifo);
+ Index++;
+ if (Index == TpmOutSize) {
+ Status = EFI_SUCCESS;
+ goto Exit;
+ }
+ }
+ Status = TisPcReadBurstCount (TisReg, &BurstCount);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_TIMEOUT;
+ goto Exit;
+ }
+ }
+Exit:
+ MmioWrite8((UINTN)&TisReg->Status, TIS_PC_STS_READY);
+ return Status;
+}
+
diff --git a/Core/SecurityPkg/Tcg/TcgPei/TpmComm.c b/Core/SecurityPkg/Tcg/TcgPei/TpmComm.c
new file mode 100644
index 0000000000..899c8e3e0b
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TcgPei/TpmComm.c
@@ -0,0 +1,274 @@
+/** @file
+ Utility functions used by TPM PEI driver.
+
+Copyright (c) 2005 - 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 "TpmComm.h"
+
+/**
+ Send a command to TPM for execution and return response data.
+
+ @param[in] PeiServices Describes the list of possible PEI Services.
+ @param[in] TisReg TPM register space base address.
+ @param[in] BufferIn Buffer for command data.
+ @param[in] SizeIn Size of command data.
+ @param[in, out] BufferOut Buffer for response data.
+ @param[in, out] SizeOut size of response data.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_TIMEOUT The register can't run into the expected status in time.
+ @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+
+**/
+EFI_STATUS
+TisTpmCommand (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN TIS_PC_REGISTERS_PTR TisReg,
+ IN UINT8 *BufferIn,
+ IN UINT32 SizeIn,
+ IN OUT UINT8 *BufferOut,
+ IN OUT UINT32 *SizeOut
+ );
+
+/**
+ Send TPM_Startup command to TPM.
+
+ @param[in] PeiServices Describes the list of possible PEI Services.
+ @param[in] TpmHandle TPM handle.
+ @param[in] BootMode Boot mode.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_TIMEOUT The register can't run into the expected status in time.
+ @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+
+**/
+EFI_STATUS
+TpmCommStartup (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN TIS_TPM_HANDLE TpmHandle,
+ IN EFI_BOOT_MODE BootMode
+ )
+{
+ EFI_STATUS Status;
+ TPM_STARTUP_TYPE TpmSt;
+ UINT32 TpmRecvSize;
+ UINT32 TpmSendSize;
+ TPM_CMD_START_UP SendBuffer;
+ UINT8 RecvBuffer[20];
+
+ TpmSt = TPM_ST_CLEAR;
+ if (BootMode == BOOT_ON_S3_RESUME) {
+ TpmSt = TPM_ST_STATE;
+ }
+ //
+ // send Tpm command TPM_ORD_Startup
+ //
+ TpmRecvSize = 20;
+ TpmSendSize = sizeof (TPM_CMD_START_UP);
+ SendBuffer.Hdr.tag = SwapBytes16 (TPM_TAG_RQU_COMMAND);
+ SendBuffer.Hdr.paramSize = SwapBytes32 (TpmSendSize);
+ SendBuffer.Hdr.ordinal = SwapBytes32 (TPM_ORD_Startup);
+ SendBuffer.TpmSt = SwapBytes16 (TpmSt);
+ Status = TisTpmCommand (PeiServices, TpmHandle, (UINT8 *)&SendBuffer, TpmSendSize, RecvBuffer, &TpmRecvSize);
+ return Status;
+}
+
+/**
+ Send TPM_ContinueSelfTest command to TPM.
+
+ @param[in] PeiServices Describes the list of possible PEI Services.
+ @param[in] TpmHandle TPM handle.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_TIMEOUT The register can't run into the expected status in time.
+ @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+
+**/
+EFI_STATUS
+TpmCommContinueSelfTest (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN TIS_TPM_HANDLE TpmHandle
+ )
+{
+ EFI_STATUS Status;
+ UINT32 TpmRecvSize;
+ UINT32 TpmSendSize;
+ TPM_CMD_SELF_TEST SendBuffer;
+ UINT8 RecvBuffer[20];
+
+ //
+ // send Tpm command TPM_ORD_ContinueSelfTest
+ //
+ TpmRecvSize = 20;
+ TpmSendSize = sizeof (TPM_CMD_SELF_TEST);
+ SendBuffer.Hdr.tag = SwapBytes16 (TPM_TAG_RQU_COMMAND);
+ SendBuffer.Hdr.paramSize = SwapBytes32 (TpmSendSize);
+ SendBuffer.Hdr.ordinal = SwapBytes32 (TPM_ORD_ContinueSelfTest);
+ Status = TisTpmCommand (PeiServices, TpmHandle, (UINT8 *)&SendBuffer, TpmSendSize, RecvBuffer, &TpmRecvSize);
+ return Status;
+}
+
+/**
+ Get TPM capability flags.
+
+ @param[in] PeiServices Describes the list of possible PEI Services.
+ @param[in] TpmHandle TPM handle.
+ @param[out] Deactivated Returns deactivated flag.
+ @param[out] LifetimeLock Returns physicalPresenceLifetimeLock permanent flag.
+ @param[out] CmdEnable Returns physicalPresenceCMDEnable permanent flag.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_TIMEOUT The register can't run into the expected status in time.
+ @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+
+**/
+EFI_STATUS
+TpmCommGetCapability (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN TIS_TPM_HANDLE TpmHandle,
+ OUT BOOLEAN *Deactivated, OPTIONAL
+ OUT BOOLEAN *LifetimeLock, OPTIONAL
+ OUT BOOLEAN *CmdEnable OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ UINT32 TpmRecvSize;
+ UINT32 TpmSendSize;
+ TPM_CMD_GET_CAPABILITY SendBuffer;
+ UINT8 RecvBuffer[40];
+ TPM_PERMANENT_FLAGS *TpmPermanentFlags;
+
+ //
+ // send Tpm command TPM_ORD_GetCapability
+ //
+ TpmRecvSize = 40;
+ TpmSendSize = sizeof (TPM_CMD_GET_CAPABILITY);
+ SendBuffer.Hdr.tag = SwapBytes16 (TPM_TAG_RQU_COMMAND);
+ SendBuffer.Hdr.paramSize = SwapBytes32 (TpmSendSize);
+ SendBuffer.Hdr.ordinal = SwapBytes32 (TPM_ORD_GetCapability);
+ SendBuffer.Capability = SwapBytes32 (TPM_CAP_FLAG);
+ SendBuffer.CapabilityFlagSize = SwapBytes32 (sizeof (TPM_CAP_FLAG_PERMANENT));
+ SendBuffer.CapabilityFlag = SwapBytes32 (TPM_CAP_FLAG_PERMANENT);
+ Status = TisTpmCommand (PeiServices, TpmHandle, (UINT8 *)&SendBuffer, TpmSendSize, RecvBuffer, &TpmRecvSize);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ TpmPermanentFlags = (TPM_PERMANENT_FLAGS *)&RecvBuffer[sizeof (TPM_RSP_COMMAND_HDR) + sizeof (UINT32)];
+ if (Deactivated != NULL) {
+ *Deactivated = TpmPermanentFlags->deactivated;
+ }
+
+ if (LifetimeLock != NULL) {
+ *LifetimeLock = TpmPermanentFlags->physicalPresenceLifetimeLock;
+ }
+
+ if (CmdEnable != NULL) {
+ *CmdEnable = TpmPermanentFlags->physicalPresenceCMDEnable;
+ }
+ return Status;
+}
+
+/**
+ Extend a TPM PCR.
+
+ @param[in] PeiServices Describes the list of possible PEI Services.
+ @param[in] TpmHandle TPM handle.
+ @param[in] DigestToExtend The 160 bit value representing the event to be recorded.
+ @param[in] PcrIndex The PCR to be updated.
+ @param[out] NewPcrValue New PCR value after extend.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_TIMEOUT The register can't run into the expected status in time.
+ @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+
+**/
+EFI_STATUS
+TpmCommExtend (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN TIS_TPM_HANDLE TpmHandle,
+ IN TPM_DIGEST *DigestToExtend,
+ IN TPM_PCRINDEX PcrIndex,
+ OUT TPM_DIGEST *NewPcrValue
+ )
+{
+ EFI_STATUS Status;
+ UINT32 TpmSendSize;
+ UINT32 TpmRecvSize;
+ TPM_CMD_EXTEND SendBuffer;
+ UINT8 RecvBuffer[10 + sizeof(TPM_DIGEST)];
+
+ //
+ // send Tpm command TPM_ORD_Extend
+ //
+ TpmRecvSize = sizeof (TPM_RSP_COMMAND_HDR) + sizeof (TPM_DIGEST);
+ TpmSendSize = sizeof (TPM_CMD_EXTEND);
+ SendBuffer.Hdr.tag = SwapBytes16 (TPM_TAG_RQU_COMMAND);
+ SendBuffer.Hdr.paramSize = SwapBytes32 (TpmSendSize);
+ SendBuffer.Hdr.ordinal = SwapBytes32 (TPM_ORD_Extend);
+ SendBuffer.PcrIndex = SwapBytes32 (PcrIndex);
+ CopyMem (&SendBuffer.TpmDigest, (UINT8 *)DigestToExtend, sizeof (TPM_DIGEST));
+ Status = TisTpmCommand (PeiServices, TpmHandle, (UINT8 *)&SendBuffer, TpmSendSize, RecvBuffer, &TpmRecvSize);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if(NewPcrValue != NULL) {
+ CopyMem ((UINT8*)NewPcrValue, &RecvBuffer[10], sizeof (TPM_DIGEST));
+ }
+
+ return Status;
+}
+
+
+/**
+ Send TSC_PhysicalPresence command to TPM.
+
+ @param[in] PeiServices Describes the list of possible PEI Services.
+ @param[in] TpmHandle TPM handle.
+ @param[in] PhysicalPresence The state to set the TPMs Physical Presence flags.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_TIMEOUT The register can't run into the expected status in time.
+ @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+
+**/
+EFI_STATUS
+TpmCommPhysicalPresence (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN TIS_TPM_HANDLE TpmHandle,
+ IN TPM_PHYSICAL_PRESENCE PhysicalPresence
+ )
+{
+ EFI_STATUS Status;
+ UINT32 TpmSendSize;
+ UINT32 TpmRecvSize;
+ TPM_CMD_PHYSICAL_PRESENCE SendBuffer;
+ UINT8 RecvBuffer[10];
+
+ //
+ // send Tpm command TSC_ORD_PhysicalPresence
+ //
+ TpmRecvSize = 10;
+ TpmSendSize = sizeof (TPM_CMD_PHYSICAL_PRESENCE);
+ SendBuffer.Hdr.tag = SwapBytes16 (TPM_TAG_RQU_COMMAND);
+ SendBuffer.Hdr.paramSize = SwapBytes32 (TpmSendSize);
+ SendBuffer.Hdr.ordinal = SwapBytes32 (TSC_ORD_PhysicalPresence);
+ SendBuffer.PhysicalPresence = SwapBytes16 (PhysicalPresence);
+ Status = TisTpmCommand (PeiServices, TpmHandle, (UINT8 *)&SendBuffer, TpmSendSize, RecvBuffer, &TpmRecvSize);
+ return Status;
+}
diff --git a/Core/SecurityPkg/Tcg/TcgPei/TpmComm.h b/Core/SecurityPkg/Tcg/TcgPei/TpmComm.h
new file mode 100644
index 0000000000..52d7f2e20d
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TcgPei/TpmComm.h
@@ -0,0 +1,163 @@
+/** @file
+ The header file for TPM PEI driver.
+
+Copyright (c) 2005 - 2010, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _TPM_COMM_H_
+#define _TPM_COMM_H_
+
+#include <IndustryStandard/Tpm12.h>
+#include <IndustryStandard/UefiTcgPlatform.h>
+#include <Library/TpmCommLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+
+#pragma pack(1)
+
+typedef struct {
+ TPM_RQU_COMMAND_HDR Hdr;
+ TPM_STARTUP_TYPE TpmSt;
+} TPM_CMD_START_UP;
+
+typedef struct {
+ TPM_RQU_COMMAND_HDR Hdr;
+} TPM_CMD_SELF_TEST;
+
+typedef struct {
+ TPM_RQU_COMMAND_HDR Hdr;
+ UINT32 Capability;
+ UINT32 CapabilityFlagSize;
+ UINT32 CapabilityFlag;
+} TPM_CMD_GET_CAPABILITY;
+
+typedef struct {
+ TPM_RQU_COMMAND_HDR Hdr;
+ TPM_PCRINDEX PcrIndex;
+ TPM_DIGEST TpmDigest;
+} TPM_CMD_EXTEND;
+
+typedef struct {
+ TPM_RQU_COMMAND_HDR Hdr;
+ TPM_PHYSICAL_PRESENCE PhysicalPresence;
+} TPM_CMD_PHYSICAL_PRESENCE;
+
+#pragma pack()
+
+/**
+ Send TPM_Startup command to TPM.
+
+ @param[in] PeiServices Describes the list of possible PEI Services.
+ @param[in] TpmHandle TPM handle.
+ @param[in] BootMode Boot mode.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_TIMEOUT The register can't run into the expected status in time.
+ @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+
+**/
+EFI_STATUS
+TpmCommStartup (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN TIS_TPM_HANDLE TpmHandle,
+ IN EFI_BOOT_MODE BootMode
+ );
+
+/**
+ Send TPM_ContinueSelfTest command to TPM.
+
+ @param[in] PeiServices Describes the list of possible PEI Services.
+ @param[in] TpmHandle TPM handle.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_TIMEOUT The register can't run into the expected status in time.
+ @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+
+**/
+EFI_STATUS
+TpmCommContinueSelfTest (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN TIS_TPM_HANDLE TpmHandle
+ );
+
+/**
+ Get TPM capability flags.
+
+ @param[in] PeiServices Describes the list of possible PEI Services.
+ @param[in] TpmHandle TPM handle.
+ @param[out] Deactivated Returns deactivated flag.
+ @param[out] LifetimeLock Returns physicalPresenceLifetimeLock permanent flag.
+ @param[out] CmdEnable Returns physicalPresenceCMDEnable permanent flag.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_TIMEOUT The register can't run into the expected status in time.
+ @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+
+**/
+EFI_STATUS
+TpmCommGetCapability (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN TIS_TPM_HANDLE TpmHandle,
+ OUT BOOLEAN *Deactivated, OPTIONAL
+ OUT BOOLEAN *LifetimeLock, OPTIONAL
+ OUT BOOLEAN *CmdEnable OPTIONAL
+ );
+
+/**
+ Extend a TPM PCR.
+
+ @param[in] PeiServices Describes the list of possible PEI Services.
+ @param[in] TpmHandle TPM handle.
+ @param[in] DigestToExtend The 160 bit value representing the event to be recorded.
+ @param[in] PcrIndex The PCR to be updated.
+ @param[out] NewPcrValue New PCR value after extend.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_TIMEOUT The register can't run into the expected status in time.
+ @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+
+**/
+EFI_STATUS
+TpmCommExtend (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN TIS_TPM_HANDLE TpmHandle,
+ IN TPM_DIGEST *DigestToExtend,
+ IN TPM_PCRINDEX PcrIndex,
+ OUT TPM_DIGEST *NewPcrValue
+ );
+
+
+/**
+ Send TSC_PhysicalPresence command to TPM.
+
+ @param[in] PeiServices Describes the list of possible PEI Services.
+ @param[in] TpmHandle TPM handle.
+ @param[in] PhysicalPresence The state to set the TPMs Physical Presence flags.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_TIMEOUT The register can't run into the expected status in time.
+ @retval EFI_BUFFER_TOO_SMALL Response data buffer is too small.
+ @retval EFI_DEVICE_ERROR Unexpected device behavior.
+
+**/
+EFI_STATUS
+TpmCommPhysicalPresence (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN TIS_TPM_HANDLE TpmHandle,
+ IN TPM_PHYSICAL_PRESENCE PhysicalPresence
+ );
+
+#endif // _TPM_COMM_H_
diff --git a/Core/SecurityPkg/Tcg/TcgSmm/TcgSmm.c b/Core/SecurityPkg/Tcg/TcgSmm/TcgSmm.c
new file mode 100644
index 0000000000..96fb456ccd
--- /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 - 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 "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->PhysicalPresence.Request) {
+ 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..d8eb82fac7
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TcgSmm/TcgSmm.h
@@ -0,0 +1,104 @@
+/** @file
+ The header file for TCG SMM driver.
+
+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.
+
+**/
+
+#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;
+} 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..ec05642df0
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TcgSmm/TcgSmm.uni
Binary files differ
diff --git a/Core/SecurityPkg/Tcg/TcgSmm/TcgSmmExtra.uni b/Core/SecurityPkg/Tcg/TcgSmm/TcgSmmExtra.uni
new file mode 100644
index 0000000000..6c6ea75eb8
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TcgSmm/TcgSmmExtra.uni
Binary files differ
diff --git a/Core/SecurityPkg/Tcg/TcgSmm/Tpm.asl b/Core/SecurityPkg/Tcg/TcgSmm/Tpm.asl
new file mode 100644
index 0000000000..087ff9f792
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TcgSmm/Tpm.asl
@@ -0,0 +1,355 @@
+/** @file
+ The TPM definition block in ACPI table for physical presence
+ and MemoryClear.
+
+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.
+
+**/
+
+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
+ }
+
+ 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)), 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/TrEEConfig/TpmDetection.c b/Core/SecurityPkg/Tcg/TrEEConfig/TpmDetection.c
new file mode 100644
index 0000000000..54b1ff1128
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TrEEConfig/TpmDetection.c
@@ -0,0 +1,130 @@
+/** @file
+ TPM1.2/dTPM2.0 auto detection.
+
+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 <Ppi/ReadOnlyVariable2.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/IoLib.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 return if dTPM (1.2 or 2.0) present.
+
+ @retval TRUE dTPM present
+ @retval FALSE dTPM not present
+**/
+BOOLEAN
+IsDtpmPresent (
+ VOID
+ )
+{
+ UINT8 RegRead;
+
+ RegRead = MmioRead8 ((UINTN)PcdGet64 (PcdTpmBaseAddress));
+ if (RegRead == 0xFF) {
+ DEBUG ((EFI_D_ERROR, "DetectTpmDevice: Dtpm not present\n"));
+ return FALSE;
+ } else {
+ DEBUG ((EFI_D_INFO, "DetectTpmDevice: Dtpm present\n"));
+ return TRUE;
+ }
+}
+
+/**
+ 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"));
+ if (!IsDtpmPresent ()) {
+ // dTPM not available
+ return TPM_DEVICE_NULL;
+ }
+
+ // 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)) {
+ return TPM_DEVICE_2_0_DTPM;
+ }
+
+ 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..9935e40497
--- /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 ## 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..1e87cf42f1
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigDxe.uni
Binary files differ
diff --git a/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigDxeExtra.uni b/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigDxeExtra.uni
new file mode 100644
index 0000000000..a1e7854d24
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigDxeExtra.uni
Binary files differ
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..e8de529f8b
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigPei.inf
@@ -0,0 +1,78 @@
+## @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 - 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 = 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
+ IoLib
+ 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..185f4561fa
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigPei.uni
Binary files differ
diff --git a/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigPeiExtra.uni b/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigPeiExtra.uni
new file mode 100644
index 0000000000..0fbd287c21
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigPeiExtra.uni
Binary files differ
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..29c02e7f88
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigStrings.uni
Binary files differ
diff --git a/Core/SecurityPkg/Tcg/TrEEDxe/MeasureBootPeCoff.c b/Core/SecurityPkg/Tcg/TrEEDxe/MeasureBootPeCoff.c
new file mode 100644
index 0000000000..b20fc70ee0
--- /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 - 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 <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) ((UINT8 *)(&Hdr.Pe32->OptionalHeader.CheckSum) - HashBase);
+ } else {
+ //
+ // Use PE32+ offset
+ //
+ NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
+ HashSize = (UINTN) ((UINT8 *)(&Hdr.Pe32Plus->OptionalHeader.CheckSum) - 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) ((UINT8 *)(&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase);
+ } else {
+ //
+ // Use PE32+ offset
+ //
+ HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);
+ HashSize = (UINTN) ((UINT8 *)(&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase);
+ }
+
+ 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..674b53fd6b
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TrEEDxe/TrEEDxe.c
@@ -0,0 +1,1912 @@
+/** @file
+ This module implements TrEE Protocol.
+
+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 <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;
+}
+
+/**
+ This function get digest from digest list.
+
+ @param HashAlg digest algorithm
+ @param DigestList digest list
+ @param Digest digest
+
+ @retval EFI_SUCCESS Sha1Digest is found and returned.
+ @retval EFI_NOT_FOUND Sha1Digest is not found.
+**/
+EFI_STATUS
+Tpm2GetDigestFromDigestList (
+ IN TPMI_ALG_HASH HashAlg,
+ IN TPML_DIGEST_VALUES *DigestList,
+ IN 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;
+}
+
+/**
+ 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 = Tpm2GetDigestFromDigestList (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, "%s 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, "%s 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, "%s 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, "%s 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, "%s 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 ((EFI_D_ERROR, "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..d2cf8252cf
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TrEEDxe/TrEEDxe.uni
Binary files differ
diff --git a/Core/SecurityPkg/Tcg/TrEEDxe/TrEEDxeExtra.uni b/Core/SecurityPkg/Tcg/TrEEDxe/TrEEDxeExtra.uni
new file mode 100644
index 0000000000..1ad7a5111d
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TrEEDxe/TrEEDxeExtra.uni
Binary files differ
diff --git a/Core/SecurityPkg/Tcg/TrEEPei/TrEEPei.c b/Core/SecurityPkg/Tcg/TrEEPei/TrEEPei.c
new file mode 100644
index 0000000000..7a17b0a5da
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TrEEPei/TrEEPei.c
@@ -0,0 +1,725 @@
+/** @file
+ Initialize TPM2 device and measure FVs before handing off control to DXE.
+
+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 <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;
+
+/**
+ This function get digest from digest list.
+
+ @param HashAlg digest algorithm
+ @param DigestList digest list
+ @param Digest digest
+
+ @retval EFI_SUCCESS Sha1Digest is found and returned.
+ @retval EFI_NOT_FOUND Sha1Digest is not found.
+**/
+EFI_STATUS
+Tpm2GetDigestFromDigestList (
+ IN TPMI_ALG_HASH HashAlg,
+ IN TPML_DIGEST_VALUES *DigestList,
+ IN 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;
+}
+
+/**
+ 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 = Tpm2GetDigestFromDigestList (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 < FixedPcdGet32 (PcdPeiCoreMaxFvSupported));
+ if (mMeasuredBaseFvIndex < FixedPcdGet32 (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 < FixedPcdGet32 (PcdPeiCoreMaxFvSupported));
+ if (mMeasuredChildFvIndex < FixedPcdGet32 (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 ((EFI_D_ERROR, "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..ea9220cad0
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TrEEPei/TrEEPei.uni
Binary files differ
diff --git a/Core/SecurityPkg/Tcg/TrEEPei/TrEEPeiExtra.uni b/Core/SecurityPkg/Tcg/TrEEPei/TrEEPeiExtra.uni
new file mode 100644
index 0000000000..5256811dfb
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TrEEPei/TrEEPeiExtra.uni
Binary files differ
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..a522cd97c6
--- /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 - 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 "TrEESmm.h"
+
+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, // 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..f53ec41b8b
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TrEESmm/TrEESmm.uni
Binary files differ
diff --git a/Core/SecurityPkg/Tcg/TrEESmm/TrEESmmExtra.uni b/Core/SecurityPkg/Tcg/TrEESmm/TrEESmmExtra.uni
new file mode 100644
index 0000000000..91627bfcfa
--- /dev/null
+++ b/Core/SecurityPkg/Tcg/TrEESmm/TrEESmmExtra.uni
Binary files differ
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..2220bbfed9
--- /dev/null
+++ b/Core/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProvider.uni
Binary files differ
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..bc807c46f9
--- /dev/null
+++ b/Core/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderExtra.uni
Binary files differ
diff --git a/Core/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderStrings.uni b/Core/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderStrings.uni
new file mode 100644
index 0000000000..48573b6e8e
--- /dev/null
+++ b/Core/SecurityPkg/UserIdentification/PwdCredentialProviderDxe/PwdCredentialProviderStrings.uni
Binary files differ
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..2ad7920d81
--- /dev/null
+++ b/Core/SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProvider.uni
Binary files differ
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..4395e9d8a2
--- /dev/null
+++ b/Core/SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProviderExtra.uni
Binary files differ
diff --git a/Core/SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProviderStrings.uni b/Core/SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProviderStrings.uni
new file mode 100644
index 0000000000..1a3375f5c4
--- /dev/null
+++ b/Core/SecurityPkg/UserIdentification/UsbCredentialProviderDxe/UsbCredentialProviderStrings.uni
Binary files differ
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..28e60fde32
--- /dev/null
+++ b/Core/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManager.uni
Binary files differ
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..9c009518d4
--- /dev/null
+++ b/Core/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManagerExtra.uni
Binary files differ
diff --git a/Core/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManagerStrings.uni b/Core/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManagerStrings.uni
new file mode 100644
index 0000000000..8ae4489715
--- /dev/null
+++ b/Core/SecurityPkg/UserIdentification/UserIdentifyManagerDxe/UserIdentifyManagerStrings.uni
Binary files differ
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..9f157f816b
--- /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 funciton 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..afa420ea7b
--- /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 funciton 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..9302a8ed80
--- /dev/null
+++ b/Core/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManager.uni
Binary files differ
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..c29b9f5185
--- /dev/null
+++ b/Core/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManagerExtra.uni
Binary files differ
diff --git a/Core/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManagerStrings.uni b/Core/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManagerStrings.uni
new file mode 100644
index 0000000000..64631bb921
--- /dev/null
+++ b/Core/SecurityPkg/UserIdentification/UserProfileManagerDxe/UserProfileManagerStrings.uni
Binary files differ
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..8d690b00a0
--- /dev/null
+++ b/Core/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/EsalVariableDxeSal.uni
Binary files differ
diff --git a/Core/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/EsalVariableDxeSalExtra.uni b/Core/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/EsalVariableDxeSalExtra.uni
new file mode 100644
index 0000000000..a5d7333179
--- /dev/null
+++ b/Core/SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/EsalVariableDxeSalExtra.uni
Binary files differ
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..ee9a52a72e
--- /dev/null
+++ b/Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfig.vfr
@@ -0,0 +1,611 @@
+/** @file
+ VFR file used by the SecureBoot configuration component.
+
+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.
+
+**/
+
+#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 FORM_FILE_EXPLORER_ID_PK,
+ prompt = STRING_TOKEN(STR_SECURE_BOOT_ENROLL_PK_FILE),
+ help = STRING_TOKEN(STR_SECURE_BOOT_ENROLL_PK_FILE),
+ flags = INTERACTIVE,
+ key = SECUREBOOT_ADD_PK_FILE_FORM_ID;
+ 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 FORM_FILE_EXPLORER_ID_KEK,
+ 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 FORM_FILE_EXPLORER_ID_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 FORM_FILE_EXPLORER_ID_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);
+
+ 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;
+
+ oneof name = SignatureFormatInDbx,
+ 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 = 0x2, flags = DEFAULT;
+ option text = STRING_TOKEN(STR_DBX_CERTIFICATE_FORMAT_SHA384), value = 0x3, flags = 0;
+ option text = STRING_TOKEN(STR_DBX_CERTIFICATE_FORMAT_SHA512), value = 0x4, flags = 0;
+ option text = STRING_TOKEN(STR_DBX_CERTIFICATE_FORMAT_RAW), value = 0x5, flags = 0;
+ endoneof;
+
+ suppressif ideqval SECUREBOOT_CONFIGURATION.CertificateFormat == 5;
+ 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 FORM_FILE_EXPLORER_ID_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;
+
+ //
+ // File Explorer for PK
+ //
+ form formid = FORM_FILE_EXPLORER_ID_PK,
+ title = STRING_TOKEN(STR_FILE_EXPLORER_TITLE);
+
+ label FORM_FILE_EXPLORER_ID;
+ label LABEL_END;
+ endform;
+
+ //
+ // File Explorer for KEK
+ //
+ form formid = FORM_FILE_EXPLORER_ID_KEK,
+ title = STRING_TOKEN(STR_FILE_EXPLORER_TITLE);
+
+ label FORM_FILE_EXPLORER_ID;
+ label LABEL_END;
+ endform;
+
+ //
+ // File Explorer for DB
+ //
+ form formid = FORM_FILE_EXPLORER_ID_DB,
+ title = STRING_TOKEN(STR_FILE_EXPLORER_TITLE);
+
+ label FORM_FILE_EXPLORER_ID;
+ label LABEL_END;
+ endform;
+
+ //
+ // File Explorer for DBX
+ //
+ form formid = FORM_FILE_EXPLORER_ID_DBX,
+ title = STRING_TOKEN(STR_FILE_EXPLORER_TITLE);
+
+ label FORM_FILE_EXPLORER_ID;
+ label LABEL_END;
+ endform;
+
+ //
+ // File Explorer for DBT
+ //
+ form formid = FORM_FILE_EXPLORER_ID_DBT,
+ title = STRING_TOKEN(STR_FILE_EXPLORER_TITLE);
+
+ label FORM_FILE_EXPLORER_ID;
+ label LABEL_END;
+ endform;
+
+ //
+ // Enroll Pk from File Commit Form
+ //
+ form formid = SECUREBOOT_ADD_PK_FILE_FORM_ID,
+ title = STRING_TOKEN(STR_SAVE_PK_FILE);
+
+ label SECUREBOOT_ADD_PK_FILE_FORM_ID;
+ label LABEL_END;
+
+ subtitle text = STRING_TOKEN(STR_NULL);
+
+ text
+ help = STRING_TOKEN(STR_SAVE_AND_EXIT),
+ text = STRING_TOKEN(STR_SAVE_AND_EXIT),
+ text = STRING_TOKEN(STR_NULL),
+ flags = INTERACTIVE,
+ key = KEY_VALUE_SAVE_AND_EXIT_PK;
+
+ text
+ help = STRING_TOKEN(STR_NO_SAVE_AND_EXIT),
+ text = STRING_TOKEN(STR_NO_SAVE_AND_EXIT),
+ text = STRING_TOKEN(STR_NULL),
+ flags = INTERACTIVE,
+ key = KEY_VALUE_NO_SAVE_AND_EXIT_PK;
+
+ 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..c2234b73f2
--- /dev/null
+++ b/Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxe.inf
@@ -0,0 +1,126 @@
+## @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.
+#
+##
+
+[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
+ 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..61558d3382
--- /dev/null
+++ b/Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxe.uni
Binary files differ
diff --git a/Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxeExtra.uni b/Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxeExtra.uni
new file mode 100644
index 0000000000..6d2115ba87
--- /dev/null
+++ b/Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxeExtra.uni
Binary files differ
diff --git a/Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigFileExplorer.c b/Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigFileExplorer.c
new file mode 100644
index 0000000000..e1fd78db4e
--- /dev/null
+++ b/Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigFileExplorer.c
@@ -0,0 +1,1234 @@
+/** @file
+ Internal file explorer functions for SecureBoot configuration module.
+
+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 "SecureBootConfigImpl.h"
+
+///
+/// File system selection menu
+///
+SECUREBOOT_MENU_OPTION FsOptionMenu = {
+ SECUREBOOT_MENU_OPTION_SIGNATURE,
+ {NULL},
+ 0
+};
+
+///
+/// Files and sub-directories in current directory menu
+///
+SECUREBOOT_MENU_OPTION DirectoryMenu = {
+ SECUREBOOT_MENU_OPTION_SIGNATURE,
+ {NULL},
+ 0
+};
+
+VOID *mStartOpCodeHandle = NULL;
+VOID *mEndOpCodeHandle = NULL;
+EFI_IFR_GUID_LABEL *mStartLabel = NULL;
+EFI_IFR_GUID_LABEL *mEndLabel = NULL;
+
+/**
+ Duplicate a string.
+
+ @param[in] Src The source string.
+
+ @return A new string which is duplicated copy of the source,
+ or NULL if there is not enough memory.
+
+**/
+CHAR16 *
+StrDuplicate (
+ IN CHAR16 *Src
+ )
+{
+ CHAR16 *Dest;
+ UINTN Size;
+
+ Size = StrSize (Src);
+ Dest = AllocateZeroPool (Size);
+ ASSERT (Dest != NULL);
+ if (Dest != NULL) {
+ CopyMem (Dest, Src, Size);
+ }
+
+ return Dest;
+}
+
+/**
+ Helper function called as part of the code needed to allocate
+ the proper sized buffer for various EFI interfaces.
+
+ @param[in, out] Status Current status
+ @param[in, out] Buffer Current allocated buffer, or NULL
+ @param[in] BufferSize Current buffer size needed
+
+ @retval TRUE If the buffer was reallocated and the caller
+ should try the API again.
+ @retval FALSE The caller should not call this function again.
+
+**/
+BOOLEAN
+GrowBuffer (
+ IN OUT EFI_STATUS *Status,
+ IN OUT VOID **Buffer,
+ IN UINTN BufferSize
+ )
+{
+ BOOLEAN TryAgain;
+
+ //
+ // If this is an initial request, buffer will be null with a new buffer size
+ //
+ if ((*Buffer == NULL) && (BufferSize != 0)) {
+ *Status = EFI_BUFFER_TOO_SMALL;
+ }
+ //
+ // If the status code is "buffer too small", resize the buffer
+ //
+ TryAgain = FALSE;
+ if (*Status == EFI_BUFFER_TOO_SMALL) {
+
+ if (*Buffer != NULL) {
+ FreePool (*Buffer);
+ }
+
+ *Buffer = AllocateZeroPool (BufferSize);
+
+ if (*Buffer != NULL) {
+ TryAgain = TRUE;
+ } else {
+ *Status = EFI_OUT_OF_RESOURCES;
+ }
+ }
+ //
+ // If there's an error, free the buffer
+ //
+ if (!TryAgain && EFI_ERROR (*Status) && (*Buffer != NULL)) {
+ FreePool (*Buffer);
+ *Buffer = NULL;
+ }
+
+ return TryAgain;
+}
+
+/**
+ Append file name to existing file name, and allocate a new buffer
+ to hold the appended result.
+
+ @param[in] Str1 The existing file name
+ @param[in] Str2 The file name to be appended
+
+ @return A new string with appended result.
+
+**/
+CHAR16 *
+AppendFileName (
+ IN CHAR16 *Str1,
+ IN CHAR16 *Str2
+ )
+{
+ UINTN Size1;
+ UINTN Size2;
+ UINTN BufferSize;
+ CHAR16 *Str;
+ CHAR16 *TmpStr;
+ CHAR16 *Ptr;
+ CHAR16 *LastSlash;
+
+ Size1 = StrSize (Str1);
+ Size2 = StrSize (Str2);
+ BufferSize = Size1 + Size2 + sizeof (CHAR16);
+ Str = AllocateZeroPool (BufferSize);
+ ASSERT (Str != NULL);
+
+ TmpStr = AllocateZeroPool (BufferSize);
+ ASSERT (TmpStr != NULL);
+
+ StrCatS (Str, BufferSize / sizeof (CHAR16), Str1);
+
+ if (!((*Str == '\\') && (*(Str + 1) == 0))) {
+ StrCatS (Str, BufferSize / sizeof (CHAR16), L"\\");
+ }
+
+ StrCatS (Str, BufferSize / sizeof (CHAR16), Str2);
+
+ Ptr = Str;
+ LastSlash = Str;
+ while (*Ptr != 0) {
+ if (*Ptr == '\\' && *(Ptr + 1) == '.' && *(Ptr + 2) == '.' && *(Ptr + 3) == L'\\') {
+ //
+ // Convert "\Name\..\" to "\"
+ // DO NOT convert the .. if it is at the end of the string. This will
+ // break the .. behavior in changing directories.
+ //
+
+ //
+ // Use TmpStr as a backup, as StrCpyS in BaseLib does not handle copy of two strings
+ // that overlap.
+ //
+ StrCpyS (TmpStr, BufferSize / sizeof (CHAR16), Ptr + 3);
+ StrCpyS (LastSlash, BufferSize / sizeof (CHAR16), TmpStr);
+ Ptr = LastSlash;
+ } else if (*Ptr == '\\' && *(Ptr + 1) == '.' && *(Ptr + 2) == '\\') {
+ //
+ // Convert a "\.\" to a "\"
+ //
+
+ //
+ // Use TmpStr as a backup, as StrCpyS in BaseLib does not handle copy of two strings
+ // that overlap.
+ //
+ StrCpyS (TmpStr, BufferSize / sizeof (CHAR16), Ptr + 2);
+ StrCpyS (Ptr, BufferSize / sizeof (CHAR16), TmpStr);
+ Ptr = LastSlash;
+ } else if (*Ptr == '\\') {
+ LastSlash = Ptr;
+ }
+
+ Ptr++;
+ }
+
+ FreePool (TmpStr);
+
+ return Str;
+}
+
+/**
+ Create a SECUREBOOT_MENU_ENTRY, and stores it in a buffer allocated from the pool.
+
+ @return The new menu entry or NULL of error happens.
+
+**/
+SECUREBOOT_MENU_ENTRY *
+CreateMenuEntry (
+ VOID
+ )
+{
+ SECUREBOOT_MENU_ENTRY *MenuEntry;
+ UINTN ContextSize;
+
+ //
+ // Create new menu entry
+ //
+ MenuEntry = AllocateZeroPool (sizeof (SECUREBOOT_MENU_ENTRY));
+ if (MenuEntry == NULL) {
+ return NULL;
+ }
+
+ ContextSize = sizeof (SECUREBOOT_FILE_CONTEXT);
+ MenuEntry->FileContext = AllocateZeroPool (ContextSize);
+ if (MenuEntry->FileContext == NULL) {
+ FreePool (MenuEntry);
+ return NULL;
+ }
+
+ MenuEntry->Signature = SECUREBOOT_MENU_ENTRY_SIGNATURE;
+
+ return MenuEntry;
+}
+
+/**
+ Get Menu Entry from the Menu Entry List by MenuNumber.
+
+ If MenuNumber is great or equal to the number of Menu
+ Entry in the list, then ASSERT.
+
+ @param[in] MenuOption The Menu Entry List to read the menu entry.
+ @param[in] MenuNumber The index of Menu Entry.
+
+ @return The Menu Entry.
+
+**/
+SECUREBOOT_MENU_ENTRY *
+GetMenuEntry (
+ IN SECUREBOOT_MENU_OPTION *MenuOption,
+ IN UINTN MenuNumber
+ )
+{
+ SECUREBOOT_MENU_ENTRY *NewMenuEntry;
+ UINTN Index;
+ LIST_ENTRY *List;
+
+ ASSERT (MenuNumber < MenuOption->MenuNumber);
+
+ List = MenuOption->Head.ForwardLink;
+ for (Index = 0; Index < MenuNumber; Index++) {
+ List = List->ForwardLink;
+ }
+
+ NewMenuEntry = CR (List, SECUREBOOT_MENU_ENTRY, Link, SECUREBOOT_MENU_ENTRY_SIGNATURE);
+
+ return NewMenuEntry;
+}
+
+/**
+ Create string tokens for a menu from its help strings and display strings.
+
+ @param[in] HiiHandle Hii Handle of the package to be updated.
+ @param[in] MenuOption The Menu whose string tokens need to be created.
+
+**/
+VOID
+CreateMenuStringToken (
+ IN EFI_HII_HANDLE HiiHandle,
+ IN SECUREBOOT_MENU_OPTION *MenuOption
+ )
+{
+ SECUREBOOT_MENU_ENTRY *NewMenuEntry;
+ UINTN Index;
+
+ for (Index = 0; Index < MenuOption->MenuNumber; Index++) {
+ NewMenuEntry = GetMenuEntry (MenuOption, Index);
+
+ NewMenuEntry->DisplayStringToken = HiiSetString (
+ HiiHandle,
+ 0,
+ NewMenuEntry->DisplayString,
+ NULL
+ );
+
+ if (NewMenuEntry->HelpString == NULL) {
+ NewMenuEntry->HelpStringToken = NewMenuEntry->DisplayStringToken;
+ } else {
+ NewMenuEntry->HelpStringToken = HiiSetString (
+ HiiHandle,
+ 0,
+ NewMenuEntry->HelpString,
+ NULL
+ );
+ }
+ }
+}
+
+/**
+ Free up all resources allocated for a SECUREBOOT_MENU_ENTRY.
+
+ @param[in, out] MenuEntry A pointer to SECUREBOOT_MENU_ENTRY.
+
+**/
+VOID
+DestroyMenuEntry (
+ IN OUT SECUREBOOT_MENU_ENTRY *MenuEntry
+ )
+{
+ SECUREBOOT_FILE_CONTEXT *FileContext;
+
+
+ FileContext = (SECUREBOOT_FILE_CONTEXT *) MenuEntry->FileContext;
+
+ if (!FileContext->IsRoot && FileContext->DevicePath != NULL) {
+ FreePool (FileContext->DevicePath);
+ } else {
+ if (FileContext->FHandle != NULL) {
+ FileContext->FHandle->Close (FileContext->FHandle);
+ }
+ }
+
+ if (FileContext->FileName != NULL) {
+ FreePool (FileContext->FileName);
+ }
+ if (FileContext->Info != NULL) {
+ FreePool (FileContext->Info);
+ }
+
+ FreePool (FileContext);
+
+ if (MenuEntry->DisplayString != NULL) {
+ FreePool (MenuEntry->DisplayString);
+ }
+ if (MenuEntry->HelpString != NULL) {
+ FreePool (MenuEntry->HelpString);
+ }
+
+ FreePool (MenuEntry);
+}
+
+/**
+ Free resources allocated in Allocate Rountine.
+
+ @param[in, out] MenuOption Menu to be freed
+
+**/
+VOID
+FreeMenu (
+ IN OUT SECUREBOOT_MENU_OPTION *MenuOption
+ )
+{
+ SECUREBOOT_MENU_ENTRY *MenuEntry;
+ while (!IsListEmpty (&MenuOption->Head)) {
+ MenuEntry = CR (
+ MenuOption->Head.ForwardLink,
+ SECUREBOOT_MENU_ENTRY,
+ Link,
+ SECUREBOOT_MENU_ENTRY_SIGNATURE
+ );
+ RemoveEntryList (&MenuEntry->Link);
+ DestroyMenuEntry (MenuEntry);
+ }
+ MenuOption->MenuNumber = 0;
+}
+
+/**
+ This function gets the file information from an open file descriptor, and stores it
+ in a buffer allocated from pool.
+
+ @param[in] FHand File Handle.
+
+ @return A pointer to a buffer with file information or NULL is returned
+
+**/
+EFI_FILE_INFO *
+FileInfo (
+ IN EFI_FILE_HANDLE FHand
+ )
+{
+ EFI_STATUS Status;
+ EFI_FILE_INFO *Buffer;
+ UINTN BufferSize;
+
+ //
+ // Initialize for GrowBuffer loop
+ //
+ Buffer = NULL;
+ BufferSize = SIZE_OF_EFI_FILE_INFO + 200;
+
+ //
+ // Call the real function
+ //
+ while (GrowBuffer (&Status, (VOID **) &Buffer, BufferSize)) {
+ Status = FHand->GetInfo (
+ FHand,
+ &gEfiFileInfoGuid,
+ &BufferSize,
+ Buffer
+ );
+ }
+
+ return Buffer;
+}
+
+/**
+ This function gets the file system information from an open file descriptor,
+ and stores it in a buffer allocated from pool.
+
+ @param[in] FHand The file handle.
+
+ @return A pointer to a buffer with file information.
+ @retval NULL is returned if failed to get Vaolume Label Info.
+
+**/
+EFI_FILE_SYSTEM_VOLUME_LABEL *
+FileSystemVolumeLabelInfo (
+ IN EFI_FILE_HANDLE FHand
+ )
+{
+ EFI_STATUS Status;
+ EFI_FILE_SYSTEM_VOLUME_LABEL *Buffer;
+ UINTN BufferSize;
+ //
+ // Initialize for GrowBuffer loop
+ //
+ Buffer = NULL;
+ BufferSize = SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL + 200;
+
+ //
+ // Call the real function
+ //
+ while (GrowBuffer (&Status, (VOID **) &Buffer, BufferSize)) {
+ Status = FHand->GetInfo (
+ FHand,
+ &gEfiFileSystemVolumeLabelInfoIdGuid,
+ &BufferSize,
+ Buffer
+ );
+ }
+
+ return Buffer;
+}
+
+/**
+ 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;
+}
+
+/**
+ Function opens and returns a file handle to the root directory of a volume.
+
+ @param[in] DeviceHandle A handle for a device
+
+ @return A valid file handle or NULL if error happens.
+
+**/
+EFI_FILE_HANDLE
+OpenRoot (
+ IN EFI_HANDLE DeviceHandle
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Volume;
+ EFI_FILE_HANDLE File;
+
+ File = NULL;
+
+ //
+ // File the file system interface to the device
+ //
+ Status = gBS->HandleProtocol (
+ DeviceHandle,
+ &gEfiSimpleFileSystemProtocolGuid,
+ (VOID *) &Volume
+ );
+
+ //
+ // Open the root directory of the volume
+ //
+ if (!EFI_ERROR (Status)) {
+ Status = Volume->OpenVolume (
+ Volume,
+ &File
+ );
+ }
+ //
+ // Done
+ //
+ return EFI_ERROR (Status) ? NULL : File;
+}
+
+/**
+ This function builds the FsOptionMenu list which records all
+ available file system in the system. They include all instances
+ of EFI_SIMPLE_FILE_SYSTEM_PROTOCOL, all instances of EFI_LOAD_FILE_SYSTEM
+ and all type of legacy boot device.
+
+ @retval EFI_SUCCESS Success find the file system
+ @retval EFI_OUT_OF_RESOURCES Can not create menu entry
+
+**/
+EFI_STATUS
+FindFileSystem (
+ VOID
+ )
+{
+ UINTN NoBlkIoHandles;
+ UINTN NoSimpleFsHandles;
+ EFI_HANDLE *BlkIoHandle;
+ EFI_HANDLE *SimpleFsHandle;
+ UINT16 *VolumeLabel;
+ EFI_BLOCK_IO_PROTOCOL *BlkIo;
+ UINTN Index;
+ EFI_STATUS Status;
+ SECUREBOOT_MENU_ENTRY *MenuEntry;
+ SECUREBOOT_FILE_CONTEXT *FileContext;
+ UINT16 *TempStr;
+ UINTN OptionNumber;
+ VOID *Buffer;
+
+ BOOLEAN RemovableMedia;
+
+
+ NoSimpleFsHandles = 0;
+ OptionNumber = 0;
+ InitializeListHead (&FsOptionMenu.Head);
+
+ //
+ // Locate Handles that support BlockIo protocol
+ //
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiBlockIoProtocolGuid,
+ NULL,
+ &NoBlkIoHandles,
+ &BlkIoHandle
+ );
+ if (!EFI_ERROR (Status)) {
+
+ for (Index = 0; Index < NoBlkIoHandles; Index++) {
+ Status = gBS->HandleProtocol (
+ BlkIoHandle[Index],
+ &gEfiBlockIoProtocolGuid,
+ (VOID **) &BlkIo
+ );
+
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ //
+ // Issue a dummy read to trigger reinstall of BlockIo protocol for removable media
+ //
+ if (BlkIo->Media->RemovableMedia) {
+ Buffer = AllocateZeroPool (BlkIo->Media->BlockSize);
+ if (NULL == Buffer) {
+ FreePool (BlkIoHandle);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ BlkIo->ReadBlocks (
+ BlkIo,
+ BlkIo->Media->MediaId,
+ 0,
+ BlkIo->Media->BlockSize,
+ Buffer
+ );
+ FreePool (Buffer);
+ }
+ }
+ FreePool (BlkIoHandle);
+ }
+
+ //
+ // Locate Handles that support Simple File System protocol
+ //
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiSimpleFileSystemProtocolGuid,
+ NULL,
+ &NoSimpleFsHandles,
+ &SimpleFsHandle
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Find all the instances of the File System prototocol
+ //
+ for (Index = 0; Index < NoSimpleFsHandles; Index++) {
+ Status = gBS->HandleProtocol (
+ SimpleFsHandle[Index],
+ &gEfiBlockIoProtocolGuid,
+ (VOID **) &BlkIo
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // If no block IO exists assume it's NOT a removable media
+ //
+ RemovableMedia = FALSE;
+ } else {
+ //
+ // If block IO exists check to see if it's remobable media
+ //
+ RemovableMedia = BlkIo->Media->RemovableMedia;
+ }
+
+ //
+ // Allocate pool for this instance.
+ //
+ MenuEntry = CreateMenuEntry ();
+ if (NULL == MenuEntry) {
+ FreePool (SimpleFsHandle);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ FileContext = (SECUREBOOT_FILE_CONTEXT *) MenuEntry->FileContext;
+
+ FileContext->Handle = SimpleFsHandle[Index];
+ MenuEntry->OptionNumber = Index;
+ FileContext->FHandle = OpenRoot (FileContext->Handle);
+ if (FileContext->FHandle == NULL) {
+ DestroyMenuEntry (MenuEntry);
+ continue;
+ }
+
+ MenuEntry->HelpString = DevicePathToStr (DevicePathFromHandle (FileContext->Handle));
+ FileContext->Info = FileSystemVolumeLabelInfo (FileContext->FHandle);
+ FileContext->FileName = StrDuplicate (L"\\");
+ FileContext->DevicePath = FileDevicePath (
+ FileContext->Handle,
+ FileContext->FileName
+ );
+ FileContext->IsDir = TRUE;
+ FileContext->IsRoot = TRUE;
+ FileContext->IsRemovableMedia = RemovableMedia;
+ FileContext->IsLoadFile = FALSE;
+
+ //
+ // Get current file system's Volume Label
+ //
+ if (FileContext->Info == NULL) {
+ VolumeLabel = L"NO FILE SYSTEM INFO";
+ } else {
+ if (FileContext->Info->VolumeLabel == NULL) {
+ VolumeLabel = L"NULL VOLUME LABEL";
+ } else {
+ VolumeLabel = FileContext->Info->VolumeLabel;
+ if (*VolumeLabel == 0x0000) {
+ VolumeLabel = L"NO VOLUME LABEL";
+ }
+ }
+ }
+
+ TempStr = MenuEntry->HelpString;
+ MenuEntry->DisplayString = AllocateZeroPool (MAX_CHAR);
+ ASSERT (MenuEntry->DisplayString != NULL);
+ UnicodeSPrint (
+ MenuEntry->DisplayString,
+ MAX_CHAR,
+ L"%s, [%s]",
+ VolumeLabel,
+ TempStr
+ );
+ OptionNumber++;
+ InsertTailList (&FsOptionMenu.Head, &MenuEntry->Link);
+ }
+ }
+
+ if (NoSimpleFsHandles != 0) {
+ FreePool (SimpleFsHandle);
+ }
+
+ //
+ // Remember how many file system options are here
+ //
+ FsOptionMenu.MenuNumber = OptionNumber;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Find files under the current directory. All files and sub-directories
+ in current directory will be stored in DirectoryMenu for future use.
+
+ @param[in] MenuEntry The Menu Entry.
+
+ @retval EFI_SUCCESS Get files from current dir successfully.
+ @return Other Can't get files from current dir.
+
+**/
+EFI_STATUS
+FindFiles (
+ IN SECUREBOOT_MENU_ENTRY *MenuEntry
+ )
+{
+ EFI_FILE_HANDLE NewDir;
+ EFI_FILE_HANDLE Dir;
+ EFI_FILE_INFO *DirInfo;
+ UINTN BufferSize;
+ UINTN DirBufferSize;
+ SECUREBOOT_MENU_ENTRY *NewMenuEntry;
+ SECUREBOOT_FILE_CONTEXT *FileContext;
+ SECUREBOOT_FILE_CONTEXT *NewFileContext;
+ UINTN Pass;
+ EFI_STATUS Status;
+ UINTN OptionNumber;
+
+ FileContext = (SECUREBOOT_FILE_CONTEXT *) MenuEntry->FileContext;
+ Dir = FileContext->FHandle;
+ OptionNumber = 0;
+ //
+ // Open current directory to get files from it
+ //
+ Status = Dir->Open (
+ Dir,
+ &NewDir,
+ FileContext->FileName,
+ EFI_FILE_READ_ONLY,
+ 0
+ );
+ if (!FileContext->IsRoot) {
+ Dir->Close (Dir);
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ DirInfo = FileInfo (NewDir);
+ if (DirInfo == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ if ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ FileContext->DevicePath = FileDevicePath (
+ FileContext->Handle,
+ FileContext->FileName
+ );
+
+ DirBufferSize = sizeof (EFI_FILE_INFO) + 1024;
+ DirInfo = AllocateZeroPool (DirBufferSize);
+ if (DirInfo == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Get all files in current directory
+ // Pass 1 to get Directories
+ // Pass 2 to get files that are EFI images
+ //
+ for (Pass = 1; Pass <= 2; Pass++) {
+ NewDir->SetPosition (NewDir, 0);
+ for (;;) {
+ BufferSize = DirBufferSize;
+ Status = NewDir->Read (NewDir, &BufferSize, DirInfo);
+ if (EFI_ERROR (Status) || BufferSize == 0) {
+ break;
+ }
+
+ if (((DirInfo->Attribute & EFI_FILE_DIRECTORY) != 0 && Pass == 2) ||
+ ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == 0 && Pass == 1)
+ ) {
+ //
+ // Pass 1 is for Directories
+ // Pass 2 is for file names
+ //
+ continue;
+ }
+
+ NewMenuEntry = CreateMenuEntry ();
+ if (NULL == NewMenuEntry) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NewFileContext = (SECUREBOOT_FILE_CONTEXT *) NewMenuEntry->FileContext;
+ NewFileContext->Handle = FileContext->Handle;
+ NewFileContext->FileName = AppendFileName (
+ FileContext->FileName,
+ DirInfo->FileName
+ );
+ NewFileContext->FHandle = NewDir;
+ NewFileContext->DevicePath = FileDevicePath (
+ NewFileContext->Handle,
+ NewFileContext->FileName
+ );
+ NewMenuEntry->HelpString = NULL;
+
+ NewFileContext->IsDir = (BOOLEAN) ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == EFI_FILE_DIRECTORY);
+ if (NewFileContext->IsDir) {
+ BufferSize = StrLen (DirInfo->FileName) * 2 + 6;
+ NewMenuEntry->DisplayString = AllocateZeroPool (BufferSize);
+
+ UnicodeSPrint (
+ NewMenuEntry->DisplayString,
+ BufferSize,
+ L"<%s>",
+ DirInfo->FileName
+ );
+
+ } else {
+ NewMenuEntry->DisplayString = StrDuplicate (DirInfo->FileName);
+ }
+
+ NewFileContext->IsRoot = FALSE;
+ NewFileContext->IsLoadFile = FALSE;
+ NewFileContext->IsRemovableMedia = FALSE;
+
+ NewMenuEntry->OptionNumber = OptionNumber;
+ OptionNumber++;
+ InsertTailList (&DirectoryMenu.Head, &NewMenuEntry->Link);
+ }
+ }
+
+ DirectoryMenu.MenuNumber = OptionNumber;
+ FreePool (DirInfo);
+ return EFI_SUCCESS;
+}
+
+/**
+ 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;
+}
+
+/**
+ Update the File Explore page.
+
+ @param[in] HiiHandle Hii Handle of the package to be updated.
+ @param[in] MenuOption The Menu whose string tokens need to be updated.
+ @param[in] FeCurrentState Current file explorer state.
+
+**/
+VOID
+UpdateFileExplorePage (
+ IN EFI_HII_HANDLE HiiHandle,
+ IN SECUREBOOT_MENU_OPTION *MenuOption,
+ IN FILE_EXPLORER_STATE FeCurrentState
+ )
+{
+ UINTN Index;
+ SECUREBOOT_MENU_ENTRY *NewMenuEntry;
+ SECUREBOOT_FILE_CONTEXT *NewFileContext;
+ EFI_FORM_ID FormId;
+ EFI_FORM_ID FileFormId;
+
+ if (FeCurrentState == FileExplorerStateEnrollPkFile) {
+ FormId = SECUREBOOT_ADD_PK_FILE_FORM_ID;
+ FileFormId = FORM_FILE_EXPLORER_ID_PK;
+ } else if (FeCurrentState == FileExplorerStateEnrollKekFile) {
+ FormId = FORMID_ENROLL_KEK_FORM;
+ FileFormId = FORM_FILE_EXPLORER_ID_KEK;
+ } else if (FeCurrentState == FileExplorerStateEnrollSignatureFileToDb) {
+ FormId = SECUREBOOT_ENROLL_SIGNATURE_TO_DB;
+ FileFormId = FORM_FILE_EXPLORER_ID_DB;
+ } else if (FeCurrentState == FileExplorerStateEnrollSignatureFileToDbx) {
+ FormId = SECUREBOOT_ENROLL_SIGNATURE_TO_DBX;
+ FileFormId = FORM_FILE_EXPLORER_ID_DBX;
+ } else if (FeCurrentState == FileExplorerStateEnrollSignatureFileToDbt) {
+ FormId = SECUREBOOT_ENROLL_SIGNATURE_TO_DBT;
+ FileFormId = FORM_FILE_EXPLORER_ID_DBT;
+ } else {
+ return;
+ }
+
+ NewMenuEntry = NULL;
+ NewFileContext = NULL;
+
+ RefreshUpdateData ();
+ mStartLabel->Number = FORM_FILE_EXPLORER_ID;
+
+ for (Index = 0; Index < MenuOption->MenuNumber; Index++) {
+ NewMenuEntry = GetMenuEntry (MenuOption, Index);
+ NewFileContext = (SECUREBOOT_FILE_CONTEXT *) NewMenuEntry->FileContext;
+
+ if (NewFileContext->IsDir) {
+ //
+ // Create Text opcode for directory.
+ //
+ HiiCreateActionOpCode (
+ mStartOpCodeHandle,
+ (UINT16) (FILE_OPTION_OFFSET + Index),
+ NewMenuEntry->DisplayStringToken,
+ STRING_TOKEN (STR_NULL),
+ EFI_IFR_FLAG_CALLBACK,
+ 0
+ );
+ } else {
+
+ //
+ // Create Goto opcode for file.
+ //
+ HiiCreateGotoOpCode (
+ mStartOpCodeHandle,
+ FormId,
+ NewMenuEntry->DisplayStringToken,
+ STRING_TOKEN (STR_NULL),
+ EFI_IFR_FLAG_CALLBACK,
+ (UINT16) (FILE_OPTION_GOTO_OFFSET + Index)
+ );
+ }
+ }
+
+ HiiUpdateForm (
+ HiiHandle,
+ &gSecureBootConfigFormSetGuid,
+ FileFormId,
+ mStartOpCodeHandle, // Label FORM_FILE_EXPLORER_ID
+ mEndOpCodeHandle // LABEL_END
+ );
+}
+
+/**
+ Update the file explorer page with the refreshed file system.
+
+ @param[in] PrivateData Module private data.
+ @param[in] KeyValue Key value to identify the type of data to expect.
+
+ @retval TRUE Inform the caller to create a callback packet to exit file explorer.
+ @retval FALSE Indicate that there is no need to exit file explorer.
+
+**/
+BOOLEAN
+UpdateFileExplorer (
+ IN SECUREBOOT_CONFIG_PRIVATE_DATA *PrivateData,
+ IN UINT16 KeyValue
+ )
+{
+ UINT16 FileOptionMask;
+ SECUREBOOT_MENU_ENTRY *NewMenuEntry;
+ SECUREBOOT_FILE_CONTEXT *NewFileContext;
+ EFI_FORM_ID FormId;
+ BOOLEAN ExitFileExplorer;
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath;
+
+ NewMenuEntry = NULL;
+ NewFileContext = NULL;
+ ExitFileExplorer = FALSE;
+ FileOptionMask = (UINT16) (FILE_OPTION_MASK & KeyValue);
+
+ if (PrivateData->FeDisplayContext == FileExplorerDisplayUnknown) {
+ //
+ // First in, display file system.
+ //
+ FreeMenu (&FsOptionMenu);
+ FindFileSystem ();
+
+ CreateMenuStringToken (PrivateData->HiiHandle, &FsOptionMenu);
+ UpdateFileExplorePage (PrivateData->HiiHandle, &FsOptionMenu, PrivateData->FeCurrentState);
+
+ PrivateData->FeDisplayContext = FileExplorerDisplayFileSystem;
+ } else {
+ if (PrivateData->FeDisplayContext == FileExplorerDisplayFileSystem) {
+ NewMenuEntry = GetMenuEntry (&FsOptionMenu, FileOptionMask);
+ } else if (PrivateData->FeDisplayContext == FileExplorerDisplayDirectory) {
+ NewMenuEntry = GetMenuEntry (&DirectoryMenu, FileOptionMask);
+ }
+
+ NewFileContext = (SECUREBOOT_FILE_CONTEXT *) NewMenuEntry->FileContext;
+
+ if (NewFileContext->IsDir ) {
+ PrivateData->FeDisplayContext = FileExplorerDisplayDirectory;
+
+ RemoveEntryList (&NewMenuEntry->Link);
+ FreeMenu (&DirectoryMenu);
+ Status = FindFiles (NewMenuEntry);
+ if (EFI_ERROR (Status)) {
+ ExitFileExplorer = TRUE;
+ goto OnExit;
+ }
+ CreateMenuStringToken (PrivateData->HiiHandle, &DirectoryMenu);
+ DestroyMenuEntry (NewMenuEntry);
+
+ UpdateFileExplorePage (PrivateData->HiiHandle, &DirectoryMenu, PrivateData->FeCurrentState);
+
+ } else {
+ if (PrivateData->FeCurrentState == FileExplorerStateEnrollPkFile) {
+ FormId = SECUREBOOT_ADD_PK_FILE_FORM_ID;
+ } else if (PrivateData->FeCurrentState == FileExplorerStateEnrollKekFile) {
+ FormId = FORMID_ENROLL_KEK_FORM;
+ } else if (PrivateData->FeCurrentState == FileExplorerStateEnrollSignatureFileToDb) {
+ FormId = SECUREBOOT_ENROLL_SIGNATURE_TO_DB;
+ } else if (PrivateData->FeCurrentState == FileExplorerStateEnrollSignatureFileToDbx) {
+ FormId = SECUREBOOT_ENROLL_SIGNATURE_TO_DBX;
+ } else if (PrivateData->FeCurrentState == FileExplorerStateEnrollSignatureFileToDbt) {
+ FormId = SECUREBOOT_ENROLL_SIGNATURE_TO_DBT;
+ } else {
+ return FALSE;
+ }
+
+ PrivateData->MenuEntry = NewMenuEntry;
+ PrivateData->FileContext->FileName = NewFileContext->FileName;
+
+ TmpDevicePath = NewFileContext->DevicePath;
+ OpenFileByDevicePath (
+ &TmpDevicePath,
+ &PrivateData->FileContext->FHandle,
+ EFI_FILE_MODE_READ,
+ 0
+ );
+
+ //
+ // Create Subtitle op-code for the display string of the option.
+ //
+ RefreshUpdateData ();
+ mStartLabel->Number = FormId;
+
+ HiiCreateSubTitleOpCode (
+ mStartOpCodeHandle,
+ NewMenuEntry->DisplayStringToken,
+ 0,
+ 0,
+ 0
+ );
+
+ HiiUpdateForm (
+ PrivateData->HiiHandle,
+ &gSecureBootConfigFormSetGuid,
+ FormId,
+ mStartOpCodeHandle, // Label FormId
+ mEndOpCodeHandle // LABEL_END
+ );
+ }
+ }
+
+OnExit:
+ return ExitFileExplorer;
+}
+
+/**
+ 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
+ );
+}
diff --git a/Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigImpl.c b/Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigImpl.c
new file mode 100644
index 0000000000..2d4b4d7f76
--- /dev/null
+++ b/Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigImpl.c
@@ -0,0 +1,3833 @@
+/** @file
+ HII Config Access protocol implementation of SecureBoot configuration module.
+
+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 "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"SHA1", 20, &mHashOidValue[8], 5, Sha1GetContextSize, Sha1Init, Sha1Update, Sha1Final },
+ { L"SHA224", 28, &mHashOidValue[13], 9, NULL, NULL, NULL, NULL },
+ { L"SHA256", 32, &mHashOidValue[22], 9, Sha256GetContextSize, Sha256Init, Sha256Update, Sha256Final},
+ { L"SHA384", 48, &mHashOidValue[31], 9, 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";
+
+/**
+ 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;
+}
+
+/**
+ 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);
+ }
+
+ if (Private->FileContext->FHandle != NULL) {
+ CloseFile (Private->FileContext->FHandle);
+ Private->FileContext->FHandle = NULL;
+ }
+
+ 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:
+
+ CloseFile (Private->FileContext->FHandle);
+ Private->FileContext->FHandle = NULL;
+ Private->FileContext->FileName = NULL;
+
+ 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:
+
+ CloseFile (Private->FileContext->FHandle);
+ Private->FileContext->FileName = NULL;
+ Private->FileContext->FHandle = NULL;
+
+ 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->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 {
+ 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:
+
+ CloseFile (Private->FileContext->FHandle);
+ Private->FileContext->FileName = NULL;
+ Private->FileContext->FHandle = NULL;
+
+ 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:
+ CloseFile (Private->FileContext->FHandle);
+ Private->FileContext->FileName = NULL;
+ Private->FileContext->FHandle = NULL;
+
+ 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_SHA1) && (HashAlg != HASHALG_SHA256)) {
+ return FALSE;
+ }
+
+ //
+ // Initialize context of hash.
+ //
+ ZeroMem (mImageDigest, MAX_DIGEST_SIZE);
+
+ if (HashAlg == HASHALG_SHA1) {
+ mImageDigestSize = SHA1_DIGEST_SIZE;
+ mCertType = gEfiCertSha1Guid;
+ } else if (HashAlg == HASHALG_SHA256) {
+ mImageDigestSize = SHA256_DIGEST_SIZE;
+ mCertType = gEfiCertSha256Guid;
+ }
+
+ 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) ((UINT8 *) (&mNtHeader.Pe32->OptionalHeader.CheckSum) - HashBase);
+ } else {
+ //
+ // Use PE32+ offset.
+ //
+ HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32Plus->OptionalHeader.CheckSum) - HashBase);
+ }
+
+ Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);
+ if (!Status) {
+ goto Done;
+ }
+ //
+ // 5. Skip over the image checksum (it occupies a single ULONG).
+ // 6. Get the address of the beginning of the Cert Directory.
+ // 7. Hash everything from the end of the checksum to the start of the Cert Directory.
+ //
+ if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ //
+ // Use PE32 offset.
+ //
+ HashBase = (UINT8 *) &mNtHeader.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);
+ HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase);
+ } else {
+ //
+ // Use PE32+ offset.
+ //
+ HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);
+ HashSize = (UINTN) ((UINT8 *) (&mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - HashBase);
+ }
+
+ Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);
+ if (!Status) {
+ goto Done;
+ }
+ //
+ // 8. Skip over the Cert Directory. (It is sizeof(IMAGE_DATA_DIRECTORY) bytes.)
+ // 9. Hash everything from the end of the Cert Directory to the end of image header.
+ //
+ if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ //
+ // Use PE32 offset
+ //
+ HashBase = (UINT8 *) &mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];
+ HashSize = mNtHeader.Pe32->OptionalHeader.SizeOfHeaders - (UINTN) ((UINT8 *) (&mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]) - mImageBase);
+ } else {
+ //
+ // Use PE32+ offset.
+ //
+ HashBase = (UINT8 *) &mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];
+ HashSize = mNtHeader.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN) ((UINT8 *) (&mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]) - mImageBase);
+ }
+
+ Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);
+ if (!Status) {
+ goto Done;
+ }
+ //
+ // 10. Set the SUM_OF_BYTES_HASHED to the size of the header.
+ //
+ if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ //
+ // Use PE32 offset.
+ //
+ SumOfBytesHashed = mNtHeader.Pe32->OptionalHeader.SizeOfHeaders;
+ } else {
+ //
+ // Use PE32+ offset
+ //
+ SumOfBytesHashed = mNtHeader.Pe32Plus->OptionalHeader.SizeOfHeaders;
+ }
+
+ //
+ // 11. Build a temporary table of pointers to all the IMAGE_SECTION_HEADER
+ // structures in the image. The 'NumberOfSections' field of the image
+ // header indicates how big the table should be. Do not include any
+ // IMAGE_SECTION_HEADERs in the table whose 'SizeOfRawData' field is zero.
+ //
+ SectionHeader = (EFI_IMAGE_SECTION_HEADER *) AllocateZeroPool (sizeof (EFI_IMAGE_SECTION_HEADER) * mNtHeader.Pe32->FileHeader.NumberOfSections);
+ ASSERT (SectionHeader != NULL);
+ //
+ // 12. Using the 'PointerToRawData' in the referenced section headers as
+ // a key, arrange the elements in the table in ascending order. In other
+ // words, sort the section headers according to the disk-file offset of
+ // the section.
+ //
+ Section = (EFI_IMAGE_SECTION_HEADER *) (
+ mImageBase +
+ mPeCoffHeaderOffset +
+ sizeof (UINT32) +
+ sizeof (EFI_IMAGE_FILE_HEADER) +
+ mNtHeader.Pe32->FileHeader.SizeOfOptionalHeader
+ );
+ for (Index = 0; Index < mNtHeader.Pe32->FileHeader.NumberOfSections; Index++) {
+ Pos = Index;
+ while ((Pos > 0) && (Section->PointerToRawData < SectionHeader[Pos - 1].PointerToRawData)) {
+ CopyMem (&SectionHeader[Pos], &SectionHeader[Pos - 1], sizeof (EFI_IMAGE_SECTION_HEADER));
+ Pos--;
+ }
+ CopyMem (&SectionHeader[Pos], Section, sizeof (EFI_IMAGE_SECTION_HEADER));
+ Section += 1;
+ }
+
+ //
+ // 13. Walk through the sorted table, bring the corresponding section
+ // into memory, and hash the entire section (using the 'SizeOfRawData'
+ // field in the section header to determine the amount of data to hash).
+ // 14. Add the section's 'SizeOfRawData' to SUM_OF_BYTES_HASHED .
+ // 15. Repeat steps 13 and 14 for all the sections in the sorted table.
+ //
+ for (Index = 0; Index < mNtHeader.Pe32->FileHeader.NumberOfSections; Index++) {
+ Section = &SectionHeader[Index];
+ if (Section->SizeOfRawData == 0) {
+ continue;
+ }
+ HashBase = mImageBase + Section->PointerToRawData;
+ HashSize = (UINTN) Section->SizeOfRawData;
+
+ Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);
+ if (!Status) {
+ goto Done;
+ }
+
+ SumOfBytesHashed += HashSize;
+ }
+
+ //
+ // 16. If the file size is greater than SUM_OF_BYTES_HASHED, there is extra
+ // data in the file that needs to be added to the hash. This data begins
+ // at file offset SUM_OF_BYTES_HASHED and its length is:
+ // FileSize - (CertDirectory->Size)
+ //
+ if (mImageSize > SumOfBytesHashed) {
+ HashBase = mImageBase + SumOfBytesHashed;
+ if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ //
+ // Use PE32 offset.
+ //
+ HashSize = (UINTN)(
+ mImageSize -
+ mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size -
+ SumOfBytesHashed);
+ } else {
+ //
+ // Use PE32+ offset.
+ //
+ HashSize = (UINTN)(
+ mImageSize -
+ mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size -
+ SumOfBytesHashed);
+ }
+
+ Status = mHash[HashAlg].HashUpdate(HashCtx, HashBase, HashSize);
+ if (!Status) {
+ goto Done;
+ }
+ }
+
+ Status = mHash[HashAlg].HashFinal(HashCtx, mImageDigest);
+
+Done:
+ if (HashCtx != NULL) {
+ FreePool (HashCtx);
+ }
+ if (SectionHeader != NULL) {
+ FreePool (SectionHeader);
+ }
+ return Status;
+}
+
+/**
+ Recognize the Hash algorithm in PE/COFF Authenticode and 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
+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:
+
+ CloseFile (Private->FileContext->FHandle);
+ Private->FileContext->FHandle = NULL;
+ Private->FileContext->FileName = NULL;
+
+ 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);
+ }
+
+ 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
+ );
+}
+
+/**
+ This function extracts configuration from variable.
+
+ @param[in, out] ConfigData Point to SecureBoot configuration private data.
+
+**/
+VOID
+SecureBootExtractConfigFromVariable (
+ 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 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;
+ UINT8 *SecureBoot;
+
+ if (Progress == NULL || Results == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ AllocatedRequest = FALSE;
+ ConfigRequestHdr = NULL;
+ ConfigRequest = NULL;
+ Size = 0;
+ SecureBoot = NULL;
+
+ ZeroMem (&Configuration, sizeof (Configuration));
+ PrivateData = SECUREBOOT_CONFIG_PRIVATE_FROM_THIS (This);
+ *Progress = Request;
+
+ if ((Request != NULL) && !HiiIsConfigHdrMatch (Request, &gSecureBootConfigFormSetGuid, mSecureBootStorageName)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Get Configuration from Variable.
+ //
+ SecureBootExtractConfigFromVariable (&Configuration);
+
+ //
+ // Update current secure boot state.
+ //
+ GetVariable2 (EFI_SECURE_BOOT_MODE_NAME, &gEfiGlobalVariableGuid, (VOID**)&SecureBoot, NULL);
+ if (SecureBoot != NULL && *SecureBoot == SECURE_BOOT_MODE_ENABLE) {
+ HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_SECURE_BOOT_STATE_CONTENT), L"Enabled", NULL);
+ } else {
+ HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_SECURE_BOOT_STATE_CONTENT), L"Disabled", NULL);
+ }
+ if (SecureBoot != NULL) {
+ FreePool (SecureBoot);
+ }
+
+ 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;
+ EFI_STATUS Status;
+
+ if (Configuration == NULL || Progress == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *Progress = Configuration;
+ if (!HiiIsConfigHdrMatch (Configuration, &gSecureBootConfigFormSetGuid, mSecureBootStorageName)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Get Configuration from Variable.
+ //
+ SecureBootExtractConfigFromVariable (&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;
+ SECUREBOOT_CONFIG_PRIVATE_DATA *Private;
+ UINTN BufferSize;
+ SECUREBOOT_CONFIGURATION *IfrNvData;
+ UINT16 LabelId;
+ UINT8 *SecureBootEnable;
+ UINT8 *Pk;
+ UINT8 *SecureBootMode;
+ UINT8 *SetupMode;
+ CHAR16 PromptString[100];
+
+ SecureBootEnable = NULL;
+ SecureBootMode = NULL;
+ SetupMode = NULL;
+
+ if ((This == NULL) || (Value == NULL) || (ActionRequest == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Action == EFI_BROWSER_ACTION_FORM_OPEN) {
+ if (QuestionId == KEY_SECURE_BOOT_MODE) {
+ mIsEnterSecureBootForm = TRUE;
+ }
+
+ return EFI_SUCCESS;
+ }
+
+ 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;
+ }
+ }
+ return Status;
+ }
+
+ if ((Action != EFI_BROWSER_ACTION_CHANGED) &&
+ (Action != EFI_BROWSER_ACTION_CHANGING) &&
+ (Action != EFI_BROWSER_ACTION_FORM_CLOSE) &&
+ (Action != EFI_BROWSER_ACTION_DEFAULT_STANDARD)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Private = SECUREBOOT_CONFIG_PRIVATE_FROM_THIS (This);
+
+ //
+ // Retrieve uncommitted data from Browser
+ //
+ BufferSize = sizeof (SECUREBOOT_CONFIGURATION);
+ IfrNvData = AllocateZeroPool (BufferSize);
+ if (IfrNvData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = EFI_SUCCESS;
+
+ HiiGetBrowserData (&gSecureBootConfigFormSetGuid, mSecureBootStorageName, BufferSize, (UINT8 *) IfrNvData);
+
+ 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_OPTION:
+ FreeMenu (&DirectoryMenu);
+ FreeMenu (&FsOptionMenu);
+ 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:
+ //
+ // 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;
+ }
+ }
+
+ 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 SECUREBOOT_ADD_PK_FILE_FORM_ID:
+ case FORMID_ENROLL_KEK_FORM:
+ case SECUREBOOT_ENROLL_SIGNATURE_TO_DB:
+ case SECUREBOOT_ENROLL_SIGNATURE_TO_DBX:
+ case SECUREBOOT_ENROLL_SIGNATURE_TO_DBT:
+ if (QuestionId == SECUREBOOT_ADD_PK_FILE_FORM_ID) {
+ Private->FeCurrentState = FileExplorerStateEnrollPkFile;
+ } else if (QuestionId == FORMID_ENROLL_KEK_FORM) {
+ Private->FeCurrentState = FileExplorerStateEnrollKekFile;
+ } else if (QuestionId == SECUREBOOT_ENROLL_SIGNATURE_TO_DB) {
+ Private->FeCurrentState = FileExplorerStateEnrollSignatureFileToDb;
+ } else if (QuestionId == SECUREBOOT_ENROLL_SIGNATURE_TO_DBX) {
+ Private->FeCurrentState = FileExplorerStateEnrollSignatureFileToDbx;
+ IfrNvData->CertificateFormat = HASHALG_SHA256;
+ } else {
+ Private->FeCurrentState = FileExplorerStateEnrollSignatureFileToDbt;
+ }
+
+ Private->FeDisplayContext = FileExplorerDisplayUnknown;
+ CleanUpPage (FORM_FILE_EXPLORER_ID, Private);
+ UpdateFileExplorer (Private, 0);
+ 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
+ );
+ break;
+ }
+
+ if ((IfrNvData != NULL) && (IfrNvData->CertificateFormat < HASHALG_MAX)) {
+ Status = EnrollX509HashtoSigDB (
+ Private,
+ IfrNvData->CertificateFormat,
+ &IfrNvData->RevocationDate,
+ &IfrNvData->RevocationTime,
+ IfrNvData->AlwaysRevocation
+ );
+ } 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 and 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;
+
+ default:
+ if (QuestionId >= FILE_OPTION_GOTO_OFFSET) {
+ UpdateFileExplorer (Private, QuestionId);
+ } else 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;
+ }
+ } else if (Action == EFI_BROWSER_ACTION_CHANGED) {
+ switch (QuestionId) {
+ case KEY_SECURE_BOOT_ENABLE:
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;
+ 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
+ );
+ } else {
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_RESET;
+ }
+ 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:
+ if (Private->FileContext->FHandle != NULL) {
+ CloseFile (Private->FileContext->FHandle);
+ Private->FileContext->FHandle = NULL;
+ Private->FileContext->FileName = NULL;
+ }
+
+ if (Private->SignatureGUID != NULL) {
+ FreePool (Private->SignatureGUID);
+ Private->SignatureGUID = NULL;
+ }
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;
+ 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);
+ Status = StringToGuid (
+ IfrNvData->SignatureGuid,
+ StrLen (IfrNvData->SignatureGuid),
+ Private->SignatureGUID
+ );
+ if (EFI_ERROR (Status)) {
+ 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:
+ if (QuestionId >= FILE_OPTION_OFFSET && QuestionId < FILE_OPTION_GOTO_OFFSET) {
+ if (UpdateFileExplorer (Private, QuestionId)) {
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;
+ }
+ }
+ 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);
+ }
+ }
+
+ if (!EFI_ERROR (Status)) {
+ BufferSize = sizeof (SECUREBOOT_CONFIGURATION);
+ HiiSetBrowserData (&gSecureBootConfigFormSetGuid, mSecureBootStorageName, BufferSize, (UINT8*) IfrNvData, NULL);
+ }
+ FreePool (IfrNvData);
+
+ 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));
+ PrivateData->MenuEntry = AllocateZeroPool (sizeof (SECUREBOOT_MENU_ENTRY));
+
+ if (PrivateData->FileContext == NULL || PrivateData->MenuEntry == NULL) {
+ UninstallSecureBootConfigForm (PrivateData);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ PrivateData->FeCurrentState = FileExplorerStateInActive;
+ PrivateData->FeDisplayContext = FileExplorerDisplayUnknown;
+
+ InitializeListHead (&FsOptionMenu.Head);
+ InitializeListHead (&DirectoryMenu.Head);
+
+ //
+ // 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->MenuEntry != NULL) {
+ FreePool (PrivateData->MenuEntry);
+ }
+
+ if (PrivateData->FileContext != NULL) {
+ FreePool (PrivateData->FileContext);
+ }
+
+ FreePool (PrivateData);
+
+ FreeMenu (&DirectoryMenu);
+ FreeMenu (&FsOptionMenu);
+
+ 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..7d1458340c
--- /dev/null
+++ b/Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigImpl.h
@@ -0,0 +1,625 @@
+/** @file
+ The header file of HII Config Access protocol implementation of SecureBoot
+ configuration module.
+
+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 __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/PeCoffLib.h>
+#include <Guid/MdeModuleHii.h>
+#include <Guid/AuthenticatedVariableFormat.h>
+#include <Guid/FileSystemVolumeLabelInfo.h>
+#include <Guid/ImageAuthentication.h>
+#include <Guid/FileInfo.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-1 digest size in bytes.
+//
+#define SHA1_DIGEST_SIZE 20
+//
+// 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_SHA1 0x00000000
+#define HASHALG_SHA224 0x00000001
+#define HASHALG_SHA256 0x00000002
+#define HASHALG_SHA384 0x00000003
+#define HASHALG_SHA512 0x00000004
+#define HASHALG_RAW 0x00000005
+#define HASHALG_MAX 0x00000005
+
+
+#define SECUREBOOT_MENU_OPTION_SIGNATURE SIGNATURE_32 ('S', 'b', 'M', 'u')
+#define SECUREBOOT_MENU_ENTRY_SIGNATURE SIGNATURE_32 ('S', 'b', 'M', 'r')
+
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ EFI_GUID Guid;
+ UINT8 VendorDefinedData[1];
+} VENDOR_DEVICE_PATH_WITH_DATA;
+
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ UINT16 NetworkProtocol;
+ UINT16 LoginOption;
+ UINT64 Lun;
+ UINT16 TargetPortalGroupTag;
+ CHAR16 TargetName[1];
+} ISCSI_DEVICE_PATH_WITH_NAME;
+
+typedef enum _FILE_EXPLORER_DISPLAY_CONTEXT {
+ FileExplorerDisplayFileSystem,
+ FileExplorerDisplayDirectory,
+ FileExplorerDisplayUnknown
+} FILE_EXPLORER_DISPLAY_CONTEXT;
+
+typedef enum _FILE_EXPLORER_STATE {
+ FileExplorerStateInActive = 0,
+ FileExplorerStateEnrollPkFile,
+ FileExplorerStateEnrollKekFile,
+ FileExplorerStateEnrollSignatureFileToDb,
+ FileExplorerStateEnrollSignatureFileToDbx,
+ FileExplorerStateEnrollSignatureFileToDbt,
+ FileExplorerStateUnknown
+} FILE_EXPLORER_STATE;
+
+typedef struct {
+ CHAR16 *Str;
+ UINTN Len;
+ UINTN Maxlen;
+} POOL_PRINT;
+
+typedef
+VOID
+(*DEV_PATH_FUNCTION) (
+ IN OUT POOL_PRINT *Str,
+ IN VOID *DevPath
+ );
+
+typedef struct {
+ UINT8 Type;
+ UINT8 SubType;
+ DEV_PATH_FUNCTION Function;
+} DEVICE_PATH_STRING_TABLE;
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Head;
+ UINTN MenuNumber;
+} SECUREBOOT_MENU_OPTION;
+
+extern SECUREBOOT_MENU_OPTION FsOptionMenu;
+extern SECUREBOOT_MENU_OPTION DirectoryMenu;
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+ UINTN OptionNumber;
+ UINT16 *DisplayString;
+ UINT16 *HelpString;
+ EFI_STRING_ID DisplayStringToken;
+ EFI_STRING_ID HelpStringToken;
+ VOID *FileContext;
+} SECUREBOOT_MENU_ENTRY;
+
+typedef struct {
+ EFI_HANDLE Handle;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_FILE_HANDLE FHandle;
+ UINT16 *FileName;
+ EFI_FILE_SYSTEM_VOLUME_LABEL *Info;
+
+ BOOLEAN IsRoot;
+ BOOLEAN IsDir;
+ BOOLEAN IsRemovableMedia;
+ BOOLEAN IsLoadFile;
+ BOOLEAN IsBootLegacy;
+} 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;
+
+ FILE_EXPLORER_STATE FeCurrentState;
+ FILE_EXPLORER_DISPLAY_CONTEXT FeDisplayContext;
+
+ SECUREBOOT_MENU_ENTRY *MenuEntry;
+ SECUREBOOT_FILE_CONTEXT *FileContext;
+
+ EFI_GUID *SignatureGUID;
+} SECUREBOOT_CONFIG_PRIVATE_DATA;
+
+extern SECUREBOOT_CONFIG_PRIVATE_DATA mSecureBootConfigPrivateDateTemplate;
+
+#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
+ );
+
+
+/**
+ Update the file explorer page with the refreshed file system.
+
+ @param[in] PrivateData Module private data.
+ @param[in] KeyValue Key value to identify the type of data to expect.
+
+ @retval TRUE Inform the caller to create a callback packet to exit file explorer.
+ @retval FALSE Indicate that there is no need to exit file explorer.
+
+**/
+BOOLEAN
+UpdateFileExplorer (
+ IN SECUREBOOT_CONFIG_PRIVATE_DATA *PrivateData,
+ IN UINT16 KeyValue
+ );
+
+
+/**
+ Free resources allocated in Allocate Rountine.
+
+ @param[in, out] MenuOption Menu to be freed
+
+**/
+VOID
+FreeMenu (
+ IN OUT SECUREBOOT_MENU_OPTION *MenuOption
+ );
+
+
+/**
+ 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
+ );
+
+
+/**
+ Convert a String to Guid Value.
+
+ @param[in] Str Specifies the String to be converted.
+ @param[in] StrLen Number of Unicode Characters of String (exclusive \0)
+ @param[out] Guid Return the result Guid value.
+
+ @retval EFI_SUCCESS The operation is finished successfully.
+ @retval EFI_NOT_FOUND Invalid string.
+
+**/
+EFI_STATUS
+StringToGuid (
+ IN CHAR16 *Str,
+ IN UINTN StrLen,
+ OUT EFI_GUID *Guid
+ );
+
+
+/**
+ 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
+ );
+
+#endif \ No newline at end of file
diff --git a/Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigMisc.c b/Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigMisc.c
new file mode 100644
index 0000000000..a83504e787
--- /dev/null
+++ b/Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigMisc.c
@@ -0,0 +1,334 @@
+/** @file
+ Helper functions for SecureBoot 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 "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;
+}
+
+
+
+/**
+ Convert a String to Guid Value.
+
+ @param[in] Str Specifies the String to be converted.
+ @param[in] StrLen Number of Unicode Characters of String (exclusive \0)
+ @param[out] Guid Return the result Guid value.
+
+ @retval EFI_SUCCESS The operation is finished successfully.
+ @retval EFI_NOT_FOUND Invalid string.
+
+**/
+EFI_STATUS
+StringToGuid (
+ IN CHAR16 *Str,
+ IN UINTN StrLen,
+ OUT EFI_GUID *Guid
+ )
+{
+ CHAR16 *PtrBuffer;
+ CHAR16 *PtrPosition;
+ UINT16 *Buffer;
+ UINTN Data;
+ UINTN Index;
+ UINT16 Digits[3];
+
+ Buffer = (CHAR16 *) AllocateZeroPool (sizeof (CHAR16) * (StrLen + 1));
+ if (Buffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ StrCpyS (Buffer, (StrLen + 1), Str);
+
+ //
+ // Data1
+ //
+ PtrBuffer = Buffer;
+ PtrPosition = PtrBuffer;
+ while (*PtrBuffer != L'\0') {
+ if (*PtrBuffer == L'-') {
+ break;
+ }
+ PtrBuffer++;
+ }
+ if (*PtrBuffer == L'\0') {
+ FreePool (Buffer);
+ return EFI_NOT_FOUND;
+ }
+
+ *PtrBuffer = L'\0';
+ Data = StrHexToUintn (PtrPosition);
+ Guid->Data1 = (UINT32)Data;
+
+ //
+ // Data2
+ //
+ PtrBuffer++;
+ PtrPosition = PtrBuffer;
+ while (*PtrBuffer != L'\0') {
+ if (*PtrBuffer == L'-') {
+ break;
+ }
+ PtrBuffer++;
+ }
+ if (*PtrBuffer == L'\0') {
+ FreePool (Buffer);
+ return EFI_NOT_FOUND;
+ }
+ *PtrBuffer = L'\0';
+ Data = StrHexToUintn (PtrPosition);
+ Guid->Data2 = (UINT16)Data;
+
+ //
+ // Data3
+ //
+ PtrBuffer++;
+ PtrPosition = PtrBuffer;
+ while (*PtrBuffer != L'\0') {
+ if (*PtrBuffer == L'-') {
+ break;
+ }
+ PtrBuffer++;
+ }
+ if (*PtrBuffer == L'\0') {
+ FreePool (Buffer);
+ return EFI_NOT_FOUND;
+ }
+ *PtrBuffer = L'\0';
+ Data = StrHexToUintn (PtrPosition);
+ Guid->Data3 = (UINT16)Data;
+
+ //
+ // Data4[0..1]
+ //
+ for ( Index = 0 ; Index < 2 ; Index++) {
+ PtrBuffer++;
+ if ((*PtrBuffer == L'\0') || ( *(PtrBuffer + 1) == L'\0')) {
+ FreePool (Buffer);
+ return EFI_NOT_FOUND;
+ }
+ Digits[0] = *PtrBuffer;
+ PtrBuffer++;
+ Digits[1] = *PtrBuffer;
+ Digits[2] = L'\0';
+ Data = StrHexToUintn (Digits);
+ Guid->Data4[Index] = (UINT8)Data;
+ }
+
+ //
+ // skip the '-'
+ //
+ PtrBuffer++;
+ if ((*PtrBuffer != L'-' ) || ( *PtrBuffer == L'\0')) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Data4[2..7]
+ //
+ for ( ; Index < 8; Index++) {
+ PtrBuffer++;
+ if ((*PtrBuffer == L'\0') || ( *(PtrBuffer + 1) == L'\0')) {
+ FreePool (Buffer);
+ return EFI_NOT_FOUND;
+ }
+ Digits[0] = *PtrBuffer;
+ PtrBuffer++;
+ Digits[1] = *PtrBuffer;
+ Digits[2] = L'\0';
+ Data = StrHexToUintn (Digits);
+ Guid->Data4[Index] = (UINT8)Data;
+ }
+
+ FreePool (Buffer);
+
+ 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..e484d6b9c5
--- /dev/null
+++ b/Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigNvData.h
@@ -0,0 +1,136 @@
+/** @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 __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 FORM_FILE_EXPLORER_ID 0x0f
+#define FORM_FILE_EXPLORER_ID_PK 0x10
+#define FORM_FILE_EXPLORER_ID_KEK 0x11
+#define FORM_FILE_EXPLORER_ID_DB 0x12
+#define FORM_FILE_EXPLORER_ID_DBX 0x13
+#define FORMID_SECURE_BOOT_DBT_OPTION_FORM 0x14
+#define SECUREBOOT_ENROLL_SIGNATURE_TO_DBT 0x15
+#define SECUREBOOT_DELETE_SIGNATURE_FROM_DBT 0x16
+#define FORM_FILE_EXPLORER_ID_DBT 0x17
+
+#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 FILE_OPTION_GOTO_OFFSET 0xC000
+#define FILE_OPTION_OFFSET 0x8000
+#define FILE_OPTION_MASK 0x3FFF
+
+#define SECURE_BOOT_GUID_SIZE 36
+#define SECURE_BOOT_GUID_STORAGE_SIZE 37
+
+//
+// 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
+} 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..ce1c08105a
--- /dev/null
+++ b/Core/SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigStrings.uni
Binary files differ