From af874ef836cedf1034bc51eb65a99e9ea4fdc904 Mon Sep 17 00:00:00 2001 From: Guo Mang Date: Thu, 27 Apr 2017 11:09:17 +0800 Subject: SecurityPkg: Move to new location Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Guo Mang --- .../Tcg/MemoryOverwriteControl/TcgMor.c | 384 +++ .../Tcg/MemoryOverwriteControl/TcgMor.h | 48 + .../Tcg/MemoryOverwriteControl/TcgMor.inf | 67 + .../Tcg/MemoryOverwriteControl/TcgMor.uni | 21 + .../Tcg/MemoryOverwriteControl/TcgMorExtra.uni | 19 + .../MemoryOverwriteRequestControlLock/TcgMorLock.c | 197 ++ .../MemoryOverwriteRequestControlLock/TcgMorLock.h | 137 + .../TcgMorLock.uni | 21 + .../TcgMorLockExtra.uni | 19 + .../TcgMorLockSmm.c | 158 ++ .../TcgMorLockSmm.inf | 70 + .../Tcg/Opal/OpalPasswordDxe/ComponentName.c | 398 +++ .../Tcg/Opal/OpalPasswordDxe/OpalDriver.c | 1091 ++++++++ .../Tcg/Opal/OpalPasswordDxe/OpalDriver.h | 412 +++ .../Tcg/Opal/OpalPasswordDxe/OpalDriverPrivate.h | 102 + .../SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalHii.c | 1483 +++++++++++ .../SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalHii.h | 146 ++ .../Tcg/Opal/OpalPasswordDxe/OpalHiiCallbacks.c | 221 ++ .../Opal/OpalPasswordDxe/OpalHiiFormStrings.uni | 103 + .../Tcg/Opal/OpalPasswordDxe/OpalHiiFormValues.h | 120 + .../Tcg/Opal/OpalPasswordDxe/OpalHiiPrivate.h | 268 ++ .../Tcg/Opal/OpalPasswordDxe/OpalPasswordDxe.inf | 82 + .../Tcg/Opal/OpalPasswordDxe/OpalPasswordForm.vfr | 350 +++ .../Tcg/Opal/OpalPasswordSmm/OpalAhciMode.c | 1295 ++++++++++ .../Tcg/Opal/OpalPasswordSmm/OpalAhciMode.h | 408 +++ .../Tcg/Opal/OpalPasswordSmm/OpalIdeMode.c | 767 ++++++ .../Tcg/Opal/OpalPasswordSmm/OpalIdeMode.h | 173 ++ .../Tcg/Opal/OpalPasswordSmm/OpalNvmeMode.c | 2165 ++++++++++++++++ .../Tcg/Opal/OpalPasswordSmm/OpalNvmeMode.h | 456 ++++ .../Tcg/Opal/OpalPasswordSmm/OpalNvmeReg.h | 814 ++++++ .../Tcg/Opal/OpalPasswordSmm/OpalPasswordSmm.c | 1139 +++++++++ .../Tcg/Opal/OpalPasswordSmm/OpalPasswordSmm.h | 300 +++ .../Tcg/Opal/OpalPasswordSmm/OpalPasswordSmm.inf | 77 + .../Tcg/PhysicalPresencePei/PhysicalPresencePei.c | 134 + .../PhysicalPresencePei/PhysicalPresencePei.inf | 64 + .../PhysicalPresencePei/PhysicalPresencePei.uni | 23 + .../PhysicalPresencePeiExtra.uni | 19 + Core/SecurityPkg/Tcg/Tcg2Config/Tcg2Config.vfr | 250 ++ Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDriver.c | 461 ++++ Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDxe.inf | 91 + Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDxe.uni | 22 + .../Tcg/Tcg2Config/Tcg2ConfigDxeExtra.uni | 19 + Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigImpl.c | 1032 ++++++++ Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigImpl.h | 201 ++ Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigNvData.h | 129 + Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPei.inf | 77 + Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPei.uni | 23 + .../Tcg/Tcg2Config/Tcg2ConfigPeiExtra.uni | 19 + Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPeim.c | 159 ++ .../Tcg/Tcg2Config/Tcg2ConfigStrings.uni | 138 ++ Core/SecurityPkg/Tcg/Tcg2Config/TpmDetection.c | 105 + Core/SecurityPkg/Tcg/Tcg2Dxe/MeasureBootPeCoff.c | 427 ++++ Core/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c | 2621 ++++++++++++++++++++ Core/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.inf | 112 + Core/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.uni | 26 + Core/SecurityPkg/Tcg/Tcg2Dxe/Tcg2DxeExtra.uni | 17 + Core/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.c | 854 +++++++ Core/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.inf | 92 + Core/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.uni | 21 + Core/SecurityPkg/Tcg/Tcg2Pei/Tcg2PeiExtra.uni | 19 + Core/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.c | 649 +++++ Core/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.h | 105 + Core/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.inf | 86 + Core/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.uni | 28 + Core/SecurityPkg/Tcg/Tcg2Smm/Tcg2SmmExtra.uni | 19 + Core/SecurityPkg/Tcg/Tcg2Smm/Tpm.asl | 368 +++ Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfig.vfr | 74 + .../SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDriver.c | 156 ++ Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDxe.inf | 83 + Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDxe.uni | 21 + .../Tcg/TcgConfigDxe/TcgConfigDxeExtra.uni | 19 + Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigImpl.c | 509 ++++ Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigImpl.h | 194 ++ .../SecurityPkg/Tcg/TcgConfigDxe/TcgConfigNvData.h | 39 + .../Tcg/TcgConfigDxe/TcgConfigStrings.uni | 40 + Core/SecurityPkg/Tcg/TcgDxe/TcgDxe.c | 1467 +++++++++++ Core/SecurityPkg/Tcg/TcgDxe/TcgDxe.inf | 86 + Core/SecurityPkg/Tcg/TcgDxe/TcgDxe.uni | 21 + Core/SecurityPkg/Tcg/TcgDxe/TcgDxeExtra.uni | 19 + Core/SecurityPkg/Tcg/TcgPei/TcgPei.c | 841 +++++++ Core/SecurityPkg/Tcg/TcgPei/TcgPei.inf | 93 + Core/SecurityPkg/Tcg/TcgPei/TcgPei.uni | 22 + Core/SecurityPkg/Tcg/TcgPei/TcgPeiExtra.uni | 19 + Core/SecurityPkg/Tcg/TcgSmm/TcgSmm.c | 465 ++++ Core/SecurityPkg/Tcg/TcgSmm/TcgSmm.h | 105 + Core/SecurityPkg/Tcg/TcgSmm/TcgSmm.inf | 83 + Core/SecurityPkg/Tcg/TcgSmm/TcgSmm.uni | 27 + Core/SecurityPkg/Tcg/TcgSmm/TcgSmmExtra.uni | 19 + Core/SecurityPkg/Tcg/TcgSmm/Tpm.asl | 356 +++ Core/SecurityPkg/Tcg/TrEEConfig/TpmDetection.c | 105 + Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfig.vfr | 68 + Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigDriver.c | 216 ++ Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigDxe.inf | 88 + Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigDxe.uni | 22 + .../Tcg/TrEEConfig/TrEEConfigDxeExtra.uni | 19 + Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigImpl.c | 344 +++ Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigImpl.h | 193 ++ Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigNvData.h | 76 + Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigPei.inf | 77 + Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigPei.uni | 23 + .../Tcg/TrEEConfig/TrEEConfigPeiExtra.uni | 19 + Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigPeim.c | 159 ++ .../Tcg/TrEEConfig/TrEEConfigStrings.uni | 40 + Core/SecurityPkg/Tcg/TrEEDxe/MeasureBootPeCoff.c | 427 ++++ Core/SecurityPkg/Tcg/TrEEDxe/TrEEDxe.c | 1877 ++++++++++++++ Core/SecurityPkg/Tcg/TrEEDxe/TrEEDxe.inf | 104 + Core/SecurityPkg/Tcg/TrEEDxe/TrEEDxe.uni | 26 + Core/SecurityPkg/Tcg/TrEEDxe/TrEEDxeExtra.uni | 17 + Core/SecurityPkg/Tcg/TrEEPei/TrEEPei.c | 690 ++++++ Core/SecurityPkg/Tcg/TrEEPei/TrEEPei.inf | 86 + Core/SecurityPkg/Tcg/TrEEPei/TrEEPei.uni | 21 + Core/SecurityPkg/Tcg/TrEEPei/TrEEPeiExtra.uni | 19 + Core/SecurityPkg/Tcg/TrEESmm/Tpm.asl | 354 +++ Core/SecurityPkg/Tcg/TrEESmm/TrEESmm.c | 521 ++++ Core/SecurityPkg/Tcg/TrEESmm/TrEESmm.h | 105 + Core/SecurityPkg/Tcg/TrEESmm/TrEESmm.inf | 85 + Core/SecurityPkg/Tcg/TrEESmm/TrEESmm.uni | 28 + Core/SecurityPkg/Tcg/TrEESmm/TrEESmmExtra.uni | 19 + 118 files changed, 32507 insertions(+) create mode 100644 Core/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.c create mode 100644 Core/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.h create mode 100644 Core/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.inf create mode 100644 Core/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.uni create mode 100644 Core/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMorExtra.uni create mode 100644 Core/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLock.c create mode 100644 Core/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLock.h create mode 100644 Core/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLock.uni create mode 100644 Core/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLockExtra.uni create mode 100644 Core/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLockSmm.c create mode 100644 Core/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLockSmm.inf create mode 100644 Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/ComponentName.c create mode 100644 Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalDriver.c create mode 100644 Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalDriver.h create mode 100644 Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalDriverPrivate.h create mode 100644 Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalHii.c create mode 100644 Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalHii.h create mode 100644 Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalHiiCallbacks.c create mode 100644 Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalHiiFormStrings.uni create mode 100644 Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalHiiFormValues.h create mode 100644 Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalHiiPrivate.h create mode 100644 Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalPasswordDxe.inf create mode 100644 Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalPasswordForm.vfr create mode 100644 Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalAhciMode.c create mode 100644 Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalAhciMode.h create mode 100644 Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalIdeMode.c create mode 100644 Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalIdeMode.h create mode 100644 Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalNvmeMode.c create mode 100644 Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalNvmeMode.h create mode 100644 Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalNvmeReg.h create mode 100644 Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalPasswordSmm.c create mode 100644 Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalPasswordSmm.h create mode 100644 Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalPasswordSmm.inf create mode 100644 Core/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePei.c create mode 100644 Core/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePei.inf create mode 100644 Core/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePei.uni create mode 100644 Core/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePeiExtra.uni create mode 100644 Core/SecurityPkg/Tcg/Tcg2Config/Tcg2Config.vfr create mode 100644 Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDriver.c create mode 100644 Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDxe.inf create mode 100644 Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDxe.uni create mode 100644 Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDxeExtra.uni create mode 100644 Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigImpl.c create mode 100644 Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigImpl.h create mode 100644 Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigNvData.h create mode 100644 Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPei.inf create mode 100644 Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPei.uni create mode 100644 Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPeiExtra.uni create mode 100644 Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPeim.c create mode 100644 Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigStrings.uni create mode 100644 Core/SecurityPkg/Tcg/Tcg2Config/TpmDetection.c create mode 100644 Core/SecurityPkg/Tcg/Tcg2Dxe/MeasureBootPeCoff.c create mode 100644 Core/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c create mode 100644 Core/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.inf create mode 100644 Core/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.uni create mode 100644 Core/SecurityPkg/Tcg/Tcg2Dxe/Tcg2DxeExtra.uni create mode 100644 Core/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.c create mode 100644 Core/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.inf create mode 100644 Core/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.uni create mode 100644 Core/SecurityPkg/Tcg/Tcg2Pei/Tcg2PeiExtra.uni create mode 100644 Core/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.c create mode 100644 Core/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.h create mode 100644 Core/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.inf create mode 100644 Core/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.uni create mode 100644 Core/SecurityPkg/Tcg/Tcg2Smm/Tcg2SmmExtra.uni create mode 100644 Core/SecurityPkg/Tcg/Tcg2Smm/Tpm.asl create mode 100644 Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfig.vfr create mode 100644 Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDriver.c create mode 100644 Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDxe.inf create mode 100644 Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDxe.uni create mode 100644 Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDxeExtra.uni create mode 100644 Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigImpl.c create mode 100644 Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigImpl.h create mode 100644 Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigNvData.h create mode 100644 Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigStrings.uni create mode 100644 Core/SecurityPkg/Tcg/TcgDxe/TcgDxe.c create mode 100644 Core/SecurityPkg/Tcg/TcgDxe/TcgDxe.inf create mode 100644 Core/SecurityPkg/Tcg/TcgDxe/TcgDxe.uni create mode 100644 Core/SecurityPkg/Tcg/TcgDxe/TcgDxeExtra.uni create mode 100644 Core/SecurityPkg/Tcg/TcgPei/TcgPei.c create mode 100644 Core/SecurityPkg/Tcg/TcgPei/TcgPei.inf create mode 100644 Core/SecurityPkg/Tcg/TcgPei/TcgPei.uni create mode 100644 Core/SecurityPkg/Tcg/TcgPei/TcgPeiExtra.uni create mode 100644 Core/SecurityPkg/Tcg/TcgSmm/TcgSmm.c create mode 100644 Core/SecurityPkg/Tcg/TcgSmm/TcgSmm.h create mode 100644 Core/SecurityPkg/Tcg/TcgSmm/TcgSmm.inf create mode 100644 Core/SecurityPkg/Tcg/TcgSmm/TcgSmm.uni create mode 100644 Core/SecurityPkg/Tcg/TcgSmm/TcgSmmExtra.uni create mode 100644 Core/SecurityPkg/Tcg/TcgSmm/Tpm.asl create mode 100644 Core/SecurityPkg/Tcg/TrEEConfig/TpmDetection.c create mode 100644 Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfig.vfr create mode 100644 Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigDriver.c create mode 100644 Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigDxe.inf create mode 100644 Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigDxe.uni create mode 100644 Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigDxeExtra.uni create mode 100644 Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigImpl.c create mode 100644 Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigImpl.h create mode 100644 Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigNvData.h create mode 100644 Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigPei.inf create mode 100644 Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigPei.uni create mode 100644 Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigPeiExtra.uni create mode 100644 Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigPeim.c create mode 100644 Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigStrings.uni create mode 100644 Core/SecurityPkg/Tcg/TrEEDxe/MeasureBootPeCoff.c create mode 100644 Core/SecurityPkg/Tcg/TrEEDxe/TrEEDxe.c create mode 100644 Core/SecurityPkg/Tcg/TrEEDxe/TrEEDxe.inf create mode 100644 Core/SecurityPkg/Tcg/TrEEDxe/TrEEDxe.uni create mode 100644 Core/SecurityPkg/Tcg/TrEEDxe/TrEEDxeExtra.uni create mode 100644 Core/SecurityPkg/Tcg/TrEEPei/TrEEPei.c create mode 100644 Core/SecurityPkg/Tcg/TrEEPei/TrEEPei.inf create mode 100644 Core/SecurityPkg/Tcg/TrEEPei/TrEEPei.uni create mode 100644 Core/SecurityPkg/Tcg/TrEEPei/TrEEPeiExtra.uni create mode 100644 Core/SecurityPkg/Tcg/TrEESmm/Tpm.asl create mode 100644 Core/SecurityPkg/Tcg/TrEESmm/TrEESmm.c create mode 100644 Core/SecurityPkg/Tcg/TrEESmm/TrEESmm.h create mode 100644 Core/SecurityPkg/Tcg/TrEESmm/TrEESmm.inf create mode 100644 Core/SecurityPkg/Tcg/TrEESmm/TrEESmm.uni create mode 100644 Core/SecurityPkg/Tcg/TrEESmm/TrEESmmExtra.uni (limited to 'Core/SecurityPkg/Tcg') 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.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE 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.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __TCG_MOR_H__ +#define __TCG_MOR_H__ + +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +// +// Supported Security Protocols List Description. +// Refer to ATA8-ACS Spec 7.57.6.2 Table 69 or SPC4 7.7.1.3 Table 511. +// +typedef struct { + UINT8 Reserved1[6]; + UINT8 SupportedSecurityListLength[2]; + UINT8 SupportedSecurityProtocol[1]; +} SUPPORTED_SECURITY_PROTOCOLS_PARAMETER_DATA; + +#define SECURITY_PROTOCOL_TCG 0x02 +#define SECURITY_PROTOCOL_IEEE1667 0xEE + +#define ROUNDUP512(x) (((x) % 512 == 0) ? (x) : ((x) / 512 + 1) * 512) + +#endif + diff --git a/Core/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.inf b/Core/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.inf new file mode 100644 index 0000000000..a131342bb6 --- /dev/null +++ b/Core/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.inf @@ -0,0 +1,67 @@ +## @file +# Initilizes MemoryOverwriteRequestControl variable +# +# This module will clear MOR_CLEAR_MEMORY_BIT bit if it is set. It will also do +# TPer Reset for those encrypted drives through EFI_STORAGE_SECURITY_COMMAND_PROTOCOL +# at EndOfDxe. +# +# Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = TcgMor + MODULE_UNI_FILE = TcgMor.uni + FILE_GUID = AD416CE3-A483-45b1-94C2-4B4E4D575562 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + + ENTRY_POINT = MorDriverEntryPoint + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + TcgMor.c + TcgMor.h + +[Packages] + MdePkg/MdePkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + UefiDriverEntryPoint + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + ReportStatusCodeLib + DebugLib + UefiLib + MemoryAllocationLib + +[Guids] + ## SOMETIMES_CONSUMES ## Variable:L"MemoryOverwriteRequestControl" + ## PRODUCES ## Variable:L"MemoryOverwriteRequestControl" + gEfiMemoryOverwriteControlDataGuid + gEfiEndOfDxeEventGroupGuid ## SOMETIMES_CONSUMES ## Event + +[Protocols] + gEfiStorageSecurityCommandProtocolGuid ## SOMETIMES_CONSUMES + gEfiBlockIoProtocolGuid ## SOMETIMES_CONSUMES + +[Depex] + gEfiVariableArchProtocolGuid AND + gEfiVariableWriteArchProtocolGuid AND + ( gEfiTcgProtocolGuid OR gEfiTcg2ProtocolGuid ) + +[UserExtensions.TianoCore."ExtraFiles"] + TcgMorExtra.uni diff --git a/Core/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.uni b/Core/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.uni new file mode 100644 index 0000000000..fc6d92ae98 --- /dev/null +++ b/Core/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.uni @@ -0,0 +1,21 @@ +// /** @file +// Initilizes MemoryOverwriteRequestControl variable +// +// This module will clear MOR_CLEAR_MEMORY_BIT bit if it is set. +// +// Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.
+// +// This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// **/ + + +#string STR_MODULE_ABSTRACT #language en-US "Initializes the MemoryOverwriteRequestControl variable" + +#string STR_MODULE_DESCRIPTION #language en-US "This module will clear MOR_CLEAR_MEMORY_BIT bit if it is set." + diff --git a/Core/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMorExtra.uni b/Core/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMorExtra.uni new file mode 100644 index 0000000000..7278fff4eb --- /dev/null +++ b/Core/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMorExtra.uni @@ -0,0 +1,19 @@ +// /** @file +// TcgMor Localized Strings and Content +// +// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.
+// +// This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// **/ + +#string STR_PROPERTIES_MODULE_NAME +#language en-US +"TCG (Trusted Computing Group) MOR" + + diff --git a/Core/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLock.c b/Core/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLock.c new file mode 100644 index 0000000000..c6f3edc756 --- /dev/null +++ b/Core/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLock.c @@ -0,0 +1,197 @@ +/** @file + TCG MOR (Memory Overwrite Request) Lock Control Driver. + + This driver initilize MemoryOverwriteRequestControlLock variable. + This module will add Variable Hook and allow MemoryOverwriteRequestControlLock variable set only once. + +Copyright (c) 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include +#include +#include +#include +#include "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.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _EFI_TCG_MOR_LOCK_H_ +#define _EFI_TCG_MOR_LOCK_H_ + +/** + This service is a wrapper for the UEFI Runtime Service GetVariable(). + + @param VariableName the name of the vendor's variable, it's a Null-Terminated Unicode String + @param VendorGuid Unify identifier for vendor. + @param Attributes Point to memory location to return the attributes of variable. If the point + is NULL, the parameter would be ignored. + @param DataSize As input, point to the maximum size of return Data-Buffer. + As output, point to the actual size of the returned Data-Buffer. + @param Data Point to return Data-Buffer. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_NOT_FOUND The variable was not found. + @retval EFI_BUFFER_TOO_SMALL The DataSize is too small for the result. DataSize has + been updated with the size needed to complete the request. + @retval EFI_INVALID_PARAMETER VariableName is NULL. + @retval EFI_INVALID_PARAMETER VendorGuid is NULL. + @retval EFI_INVALID_PARAMETER DataSize is NULL. + @retval EFI_INVALID_PARAMETER The DataSize is not too small and Data is NULL. + @retval EFI_DEVICE_ERROR The variable could not be retrieved due to a hardware error. + @retval EFI_SECURITY_VIOLATION The variable could not be retrieved due to an authentication failure. +**/ +EFI_STATUS +EFIAPI +InternalGetVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + OUT UINT32 *Attributes OPTIONAL, + IN OUT UINTN *DataSize, + OUT VOID *Data + ); + +/** + This service is a wrapper for the UEFI Runtime Service SetVariable() + + @param VariableName the name of the vendor's variable, as a + Null-Terminated Unicode String + @param VendorGuid Unify identifier for vendor. + @param Attributes Point to memory location to return the attributes of variable. If the point + is NULL, the parameter would be ignored. + @param DataSize The size in bytes of Data-Buffer. + @param Data Point to the content of the variable. + + @retval EFI_SUCCESS The firmware has successfully stored the variable and its data as + defined by the Attributes. + @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied, or the + DataSize exceeds the maximum allowed. + @retval EFI_INVALID_PARAMETER VariableName is an empty Unicode string. + @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the variable and its data. + @retval EFI_DEVICE_ERROR The variable could not be saved due to a hardware failure. + @retval EFI_WRITE_PROTECTED The variable in question is read-only. + @retval EFI_WRITE_PROTECTED The variable in question cannot be deleted. + @retval EFI_SECURITY_VIOLATION The variable could not be written due to EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS + set but the AuthInfo does NOT pass the validation check carried + out by the firmware. + @retval EFI_NOT_FOUND The variable trying to be updated or deleted was not found. + +**/ +EFI_STATUS +EFIAPI +InternalSetVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN UINT32 Attributes, + IN UINTN DataSize, + IN VOID *Data + ); + +/** + This service is a checker handler for the UEFI Runtime Service SetVariable() + + @param VariableName the name of the vendor's variable, as a + Null-Terminated Unicode String + @param VendorGuid Unify identifier for vendor. + @param Attributes Point to memory location to return the attributes of variable. If the point + is NULL, the parameter would be ignored. + @param DataSize The size in bytes of Data-Buffer. + @param Data Point to the content of the variable. + + @retval EFI_SUCCESS The firmware has successfully stored the variable and its data as + defined by the Attributes. + @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied, or the + DataSize exceeds the maximum allowed. + @retval EFI_INVALID_PARAMETER VariableName is an empty Unicode string. + @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the variable and its data. + @retval EFI_DEVICE_ERROR The variable could not be saved due to a hardware failure. + @retval EFI_WRITE_PROTECTED The variable in question is read-only. + @retval EFI_WRITE_PROTECTED The variable in question cannot be deleted. + @retval EFI_SECURITY_VIOLATION The variable could not be written due to EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS + set but the AuthInfo does NOT pass the validation check carried + out by the firmware. + @retval EFI_NOT_FOUND The variable trying to be updated or deleted was not found. + +**/ +EFI_STATUS +EFIAPI +SetVariableCheckHandlerMor ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN UINT32 Attributes, + IN UINTN DataSize, + IN VOID *Data + ); + +/** + Entry Point for MOR Lock Control driver. + + @param[in] ImageHandle Image handle of this driver. + @param[in] SystemTable A Pointer to the EFI System Table. + + @retval EFI_SUCEESS + @return Others Some error occurs. +**/ +EFI_STATUS +EFIAPI +MorLockDriverInit ( + VOID + ); + +#endif diff --git a/Core/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLock.uni b/Core/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLock.uni new file mode 100644 index 0000000000..2a40f9d006 --- /dev/null +++ b/Core/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLock.uni @@ -0,0 +1,21 @@ +// /** @file +// Initilizes MemoryOverwriteRequestControlLock variable +// +// This module will add Variable Hook and allow MemoryOverwriteRequestControlLock variable set only once. +// +// Copyright (c) 2015, Intel Corporation. All rights reserved.
+// +// This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// **/ + + +#string STR_MODULE_ABSTRACT #language en-US "Initilizes MemoryOverwriteRequestControlLock variable" + +#string STR_MODULE_DESCRIPTION #language en-US "This module will add Variable Hook and allow MemoryOverwriteRequestControlLock variable set only once." + diff --git a/Core/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLockExtra.uni b/Core/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLockExtra.uni new file mode 100644 index 0000000000..770092dafc --- /dev/null +++ b/Core/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLockExtra.uni @@ -0,0 +1,19 @@ +// /** @file +// TcgMorLock Localized Strings and Content +// +// Copyright (c) 2015, Intel Corporation. All rights reserved.
+// +// This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// **/ + +#string STR_PROPERTIES_MODULE_NAME +#language en-US +"TCG (Trusted Computing Group) MOR Lock" + + diff --git a/Core/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLockSmm.c b/Core/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLockSmm.c new file mode 100644 index 0000000000..019cb8bb24 --- /dev/null +++ b/Core/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLockSmm.c @@ -0,0 +1,158 @@ +/** @file + TCG MOR (Memory Overwrite Request) Lock Control Driver SMM wrapper. + +Copyright (c) 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include +#include +#include +#include "TcgMorLock.h" + +EFI_SMM_VARIABLE_PROTOCOL *mSmmVariable; + +/** + This service is a wrapper for the UEFI Runtime Service GetVariable(). + + @param VariableName the name of the vendor's variable, it's a Null-Terminated Unicode String + @param VendorGuid Unify identifier for vendor. + @param Attributes Point to memory location to return the attributes of variable. If the point + is NULL, the parameter would be ignored. + @param DataSize As input, point to the maximum size of return Data-Buffer. + As output, point to the actual size of the returned Data-Buffer. + @param Data Point to return Data-Buffer. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_NOT_FOUND The variable was not found. + @retval EFI_BUFFER_TOO_SMALL The DataSize is too small for the result. DataSize has + been updated with the size needed to complete the request. + @retval EFI_INVALID_PARAMETER VariableName is NULL. + @retval EFI_INVALID_PARAMETER VendorGuid is NULL. + @retval EFI_INVALID_PARAMETER DataSize is NULL. + @retval EFI_INVALID_PARAMETER The DataSize is not too small and Data is NULL. + @retval EFI_DEVICE_ERROR The variable could not be retrieved due to a hardware error. + @retval EFI_SECURITY_VIOLATION The variable could not be retrieved due to an authentication failure. +**/ +EFI_STATUS +EFIAPI +InternalGetVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + OUT UINT32 *Attributes OPTIONAL, + IN OUT UINTN *DataSize, + OUT VOID *Data + ) +{ + return mSmmVariable->SmmGetVariable ( + VariableName, + VendorGuid, + Attributes, + DataSize, + Data + ); +} + +/** + This service is a wrapper for the UEFI Runtime Service SetVariable() + + @param VariableName the name of the vendor's variable, as a + Null-Terminated Unicode String + @param VendorGuid Unify identifier for vendor. + @param Attributes Point to memory location to return the attributes of variable. If the point + is NULL, the parameter would be ignored. + @param DataSize The size in bytes of Data-Buffer. + @param Data Point to the content of the variable. + + @retval EFI_SUCCESS The firmware has successfully stored the variable and its data as + defined by the Attributes. + @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied, or the + DataSize exceeds the maximum allowed. + @retval EFI_INVALID_PARAMETER VariableName is an empty Unicode string. + @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the variable and its data. + @retval EFI_DEVICE_ERROR The variable could not be saved due to a hardware failure. + @retval EFI_WRITE_PROTECTED The variable in question is read-only. + @retval EFI_WRITE_PROTECTED The variable in question cannot be deleted. + @retval EFI_SECURITY_VIOLATION The variable could not be written due to EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS + set but the AuthInfo does NOT pass the validation check carried + out by the firmware. + @retval EFI_NOT_FOUND The variable trying to be updated or deleted was not found. + +**/ +EFI_STATUS +EFIAPI +InternalSetVariable ( + IN CHAR16 *VariableName, + IN EFI_GUID *VendorGuid, + IN UINT32 Attributes, + IN UINTN DataSize, + IN VOID *Data + ) +{ + return mSmmVariable->SmmSetVariable ( + VariableName, + VendorGuid, + Attributes, + DataSize, + Data + ); +} + +/** + Entry Point for MOR Lock Control driver. + + @param[in] ImageHandle The firmware allocated handle for the EFI image. + @param[in] SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS EntryPoint runs successfully. + +**/ +EFI_STATUS +EFIAPI +MorLockDriverEntryPointSmm ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EDKII_SMM_VAR_CHECK_PROTOCOL *SmmVarCheck; + + // + // This driver link to Smm Variable driver + // + DEBUG ((EFI_D_INFO, "MorLockDriverEntryPointSmm\n")); + + Status = gSmst->SmmLocateProtocol ( + &gEfiSmmVariableProtocolGuid, + NULL, + (VOID **) &mSmmVariable + ); + ASSERT_EFI_ERROR (Status); + + Status = gSmst->SmmLocateProtocol ( + &gEdkiiSmmVarCheckProtocolGuid, + NULL, + (VOID **) &SmmVarCheck + ); + ASSERT_EFI_ERROR (Status); + + Status = MorLockDriverInit (); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = SmmVarCheck->SmmRegisterSetVariableCheckHandler (SetVariableCheckHandlerMor); + ASSERT_EFI_ERROR (Status); + + return Status; +} + diff --git a/Core/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLockSmm.inf b/Core/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLockSmm.inf new file mode 100644 index 0000000000..1623bd03bb --- /dev/null +++ b/Core/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLockSmm.inf @@ -0,0 +1,70 @@ +## @file +# Initilizes MemoryOverwriteRequestControlLock variable +# +# This module will add Variable Hook and allow MemoryOverwriteRequestControlLock variable set only once. +# +# NOTE: This module only handles secure MOR V1 and is deprecated. +# The secure MOR V2 is handled inside of variable driver. +# +# Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = TcgMorLockSmm + MODULE_UNI_FILE = TcgMorLock.uni + FILE_GUID = E2EA6F47-E678-47FA-8C1B-02A03E825C6E + MODULE_TYPE = DXE_SMM_DRIVER + VERSION_STRING = 1.0 + PI_SPECIFICATION_VERSION = 0x0001000A + ENTRY_POINT = MorLockDriverEntryPointSmm + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + TcgMorLock.h + TcgMorLock.c + TcgMorLockSmm.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + UefiDriverEntryPoint + SmmServicesTableLib + DebugLib + BaseLib + BaseMemoryLib + +[Guids] + ## SOMETIMES_CONSUMES ## Variable:L"MemoryOverwriteRequestControl" + gEfiMemoryOverwriteControlDataGuid + + ## SOMETIMES_CONSUMES ## Variable:L"MemoryOverwriteRequestControlLock" + ## PRODUCES ## Variable:L"MemoryOverwriteRequestControlLock" + gEfiMemoryOverwriteRequestControlLockGuid + +[Protocols] + gEdkiiSmmVarCheckProtocolGuid ## CONSUMES + gEfiSmmVariableProtocolGuid ## CONSUMES + +[Depex] + gEfiSmmVariableProtocolGuid AND + gSmmVariableWriteGuid AND + ( gEfiTcgProtocolGuid OR gEfiTcg2ProtocolGuid ) + +[UserExtensions.TianoCore."ExtraFiles"] + TcgMorLockExtra.uni diff --git a/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/ComponentName.c b/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/ComponentName.c new file mode 100644 index 0000000000..ef963d0e0b --- /dev/null +++ b/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/ComponentName.c @@ -0,0 +1,398 @@ +/** @file + UEFI Component Name(2) protocol implementation for Opal driver. + +Copyright (c) 2016, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "OpalDriver.h" + +// +// EFI Component Name Protocol +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gOpalComponentName = { + OpalEfiDriverComponentNameGetDriverName, + OpalEfiDriverComponentNameGetControllerName, + "eng" +}; + +// +// EFI Component Name 2 Protocol +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gOpalComponentName2 = { + OpalEfiDriverComponentName2GetDriverName, + OpalEfiDriverComponentName2GetControllerName, + "en" +}; + + +/// The name of the driver in all the languages we support. +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mOpalDriverNameTable[] = { + { LANGUAGE_RFC_3066_ENGLISH, (CHAR16*)EFI_DRIVER_NAME_UNICODE }, + { LANGUAGE_ISO_639_2_ENGLISH, (CHAR16*)EFI_DRIVER_NAME_UNICODE }, + { 0, 0 } +}; + +/** + Retrieves a Unicode string that is the user readable name of the driver. + + This function retrieves the user readable name of a driver in the form of a + Unicode string. If the driver specified by This has a user readable name in + the language specified by Language, then a pointer to the driver name is + returned in DriverName, and EFI_SUCCESS is returned. If the driver specified + by This does not support the language specified by Language, + then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified + in RFC 4646 or ISO 639-2 language code format. + + @param DriverName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the Driver specified by + This and the language specified by Language was + returned in DriverName. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER DriverName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +OpalEfiDriverComponentNameGetDriverName( + EFI_COMPONENT_NAME_PROTOCOL* This, + CHAR8* Language, + CHAR16** DriverName + ) +{ + return LookupUnicodeString2( + Language, + This->SupportedLanguages, + mOpalDriverNameTable, + DriverName, + TRUE + ); +} + +/** + Retrieves a Unicode string that is the user readable name of the driver. + + This function retrieves the user readable name of a driver in the form of a + Unicode string. If the driver specified by This has a user readable name in + the language specified by Language, then a pointer to the driver name is + returned in DriverName, and EFI_SUCCESS is returned. If the driver specified + by This does not support the language specified by Language, + then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified + in RFC 4646 or ISO 639-2 language code format. + + @param DriverName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + driver specified by This in the language + specified by Language. + + @retval EFI_SUCCESS The Unicode string for the Driver specified by + This and the language specified by Language was + returned in DriverName. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER DriverName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +OpalEfiDriverComponentName2GetDriverName( + EFI_COMPONENT_NAME2_PROTOCOL* This, + CHAR8* Language, + CHAR16** DriverName + ) +{ + return LookupUnicodeString2( + Language, + This->SupportedLanguages, + mOpalDriverNameTable, + DriverName, + FALSE + ); +} + +/** + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by a driver. + + This function retrieves the user readable name of the controller specified by + ControllerHandle and ChildHandle in the form of a Unicode string. If the + driver specified by This has a user readable name in the language specified by + Language, then a pointer to the controller name is returned in ControllerName, + and EFI_SUCCESS is returned. If the driver specified by This is not currently + managing the controller specified by ControllerHandle and ChildHandle, + then EFI_UNSUPPORTED is returned. If the driver specified by This does not + support the language specified by Language, then EFI_UNSUPPORTED is returned. + + @param ControllerHandle[in] The handle of a controller that the driver + specified by This is managing. This handle + specifies the controller whose name is to be + returned. + + @param ChildHandle[in] The handle of the child controller to retrieve + the name of. This is an optional parameter that + may be NULL. It will be NULL for device + drivers. It will also be NULL for a bus drivers + that wish to retrieve the name of the bus + controller. It will not be NULL for a bus + driver that wishes to retrieve the name of a + child controller. + + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified in + RFC 4646 or ISO 639-2 language code format. + + @param ControllerName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + controller specified by ControllerHandle and + ChildHandle in the language specified by + Language from the point of view of the driver + specified by This. + + @retval EFI_SUCCESS The Unicode string for the user readable name in + the language specified by Language for the + driver specified by This was returned in + DriverName. + + @retval EFI_INVALID_PARAMETER ControllerHandle is NULL. + + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +GetControllerName( + EFI_HANDLE ControllerHandle, + EFI_HANDLE ChildHandle, + CHAR8* Language, + CHAR16** ControllerName + ) +{ + if (Language == NULL || ControllerName == NULL || ControllerHandle == NULL) { + return EFI_INVALID_PARAMETER; + } + + // don't support any controller or children names + return EFI_UNSUPPORTED; +} + +/** + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by a driver. + + This function retrieves the user readable name of the controller specified by + ControllerHandle and ChildHandle in the form of a Unicode string. If the + driver specified by This has a user readable name in the language specified by + Language, then a pointer to the controller name is returned in ControllerName, + and EFI_SUCCESS is returned. If the driver specified by This is not currently + managing the controller specified by ControllerHandle and ChildHandle, + then EFI_UNSUPPORTED is returned. If the driver specified by This does not + support the language specified by Language, then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param ControllerHandle[in] The handle of a controller that the driver + specified by This is managing. This handle + specifies the controller whose name is to be + returned. + + @param ChildHandle[in] The handle of the child controller to retrieve + the name of. This is an optional parameter that + may be NULL. It will be NULL for device + drivers. It will also be NULL for a bus drivers + that wish to retrieve the name of the bus + controller. It will not be NULL for a bus + driver that wishes to retrieve the name of a + child controller. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified in + RFC 4646 or ISO 639-2 language code format. + + @param ControllerName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + controller specified by ControllerHandle and + ChildHandle in the language specified by + Language from the point of view of the driver + specified by This. + + @retval EFI_SUCCESS The Unicode string for the user readable name in + the language specified by Language for the + driver specified by This was returned in + DriverName. + + @retval EFI_INVALID_PARAMETER ControllerHandle is NULL. + + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +OpalEfiDriverComponentNameGetControllerName( + EFI_COMPONENT_NAME_PROTOCOL* This, + EFI_HANDLE ControllerHandle, + EFI_HANDLE ChildHandle, + CHAR8* Language, + CHAR16** ControllerName + ) +{ + return (GetControllerName( ControllerHandle, ChildHandle, Language, ControllerName)); +} + +/** + Retrieves a Unicode string that is the user readable name of the controller + that is being managed by a driver. + + This function retrieves the user readable name of the controller specified by + ControllerHandle and ChildHandle in the form of a Unicode string. If the + driver specified by This has a user readable name in the language specified by + Language, then a pointer to the controller name is returned in ControllerName, + and EFI_SUCCESS is returned. If the driver specified by This is not currently + managing the controller specified by ControllerHandle and ChildHandle, + then EFI_UNSUPPORTED is returned. If the driver specified by This does not + support the language specified by Language, then EFI_UNSUPPORTED is returned. + + @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param ControllerHandle[in] The handle of a controller that the driver + specified by This is managing. This handle + specifies the controller whose name is to be + returned. + + @param ChildHandle[in] The handle of the child controller to retrieve + the name of. This is an optional parameter that + may be NULL. It will be NULL for device + drivers. It will also be NULL for a bus drivers + that wish to retrieve the name of the bus + controller. It will not be NULL for a bus + driver that wishes to retrieve the name of a + child controller. + + @param Language[in] A pointer to a Null-terminated ASCII string + array indicating the language. This is the + language of the driver name that the caller is + requesting, and it must match one of the + languages specified in SupportedLanguages. The + number of languages supported by a driver is up + to the driver writer. Language is specified in + RFC 4646 or ISO 639-2 language code format. + + @param ControllerName[out] A pointer to the Unicode string to return. + This Unicode string is the name of the + controller specified by ControllerHandle and + ChildHandle in the language specified by + Language from the point of view of the driver + specified by This. + + @retval EFI_SUCCESS The Unicode string for the user readable name in + the language specified by Language for the + driver specified by This was returned in + DriverName. + + @retval EFI_INVALID_PARAMETER ControllerHandle is NULL. + + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid + EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This is not currently + managing the controller specified by + ControllerHandle and ChildHandle. + + @retval EFI_UNSUPPORTED The driver specified by This does not support + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +OpalEfiDriverComponentName2GetControllerName( + EFI_COMPONENT_NAME2_PROTOCOL* This, + EFI_HANDLE ControllerHandle, + EFI_HANDLE ChildHandle, + CHAR8* Language, + CHAR16** ControllerName + ) +{ + return (GetControllerName(ControllerHandle, ChildHandle, Language, ControllerName)); +} + diff --git a/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalDriver.c b/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalDriver.c new file mode 100644 index 0000000000..cd0c5a4096 --- /dev/null +++ b/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalDriver.c @@ -0,0 +1,1091 @@ +/** @file + Entrypoint of Opal UEFI Driver and contains all the logic to + register for new Opal device instances. + +Copyright (c) 2016, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +// This UEFI driver consumes EFI_STORAGE_SECURITY_PROTOCOL instances and installs an +// HII GUI to manage Opal features if the device is Opal capable +// If the Opal device is being managed by the UEFI Driver, it shall provide a popup +// window during boot requesting a user password + +#include "OpalDriver.h" +#include "OpalDriverPrivate.h" +#include "OpalHii.h" + +OPAL_DRIVER mOpalDriver; + +#define MAX_PASSWORD_SIZE 32 +#define MAX_PASSWORD_TRY_COUNT 5 + +// +// Globals +// +EFI_DRIVER_BINDING_PROTOCOL gOpalDriverBinding = { + OpalEfiDriverBindingSupported, + OpalEfiDriverBindingStart, + OpalEfiDriverBindingStop, + 0x1b, + NULL, + NULL +}; + + +/** + Add new device to the global device list. + + @param Dev New create device. + +**/ +VOID +AddDeviceToTail( + IN OPAL_DRIVER_DEVICE *Dev + ) +{ + OPAL_DRIVER_DEVICE *TmpDev; + + if (mOpalDriver.DeviceList == NULL) { + mOpalDriver.DeviceList = Dev; + } else { + TmpDev = mOpalDriver.DeviceList; + while (TmpDev->Next != NULL) { + TmpDev = TmpDev->Next; + } + + TmpDev->Next = Dev; + } +} + +/** + Remove one device in the global device list. + + @param Dev The device need to be removed. + +**/ +VOID +RemoveDevice ( + IN OPAL_DRIVER_DEVICE *Dev + ) +{ + OPAL_DRIVER_DEVICE *TmpDev; + + if (mOpalDriver.DeviceList == NULL) { + return; + } + + if (mOpalDriver.DeviceList == Dev) { + mOpalDriver.DeviceList = NULL; + return; + } + + TmpDev = mOpalDriver.DeviceList; + while (TmpDev->Next != NULL) { + if (TmpDev->Next == Dev) { + TmpDev->Next = Dev->Next; + break; + } + } +} + +/** + Get current device count. + + @retval return the current created device count. + +**/ +UINT8 +GetDeviceCount ( + VOID + ) +{ + UINT8 Count; + OPAL_DRIVER_DEVICE *TmpDev; + + Count = 0; + TmpDev = mOpalDriver.DeviceList; + + while (TmpDev != NULL) { + Count++; + TmpDev = TmpDev->Next; + } + + return Count; +} + +/** + Get password input from the popup windows, and unlock the device. + + @param[in] Dev The device which need to be unlock. + @param[out] PressEsc Whether user escape function through Press ESC. + + @retval Password string if success. NULL if failed. + +**/ +CHAR8 * +OpalDriverPopUpHddPassword ( + IN OPAL_DRIVER_DEVICE *Dev, + OUT BOOLEAN *PressEsc + ) +{ + EFI_INPUT_KEY InputKey; + UINTN InputLength; + CHAR16 Mask[MAX_PASSWORD_SIZE + 1]; + CHAR16 Unicode[MAX_PASSWORD_SIZE + 1]; + CHAR8 *Ascii; + CHAR16 *PopUpString; + UINTN StrLength; + + ZeroMem(Unicode, sizeof(Unicode)); + ZeroMem(Mask, sizeof(Mask)); + + StrLength = StrLen(Dev->Name16); + PopUpString = (CHAR16*) AllocateZeroPool ((8 + StrLength) * 2); + *PressEsc = FALSE; + + if (Dev->Name16 == NULL) { + UnicodeSPrint(PopUpString, StrLen(L"Unlock Disk") + 1, L"Unlock Disk"); + } else { + UnicodeSPrint(PopUpString, StrLen(L"Unlock ") + StrLength + 1, L"Unlock %s", Dev->Name16); + } + + gST->ConOut->ClearScreen(gST->ConOut); + + InputLength = 0; + while (TRUE) { + Mask[InputLength] = L'_'; + CreatePopUp( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &InputKey, + PopUpString, + L"---------------------", + Mask, + NULL + ); + + // + // Check key. + // + if (InputKey.ScanCode == SCAN_NULL) { + // + // password finished + // + if (InputKey.UnicodeChar == CHAR_CARRIAGE_RETURN) { + // + // Add the null terminator. + // + Unicode[InputLength] = 0; + InputLength++; + break; + } else if ((InputKey.UnicodeChar == CHAR_NULL) || + (InputKey.UnicodeChar == CHAR_TAB) || + (InputKey.UnicodeChar == CHAR_LINEFEED) + ) { + continue; + } else { + // + // delete last key entered + // + if (InputKey.UnicodeChar == CHAR_BACKSPACE) { + if (InputLength > 0) { + Unicode[InputLength] = 0; + Mask[InputLength] = 0; + InputLength--; + } + } else { + // + // add Next key entry + // + Unicode[InputLength] = InputKey.UnicodeChar; + Mask[InputLength] = L'*'; + InputLength++; + if (InputLength == MAX_PASSWORD_SIZE) { + // + // Add the null terminator. + // + Unicode[InputLength] = 0; + Mask[InputLength] = 0; + break; + } + } + } + } + + // + // exit on ESC + // + if (InputKey.ScanCode == SCAN_ESC) { + *PressEsc = TRUE; + break; + } + } + + gST->ConOut->ClearScreen(gST->ConOut); + + if (InputLength == 0 || InputKey.ScanCode == SCAN_ESC) { + return NULL; + } + + Ascii = AllocateZeroPool (MAX_PASSWORD_SIZE + 1); + if (Ascii == NULL) { + return NULL; + } + + UnicodeStrToAsciiStrS (Unicode, Ascii, MAX_PASSWORD_SIZE + 1); + ZeroMem (Unicode, sizeof (Unicode)); + + return Ascii; +} + +/** + Check if disk is locked, show popup window and ask for password if it is + + @param[in] Dev The device which need to be unlock. + +**/ +VOID +OpalDriverRequestPassword ( + OPAL_DRIVER_DEVICE *Dev + ) +{ + UINT8 Count; + BOOLEAN IsEnabled; + CHAR8 *Password; + UINT32 PasswordLen; + TCG_RESULT Ret; + EFI_INPUT_KEY Key; + OPAL_SESSION Session; + BOOLEAN PressEsc; + BOOLEAN Locked; + + if (Dev == NULL) { + return; + } + + Count = 0; + + IsEnabled = OpalFeatureEnabled (&Dev->OpalDisk.SupportedAttributes, &Dev->OpalDisk.LockingFeature); + if (IsEnabled) { + ZeroMem(&Session, sizeof(Session)); + Session.Sscp = Dev->OpalDisk.Sscp; + Session.MediaId = Dev->OpalDisk.MediaId; + Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId; + + Locked = OpalDeviceLocked (&Dev->OpalDisk.SupportedAttributes, &Dev->OpalDisk.LockingFeature); + + while (Count < MAX_PASSWORD_TRY_COUNT) { + Password = OpalDriverPopUpHddPassword (Dev, &PressEsc); + if (PressEsc) { + if (Locked) { + // + // Current device in the lock status and + // User not input password and press ESC, + // keep device in lock status and continue boot. + // + do { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Press ENTER to skip password, Press ESC to input password", + NULL + ); + } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN)); + + if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) { + gST->ConOut->ClearScreen(gST->ConOut); + // + // Keep lock and continue boot. + // + return; + } else { + // + // Let user input password again. + // + continue; + } + } else { + // + // Current device in the unlock status and + // User not input password and press ESC, + // Shutdown the device. + // + do { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Press ENTER to shutdown, Press ESC to input password", + NULL + ); + } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN)); + + if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) { + gRT->ResetSystem (EfiResetShutdown, EFI_SUCCESS, 0, NULL); + } else { + // + // Let user input password again. + // + continue; + } + } + } + + if (Password == NULL) { + Count ++; + continue; + } + PasswordLen = (UINT32) AsciiStrLen(Password); + + if (Locked) { + Ret = OpalSupportUnlock(&Session, Password, PasswordLen, Dev->OpalDevicePath); + } else { + Ret = OpalSupportLock(&Session, Password, PasswordLen, Dev->OpalDevicePath); + if (Ret == TcgResultSuccess) { + Ret = OpalSupportUnlock(&Session, Password, PasswordLen, Dev->OpalDevicePath); + } + } + + if (Password != NULL) { + ZeroMem (Password, PasswordLen); + FreePool (Password); + } + + if (Ret == TcgResultSuccess) { + break; + } + + Count++; + + do { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Invalid password.", + L"Press ENTER to retry", + NULL + ); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + } + + if (Count >= MAX_PASSWORD_TRY_COUNT) { + do { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Opal password retry count exceeds the limit. Must shutdown!", + L"Press ENTER to shutdown", + NULL + ); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + + gRT->ResetSystem (EfiResetShutdown, EFI_SUCCESS, 0, NULL); + } + } +} + +/** + Get devcie list info. + + @retval return the device list pointer. +**/ +OPAL_DRIVER_DEVICE* +OpalDriverGetDeviceList( + VOID + ) +{ + return mOpalDriver.DeviceList; +} + +/** + ReadyToBoot callback to send BlockSid command. + + @param Event Pointer to this event + @param Context Event handler private Data + +**/ +VOID +EFIAPI +ReadyToBootCallback ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + OPAL_DRIVER_DEVICE *Itr; + TCG_RESULT Result; + OPAL_SESSION Session; + UINT32 PpStorageFlag; + + gBS->CloseEvent (Event); + + PpStorageFlag = Tcg2PhysicalPresenceLibGetManagementFlags (); + if ((PpStorageFlag & TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_ENABLE_BLOCK_SID) != 0) { + // + // Send BlockSID command to each Opal disk + // + Itr = mOpalDriver.DeviceList; + while (Itr != NULL) { + if (Itr->OpalDisk.SupportedAttributes.BlockSid) { + ZeroMem(&Session, sizeof(Session)); + Session.Sscp = Itr->OpalDisk.Sscp; + Session.MediaId = Itr->OpalDisk.MediaId; + Session.OpalBaseComId = Itr->OpalDisk.OpalBaseComId; + + Result = OpalBlockSid (&Session, TRUE); // HardwareReset must always be TRUE + if (Result != TcgResultSuccess) { + DEBUG ((DEBUG_ERROR, "OpalBlockSid fail\n")); + break; + } + } + + Itr = Itr->Next; + } + } +} + +/** + Stop this Controller. + + @param Dev The device need to be stopped. + +**/ +VOID +OpalDriverStopDevice ( + OPAL_DRIVER_DEVICE *Dev + ) +{ + // + // free each name + // + FreePool(Dev->Name16); + + // + // remove OPAL_DRIVER_DEVICE from the list + // it updates the controllerList pointer + // + RemoveDevice(Dev); + + // + // close protocols that were opened + // + gBS->CloseProtocol( + Dev->Handle, + &gEfiStorageSecurityCommandProtocolGuid, + gOpalDriverBinding.DriverBindingHandle, + Dev->Handle + ); + + gBS->CloseProtocol( + Dev->Handle, + &gEfiBlockIoProtocolGuid, + gOpalDriverBinding.DriverBindingHandle, + Dev->Handle + ); + + FreePool(Dev); +} + +/** + Get devcie name through the component name protocol. + + @param[in] AllHandlesBuffer The handle buffer for current system. + @param[in] NumAllHandles The number of handles for the handle buffer. + @param[in] Dev The device which need to get name. + @param[in] UseComp1 Whether use component name or name2 protocol. + + @retval TRUE Find the name for this device. + @retval FALSE Not found the name for this device. +**/ +BOOLEAN +OpalDriverGetDeviceNameByProtocol( + EFI_HANDLE *AllHandlesBuffer, + UINTN NumAllHandles, + OPAL_DRIVER_DEVICE *Dev, + BOOLEAN UseComp1 + ) +{ + EFI_HANDLE* ProtocolHandlesBuffer; + UINTN NumProtocolHandles; + EFI_STATUS Status; + EFI_COMPONENT_NAME2_PROTOCOL* Cnp1_2; // efi component name and componentName2 have same layout + EFI_GUID Protocol; + UINTN StrLength; + EFI_DEVICE_PATH_PROTOCOL* TmpDevPath; + UINTN Index1; + UINTN Index2; + EFI_HANDLE TmpHandle; + CHAR16 *DevName; + + if (Dev == NULL || AllHandlesBuffer == NULL || NumAllHandles == 0) { + return FALSE; + } + + Protocol = UseComp1 ? gEfiComponentNameProtocolGuid : gEfiComponentName2ProtocolGuid; + + // + // Find all EFI_HANDLES with protocol + // + Status = gBS->LocateHandleBuffer( + ByProtocol, + &Protocol, + NULL, + &NumProtocolHandles, + &ProtocolHandlesBuffer + ); + if (EFI_ERROR(Status)) { + return FALSE; + } + + + // + // Exit early if no supported devices + // + if (NumProtocolHandles == 0) { + return FALSE; + } + + // + // Get printable name by iterating through all protocols + // using the handle as the child, and iterate through all handles for the controller + // exit loop early once found, if not found, then delete device + // storage security protocol instances already exist, add them to internal list + // + Status = EFI_DEVICE_ERROR; + for (Index1 = 0; Index1 < NumProtocolHandles; Index1++) { + DevName = NULL; + + if (Dev->Name16 != NULL) { + return TRUE; + } + + TmpHandle = ProtocolHandlesBuffer[Index1]; + + Status = gBS->OpenProtocol( + TmpHandle, + &Protocol, + (VOID**)&Cnp1_2, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR(Status) || Cnp1_2 == NULL) { + continue; + } + + // + // Use all handles array as controller handle + // + for (Index2 = 0; Index2 < NumAllHandles; Index2++) { + Status = Cnp1_2->GetControllerName( + Cnp1_2, + AllHandlesBuffer[Index2], + Dev->Handle, + LANGUAGE_ISO_639_2_ENGLISH, + &DevName + ); + if (EFI_ERROR(Status)) { + Status = Cnp1_2->GetControllerName( + Cnp1_2, + AllHandlesBuffer[Index2], + Dev->Handle, + LANGUAGE_RFC_3066_ENGLISH, + &DevName + ); + } + if (!EFI_ERROR(Status) && DevName != NULL) { + StrLength = StrLen(DevName) + 1; // Add one for NULL terminator + Dev->Name16 = AllocateZeroPool(StrLength * sizeof (CHAR16)); + ASSERT (Dev->Name16 != NULL); + StrCpyS (Dev->Name16, StrLength, DevName); + Dev->NameZ = (CHAR8*)AllocateZeroPool(StrLength); + UnicodeStrToAsciiStrS (DevName, Dev->NameZ, StrLength); + + // + // Retrieve bridge BDF info and port number or namespace depending on type + // + TmpDevPath = NULL; + Status = gBS->OpenProtocol( + Dev->Handle, + &gEfiDevicePathProtocolGuid, + (VOID**)&TmpDevPath, + gImageHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (!EFI_ERROR(Status)) { + Dev->OpalDevicePath = DuplicateDevicePath (TmpDevPath); + return TRUE; + } + + if (Dev->Name16 != NULL) { + FreePool(Dev->Name16); + Dev->Name16 = NULL; + } + if (Dev->NameZ != NULL) { + FreePool(Dev->NameZ); + Dev->NameZ = NULL; + } + } + } + } + + return FALSE; +} + +/** + Get devcie name through the component name protocol. + + @param[in] Dev The device which need to get name. + + @retval TRUE Find the name for this device. + @retval FALSE Not found the name for this device. +**/ +BOOLEAN +OpalDriverGetDriverDeviceName( + OPAL_DRIVER_DEVICE *Dev + ) +{ + EFI_HANDLE* AllHandlesBuffer; + UINTN NumAllHandles; + EFI_STATUS Status; + + if (Dev == NULL) { + DEBUG((DEBUG_ERROR | DEBUG_INIT, "OpalDriverGetDriverDeviceName Exiting, Dev=NULL\n")); + return FALSE; + } + + // + // Iterate through ComponentName2 handles to get name, if fails, try ComponentName + // + if (Dev->Name16 == NULL) { + DEBUG((DEBUG_ERROR | DEBUG_INIT, "Name is null, update it\n")); + // + // Find all EFI_HANDLES + // + Status = gBS->LocateHandleBuffer( + AllHandles, + NULL, + NULL, + &NumAllHandles, + &AllHandlesBuffer + ); + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_INFO, "LocateHandleBuffer for AllHandles failed %r\n", Status )); + return FALSE; + } + + // + // Try component Name2 + // + if (!OpalDriverGetDeviceNameByProtocol(AllHandlesBuffer, NumAllHandles, Dev, FALSE)) { + DEBUG((DEBUG_ERROR | DEBUG_INIT, "ComponentName2 failed to get device name, try ComponentName\n")); + if (!OpalDriverGetDeviceNameByProtocol(AllHandlesBuffer, NumAllHandles, Dev, TRUE)) { + DEBUG((DEBUG_ERROR | DEBUG_INIT, "ComponentName failed to get device name, skip device\n")); + return FALSE; + } + } + } + + return TRUE; +} + +/** + Main entry for this driver. + + @param ImageHandle Image Handle this driver. + @param SystemTable Pointer to SystemTable. + + @retval EFI_SUCESS This function always complete successfully. +**/ +EFI_STATUS +EFIAPI +EfiDriverEntryPoint( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE* SystemTable + ) +{ + EFI_STATUS Status; + EFI_EVENT ReadyToBootEvent; + + Status = EfiLibInstallDriverBindingComponentName2 ( + ImageHandle, + SystemTable, + &gOpalDriverBinding, + ImageHandle, + &gOpalComponentName, + &gOpalComponentName2 + ); + + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, "Install protocols to Opal driver Handle failed\n")); + return Status ; + } + + // + // Initialize Driver object + // + ZeroMem(&mOpalDriver, sizeof(mOpalDriver)); + mOpalDriver.Handle = ImageHandle; + + // + // register a ReadyToBoot event callback for sending BlockSid command + // + Status = EfiCreateEventReadyToBootEx ( + TPL_CALLBACK, + ReadyToBootCallback, + (VOID *) &ImageHandle, + &ReadyToBootEvent + ); + + // + // Install Hii packages. + // + HiiInstall(); + + return Status; +} + +/** + Tests to see if this driver supports a given controller. + + This function checks to see if the controller contains an instance of the + EFI_STORAGE_SECURITY_COMMAND_PROTOCOL and the EFI_BLOCK_IO_PROTOCL + and returns EFI_SUCCESS if it does. + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param[in] ControllerHandle The Handle of the controller to test. This Handle + must support a protocol interface that supplies + an I/O abstraction to the driver. + @param[in] RemainingDevicePath This parameter is ignored. + + @retval EFI_SUCCESS The device contains required protocols + @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and + RemainingDevicePath is already being managed by the driver + specified by This. + @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and + RemainingDevicePath is already being managed by a different + driver or an application that requires exclusive access. + Currently not implemented. + @retval EFI_UNSUPPORTED The device does not contain requires protocols + +**/ +EFI_STATUS +EFIAPI +OpalEfiDriverBindingSupported( + IN EFI_DRIVER_BINDING_PROTOCOL* This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL* RemainingDevicePath + ) +{ + EFI_STATUS Status; + EFI_STORAGE_SECURITY_COMMAND_PROTOCOL* SecurityCommand; + EFI_BLOCK_IO_PROTOCOL* BlkIo; + + // + // Test EFI_STORAGE_SECURITY_COMMAND_PROTOCOL on controller Handle. + // + Status = gBS->OpenProtocol( + Controller, + &gEfiStorageSecurityCommandProtocolGuid, + ( VOID ** )&SecurityCommand, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + + if (Status == EFI_ALREADY_STARTED) { + return EFI_SUCCESS; + } + + if (EFI_ERROR(Status)) { + return Status; + } + + // + // Close protocol and reopen in Start call + // + gBS->CloseProtocol( + Controller, + &gEfiStorageSecurityCommandProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + // + // Test EFI_BLOCK_IO_PROTOCOL on controller Handle, required by EFI_STORAGE_SECURITY_COMMAND_PROTOCOL + // function APIs + // + Status = gBS->OpenProtocol( + Controller, + &gEfiBlockIoProtocolGuid, + (VOID **)&BlkIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_INFO, "No EFI_BLOCK_IO_PROTOCOL on controller\n")); + return Status; + } + + // + // Close protocol and reopen in Start call + // + gBS->CloseProtocol( + Controller, + &gEfiBlockIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + return EFI_SUCCESS; +} + +/** + Enables Opal Management on a supported device if available. + + The start function is designed to be called after the Opal UEFI Driver has confirmed the + "controller", which is a child Handle, contains the EF_STORAGE_SECURITY_COMMAND protocols. + This function will complete the other necessary checks, such as verifying the device supports + the correct version of Opal. Upon verification, it will add the device to the + Opal HII list in order to expose Opal managmeent options. + + @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance. + @param[in] ControllerHandle The Handle of the controller to start. This Handle + must support a protocol interface that supplies + an I/O abstraction to the driver. + @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This + parameter is ignored by device drivers, and is optional for bus + drivers. For a bus driver, if this parameter is NULL, then handles + for all the children of Controller are created by this driver. + If this parameter is not NULL and the first Device Path Node is + not the End of Device Path Node, then only the Handle for the + child device specified by the first Device Path Node of + RemainingDevicePath is created by this driver. + If the first Device Path Node of RemainingDevicePath is + the End of Device Path Node, no child Handle is created by this + driver. + + @retval EFI_SUCCESS Opal management was enabled. + @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented. + @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources. + @retval Others The driver failed to start the device. + +**/ +EFI_STATUS +EFIAPI +OpalEfiDriverBindingStart( + IN EFI_DRIVER_BINDING_PROTOCOL* This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL* RemainingDevicePath + ) +{ + EFI_STATUS Status; + EFI_BLOCK_IO_PROTOCOL *BlkIo; + OPAL_DRIVER_DEVICE *Dev; + OPAL_DRIVER_DEVICE *Itr; + BOOLEAN Result; + + Itr = mOpalDriver.DeviceList; + while (Itr != NULL) { + if (Controller == Itr->Handle) { + return EFI_SUCCESS; + } + Itr = Itr->Next; + } + + // + // Create internal device for tracking. This allows all disks to be tracked + // by same HII form + // + Dev = (OPAL_DRIVER_DEVICE*)AllocateZeroPool(sizeof(OPAL_DRIVER_DEVICE)); + if (Dev == NULL) { + return EFI_OUT_OF_RESOURCES; + } + Dev->Handle = Controller; + + // + // Open EFI_STORAGE_SECURITY_COMMAND_PROTOCOL to perform Opal supported checks + // + Status = gBS->OpenProtocol( + Controller, + &gEfiStorageSecurityCommandProtocolGuid, + (VOID **)&Dev->Sscp, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR(Status)) { + FreePool(Dev); + return Status; + } + + // + // Open EFI_BLOCK_IO_PROTOCOL on controller Handle, required by EFI_STORAGE_SECURITY_COMMAND_PROTOCOL + // function APIs + // + Status = gBS->OpenProtocol( + Controller, + &gEfiBlockIoProtocolGuid, + (VOID **)&BlkIo, + This->DriverBindingHandle, + Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR(Status)) { + // + // Close storage security that was opened + // + gBS->CloseProtocol( + Controller, + &gEfiStorageSecurityCommandProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + FreePool(Dev); + return Status; + } + + // + // Save mediaId + // + Dev->MediaId = BlkIo->Media->MediaId; + + gBS->CloseProtocol( + Controller, + &gEfiBlockIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + // + // Acquire Ascii printable name of child, if not found, then ignore device + // + Result = OpalDriverGetDriverDeviceName (Dev); + if (!Result) { + goto Done; + } + + Status = OpalDiskInitialize (Dev); + if (EFI_ERROR (Status)) { + goto Done; + } + + AddDeviceToTail(Dev); + + // + // check if device is locked and prompt for password + // + OpalDriverRequestPassword (Dev); + + return EFI_SUCCESS; + +Done: + // + // free device, close protocols and exit + // + gBS->CloseProtocol( + Controller, + &gEfiStorageSecurityCommandProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + FreePool(Dev); + + return EFI_DEVICE_ERROR; +} + +/** + Stop this driver on Controller. + + @param This Protocol instance pointer. + @param Controller Handle of device to stop driver on + @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of + children is zero stop the entire bus driver. + @param ChildHandleBuffer List of Child Handles to Stop. + + @retval EFI_SUCCESS This driver is removed Controller. + @retval other This driver could not be removed from this device. + +**/ +EFI_STATUS +EFIAPI +OpalEfiDriverBindingStop( + EFI_DRIVER_BINDING_PROTOCOL* This, + EFI_HANDLE Controller, + UINTN NumberOfChildren, + EFI_HANDLE* ChildHandleBuffer + ) +{ + OPAL_DRIVER_DEVICE* Itr; + + Itr = mOpalDriver.DeviceList; + + // + // does Controller match any of the devices we are managing for Opal + // + while (Itr != NULL) { + if (Itr->Handle == Controller) { + OpalDriverStopDevice (Itr); + return EFI_SUCCESS; + } + + Itr = Itr->Next; + } + + return EFI_NOT_FOUND; +} + + +/** + Unloads UEFI Driver. Very useful for debugging and testing. + + @param ImageHandle Image Handle this driver. + + @retval EFI_SUCCESS This function always complete successfully. + @retval EFI_INVALID_PARAMETER The input ImageHandle is not valid. +**/ +EFI_STATUS +EFIAPI +OpalEfiDriverUnload ( + IN EFI_HANDLE ImageHandle + ) +{ + EFI_STATUS Status; + OPAL_DRIVER_DEVICE *Itr; + + Status = EFI_SUCCESS; + + if (ImageHandle != gImageHandle) { + return (EFI_INVALID_PARAMETER); + } + + // + // Uninstall any interface added to each device by us + // + while (mOpalDriver.DeviceList) { + Itr = mOpalDriver.DeviceList; + // + // Remove OPAL_DRIVER_DEVICE from the list + // it updates the controllerList pointer + // + OpalDriverStopDevice(Itr); + } + + // + // Uninstall the HII capability + // + Status = HiiUninstall(); + + return Status; +} + diff --git a/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalDriver.h b/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalDriver.h new file mode 100644 index 0000000000..7761d64cbb --- /dev/null +++ b/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalDriver.h @@ -0,0 +1,412 @@ +/** @file + Values defined and used by the Opal UEFI Driver. + +Copyright (c) 2016, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +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 + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef _OPAL_DRIVER_PRIVATE_H_ +#define _OPAL_DRIVER_PRIVATE_H_ +#include "OpalDriver.h" + +#define OPAL_MSID_LENGHT 128 + +#pragma pack(1) +// +// Structure that is used to represent an OPAL_DISK. +// +typedef struct { + UINT32 MsidLength; // Byte length of MSID Pin for device + UINT8 Msid[OPAL_MSID_LENGHT]; // MSID Pin for device + EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *Sscp; + UINT32 MediaId; // MediaId is used by Ssc Protocol. + EFI_DEVICE_PATH_PROTOCOL *OpalDevicePath; + UINT16 OpalBaseComId; // Opal SSC 1 base com id. + OPAL_OWNER_SHIP Owner; + OPAL_DISK_SUPPORT_ATTRIBUTE SupportedAttributes; + TCG_LOCKING_FEATURE_DESCRIPTOR LockingFeature; // Locking Feature Descriptor retrieved from performing a Level 0 Discovery +} OPAL_DISK; + +// +// Device with block IO protocol +// +typedef struct _OPAL_DRIVER_DEVICE OPAL_DRIVER_DEVICE; + +struct _OPAL_DRIVER_DEVICE { + OPAL_DRIVER_DEVICE *Next; ///< Linked list pointer + EFI_HANDLE Handle; ///< Device handle + OPAL_DISK OpalDisk; ///< User context + CHAR16 *Name16; ///< Allocated/freed by UEFI Filter Driver at device creation/removal + CHAR8 *NameZ; ///< Allocated/freed by UEFI Filter Driver at device creation/removal + UINT32 MediaId; ///< Required parameter for EFI_STORAGE_SECURITY_COMMAND_PROTOCOL, from BLOCK_IO_MEDIA + + EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *Sscp; /// Device protocols consumed + EFI_DEVICE_PATH_PROTOCOL *OpalDevicePath; +}; + +// +// Opal Driver UEFI Driver Model +// +typedef struct { + EFI_HANDLE Handle; ///< Driver image handle + OPAL_DRIVER_DEVICE *DeviceList; ///< Linked list of controllers owned by this Driver +} OPAL_DRIVER; +#pragma pack() + +// +// Retrieves a OPAL_DRIVER_DEVICE based on the pointer to its StorageSecurity protocol. +// +#define DRIVER_DEVICE_FROM_OPALDISK(OpalDiskPointer) (OPAL_DRIVER_DEVICE*)(BASE_CR(OpalDiskPointer, OPAL_DRIVER_DEVICE, OpalDisk)) + +/** + Get devcie list info. + + @retval return the device list pointer. +**/ +OPAL_DRIVER_DEVICE* +OpalDriverGetDeviceList( + VOID + ); + +/** + Get devcie name through the component name protocol. + + @param[in] Dev The device which need to get name. + + @retval TRUE Find the name for this device. + @retval FALSE Not found the name for this device. +**/ +BOOLEAN +OpalDriverGetDriverDeviceName( + OPAL_DRIVER_DEVICE *Dev + ); + +/** + Get current device count. + + @retval return the current created device count. + +**/ +UINT8 +GetDeviceCount ( + VOID + ); + +#endif // _OPAL_DRIVER_P_H_ diff --git a/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalHii.c b/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalHii.c new file mode 100644 index 0000000000..4881e72c55 --- /dev/null +++ b/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalHii.c @@ -0,0 +1,1483 @@ +/** @file + Implementation of the HII for the Opal UEFI Driver. + +Copyright (c) 2016, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "OpalHii.h" +#include "OpalDriver.h" +#include "OpalHiiPrivate.h" + +// +// This is the generated IFR binary Data for each formset defined in VFR. +// This Data array is ready to be used as input of HiiAddPackages() to +// create a packagelist (which contains Form packages, String packages, etc). +// +extern UINT8 OpalPasswordFormBin[]; + +// +// This is the generated String package Data for all .UNI files. +// This Data array is ready to be used as input of HiiAddPackages() to +// create a packagelist (which contains Form packages, String packages, etc). +// +extern UINT8 OpalPasswordDxeStrings[]; + +CHAR16 OpalPasswordStorageName[] = L"OpalHiiConfig"; + +EFI_HII_CONFIG_ACCESS_PROTOCOL gHiiConfigAccessProtocol; + +// +// Handle to the list of HII packages (forms and strings) for this driver +// +EFI_HII_HANDLE gHiiPackageListHandle = NULL; + +// +// Package List GUID containing all form and string packages +// +const EFI_GUID gHiiPackageListGuid = PACKAGE_LIST_GUID; +const EFI_GUID gHiiSetupVariableGuid = SETUP_VARIABLE_GUID; + +// +// Structure that contains state of the HII +// This structure is updated by Hii.cpp and its contents +// is rendered in the HII. +// +OPAL_HII_CONFIGURATION gHiiConfiguration; + +CHAR8 gHiiOldPassword[MAX_PASSWORD_CHARACTER_LENGTH] = {0}; +UINT32 gHiiOldPasswordLength = 0; + +// +// The device path containing the VENDOR_DEVICE_PATH and EFI_DEVICE_PATH_PROTOCOL +// +HII_VENDOR_DEVICE_PATH gHiiVendorDevicePath = { + { + { + HARDWARE_DEVICE_PATH, + HW_VENDOR_DP, + { + (UINT8)(sizeof(VENDOR_DEVICE_PATH)), + (UINT8)((sizeof(VENDOR_DEVICE_PATH)) >> 8) + } + }, + OPAL_PASSWORD_CONFIG_GUID + }, + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { + (UINT8)(END_DEVICE_PATH_LENGTH), + (UINT8)((END_DEVICE_PATH_LENGTH) >> 8) + } + } +}; + + +/** + Sets the current system state of global config variables. + +**/ +VOID +HiiSetCurrentConfiguration( + VOID + ) +{ + UINT32 PpStorageFlag; + EFI_STRING NewString; + + gHiiConfiguration.NumDisks = GetDeviceCount(); + + // + // Update the BlockSID status string. + // + PpStorageFlag = Tcg2PhysicalPresenceLibGetManagementFlags (); + + if ((PpStorageFlag & TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_ENABLE_BLOCK_SID) != 0) { + NewString = HiiGetString (gHiiPackageListHandle, STRING_TOKEN(STR_ENABLED), NULL); + if (NewString == NULL) { + DEBUG ((DEBUG_INFO, "HiiSetCurrentConfiguration: HiiGetString( ) failed\n")); + return; + } + } else { + NewString = HiiGetString (gHiiPackageListHandle, STRING_TOKEN(STR_DISABLED), NULL); + if (NewString == NULL) { + DEBUG ((DEBUG_INFO, "HiiSetCurrentConfiguration: HiiGetString( ) failed\n")); + return; + } + } + HiiSetString(gHiiPackageListHandle, STRING_TOKEN(STR_BLOCKSID_STATUS1), NewString, NULL); + FreePool (NewString); + + if ((PpStorageFlag & TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_PP_REQUIRED_FOR_ENABLE_BLOCK_SID) != 0) { + NewString = HiiGetString (gHiiPackageListHandle, STRING_TOKEN(STR_DISK_INFO_ENABLE_BLOCKSID_TRUE), NULL); + if (NewString == NULL) { + DEBUG ((DEBUG_INFO, "HiiSetCurrentConfiguration: HiiGetString( ) failed\n")); + return; + } + } else { + NewString = HiiGetString (gHiiPackageListHandle, STRING_TOKEN(STR_DISK_INFO_ENABLE_BLOCKSID_FALSE), NULL); + if (NewString == NULL) { + DEBUG ((DEBUG_INFO, "HiiSetCurrentConfiguration: HiiGetString( ) failed\n")); + return; + } + } + HiiSetString(gHiiPackageListHandle, STRING_TOKEN(STR_BLOCKSID_STATUS2), NewString, NULL); + FreePool (NewString); + + if ((PpStorageFlag & TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_PP_REQUIRED_FOR_DISABLE_BLOCK_SID) != 0) { + NewString = HiiGetString (gHiiPackageListHandle, STRING_TOKEN(STR_DISK_INFO_DISABLE_BLOCKSID_TRUE), NULL); + if (NewString == NULL) { + DEBUG ((DEBUG_INFO, "HiiSetCurrentConfiguration: HiiGetString( ) failed\n")); + return; + } + } else { + NewString = HiiGetString (gHiiPackageListHandle, STRING_TOKEN(STR_DISK_INFO_DISABLE_BLOCKSID_FALSE), NULL); + if (NewString == NULL) { + DEBUG ((DEBUG_INFO, "HiiSetCurrentConfiguration: HiiGetString( ) failed\n")); + return; + } + } + HiiSetString(gHiiPackageListHandle, STRING_TOKEN(STR_BLOCKSID_STATUS3), NewString, NULL); + FreePool (NewString); +} + +/** + Install the HII related resources. + + @retval EFI_SUCCESS Install all the resources success. + @retval other Error occur when install the resources. +**/ +EFI_STATUS +HiiInstall( + VOID + ) +{ + EFI_STATUS Status; + EFI_HANDLE DriverHandle; + + // + // Clear the global configuration. + // + ZeroMem(&gHiiConfiguration, sizeof(gHiiConfiguration)); + + // + // Obtain the driver handle that the BIOS assigned us + // + DriverHandle = HiiGetDriverImageHandleCB(); + + // + // Populate the config access protocol with the three functions we are publishing + // + gHiiConfigAccessProtocol.ExtractConfig = ExtractConfig; + gHiiConfigAccessProtocol.RouteConfig = RouteConfig; + gHiiConfigAccessProtocol.Callback = DriverCallback; + + // + // Associate the required protocols with our driver handle + // + Status = gBS->InstallMultipleProtocolInterfaces( + &DriverHandle, + &gEfiHiiConfigAccessProtocolGuid, + &gHiiConfigAccessProtocol, // HII callback + &gEfiDevicePathProtocolGuid, + &gHiiVendorDevicePath, // required for HII callback allow all disks to be shown in same hii + NULL + ); + + if (EFI_ERROR(Status)) { + return Status; + } + + return OpalHiiAddPackages(); +} + +/** + Install the HII form and string packages. + + @retval EFI_SUCCESS Install all the resources success. + @retval EFI_OUT_OF_RESOURCES Out of resource error. +**/ +EFI_STATUS +OpalHiiAddPackages( + VOID + ) +{ + EFI_HANDLE DriverHandle; + CHAR16 *NewString; + + DriverHandle = HiiGetDriverImageHandleCB(); + + // + // Publish the HII form and HII string packages + // + gHiiPackageListHandle = HiiAddPackages( + &gHiiPackageListGuid, + DriverHandle, + OpalPasswordDxeStrings, + OpalPasswordFormBin, + (VOID*)NULL + ); + + // + // Make sure the packages installed successfully + // + if (gHiiPackageListHandle == NULL) { + DEBUG ((DEBUG_INFO, "OpalHiiAddPackages failed\n")); + return EFI_OUT_OF_RESOURCES; + } + + // + // Update Version String in main window + // + NewString = HiiGetDriverNameCB (); + if (HiiSetString(gHiiPackageListHandle, STRING_TOKEN(STR_MAIN_OPAL_VERSION), NewString, NULL) == 0) { + DEBUG ((DEBUG_INFO, "OpalHiiAddPackages: HiiSetString( ) failed\n")); + return EFI_OUT_OF_RESOURCES; + } + + return EFI_SUCCESS; +} + +/** + Uninstall the HII capability. + + @retval EFI_SUCCESS Uninstall all the resources success. + @retval others Other errors occur when unistall the hii resource. +**/ +EFI_STATUS +HiiUninstall( + VOID + ) +{ + EFI_STATUS Status; + + // + // Remove the packages we've provided to the BIOS + // + HiiRemovePackages(gHiiPackageListHandle); + + // + // Remove the protocols from our driver handle + // + Status = gBS->UninstallMultipleProtocolInterfaces( + HiiGetDriverImageHandleCB(), + &gEfiHiiConfigAccessProtocolGuid, + &gHiiConfigAccessProtocol, // HII callback + &gEfiDevicePathProtocolGuid, + &gHiiVendorDevicePath, // required for HII callback + NULL + ); + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_INFO, "Cannot uninstall Hii Protocols: %r\n", Status)); + } + + return Status; +} + +/** + Updates the main menu form. + + @retval EFI_SUCCESS update the main form success. +**/ +EFI_STATUS +HiiPopulateMainMenuForm ( + VOID + ) +{ + UINT8 Index; + CHAR8 *DiskName; + EFI_STRING_ID DiskNameId; + OPAL_DISK *OpalDisk; + + HiiSetCurrentConfiguration(); + + gHiiConfiguration.SupportedDisks = 0; + + for (Index = 0; Index < gHiiConfiguration.NumDisks; Index++) { + OpalDisk = HiiGetOpalDiskCB (Index); + if ((OpalDisk != NULL) && OpalFeatureSupported (&OpalDisk->SupportedAttributes)) { + gHiiConfiguration.SupportedDisks |= (1 << Index); + DiskNameId = GetDiskNameStringId (Index); + DiskName = HiiDiskGetNameCB (Index); + if ((DiskName == NULL) || (DiskNameId == 0)) { + return EFI_UNSUPPORTED; + } + HiiSetFormString(DiskNameId, DiskName); + } + } + + OpalHiiSetBrowserData (); + return EFI_SUCCESS; +} + +/** + Update the disk action info. + + @param ActionString + @param SelectedAction + + @retval EFI_SUCCESS Uninstall all the resources success. +**/ +EFI_STATUS +HiiSelectDiskAction ( + CHAR8 *ActionString, + UINT8 SelectedAction + ) +{ + OPAL_DISK *OpalDisk; + OPAL_DISK_ACTIONS AvailActions; + + OpalHiiGetBrowserData (); + + HiiSetFormString(STRING_TOKEN(STR_DISK_ACTION_LBL), ActionString); + HiiSetFormString(STRING_TOKEN(STR_ACTION_STATUS), " "); + + gHiiConfiguration.SelectedAction = SelectedAction; + gHiiConfiguration.AvailableFields = 0; + + OpalDisk = HiiGetOpalDiskCB(gHiiConfiguration.SelectedDiskIndex); + if (OpalDisk == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (OpalSupportGetAvailableActions (&OpalDisk->SupportedAttributes, &OpalDisk->LockingFeature, OpalDisk->Owner, &AvailActions) != TcgResultSuccess) { + return EFI_DEVICE_ERROR; + } + + switch (SelectedAction) { + case HII_KEY_ID_GOTO_LOCK: + case HII_KEY_ID_GOTO_UNLOCK: + case HII_KEY_ID_GOTO_SET_ADMIN_PWD: + case HII_KEY_ID_GOTO_SET_USER_PWD: + case HII_KEY_ID_GOTO_SECURE_ERASE: + case HII_KEY_ID_GOTO_DISABLE_USER: + case HII_KEY_ID_GOTO_ENABLE_FEATURE: // User is required to enter Password to enable Feature + gHiiConfiguration.AvailableFields |= HII_FIELD_PASSWORD; + break; + + case HII_KEY_ID_GOTO_PSID_REVERT: + gHiiConfiguration.AvailableFields |= HII_FIELD_PSID; + break; + + case HII_KEY_ID_GOTO_REVERT: + gHiiConfiguration.AvailableFields |= HII_FIELD_PASSWORD; + gHiiConfiguration.AvailableFields |= HII_FIELD_KEEP_USER_DATA; + if (AvailActions.RevertKeepDataForced) { + gHiiConfiguration.AvailableFields |= HII_FIELD_KEEP_USER_DATA_FORCED; + } + break; + } + + OpalHiiSetBrowserData (); + + return EFI_SUCCESS; +} + +/** + Get disk name string id. + + @param DiskIndex The input disk index info. + + @retval The disk name string id. + +**/ +EFI_STRING_ID +GetDiskNameStringId( + UINT8 DiskIndex + ) +{ + switch (DiskIndex) { + case 0: return STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_0); + case 1: return STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_1); + case 2: return STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_2); + case 3: return STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_3); + case 4: return STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_4); + case 5: return STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_5); + } + return 0; +} + +/** + This function processes the results of changes in configuration. + + @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + @param Action Specifies the type of action taken by the browser. + @param QuestionId A unique value which is sent to the original + exporting driver so that it can identify the type + of data to expect. + @param Type The type of value for the question. + @param Value A pointer to the data being sent to the original + exporting driver. + @param ActionRequest On return, points to the action requested by the + callback function. + + @retval EFI_SUCCESS The callback successfully handled the action. + @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the + variable and its data. + @retval EFI_DEVICE_ERROR The variable could not be saved. + @retval EFI_UNSUPPORTED The specified Action is not supported by the + callback. + +**/ +EFI_STATUS +EFIAPI +DriverCallback( + CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, + EFI_BROWSER_ACTION Action, + EFI_QUESTION_ID QuestionId, + UINT8 Type, + EFI_IFR_TYPE_VALUE *Value, + EFI_BROWSER_ACTION_REQUEST *ActionRequest + ) +{ + HII_KEY HiiKey; + UINT8 HiiKeyId; + UINT32 PpRequest; + + if (ActionRequest != NULL) { + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE; + } else { + return EFI_INVALID_PARAMETER; + } + + // + // If QuestionId is an auto-generated key (label, empty line, etc.), ignore it. + // + if ((QuestionId & HII_KEY_FLAG) == 0) { + return EFI_SUCCESS; + } + + HiiKey.Raw = QuestionId; + HiiKeyId = (UINT8) HiiKey.KeyBits.Id; + + if (Action == EFI_BROWSER_ACTION_FORM_OPEN) { + switch (HiiKeyId) { + case HII_KEY_ID_VAR_SUPPORTED_DISKS: + DEBUG ((DEBUG_INFO, "HII_KEY_ID_VAR_SUPPORTED_DISKS\n")); + return HiiPopulateMainMenuForm (); + + case HII_KEY_ID_VAR_SELECTED_DISK_AVAILABLE_ACTIONS: + return HiiPopulateDiskInfoForm(); + } + } else if (Action == EFI_BROWSER_ACTION_CHANGING) { + switch (HiiKeyId) { + case HII_KEY_ID_GOTO_DISK_INFO: + return HiiSelectDisk((UINT8)HiiKey.KeyBits.Index); + + case HII_KEY_ID_GOTO_LOCK: + return HiiSelectDiskAction("Action: Lock", HiiKeyId); + + case HII_KEY_ID_GOTO_UNLOCK: + return HiiSelectDiskAction("Action: Unlock", HiiKeyId); + + case HII_KEY_ID_GOTO_SET_ADMIN_PWD: + return HiiSelectDiskAction("Action: Set Administrator Password", HiiKeyId); + + case HII_KEY_ID_GOTO_SET_USER_PWD: + return HiiSelectDiskAction("Action: Set User Password", HiiKeyId); + + case HII_KEY_ID_GOTO_SECURE_ERASE: + return HiiSelectDiskAction("Action: Secure Erase", HiiKeyId); + + case HII_KEY_ID_GOTO_PSID_REVERT: + return HiiSelectDiskAction("Action: Revert to Factory Defaults with PSID", HiiKeyId); + + case HII_KEY_ID_GOTO_REVERT: + return HiiSelectDiskAction("Action: Revert to Factory Defaults", HiiKeyId); + + case HII_KEY_ID_GOTO_DISABLE_USER: + return HiiSelectDiskAction("Action: Disable User", HiiKeyId); + + case HII_KEY_ID_GOTO_ENABLE_FEATURE: + return HiiSelectDiskAction("Action: Enable Feature", HiiKeyId); + + case HII_KEY_ID_ENTER_PASSWORD: + return HiiPasswordEntered(Value->string); + + case HII_KEY_ID_ENTER_PSID: + return HiiPsidRevert(Value->string); + + } + } else if (Action == EFI_BROWSER_ACTION_CHANGED) { + switch (HiiKeyId) { + case HII_KEY_ID_BLOCKSID: + switch (Value->u8) { + case 0: + PpRequest = TCG2_PHYSICAL_PRESENCE_NO_ACTION; + break; + + case 1: + PpRequest = TCG2_PHYSICAL_PRESENCE_ENABLE_BLOCK_SID; + break; + + case 2: + PpRequest = TCG2_PHYSICAL_PRESENCE_DISABLE_BLOCK_SID; + break; + + case 3: + PpRequest = TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_ENABLE_BLOCK_SID_FUNC_TRUE; + break; + + case 4: + PpRequest = TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_ENABLE_BLOCK_SID_FUNC_FALSE; + break; + + case 5: + PpRequest = TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_DISABLE_BLOCK_SID_FUNC_TRUE; + break; + + case 6: + PpRequest = TCG2_PHYSICAL_PRESENCE_SET_PP_REQUIRED_FOR_DISABLE_BLOCK_SID_FUNC_FALSE; + break; + + default: + PpRequest = TCG2_PHYSICAL_PRESENCE_NO_ACTION; + DEBUG ((DEBUG_ERROR, "Invalid value input!\n")); + break; + } + HiiSetBlockSidAction(PpRequest); + + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY; + return EFI_SUCCESS; + + default: + break; + } + } + + return EFI_UNSUPPORTED; +} + +/** + Update the global Disk index info. + + @param Index The input disk index info. + + @retval EFI_SUCCESS Update the disk index info success. + +**/ +EFI_STATUS +HiiSelectDisk( + UINT8 Index + ) +{ + OpalHiiGetBrowserData(); + gHiiConfiguration.SelectedDiskIndex = Index; + OpalHiiSetBrowserData (); + + return EFI_SUCCESS; +} + +/** + Draws the disk info form. + + @retval EFI_SUCCESS Draw the disk info success. + +**/ +EFI_STATUS +HiiPopulateDiskInfoForm( + VOID + ) +{ + OPAL_DISK* OpalDisk; + OPAL_DISK_ACTIONS AvailActions; + TCG_RESULT Ret; + CHAR8 *DiskName; + + OpalHiiGetBrowserData(); + + DiskName = HiiDiskGetNameCB (gHiiConfiguration.SelectedDiskIndex); + if (DiskName == NULL) { + return EFI_UNSUPPORTED; + } + HiiSetFormString(STRING_TOKEN(STR_DISK_INFO_SELECTED_DISK_NAME), DiskName); + + ZeroMem(gHiiConfiguration.Psid, sizeof(gHiiConfiguration.Psid)); + + gHiiConfiguration.SelectedDiskAvailableActions = HII_ACTION_NONE; + + OpalDisk = HiiGetOpalDiskCB(gHiiConfiguration.SelectedDiskIndex); + + if (OpalDisk != NULL) { + OpalDiskUpdateStatus (OpalDisk); + Ret = OpalSupportGetAvailableActions(&OpalDisk->SupportedAttributes, &OpalDisk->LockingFeature, OpalDisk->Owner, &AvailActions); + if (Ret == TcgResultSuccess) { + // + // Update actions, always allow PSID Revert + // + gHiiConfiguration.SelectedDiskAvailableActions |= (AvailActions.PsidRevert == 1) ? HII_ACTION_PSID_REVERT : HII_ACTION_NONE; + + // + // Always allow unlock to handle device migration + // + gHiiConfiguration.SelectedDiskAvailableActions |= (AvailActions.Unlock == 1) ? HII_ACTION_UNLOCK : HII_ACTION_NONE; + + if (!OpalFeatureEnabled (&OpalDisk->SupportedAttributes, &OpalDisk->LockingFeature)) { + if (OpalDisk->Owner == OpalOwnershipNobody) { + gHiiConfiguration.SelectedDiskAvailableActions |= HII_ACTION_ENABLE_FEATURE; + + // + // Update strings + // + HiiSetFormString( STRING_TOKEN(STR_DISK_INFO_PSID_REVERT), "PSID Revert to factory default"); + } else { + DEBUG ((DEBUG_INFO, "Feature disabled but ownership != nobody\n")); + } + } else { + gHiiConfiguration.SelectedDiskAvailableActions |= (AvailActions.Revert == 1) ? HII_ACTION_REVERT : HII_ACTION_NONE; + gHiiConfiguration.SelectedDiskAvailableActions |= (AvailActions.AdminPass == 1) ? HII_ACTION_SET_ADMIN_PWD : HII_ACTION_NONE; + gHiiConfiguration.SelectedDiskAvailableActions |= (AvailActions.UserPass == 1) ? HII_ACTION_SET_USER_PWD : HII_ACTION_NONE; + gHiiConfiguration.SelectedDiskAvailableActions |= (AvailActions.SecureErase == 1) ? HII_ACTION_SECURE_ERASE : HII_ACTION_NONE; + gHiiConfiguration.SelectedDiskAvailableActions |= (AvailActions.DisableUser == 1) ? HII_ACTION_DISABLE_USER : HII_ACTION_NONE; + + HiiSetFormString (STRING_TOKEN(STR_DISK_INFO_PSID_REVERT), "PSID Revert to factory default and Disable"); + + // + // Determine revert options for disk + // Default initialize keep user Data to be true + // + gHiiConfiguration.KeepUserData = 1; + } + } + } + + // + // Pass the current configuration to the BIOS + // + OpalHiiSetBrowserData (); + + return EFI_SUCCESS; +} + +/** + Reverts the Opal disk to factory default. + + @param PsidStringId The string id for the PSID info. + + @retval EFI_SUCCESS Do the required action success. + +**/ +EFI_STATUS +HiiPsidRevert( + EFI_STRING_ID PsidStringId + ) +{ + CHAR8 Response[DEFAULT_RESPONSE_SIZE]; + TCG_PSID Psid; + OPAL_DISK *OpalDisk; + TCG_RESULT Ret; + OPAL_SESSION Session; + CHAR16 *UnicodeStr; + UINT8 TmpBuf[PSID_CHARACTER_STRING_END_LENGTH]; + + Ret = TcgResultFailure; + + UnicodeStr = HiiGetString (gHiiPackageListHandle, PsidStringId, NULL); + ZeroMem (TmpBuf, sizeof (TmpBuf)); + UnicodeStrToAsciiStrS (UnicodeStr, (CHAR8*)TmpBuf, PSID_CHARACTER_STRING_END_LENGTH); + CopyMem (Psid.Psid, TmpBuf, PSID_CHARACTER_LENGTH); + HiiSetString (gHiiPackageListHandle, PsidStringId, L"", NULL); + ZeroMem (TmpBuf, sizeof (TmpBuf)); + ZeroMem (UnicodeStr, StrSize (UnicodeStr)); + FreePool (UnicodeStr); + + OpalDisk = HiiGetOpalDiskCB (gHiiConfiguration.SelectedDiskIndex); + if (OpalDisk != NULL) { + ZeroMem(&Session, sizeof(Session)); + Session.Sscp = OpalDisk->Sscp; + Session.MediaId = OpalDisk->MediaId; + Session.OpalBaseComId = OpalDisk->OpalBaseComId; + + Ret = OpalSupportPsidRevert(&Session, Psid.Psid, (UINT32)sizeof(Psid.Psid), OpalDisk->OpalDevicePath); + } + + ZeroMem (Psid.Psid, PSID_CHARACTER_LENGTH); + + if (Ret == TcgResultSuccess) { + AsciiSPrint( Response, DEFAULT_RESPONSE_SIZE, "%a", "PSID Revert: Success" ); + } else { + AsciiSPrint( Response, DEFAULT_RESPONSE_SIZE, "%a", "PSID Revert: Failure" ); + } + + HiiSetFormString(STRING_TOKEN(STR_ACTION_STATUS), Response); + + return EFI_SUCCESS; +} + +/** + Set password for the disk. + + @param OpalDisk The disk need to set the password. + @param Password The input password. + @param PassLength The input password length. + + @retval EFI_SUCCESS Do the required action success. + +**/ +EFI_STATUS +HiiSetPassword( + OPAL_DISK *OpalDisk, + VOID *Password, + UINT32 PassLength + ) +{ + CHAR8 Response[DEFAULT_RESPONSE_SIZE]; + TCG_RESULT Ret; + BOOLEAN ExistingPassword; + OPAL_SESSION Session; + + ExistingPassword = FALSE; + + // + // PassLength = 0 means check whether exist old password. + // + if (PassLength == 0) { + ZeroMem(gHiiOldPassword, sizeof(gHiiOldPassword)); + gHiiOldPasswordLength = 0; + + if (gHiiConfiguration.SelectedAction == HII_KEY_ID_GOTO_ENABLE_FEATURE) { + ExistingPassword = FALSE; + } else if (gHiiConfiguration.SelectedAction == HII_KEY_ID_GOTO_SET_ADMIN_PWD) { + ExistingPassword = OpalUtilAdminPasswordExists(OpalDisk->Owner, &OpalDisk->LockingFeature); + } else if (gHiiConfiguration.SelectedAction == HII_KEY_ID_GOTO_SET_USER_PWD) { + // + // Set user Password option shall only be shown if an Admin Password exists + // so a Password is always required (Admin or Existing User Password) + // + ExistingPassword = TRUE; + } + + // + // Return error if there is a previous Password + // see UEFI 2.4 errata B, Figure 121. Password Flowchart + // + return ExistingPassword ? EFI_DEVICE_ERROR : EFI_SUCCESS; + } + + ZeroMem(&Session, sizeof(Session)); + Session.Sscp = OpalDisk->Sscp; + Session.MediaId = OpalDisk->MediaId; + Session.OpalBaseComId = OpalDisk->OpalBaseComId; + + AsciiSPrint(Response, DEFAULT_RESPONSE_SIZE, "%a", "Set Password: Failure"); + // + // Password entered. + // No current Owner, so set new Password, must be admin Password + // + if (OpalDisk->Owner == OpalOwnershipNobody) { + Ret = OpalSupportEnableOpalFeature (&Session, OpalDisk->Msid, OpalDisk->MsidLength,Password, PassLength, OpalDisk->OpalDevicePath); + if (Ret == TcgResultSuccess) { + AsciiSPrint(Response, DEFAULT_RESPONSE_SIZE, "%a", "Set Password: Success"); + } + + HiiSetFormString(STRING_TOKEN(STR_ACTION_STATUS), Response); + return EFI_SUCCESS; + } + + // + // 1st Password entered + // + if (OpalDisk->Owner == OpalOwnershipUnknown && gHiiOldPasswordLength == 0) { + + // + // Unknown ownership - prompt for old Password, then new + // old Password is not set yet - first time through + // assume authority provided is admin1, overwritten if user1 authority works below + // + if (gHiiConfiguration.SelectedAction == HII_KEY_ID_GOTO_SET_USER_PWD) { + // + // First try to login as USER1 to Locking SP to see if we're simply updating its Password + // + Ret = OpalUtilVerifyPassword (&Session, Password, PassLength, OPAL_LOCKING_SP_USER1_AUTHORITY); + if (Ret == TcgResultSuccess) { + // + // User1 worked so authority 1 means user 1 + // + CopyMem(gHiiOldPassword, Password, PassLength); + gHiiOldPasswordLength = PassLength; + + return EFI_SUCCESS; + } + } + + // + // Else try admin1 below + // + Ret = OpalUtilVerifyPassword (&Session, Password, PassLength, OPAL_LOCKING_SP_ADMIN1_AUTHORITY); + if (Ret == TcgResultSuccess) { + CopyMem(gHiiOldPassword, Password, PassLength); + gHiiOldPasswordLength = PassLength; + + return EFI_SUCCESS; + } else { + DEBUG ((DEBUG_INFO, "start session with old PW failed - return EFI_NOT_READY - mistyped old PW\n")); + HiiSetFormString(STRING_TOKEN(STR_ACTION_STATUS), "Authentication Failure"); + + ZeroMem(gHiiOldPassword, sizeof(gHiiOldPassword)); + gHiiOldPasswordLength = 0; + + return EFI_NOT_READY; + } + } + + // + // New Password entered + // + if (gHiiConfiguration.SelectedAction == HII_KEY_ID_GOTO_SET_USER_PWD) { + Ret = OpalSupportSetPassword( + &Session, + gHiiOldPassword, + gHiiOldPasswordLength, + Password, + PassLength, + OpalDisk->OpalDevicePath, + FALSE + ); + } else { + Ret = OpalSupportSetPassword( + &Session, + gHiiOldPassword, + gHiiOldPasswordLength, + Password, + PassLength, + OpalDisk->OpalDevicePath, + TRUE + ); + } + + if (Ret == TcgResultSuccess) { + AsciiSPrint(Response, DEFAULT_RESPONSE_SIZE, "%a", "Set Password: Success"); + } + + // + // Reset old Password storage + // + ZeroMem(gHiiOldPassword, sizeof(gHiiOldPassword)); + gHiiOldPasswordLength = 0; + + HiiSetFormString(STRING_TOKEN(STR_ACTION_STATUS), Response); + return Ret == TcgResultSuccess ? EFI_SUCCESS : EFI_NOT_READY; +} + +/** + Secure Erases Opal Disk. + + @param OpalDisk The disk need to erase data. + @param Password The input password. + @param PassLength The input password length. + + @retval EFI_SUCCESS Do the required action success. + +**/ +EFI_STATUS +HiiSecureErase( + OPAL_DISK *OpalDisk, + const VOID *Password, + UINT32 PassLength + ) +{ + CHAR8 Response[DEFAULT_RESPONSE_SIZE]; + BOOLEAN PasswordFailed; + TCG_RESULT Ret; + OPAL_SESSION AdminSpSession; + + if (PassLength == 0) { + return EFI_DEVICE_ERROR; // return error to indicate there is an existing Password + } + + ZeroMem(&AdminSpSession, sizeof(AdminSpSession)); + AdminSpSession.Sscp = OpalDisk->Sscp; + AdminSpSession.MediaId = OpalDisk->MediaId; + AdminSpSession.OpalBaseComId = OpalDisk->OpalBaseComId; + + Ret = OpalUtilSecureErase(&AdminSpSession, Password, PassLength, &PasswordFailed); + if (Ret == TcgResultSuccess) { + AsciiSPrint( Response, DEFAULT_RESPONSE_SIZE, "%a", "Secure Erase: Success" ); + } else { + AsciiSPrint( Response, DEFAULT_RESPONSE_SIZE, "%a", "Secure Erase: Failure" ); + } + HiiSetFormString(STRING_TOKEN(STR_ACTION_STATUS), Response); + + // + // If Password failed, return invalid passowrd + // + if (PasswordFailed) { + DEBUG ((DEBUG_INFO, "returning EFI_NOT_READY to indicate Password was not correct\n")); + return EFI_NOT_READY; + } + + // + // Indicates Password was valid and is not changing to UEFI + // Response string will indicate action error + // + return EFI_DEVICE_ERROR; +} + + +/** + Disables User for Opal Disk. + + @param OpalDisk The disk need to the action. + @param Password The input password. + @param PassLength The input password length. + + @retval EFI_SUCCESS Do the required action success. + +**/ +EFI_STATUS +HiiDisableUser( + OPAL_DISK *OpalDisk, + VOID *Password, + UINT32 PassLength + ) +{ + CHAR8 Response[ DEFAULT_RESPONSE_SIZE ]; + BOOLEAN PasswordFailed; + TCG_RESULT Ret; + OPAL_SESSION Session; + + if (PassLength == 0) { + return EFI_DEVICE_ERROR; // return error to indicate there is an existing Password + } + + ZeroMem(&Session, sizeof(Session)); + Session.Sscp = OpalDisk->Sscp; + Session.MediaId = OpalDisk->MediaId; + Session.OpalBaseComId = OpalDisk->OpalBaseComId; + + Ret = OpalSupportDisableUser(&Session, Password, PassLength, &PasswordFailed, OpalDisk->OpalDevicePath); + if (Ret == TcgResultSuccess) { + AsciiSPrint( Response, DEFAULT_RESPONSE_SIZE, "%a", "Disable User: Success" ); + } else { + AsciiSPrint( Response, DEFAULT_RESPONSE_SIZE, "%a", "Disable User: Failure" ); + } + HiiSetFormString (STRING_TOKEN(STR_ACTION_STATUS), Response); + + // + // If Password failed, return invalid passowrd + // + if (PasswordFailed) { + DEBUG ((DEBUG_INFO, "returning EFI_NOT_READY to indicate Password was not correct\n")); + return EFI_NOT_READY; + } + + // + // Indicates Password was valid and is not changing to UEFI + // Response string will indicate action error + // + return EFI_DEVICE_ERROR; +} + +/** + Revert Opal Disk as Admin1. + + @param OpalDisk The disk need to the action. + @param Password The input password. + @param PassLength The input password length. + @param KeepUserData Whether need to keey user data. + + @retval EFI_SUCCESS Do the required action success. + +**/ +EFI_STATUS +HiiRevert( + OPAL_DISK *OpalDisk, + VOID *Password, + UINT32 PassLength, + BOOLEAN KeepUserData + ) +{ + CHAR8 Response[ DEFAULT_RESPONSE_SIZE ]; + BOOLEAN PasswordFailed; + TCG_RESULT Ret; + OPAL_SESSION Session; + + if (PassLength == 0) { + DEBUG ((DEBUG_INFO, "Returning error to indicate there is an existing Password\n")); + // return error to indicate there is an existing Password + return EFI_DEVICE_ERROR; + } + + ZeroMem(&Session, sizeof(Session)); + Session.Sscp = OpalDisk->Sscp; + Session.MediaId = OpalDisk->MediaId; + Session.OpalBaseComId = OpalDisk->OpalBaseComId; + + Ret = OpalSupportRevert( + &Session, + KeepUserData, + Password, + PassLength, + OpalDisk->Msid, + OpalDisk->MsidLength, + &PasswordFailed, + OpalDisk->OpalDevicePath + ); + if (Ret == TcgResultSuccess) { + AsciiSPrint( Response, DEFAULT_RESPONSE_SIZE, "%a", "Revert: Success" ); + } else { + AsciiSPrint( Response, DEFAULT_RESPONSE_SIZE, "%a", "Revert: Failure" ); + } + HiiSetFormString(STRING_TOKEN(STR_ACTION_STATUS), Response); + + // + // If Password failed, return invalid passowrd + // + if (PasswordFailed) { + DEBUG ((DEBUG_INFO, "returning EFI_NOT_READY to indicate Password was not correct\n")); + return EFI_NOT_READY; + } + + // + // Indicates Password was valid and is not changing to UEFI + // Response string will indicate action error + // + return EFI_DEVICE_ERROR; +} + +/** + Unlocks Opal Disk. + + @param OpalDisk The disk need to the action. + @param Password The input password. + @param PassLength The input password length. + + @retval EFI_SUCCESS Do the required action success. + +**/ +EFI_STATUS +HiiUnlock( + OPAL_DISK *OpalDisk, + VOID *Password, + UINT32 PassLength + ) +{ + CHAR8 Response[DEFAULT_RESPONSE_SIZE]; + TCG_RESULT Ret; + OPAL_SESSION Session; + + if (PassLength == 0) { + DEBUG ((DEBUG_INFO, "Returning error to indicate there is an existing Password\n")); + return EFI_DEVICE_ERROR; // return error to indicate there is an existing Password + } + + ZeroMem(&Session, sizeof(Session)); + Session.Sscp = OpalDisk->Sscp; + Session.MediaId = OpalDisk->MediaId; + Session.OpalBaseComId = OpalDisk->OpalBaseComId; + + Ret = OpalSupportUnlock(&Session, Password, PassLength, OpalDisk->OpalDevicePath); + if (Ret == TcgResultSuccess) { + AsciiSPrint( Response, DEFAULT_RESPONSE_SIZE, "%a", "Unlock: Success" ); + } else { + AsciiSPrint( Response, DEFAULT_RESPONSE_SIZE, "%a", "Unlock: Failure" ); + } + + HiiSetFormString(STRING_TOKEN(STR_ACTION_STATUS), Response); + + if (Ret == TcgResultSuccess) { + DEBUG ((DEBUG_INFO, "returning error to indicate Password was correct but is not changing\n")); + return EFI_DEVICE_ERROR; + } else { + DEBUG ((DEBUG_INFO, "returning EFI_NOT_READY to indicate Password was not correct\n")); + return EFI_NOT_READY; + } +} + +/** + Use the input password to do the specified action. + + @param Str The input password saved in. + + @retval EFI_SUCCESS Do the required action success. + @retval Others Other error occur. + +**/ +EFI_STATUS +HiiPasswordEntered( + EFI_STRING_ID Str + ) +{ + OPAL_DISK* OpalDisk; + CHAR8 Password[MAX_PASSWORD_CHARACTER_LENGTH + 1]; + CHAR16* UniStr; + UINT32 PassLength; + EFI_STATUS Status; + + OpalHiiGetBrowserData(); + + OpalDisk = HiiGetOpalDiskCB(gHiiConfiguration.SelectedDiskIndex); + if (OpalDisk == NULL) { + DEBUG ((DEBUG_INFO, "ERROR: disk %u not found\n", gHiiConfiguration.SelectedDiskIndex)); + return EFI_NOT_FOUND; + } + + if (Str == 0) { + DEBUG ((DEBUG_INFO, "ERROR: str=NULL\n")); + return EFI_INVALID_PARAMETER; + } + + ZeroMem(Password, sizeof(Password)); + + UniStr = HiiGetString(gHiiPackageListHandle, Str, NULL); + if (UniStr == NULL) { + return EFI_NOT_FOUND; + } + + HiiSetString(gHiiPackageListHandle, Str, L"", NULL); + + PassLength = (UINT32) StrLen (UniStr); + if (PassLength >= sizeof(Password)) { + HiiSetFormString(STRING_TOKEN(STR_ACTION_STATUS), "Password too long"); + ZeroMem (UniStr, StrSize (UniStr)); + FreePool(UniStr); + return EFI_BUFFER_TOO_SMALL; + } + + UnicodeStrToAsciiStrS (UniStr, Password, sizeof (Password)); + ZeroMem (UniStr, StrSize (UniStr)); + FreePool(UniStr); + + if (gHiiConfiguration.SelectedAction == HII_KEY_ID_GOTO_UNLOCK) { + Status = HiiUnlock (OpalDisk, Password, PassLength); + } else if (gHiiConfiguration.SelectedAction == HII_KEY_ID_GOTO_SECURE_ERASE) { + Status = HiiSecureErase (OpalDisk, Password, PassLength); + } else if (gHiiConfiguration.SelectedAction == HII_KEY_ID_GOTO_DISABLE_USER) { + Status = HiiDisableUser (OpalDisk, Password, PassLength); + } else if (gHiiConfiguration.SelectedAction == HII_KEY_ID_GOTO_REVERT) { + if (OpalDisk->SupportedAttributes.PyriteSsc == 1 && OpalDisk->LockingFeature.MediaEncryption == 0) { + // + // For pyrite type device which also not supports media encryption, it not accept "Keep User Data" parameter. + // So here hardcode a FALSE for this case. + // + Status = HiiRevert(OpalDisk, Password, PassLength, FALSE); + } else { + Status = HiiRevert(OpalDisk, Password, PassLength, gHiiConfiguration.KeepUserData); + } + } else { + Status = HiiSetPassword(OpalDisk, Password, PassLength); + } + + ZeroMem (Password, sizeof (Password)); + + OpalHiiSetBrowserData (); + + return Status; +} + +/** + Send BlockSid request through TPM physical presence module. + + @param PpRequest TPM physical presence operation request. + + @retval EFI_SUCCESS Do the required action success. + @retval Others Other error occur. + +**/ +EFI_STATUS +HiiSetBlockSidAction ( + IN UINT32 PpRequest + ) +{ + UINT32 ReturnCode; + EFI_STATUS Status; + + ReturnCode = Tcg2PhysicalPresenceLibSubmitRequestToPreOSFunction (PpRequest, 0); + if (ReturnCode == TCG_PP_SUBMIT_REQUEST_TO_PREOS_SUCCESS) { + Status = EFI_SUCCESS; + } else if (ReturnCode == TCG_PP_SUBMIT_REQUEST_TO_PREOS_GENERAL_FAILURE) { + Status = EFI_OUT_OF_RESOURCES; + } else if (ReturnCode == TCG_PP_SUBMIT_REQUEST_TO_PREOS_NOT_IMPLEMENTED) { + Status = EFI_UNSUPPORTED; + } else { + Status = EFI_DEVICE_ERROR; + } + + return Status; +} + +/** + This function processes the results of changes in configuration. + + @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + @param Configuration A null-terminated Unicode string in + format. + @param Progress A pointer to a string filled in with the offset of + the most recent '&' before the first failing + name/value pair (or the beginning of the string if + the failure is in the first name/value pair) or + the terminating NULL if all was successful. + + @retval EFI_SUCCESS The Results is processed successfully. + @retval EFI_INVALID_PARAMETER Configuration is NULL. + @retval EFI_NOT_FOUND Routing data doesn't match any storage in this + driver. + +**/ +EFI_STATUS +EFIAPI +RouteConfig( + CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, + CONST EFI_STRING Configuration, + EFI_STRING *Progress + ) +{ + if (Configuration == NULL || Progress == NULL) { + return (EFI_INVALID_PARAMETER); + } + + *Progress = Configuration; + if (!HiiIsConfigHdrMatch (Configuration, &gHiiSetupVariableGuid, OpalPasswordStorageName)) { + return EFI_NOT_FOUND; + } + + *Progress = Configuration + StrLen (Configuration); + + return EFI_SUCCESS; +} + +/** + This function allows a caller to extract the current configuration for one + or more named elements from the target driver. + + @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + @param Request A null-terminated Unicode string in + format. + @param Progress On return, points to a character in the Request + string. Points to the string's null terminator if + request was successful. Points to the most recent + '&' before the first failing name/value pair (or + the beginning of the string if the failure is in + the first name/value pair) if the request was not + successful. + @param Results A null-terminated Unicode string in + format which has all values filled + in for the names in the Request string. String to + be allocated by the called function. + + @retval EFI_SUCCESS The Results is filled with the requested values. + @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results. + @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name. + @retval EFI_NOT_FOUND Routing data doesn't match any storage in this + driver. + +**/ +EFI_STATUS +EFIAPI +ExtractConfig( + CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, + CONST EFI_STRING Request, + EFI_STRING *Progress, + EFI_STRING *Results + ) +{ + EFI_STATUS Status; + + // + // Check for valid parameters + // + if (Progress == NULL || Results == NULL) { + return (EFI_INVALID_PARAMETER); + } + + *Progress = Request; + if ((Request != NULL) && + !HiiIsConfigHdrMatch (Request, &gHiiSetupVariableGuid, OpalPasswordStorageName)) { + return EFI_NOT_FOUND; + } + + // + // Convert Buffer Data to 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.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +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 +#include + +#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.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "OpalHii.h" +#include "OpalDriver.h" +#include "OpalDriverPrivate.h" + +/** + Get Opal var name. + The return Value must be freed by caller if not NULL + + @param OpalDisk The disk. + @param Prefix The prefix string. + + @retval The var name string. + +**/ +CHAR16* +OpalDriverGetOpalVarName( + OPAL_DISK *OpalDisk, + const CHAR16 *Prefix + ) +{ + OPAL_DRIVER_DEVICE* Dev; + UINTN PrefixLen; + UINTN NameLen; + UINTN VarNameLen; + CHAR16* VarName; + + Dev = DRIVER_DEVICE_FROM_OPALDISK(OpalDisk); + if (Dev == NULL) { + return NULL; + } + + PrefixLen = StrLen(Prefix); + + NameLen = 0; + if (Dev->Name16 != NULL) { + NameLen = StrLen(Dev->Name16); + } + + VarNameLen = PrefixLen + NameLen; + + VarName = (CHAR16*)AllocateZeroPool((VarNameLen + 1) * sizeof(CHAR16)); + if (VarName == NULL) { + return NULL; + } + + CopyMem(VarName, Prefix, PrefixLen * sizeof(CHAR16)); + if (Dev->Name16 != NULL) { + CopyMem(VarName + PrefixLen, Dev->Name16, NameLen * sizeof(CHAR16)); + } + VarName[VarNameLen] = 0; + + return VarName; +} + +/** + Get the driver image handle. + + @retval the driver image handle. + +**/ +EFI_HANDLE +HiiGetDriverImageHandleCB( + VOID + ) +{ + return gImageHandle; +} + +/** + Check whether enable feature or not. + + @retval Return the disk number. + +**/ +UINT8 +HiiGetNumConfigRequiredOpalDisksCB( + VOID + ) +{ + UINT8 NumDisks; + UINT8 NumLockedOpalDisks; + OPAL_DISK *OpalDisk; + UINT8 Index; + + NumLockedOpalDisks = 0; + + NumDisks = GetDeviceCount(); + + for (Index = 0; Index < NumDisks; Index++) { + OpalDisk = HiiGetOpalDiskCB(Index); + + if (OpalDisk != NULL) { + if (!OpalFeatureEnabled (&OpalDisk->SupportedAttributes, &OpalDisk->LockingFeature)) { + DEBUG ((DEBUG_INFO, "Ignoring disk %u because feature is disabled or health has already been inspected\n", Index)); + } else if (OpalDeviceLocked (&OpalDisk->SupportedAttributes, &OpalDisk->LockingFeature)) { + NumLockedOpalDisks++; + } + } + } + + return NumLockedOpalDisks; +} + + + +/** + Returns the opaque pointer to a physical disk context. + + @param DiskIndex Input the disk index. + + @retval The device pointer. + +**/ +VOID * +HiiGetDiskContextCB( + UINT8 DiskIndex + ) +{ + OPAL_DRIVER_DEVICE* Dev; + UINT8 CurrentDisk; + + Dev = OpalDriverGetDeviceList(); + CurrentDisk = 0; + + if (DiskIndex >= GetDeviceCount()) { + return NULL; + } + + while (Dev != NULL) { + if (CurrentDisk == DiskIndex) { + return Dev; + } else { + Dev = Dev->Next; + CurrentDisk++; + } + } + + return NULL; +} + +/** + Returns the opaque pointer to a physical disk context. + + @param DiskIndex Input the disk index. + + @retval The device pointer. + +**/ +OPAL_DISK* +HiiGetOpalDiskCB( + UINT8 DiskIndex + ) +{ + VOID *Ctx; + OPAL_DRIVER_DEVICE *Tmp; + + Ctx = HiiGetDiskContextCB (DiskIndex); + + if (Ctx == NULL) { + return NULL; + } + + Tmp = (OPAL_DRIVER_DEVICE*) Ctx; + + return &Tmp->OpalDisk; +} + +/** + Returns the disk name. + + @param DiskIndex Input the disk index. + + @retval Returns the disk name. + +**/ +CHAR8* +HiiDiskGetNameCB( + UINT8 DiskIndex + ) +{ + OPAL_DRIVER_DEVICE* Ctx; + + Ctx = (OPAL_DRIVER_DEVICE*) HiiGetDiskContextCB (DiskIndex); + + if (Ctx != NULL) { + if (Ctx->NameZ == NULL) { + OpalDriverGetDriverDeviceName (Ctx); + } + return Ctx->NameZ; + } + return NULL; +} + +/** + Returns the driver name. + + @retval Returns the driver name. + +**/ +CHAR16* +HiiGetDriverNameCB( + VOID + ) +{ + return (CHAR16*)EFI_DRIVER_NAME_UNICODE; +} diff --git a/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalHiiFormStrings.uni b/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalHiiFormStrings.uni new file mode 100644 index 0000000000..4cfbde3f84 --- /dev/null +++ b/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalHiiFormStrings.uni @@ -0,0 +1,103 @@ +// /** @file +// +// String definitions for Setup formset. +// +// Copyright (c) 2016, Intel Corporation. All rights reserved.
+// +// This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// **/ + +/=# +///////////////////////////////// GENERIC DEFINITIONS ///////////////////////////////// +#langdef en-US "English" +#string STR_NULL #language en-US " " + +///////////////////////////////// FORM SET ///////////////////////////////// +#string STR_FORM_SET_HELP #language en-US "Manage Opal disks" + +///////////////////////////////// MULTIPLE FORMS ///////////////////////////////// +#string STR_OPAL #language en-US "Opal" +#string STR_MAIN_OPAL_VERSION #language en-US "Version 00.0.0.0000" + +///////////////////////////////// MAIN MENU FORM ///////////////////////////////// +#string STR_MAIN_PHY_DISKS_LBL #language en-US "Physical Disks:" +#string STR_MAIN_LOCKED_DISKS_LBL #language en-US "Locked Disks:" + +#string STR_MAIN_GOTO_DISK_INFO_0 #language en-US " " +#string STR_MAIN_GOTO_DISK_INFO_1 #language en-US " " +#string STR_MAIN_GOTO_DISK_INFO_2 #language en-US " " +#string STR_MAIN_GOTO_DISK_INFO_3 #language en-US " " +#string STR_MAIN_GOTO_DISK_INFO_4 #language en-US " " +#string STR_MAIN_GOTO_DISK_INFO_5 #language en-US " " + +#string STR_MAIN_GOTO_DISK_INFO_HELP #language en-US "Select to see Opal disk actions" +#string STR_MAIN_GOTO_DISK_HEALTH_HELP #language en-US "Select disk to unlock" + +#string STR_MAIN_NO_DISKS_PRESENT_LBL #language en-US "No disks connected to system" + +///////////////////////////////// DISK INFO MENU FORM ///////////////////////////////// +#string STR_DISK_INFO_SELECTED_DISK_NAME #language en-US " " + +#string STR_DISK_INFO_LOCK #language en-US "Lock" +#string STR_DISK_INFO_UNLOCK #language en-US "Unlock" +#string STR_DISK_INFO_SET_ADMIN_PSWD #language en-US "Update Drive Admin Password" +#string STR_DISK_INFO_SET_USER_PSWD #language en-US "Set Drive User Password" +#string STR_DISK_INFO_SECURE_ERASE #language en-US "Secure Erase User Data" +#string STR_DISK_INFO_PSID_REVERT #language en-US "PSID Revert to factory default" +#string STR_DISK_INFO_REVERT #language en-US "Admin Revert to factory default and Disable" +#string STR_DISK_INFO_DISABLE_USER #language en-US "Disable User" +#string STR_DISK_INFO_ENABLE_FEATURE #language en-US "Enable Feature" +#string STR_DISK_INFO_ENABLE_BLOCKSID #language en-US "TCG Storage Action" +#string STR_ENABLED #language en-US "Enable BlockSID" +#string STR_DISABLED #language en-US "Disable BlockSID" + +#string STR_NONE #language en-US "None" +#string STR_DISK_INFO_ENABLE_BLOCKSID_TRUE #language en-US "Require physical presence when remote enable BlockSID" +#string STR_DISK_INFO_ENABLE_BLOCKSID_FALSE #language en-US "Not require physical presence when remote enable BlockSID" +#string STR_DISK_INFO_DISABLE_BLOCKSID_TRUE #language en-US "Require physical presence when remote disable BlockSID" +#string STR_DISK_INFO_DISABLE_BLOCKSID_FALSE #language en-US "Not require physical presence when remote disable BlockSID" + +#string STR_BLOCKSID_STATUS_HELP #language en-US "BlockSID action change status" +#string STR_BLOCKSID_STATUS #language en-US "Current BlockSID Status:" +#string STR_BLOCKSID_STATUS1 #language en-US "" +#string STR_BLOCKSID_STATUS2 #language en-US "" +#string STR_BLOCKSID_STATUS3 #language en-US "" + +#string STR_DISK_INFO_GOTO_LOCK_HELP #language en-US "Lock the disk" +#string STR_DISK_INFO_GOTO_UNLOCK_HELP #language en-US "Unlock the disk" +#string STR_DISK_INFO_GOTO_SET_ADMIN_PSWD_HELP #language en-US "Set password for the administrator" +#string STR_DISK_INFO_GOTO_SET_USER_PSWD_HELP #language en-US "Set password for User 1" +#string STR_DISK_INFO_GOTO_SECURE_ERASE_HELP #language en-US "Securely erase the disk" +#string STR_DISK_INFO_GOTO_PSID_REVERT_HELP #language en-US "Revert the disk to factory defaults" +#string STR_DISK_INFO_GOTO_DISABLE_USER_HELP #language en-US "Disable User" +#string STR_DISK_INFO_GOTO_ENABLE_FEATURE_HELP #language en-US "Enable Feature" +#string STR_DISK_INFO_GOTO_ENABLE_BLOCKSID_HELP #language en-US "Change BlockSID actions, includes enable or disable BlockSID, Require or not require physical presence when remote enable or disable BlockSID" + +///////////////////////////////// DISK ACTION MENU FORM ///////////////////////////////// +#string STR_DISK_ACTION_LBL #language en-US " " + +#string STR_PASSWORD_PROMPT #language en-US "Enter Password" +#string STR_PASSWORD_HELP #language en-US "Password must be between 6 and 20 characters" + +#string STR_REVERT_PROMPT #language en-US "Enter PSID" +#string STR_REVERT_HELP #language en-US "PSID is a 32 character case sensitive value" +#string STR_ACTION_STATUS #language en-US " " + +#string STR_PASSWORD_SUBMIT #language en-US "Submit Password Changes" +#string STR_PASSWORD_SUBMIT_HELP #language en-US "Submits Password Changes (new and update) after passwords have been entered" + +#string STR_GOTO_HOME #language en-US "Main Menu" +#string STR_GOTO_HOME_HELP #language en-US "Return to the main menu" + +#string STR_KEEP_USER_DATA_PROMPT #language en-US "Keep User Data" +#string STR_KEEP_USER_DATA_HELP #language en-US "Checkmark to keep user data, otherwise data will be lost" + +#string STR_OK #language en-US "OK" + diff --git a/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalHiiFormValues.h b/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalHiiFormValues.h new file mode 100644 index 0000000000..88cf9f5b59 --- /dev/null +++ b/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalHiiFormValues.h @@ -0,0 +1,120 @@ +/** @file + Defines Opal HII form ids, structures and values. + +Copyright (c) 2016, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + + +#ifndef _OPAL_HII_FORM_VALUES_H_ +#define _OPAL_HII_FORM_VALUES_H_ + +// Maximum Opal password Length +#define MAX_PASSWORD_CHARACTER_LENGTH 0x14 + +// PSID Length +#define PSID_CHARACTER_LENGTH 0x20 +#define PSID_CHARACTER_STRING_END_LENGTH 0x21 + +// ID's for various forms that will be used by HII +#define FORMID_VALUE_MAIN_MENU 0x01 +#define FORMID_VALUE_DISK_INFO_FORM_MAIN 0x02 +#define FORMID_VALUE_DISK_ACTION_FORM 0x03 + +// Structure defining the OPAL_HII_CONFIGURATION +#pragma pack(1) +typedef struct { + UINT8 NumDisks; + UINT8 SelectedDiskIndex; + UINT8 SelectedAction; + UINT16 SelectedDiskAvailableActions; + UINT16 SupportedDisks; + UINT8 KeepUserData; + UINT16 AvailableFields; + UINT16 Password[MAX_PASSWORD_CHARACTER_LENGTH]; + UINT16 Psid[PSID_CHARACTER_STRING_END_LENGTH]; + UINT8 EnableBlockSid; +} OPAL_HII_CONFIGURATION; +#pragma pack() + +/* Action Flags */ +#define HII_ACTION_NONE 0x0000 +#define HII_ACTION_LOCK 0x0001 +#define HII_ACTION_UNLOCK 0x0002 +#define HII_ACTION_SET_ADMIN_PWD 0x0004 +#define HII_ACTION_SET_USER_PWD 0x0008 +#define HII_ACTION_SECURE_ERASE 0x0010 +#define HII_ACTION_PSID_REVERT 0x0020 +#define HII_ACTION_DISABLE_USER 0x0040 +#define HII_ACTION_REVERT 0x0080 +#define HII_ACTION_DISABLE_FEATURE 0x0100 +#define HII_ACTION_ENABLE_FEATURE 0x0200 + +/* Flags for diskActionAvailableFields */ +#define HII_FIELD_PASSWORD 0x0001 +#define HII_FIELD_PSID 0x0002 +#define HII_FIELD_KEEP_USER_DATA 0x0004 +#define HII_FIELD_KEEP_USER_DATA_FORCED 0x0008 + +/* Number of bits allocated for each part of a unique key for an HII_ITEM + * all bits together must be <= 16 (EFI_QUESTION_ID is UINT16) + * 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + * | |-----------------------| |---------------------------| + * FLG INDEX ID + */ +#define HII_KEY_ID_BITS 8 +#define HII_KEY_INDEX_BITS 7 +#define HII_KEY_FLAG_BITS 1 + +#define HII_KEY_FLAG 0x8000 // bit 15 (zero based) + +/***********/ +/* Key IDs */ +/***********/ + +#define HII_KEY_ID_GOTO_MAIN_MENU 0 +#define HII_KEY_ID_GOTO_DISK_INFO 1 +#define HII_KEY_ID_GOTO_LOCK 2 +#define HII_KEY_ID_GOTO_UNLOCK 3 +#define HII_KEY_ID_GOTO_SET_ADMIN_PWD 4 +#define HII_KEY_ID_GOTO_SET_USER_PWD 5 +#define HII_KEY_ID_GOTO_SECURE_ERASE 6 +#define HII_KEY_ID_GOTO_PSID_REVERT 7 +#define HII_KEY_ID_GOTO_REVERT 8 +#define HII_KEY_ID_GOTO_DISABLE_USER 9 +#define HII_KEY_ID_GOTO_ENABLE_FEATURE 0xA //10 +#define HII_KEY_ID_GOTO_CONFIRM_TO_MAIN_MENU 0xB //11 +#define HII_KEY_ID_ENTER_PASSWORD 0xC //12 +#define HII_KEY_ID_ENTER_PSID 0xD //13 +#define HII_KEY_ID_VAR_SUPPORTED_DISKS 0xE //14 +#define HII_KEY_ID_VAR_SELECTED_DISK_AVAILABLE_ACTIONS 0xF //15 + +#define HII_KEY_ID_BLOCKSID 0x17 //23 +#define HII_KEY_ID_MAX 0x17 //23 // !!Update each time a new ID is added!! + +#define HII_KEY_WITH_INDEX(id, index) \ + ( \ + HII_KEY_FLAG | \ + (id) | \ + ((index) << HII_KEY_ID_BITS) \ + ) + +#define HII_KEY(id) HII_KEY_WITH_INDEX(id, 0) + +#define PACKAGE_LIST_GUID { 0xf0308176, 0x9058, 0x4153, { 0x93, 0x3d, 0xda, 0x2f, 0xdc, 0xc8, 0x3e, 0x44 } } + +/* {410483CF-F4F9-4ece-848A-1958FD31CEB7} */ +#define SETUP_FORMSET_GUID { 0x410483cf, 0xf4f9, 0x4ece, { 0x84, 0x8a, 0x19, 0x58, 0xfd, 0x31, 0xce, 0xb7 } } + +// {BBF1ACD2-28D8-44ea-A291-58A237FEDF1A} +#define SETUP_VARIABLE_GUID { 0xbbf1acd2, 0x28d8, 0x44ea, { 0xa2, 0x91, 0x58, 0xa2, 0x37, 0xfe, 0xdf, 0x1a } } + +#endif //_HII_FORM_VALUES_H_ + diff --git a/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalHiiPrivate.h b/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalHiiPrivate.h new file mode 100644 index 0000000000..ec5a93cf3f --- /dev/null +++ b/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalHiiPrivate.h @@ -0,0 +1,268 @@ +/** @file + Private functions and sturctures used by the Opal UEFI Driver. + +Copyright (c) 2016, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +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 +#include + +#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 + 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 + format. + @param Progress On return, points to a character in the Request + string. Points to the string's null terminator if + request was successful. Points to the most recent + '&' before the first failing name/value pair (or + the beginning of the string if the failure is in + the first name/value pair) if the request was not + successful. + @param Results A null-terminated Unicode string in + format which has all values filled + in for the names in the Request string. String to + be allocated by the called function. + + @retval EFI_SUCCESS The Results is filled with the requested values. + @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results. + @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name. + @retval EFI_NOT_FOUND Routing data doesn't match any storage in this + driver. + +**/ +EFI_STATUS +EFIAPI +ExtractConfig( + CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, + CONST EFI_STRING Request, + EFI_STRING *Progress, + EFI_STRING *Results + ); + +/** + This function processes the results of changes in configuration. + + @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + @param Action Specifies the type of action taken by the browser. + @param QuestionId A unique value which is sent to the original + exporting driver so that it can identify the type + of data to expect. + @param Type The type of value for the question. + @param Value A pointer to the data being sent to the original + exporting driver. + @param ActionRequest On return, points to the action requested by the + callback function. + + @retval EFI_SUCCESS The callback successfully handled the action. + @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the + variable and its data. + @retval EFI_DEVICE_ERROR The variable could not be saved. + @retval EFI_UNSUPPORTED The specified Action is not supported by the + callback. + +**/ +EFI_STATUS +EFIAPI +DriverCallback( + CONST EFI_HII_CONFIG_ACCESS_PROTOCOL* This, + EFI_BROWSER_ACTION Action, + EFI_QUESTION_ID QuestionId, + UINT8 Type, + EFI_IFR_TYPE_VALUE* Value, + EFI_BROWSER_ACTION_REQUEST* ActionRequest + ); + +/** + + Pass the current system state to the bios via the hii_G_Configuration. + +**/ +VOID +OpalHiiSetBrowserData ( + VOID + ); + +/** + + Populate the hii_g_Configuraton with the browser Data. + +**/ +VOID +OpalHiiGetBrowserData ( + VOID + ); + +/** + Draws the disk info form. + + @retval EFI_SUCCESS Draw the disk info success. + +**/ +EFI_STATUS +HiiPopulateDiskInfoForm( + VOID + ); + +/** + Update the global Disk index info. + + @param Index The input disk index info. + + @retval EFI_SUCCESS Update the disk index info success. + +**/ +EFI_STATUS +HiiSelectDisk( + UINT8 Index + ); + +/** + Use the input password to do the specified action. + + @param Str The input password saved in. + + @retval EFI_SUCCESS Do the required action success. + @retval Others Other error occur. + +**/ +EFI_STATUS +HiiPasswordEntered( + EFI_STRING_ID Str + ); + +/** + Update block sid info. + + @param PpRequest Input the Pp Request. + + @retval EFI_SUCCESS Do the required action success. + @retval Others Other error occur. + +**/ +EFI_STATUS +HiiSetBlockSidAction ( + UINT32 PpRequest + ); + +/** + Reverts the Opal disk to factory default. + + @param PsidStringId The string id for the PSID info. + + @retval EFI_SUCCESS Do the required action success. + +**/ +EFI_STATUS +HiiPsidRevert( + EFI_STRING_ID PsidStringId + ); + +/** + Get disk name string id. + + @param DiskIndex The input disk index info. + + @retval The disk name string id. + +**/ +EFI_STRING_ID +GetDiskNameStringId( + UINT8 DiskIndex + ); + +/** + Update the device info. + + @param OpalDisk The Opal device. + + @retval EFI_SUCESS Initialize the device success. + @retval EFI_DEVICE_ERROR Get info from device failed. + @retval EFI_INVALID_PARAMETER Not get Msid info before get ownership info. + +**/ +EFI_STATUS +OpalDiskUpdateStatus ( + OPAL_DISK *OpalDisk + ); + +#pragma pack() + +#endif // _HII_P_H_ diff --git a/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalPasswordDxe.inf b/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalPasswordDxe.inf new file mode 100644 index 0000000000..f2afc37810 --- /dev/null +++ b/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalPasswordDxe.inf @@ -0,0 +1,82 @@ +## @file +# This is a OpalPasswordDxe driver. +# +# This module is used to Management the Opal feature +# for Opal supported devices. +# +# +# Copyright (c) 2016, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## +[Defines] + INF_VERSION = 0x00010007 + BASE_NAME = OpalPasswordDxe + FILE_GUID = E3E4048D-6C0C-43E4-AE1C-FFB579D8EF41 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = EfiDriverEntryPoint + UNLOAD_IMAGE = OpalEfiDriverUnload + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + OpalDriver.h + OpalHii.c + OpalHiiCallbacks.c + OpalDriver.c + OpalDriverPrivate.h + OpalHii.h + OpalHiiPrivate.h + OpalHiiFormValues.h + OpalPasswordForm.vfr + OpalHiiFormStrings.uni + ComponentName.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + BaseLib + MemoryAllocationLib + UefiBootServicesTableLib + UefiDriverEntryPoint + UefiHiiServicesLib + UefiRuntimeServicesTableLib + BaseMemoryLib + DebugLib + HiiLib + PrintLib + DevicePathLib + OpalPasswordSupportLib + UefiLib + TcgStorageOpalLib + Tcg2PhysicalPresenceLib + +[Protocols] + gEfiHiiConfigAccessProtocolGuid ## PRODUCES + gEfiStorageSecurityCommandProtocolGuid ## CONSUMES + gEfiComponentNameProtocolGuid ## PRODUCES + gEfiComponentName2ProtocolGuid ## PRODUCES + gEfiBlockIoProtocolGuid ## CONSUMES + gEfiSmmCommunicationProtocolGuid ## PRODUCES + gEfiPciIoProtocolGuid ## CONSUMES + gEfiDevicePathToTextProtocolGuid ## CONSUMES + +[Guids] + gEfiEventExitBootServicesGuid ## CONSUMES ## Event + gOpalExtraInfoVariableGuid ## PRODUCES ## GUID + +[Depex] + gEfiSmmCommunicationProtocolGuid AND gEfiHiiStringProtocolGuid AND gEfiHiiDatabaseProtocolGuid diff --git a/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalPasswordForm.vfr b/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalPasswordForm.vfr new file mode 100644 index 0000000000..218e0f442c --- /dev/null +++ b/Core/SecurityPkg/Tcg/Opal/OpalPasswordDxe/OpalPasswordForm.vfr @@ -0,0 +1,350 @@ +/** @file + +Copyright (c) 2016, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ +#include "OpalHiiFormValues.h" + + +#define EFI_HII_PLATFORM_SETUP_FORMSET_GUID \ + { 0x93039971, 0x8545, 0x4b04, { 0xb4, 0x5e, 0x32, 0xeb, 0x83, 0x26, 0x4, 0xe } } + +formset + guid = SETUP_FORMSET_GUID, + title = STRING_TOKEN(STR_OPAL), + help = STRING_TOKEN(STR_FORM_SET_HELP), + classguid = EFI_HII_PLATFORM_SETUP_FORMSET_GUID, + + // Define a Buffer Storage (EFI_IFR_VARSTORE) that will be filled + // out initially through extractConfig call + varstore OPAL_HII_CONFIGURATION, // This is the Data structure type + name = OpalHiiConfig, // Define referenced name in vfr + guid = SETUP_VARIABLE_GUID; // GUID of this Buffer storage + +form formid = FORMID_VALUE_MAIN_MENU, + title = STRING_TOKEN(STR_OPAL); + + //CONFIG_VARIABLE(HII_KEY(HII_KEY_ID_VAR_SUPPORTED_DISKS), SupportedDisks, 0x0, 0xFFFF); + suppressif TRUE; + numeric + name = SupportedDisks, + varid = OpalHiiConfig.SupportedDisks, + prompt = STRING_TOKEN(STR_NULL), + help = STRING_TOKEN(STR_NULL), + flags = INTERACTIVE, + key = 0x800E, //32782, + minimum = 0x0, + maximum = 0xFFFF, + endnumeric; + endif; + + subtitle text = STRING_TOKEN(STR_MAIN_OPAL_VERSION); + + subtitle text = STRING_TOKEN(STR_NULL); + + text + help = STRING_TOKEN(STR_NULL), + text = STRING_TOKEN(STR_MAIN_PHY_DISKS_LBL); + + subtitle text = STRING_TOKEN(STR_NULL); + + //DISK( 0 ); + suppressif ( questionref(SupportedDisks) & ( 0x1 ) ) == 0; + goto FORMID_VALUE_DISK_INFO_FORM_MAIN, + prompt = STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_0 ), + help = STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_HELP), + flags = INTERACTIVE, \ + key = 0x8001; //32769 + endif; + + //DISK( 1 ); + suppressif ( questionref(SupportedDisks) & ( 0x2 ) ) == 0; + goto FORMID_VALUE_DISK_INFO_FORM_MAIN, + prompt = STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_1 ), + help = STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_HELP), + flags = INTERACTIVE, \ + key = 0x8101; //33025 + endif; + + //DISK( 2 ); + suppressif ( questionref(SupportedDisks) & ( 0x4 ) ) == 0; + goto FORMID_VALUE_DISK_INFO_FORM_MAIN, + prompt = STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_2 ), + help = STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_HELP), + flags = INTERACTIVE, \ + key = 0x8201; //33281 + endif; + + //DISK( 3 ); + suppressif ( questionref(SupportedDisks) & ( 0x8 ) ) == 0; + goto FORMID_VALUE_DISK_INFO_FORM_MAIN, + prompt = STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_3 ), + help = STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_HELP), + flags = INTERACTIVE, \ + key = 0x8301; // 33537 + endif; + + //DISK( 4 ); + suppressif ( questionref(SupportedDisks) & ( 0x10 ) ) == 0; + goto FORMID_VALUE_DISK_INFO_FORM_MAIN, + prompt = STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_4 ), + help = STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_HELP), + flags = INTERACTIVE, \ + key = 0x8401; // 33793 + endif; + + //DISK( 5 ); + suppressif ( questionref(SupportedDisks) & ( 0x20 ) ) == 0; + goto FORMID_VALUE_DISK_INFO_FORM_MAIN, + prompt = STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_5 ), + help = STRING_TOKEN(STR_MAIN_GOTO_DISK_INFO_HELP), + flags = INTERACTIVE, \ + key = 0x8501; // 34049 + endif; + + //No disks on system + suppressif ideqval OpalHiiConfig.NumDisks > 0; + text + help = STRING_TOKEN(STR_NULL), + text = STRING_TOKEN(STR_MAIN_NO_DISKS_PRESENT_LBL); + endif; + + subtitle text = STRING_TOKEN(STR_NULL); + + grayoutif TRUE; + text + help = STRING_TOKEN(STR_BLOCKSID_STATUS_HELP), + text = STRING_TOKEN(STR_BLOCKSID_STATUS); + text + help = STRING_TOKEN(STR_BLOCKSID_STATUS_HELP), + text = STRING_TOKEN(STR_BLOCKSID_STATUS1); + text + help = STRING_TOKEN(STR_BLOCKSID_STATUS_HELP), + text = STRING_TOKEN(STR_BLOCKSID_STATUS2); + text + help = STRING_TOKEN(STR_BLOCKSID_STATUS_HELP), + text = STRING_TOKEN(STR_BLOCKSID_STATUS3); + subtitle text = STRING_TOKEN(STR_NULL); + endif; + + oneof varid = OpalHiiConfig.EnableBlockSid, + questionid = 0x8017, // 32791, + prompt = STRING_TOKEN(STR_DISK_INFO_ENABLE_BLOCKSID), + help = STRING_TOKEN(STR_DISK_INFO_GOTO_ENABLE_BLOCKSID_HELP), + flags = INTERACTIVE, + option text = STRING_TOKEN(STR_NONE), value = 0, flags = DEFAULT | MANUFACTURING | RESET_REQUIRED; + option text = STRING_TOKEN(STR_ENABLED), value = 1, flags = RESET_REQUIRED; + option text = STRING_TOKEN(STR_DISABLED), value = 2, flags = RESET_REQUIRED; + option text = STRING_TOKEN(STR_DISK_INFO_ENABLE_BLOCKSID_TRUE), value = 3, flags = RESET_REQUIRED; + option text = STRING_TOKEN(STR_DISK_INFO_ENABLE_BLOCKSID_FALSE), value = 4, flags = RESET_REQUIRED; + option text = STRING_TOKEN(STR_DISK_INFO_DISABLE_BLOCKSID_TRUE), value = 5, flags = RESET_REQUIRED; + option text = STRING_TOKEN(STR_DISK_INFO_DISABLE_BLOCKSID_FALSE), value = 6, flags = RESET_REQUIRED; + endoneof; + + + +endform; // MAIN MENU FORM + +// +///////////////// DISK INFO FORM ///////////////// +// +form formid = FORMID_VALUE_DISK_INFO_FORM_MAIN, + title = STRING_TOKEN(STR_OPAL); + + suppressif TRUE; + numeric + name = SelectedDiskAvailableActions, + varid = OpalHiiConfig.SelectedDiskAvailableActions, + prompt = STRING_TOKEN(STR_NULL), + help = STRING_TOKEN(STR_NULL), + flags = INTERACTIVE, + key = 0x800F, // 32783 + minimum = 0x0, + maximum = 0xFFFF, + endnumeric; + endif; + + subtitle text = STRING_TOKEN(STR_MAIN_OPAL_VERSION); + + subtitle text = STRING_TOKEN(STR_NULL); + + text + help = STRING_TOKEN(STR_NULL), + text = STRING_TOKEN(STR_DISK_INFO_SELECTED_DISK_NAME); + + subtitle text = STRING_TOKEN(STR_NULL); + + suppressif ( questionref(SelectedDiskAvailableActions) & HII_ACTION_LOCK ) == 0; + goto FORMID_VALUE_DISK_ACTION_FORM, + prompt = STRING_TOKEN(STR_DISK_INFO_LOCK), + help = STRING_TOKEN(STR_DISK_INFO_GOTO_LOCK_HELP), + flags = INTERACTIVE, + key = 0x8002; // 32770 + endif; + + suppressif ( questionref(SelectedDiskAvailableActions) & HII_ACTION_UNLOCK ) == 0; + goto FORMID_VALUE_DISK_ACTION_FORM, + prompt = STRING_TOKEN(STR_DISK_INFO_UNLOCK), + help = STRING_TOKEN(STR_DISK_INFO_GOTO_UNLOCK_HELP), + flags = INTERACTIVE, + key = 0x8003; //32771; + endif; + + suppressif ( questionref(SelectedDiskAvailableActions) & HII_ACTION_SET_ADMIN_PWD ) == 0; + goto FORMID_VALUE_DISK_ACTION_FORM, + prompt = STRING_TOKEN(STR_DISK_INFO_SET_ADMIN_PSWD), + help = STRING_TOKEN(STR_DISK_INFO_GOTO_SET_ADMIN_PSWD_HELP), + flags = INTERACTIVE, + key = 0x8004; //32772; + endif; + + suppressif ( questionref(SelectedDiskAvailableActions) & HII_ACTION_SET_USER_PWD ) == 0; + goto FORMID_VALUE_DISK_ACTION_FORM, + prompt = STRING_TOKEN(STR_DISK_INFO_SET_USER_PSWD), + help = STRING_TOKEN(STR_DISK_INFO_GOTO_SET_USER_PSWD_HELP), + flags = INTERACTIVE, + key = 0x8005; //32773; + endif; + + suppressif ( questionref(SelectedDiskAvailableActions) & HII_ACTION_SECURE_ERASE ) == 0; + goto FORMID_VALUE_DISK_ACTION_FORM, + prompt = STRING_TOKEN(STR_DISK_INFO_SECURE_ERASE), + help = STRING_TOKEN(STR_DISK_INFO_GOTO_SECURE_ERASE_HELP), + flags = INTERACTIVE, + key = 0x8006; //32774; + endif; + + suppressif ( questionref(SelectedDiskAvailableActions) & HII_ACTION_REVERT ) == 0; + goto FORMID_VALUE_DISK_ACTION_FORM, + prompt = STRING_TOKEN(STR_DISK_INFO_REVERT), + help = STRING_TOKEN(STR_DISK_INFO_GOTO_PSID_REVERT_HELP), + flags = INTERACTIVE, + key = 0x8008; //32776; + endif; + + suppressif ( questionref(SelectedDiskAvailableActions) & HII_ACTION_PSID_REVERT ) == 0; + goto FORMID_VALUE_DISK_ACTION_FORM, + prompt = STRING_TOKEN(STR_DISK_INFO_PSID_REVERT), + help = STRING_TOKEN(STR_DISK_INFO_GOTO_PSID_REVERT_HELP), + flags = INTERACTIVE, + key = 0x8007; //32775; + endif; + + suppressif ( questionref(SelectedDiskAvailableActions) & HII_ACTION_DISABLE_USER ) == 0; + goto FORMID_VALUE_DISK_ACTION_FORM, + prompt = STRING_TOKEN(STR_DISK_INFO_DISABLE_USER), + help = STRING_TOKEN(STR_DISK_INFO_GOTO_DISABLE_USER_HELP), + flags = INTERACTIVE, + key = 0x8009; //32777; + endif; + + suppressif ( questionref(SelectedDiskAvailableActions) & HII_ACTION_ENABLE_FEATURE ) == 0; + goto FORMID_VALUE_DISK_ACTION_FORM, + prompt = STRING_TOKEN(STR_DISK_INFO_ENABLE_FEATURE), + help = STRING_TOKEN(STR_DISK_INFO_GOTO_ENABLE_FEATURE_HELP), + flags = INTERACTIVE, + key = 0x800A; //32778; + endif; + +endform; // DISK INFO FORM + +// +///////////////// DISK ACTION FORM ///////////////// +// +form formid = FORMID_VALUE_DISK_ACTION_FORM, + title = STRING_TOKEN(STR_OPAL); + + suppressif TRUE; + numeric + name = AvailableFields, + varid = OpalHiiConfig.AvailableFields, + prompt = STRING_TOKEN(STR_NULL), + help = STRING_TOKEN(STR_NULL), + flags = INTERACTIVE, + key = 0x8012, //32786, + minimum = 0x0, + maximum = 0xFFFF, + endnumeric; + endif; + + subtitle text = STRING_TOKEN(STR_MAIN_OPAL_VERSION); + + subtitle text = STRING_TOKEN(STR_NULL); + + text + help = STRING_TOKEN(STR_NULL), + text = STRING_TOKEN(STR_DISK_INFO_SELECTED_DISK_NAME); + + subtitle text = STRING_TOKEN(STR_NULL); + + text + help = STRING_TOKEN(STR_NULL), + text = STRING_TOKEN(STR_DISK_ACTION_LBL); + + subtitle text = STRING_TOKEN(STR_NULL); + + suppressif (questionref(AvailableFields) & HII_FIELD_KEEP_USER_DATA) == 0; + grayoutif (questionref(AvailableFields) & HII_FIELD_KEEP_USER_DATA_FORCED) != 0; + checkbox + name = MyCheckbox, + varid = OpalHiiConfig.KeepUserData, + prompt = STRING_TOKEN(STR_KEEP_USER_DATA_PROMPT), + help = STRING_TOKEN(STR_KEEP_USER_DATA_HELP), + key = 0x8011, //32785, + endcheckbox; + + //EMPTY_LINE; + text + help = STRING_TOKEN(STR_NULL), + text = STRING_TOKEN(STR_NULL); + endif; + endif; + + suppressif (questionref(AvailableFields) & HII_FIELD_PASSWORD) == 0; + password + varid = OpalHiiConfig.Password, + prompt = STRING_TOKEN(STR_PASSWORD_PROMPT), + help = STRING_TOKEN(STR_PASSWORD_HELP), + flags = INTERACTIVE, + key = 0x800C, //32780, + minsize = 6, + maxsize = 20, + endpassword; + endif; + + suppressif (questionref(AvailableFields) & HII_FIELD_PSID) == 0; + string + varid = OpalHiiConfig.Psid, + prompt = STRING_TOKEN(STR_REVERT_PROMPT), + help = STRING_TOKEN(STR_REVERT_HELP), + flags = INTERACTIVE, + key = 0x800D, //32781, + minsize = PSID_CHARACTER_LENGTH, + maxsize = PSID_CHARACTER_LENGTH, + endstring; + endif; + + subtitle text = STRING_TOKEN(STR_NULL); + + text + help = STRING_TOKEN(STR_NULL), + text = STRING_TOKEN(STR_ACTION_STATUS); + + subtitle text = STRING_TOKEN(STR_NULL); + + goto FORMID_VALUE_MAIN_MENU, + prompt = STRING_TOKEN(STR_GOTO_HOME), + help = STRING_TOKEN(STR_GOTO_HOME_HELP), + flags = INTERACTIVE, + key = 0x8000; //32768; + +endform; // DISK ACTION FORM + +endformset; diff --git a/Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalAhciMode.c b/Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalAhciMode.c new file mode 100644 index 0000000000..33f77bd8a2 --- /dev/null +++ b/Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalAhciMode.c @@ -0,0 +1,1295 @@ +/** @file + This driver is used for Opal Password Feature support at AHCI mode. + +Copyright (c) 2016, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE 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.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +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.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE 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.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + + + +#ifndef __OPAL_PASSWORD_IDE_MODE_H__ +#define __OPAL_PASSWORD_IDE_MODE_H__ + +typedef enum { + EfiIdePrimary = 0, + EfiIdeSecondary = 1, + EfiIdeMaxChannel = 2 +} EFI_IDE_CHANNEL; + +typedef enum { + EfiIdeMaster = 0, + EfiIdeSlave = 1, + EfiIdeMaxDevice = 2 +} EFI_IDE_DEVICE; + +// +// IDE registers set +// +typedef struct { + UINT16 Data; + UINT16 ErrOrFeature; + UINT16 SectorCount; + UINT16 SectorNumber; + UINT16 CylinderLsb; + UINT16 CylinderMsb; + UINT16 Head; + UINT16 CmdOrStatus; + UINT16 AltOrDev; +} EFI_IDE_REGISTERS; + +// +// Bit definitions in Programming Interface byte of the Class Code field +// in PCI IDE controller's Configuration Space +// +#define IDE_PRIMARY_OPERATING_MODE BIT0 +#define IDE_PRIMARY_PROGRAMMABLE_INDICATOR BIT1 +#define IDE_SECONDARY_OPERATING_MODE BIT2 +#define IDE_SECONDARY_PROGRAMMABLE_INDICATOR BIT3 + +/** + Get IDE i/o port registers' base addresses by mode. + + In 'Compatibility' mode, use fixed addresses. + In Native-PCI mode, get base addresses from BARs in the PCI IDE controller's + Configuration Space. + + The steps to get IDE i/o port registers' base addresses for each channel + as follows: + + 1. Examine the Programming Interface byte of the Class Code fields in PCI IDE + controller's Configuration Space to determine the operating mode. + + 2. a) In 'Compatibility' mode, use fixed addresses shown in the Table 1 below. + ___________________________________________ + | | Command Block | Control Block | + | Channel | Registers | Registers | + |___________|_______________|_______________| + | Primary | 1F0h - 1F7h | 3F6h - 3F7h | + |___________|_______________|_______________| + | Secondary | 170h - 177h | 376h - 377h | + |___________|_______________|_______________| + + Table 1. Compatibility resource mappings + + b) In Native-PCI mode, IDE registers are mapped into IO space using the BARs + in IDE controller's PCI Configuration Space, shown in the Table 2 below. + ___________________________________________________ + | | Command Block | Control Block | + | Channel | Registers | Registers | + |___________|___________________|___________________| + | Primary | BAR at offset 0x10| BAR at offset 0x14| + |___________|___________________|___________________| + | Secondary | BAR at offset 0x18| BAR at offset 0x1C| + |___________|___________________|___________________| + + Table 2. BARs for Register Mapping + + @param[in] Bus The bus number of ata host controller. + @param[in] Device The device number of ata host controller. + @param[in] Function The function number of ata host controller. + @param[in, out] IdeRegisters Pointer to EFI_IDE_REGISTERS which is used to + store the IDE i/o port registers' base addresses + + @retval EFI_UNSUPPORTED Return this Value when the BARs is not IO type + @retval EFI_SUCCESS Get the Base address successfully + @retval Other Read the pci configureation Data error + +**/ +EFI_STATUS +EFIAPI +GetIdeRegisterIoAddr ( + IN UINTN Bus, + IN UINTN Device, + IN UINTN Function, + IN OUT EFI_IDE_REGISTERS *IdeRegisters + ); + +/** + Sends out an ATA Identify Command to the specified device. + + This function sends out the ATA Identify Command to the + specified device. Only ATA device responses to this command. If + the command succeeds, it returns the Identify Data structure which + contains information about the device. This function extracts the + information it needs to fill the IDE_BLK_IO_DEV Data structure, + including device type, media block Size, media capacity, and etc. + + @param IdeRegisters A pointer to EFI_IDE_REGISTERS Data structure. + @param Channel The channel number of device. + @param Device The device number of device. + @param Buffer A pointer to Data Buffer which is used to contain IDENTIFY Data. + + @retval EFI_SUCCESS Identify ATA device successfully. + @retval EFI_DEVICE_ERROR ATA Identify Device Command failed or device is not ATA device. + @retval EFI_OUT_OF_RESOURCES Allocate memory failed. +**/ +EFI_STATUS +EFIAPI +AtaIdentify ( + IN EFI_IDE_REGISTERS *IdeRegisters, + IN UINT8 Channel, + IN UINT8 Device, + IN OUT ATA_IDENTIFY_DATA *Buffer + ); + +/** + This function is used to send out ATA commands conforms to the PIO Data In Protocol. + + @param IdeRegisters A pointer to EFI_IDE_REGISTERS Data structure. + @param Buffer A pointer to the source Buffer for the Data. + @param ByteCount The Length of the Data. + @param Read Flag used to determine the Data transfer direction. + Read equals 1, means Data transferred from device to host; + Read equals 0, means Data transferred from host to device. + @param AtaCommandBlock A pointer to EFI_ATA_COMMAND_BLOCK Data structure. + @param AtaStatusBlock A pointer to EFI_ATA_STATUS_BLOCK Data structure. + @param Timeout The time to complete the command. + + @retval EFI_SUCCESS send out the ATA command and device send required Data successfully. + @retval EFI_DEVICE_ERROR command sent failed. + +**/ +EFI_STATUS +EFIAPI +AtaPioDataInOut ( + IN EFI_IDE_REGISTERS *IdeRegisters, + IN OUT VOID *Buffer, + IN UINT64 ByteCount, + IN BOOLEAN Read, + IN EFI_ATA_COMMAND_BLOCK *AtaCommandBlock, + IN OUT EFI_ATA_STATUS_BLOCK *AtaStatusBlock, + IN UINT64 Timeout + ); + + +#endif + diff --git a/Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalNvmeMode.c b/Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalNvmeMode.c new file mode 100644 index 0000000000..a47d2764c3 --- /dev/null +++ b/Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalNvmeMode.c @@ -0,0 +1,2165 @@ +/** @file + Provide functions to initialize NVME controller and perform NVME commands + +Copyright (c) 2016 - 2017, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "OpalPasswordSmm.h" + + +#define ALIGN(v, a) (UINTN)((((v) - 1) | ((a) - 1)) + 1) + +/// +/// NVME Host controller registers operation +/// +#define NVME_GET_CAP(Nvme, Cap) NvmeMmioRead (Cap, Nvme->Nbar + NVME_CAP_OFFSET, sizeof (NVME_CAP)) +#define NVME_GET_CC(Nvme, Cc) NvmeMmioRead (Cc, Nvme->Nbar + NVME_CC_OFFSET, sizeof (NVME_CC)) +#define NVME_SET_CC(Nvme, Cc) NvmeMmioWrite (Nvme->Nbar + NVME_CC_OFFSET, Cc, sizeof (NVME_CC)) +#define NVME_GET_CSTS(Nvme, Csts) NvmeMmioRead (Csts, Nvme->Nbar + NVME_CSTS_OFFSET, sizeof (NVME_CSTS)) +#define NVME_GET_AQA(Nvme, Aqa) NvmeMmioRead (Aqa, Nvme->Nbar + NVME_AQA_OFFSET, sizeof (NVME_AQA)) +#define NVME_SET_AQA(Nvme, Aqa) NvmeMmioWrite (Nvme->Nbar + NVME_AQA_OFFSET, Aqa, sizeof (NVME_AQA)) +#define NVME_GET_ASQ(Nvme, Asq) NvmeMmioRead (Asq, Nvme->Nbar + NVME_ASQ_OFFSET, sizeof (NVME_ASQ)) +#define NVME_SET_ASQ(Nvme, Asq) NvmeMmioWrite (Nvme->Nbar + NVME_ASQ_OFFSET, Asq, sizeof (NVME_ASQ)) +#define NVME_GET_ACQ(Nvme, Acq) NvmeMmioRead (Acq, Nvme->Nbar + NVME_ACQ_OFFSET, sizeof (NVME_ACQ)) +#define NVME_SET_ACQ(Nvme, Acq) NvmeMmioWrite (Nvme->Nbar + NVME_ACQ_OFFSET, Acq, sizeof (NVME_ACQ)) +#define NVME_GET_VER(Nvme, Ver) NvmeMmioRead (Ver, Nvme->Nbar + NVME_VER_OFFSET, sizeof (NVME_VER)) +#define NVME_SET_SQTDBL(Nvme, Qid, Sqtdbl) NvmeMmioWrite (Nvme->Nbar + NVME_SQTDBL_OFFSET(Qid, Nvme->Cap.Dstrd), Sqtdbl, sizeof (NVME_SQTDBL)) +#define NVME_SET_CQHDBL(Nvme, Qid, Cqhdbl) NvmeMmioWrite (Nvme->Nbar + NVME_CQHDBL_OFFSET(Qid, Nvme->Cap.Dstrd), Cqhdbl, sizeof (NVME_CQHDBL)) + +/// +/// Base memory address +/// +enum { + BASEMEM_CONTROLLER_DATA, + BASEMEM_IDENTIFY_DATA, + BASEMEM_ASQ, + BASEMEM_ACQ, + BASEMEM_SQ, + BASEMEM_CQ, + BASEMEM_PRP, + BASEMEM_SECURITY, + MAX_BASEMEM_COUNT +}; + +/// +/// All of base memories are 4K(0x1000) alignment +/// +#define NVME_MEM_BASE(Nvme) ((UINTN)(Nvme->BaseMem)) +#define NVME_CONTROL_DATA_BASE(Nvme) (ALIGN (NVME_MEM_BASE(Nvme) + ((NvmeGetBaseMemPages (BASEMEM_CONTROLLER_DATA)) * EFI_PAGE_SIZE), EFI_PAGE_SIZE)) +#define NVME_NAMESPACE_DATA_BASE(Nvme) (ALIGN (NVME_MEM_BASE(Nvme) + ((NvmeGetBaseMemPages (BASEMEM_IDENTIFY_DATA)) * EFI_PAGE_SIZE), EFI_PAGE_SIZE)) +#define NVME_ASQ_BASE(Nvme) (ALIGN (NVME_MEM_BASE(Nvme) + ((NvmeGetBaseMemPages (BASEMEM_ASQ)) * EFI_PAGE_SIZE), EFI_PAGE_SIZE)) +#define NVME_ACQ_BASE(Nvme) (ALIGN (NVME_MEM_BASE(Nvme) + ((NvmeGetBaseMemPages (BASEMEM_ACQ)) * EFI_PAGE_SIZE), EFI_PAGE_SIZE)) +#define NVME_SQ_BASE(Nvme, index) (ALIGN (NVME_MEM_BASE(Nvme) + ((NvmeGetBaseMemPages (BASEMEM_SQ) + ((index)*(NVME_MAX_IO_QUEUES-1))) * EFI_PAGE_SIZE), EFI_PAGE_SIZE)) +#define NVME_CQ_BASE(Nvme, index) (ALIGN (NVME_MEM_BASE(Nvme) + ((NvmeGetBaseMemPages (BASEMEM_CQ) + ((index)*(NVME_MAX_IO_QUEUES-1))) * EFI_PAGE_SIZE), EFI_PAGE_SIZE)) +#define NVME_PRP_BASE(Nvme, index) (ALIGN (NVME_MEM_BASE(Nvme) + ((NvmeGetBaseMemPages (BASEMEM_PRP) + ((index)*NVME_PRP_SIZE)) * EFI_PAGE_SIZE), EFI_PAGE_SIZE)) +#define NVME_SEC_BASE(Nvme) (ALIGN (NVME_MEM_BASE(Nvme) + ((NvmeGetBaseMemPages (BASEMEM_SECURITY)) * EFI_PAGE_SIZE), EFI_PAGE_SIZE)) + +/** + Transfer MMIO Data to memory. + + @param[in,out] MemBuffer - Destination: Memory address + @param[in] MmioAddr - Source: MMIO address + @param[in] Size - Size for read + + @retval EFI_SUCCESS - MMIO read sucessfully +**/ +EFI_STATUS +NvmeMmioRead ( + IN OUT VOID *MemBuffer, + IN UINTN MmioAddr, + IN UINTN Size + ) +{ + UINTN Offset; + UINT8 Data; + UINT8 *Ptr; + + // priority has adjusted + switch (Size) { + case 4: + *((UINT32 *)MemBuffer) = MmioRead32 (MmioAddr); + break; + + case 8: + *((UINT64 *)MemBuffer) = MmioRead64 (MmioAddr); + break; + + case 2: + *((UINT16 *)MemBuffer) = MmioRead16 (MmioAddr); + break; + + case 1: + *((UINT8 *)MemBuffer) = MmioRead8 (MmioAddr); + break; + + default: + Ptr = (UINT8 *)MemBuffer; + for (Offset = 0; Offset < Size; Offset += 1) { + Data = MmioRead8 (MmioAddr + Offset); + Ptr[Offset] = Data; + } + break; + } + + return EFI_SUCCESS; +} + +/** + Transfer memory data to MMIO. + + @param[in,out] MmioAddr - Destination: MMIO address + @param[in] MemBuffer - Source: Memory address + @param[in] Size - Size for write + + @retval EFI_SUCCESS - MMIO write sucessfully +**/ +EFI_STATUS +NvmeMmioWrite ( + IN OUT UINTN MmioAddr, + IN VOID *MemBuffer, + IN UINTN Size + ) +{ + UINTN Offset; + UINT8 Data; + UINT8 *Ptr; + + // priority has adjusted + switch (Size) { + case 4: + MmioWrite32 (MmioAddr, *((UINT32 *)MemBuffer)); + break; + + case 8: + MmioWrite64 (MmioAddr, *((UINT64 *)MemBuffer)); + break; + + case 2: + MmioWrite16 (MmioAddr, *((UINT16 *)MemBuffer)); + break; + + case 1: + MmioWrite8 (MmioAddr, *((UINT8 *)MemBuffer)); + break; + + default: + Ptr = (UINT8 *)MemBuffer; + for (Offset = 0; Offset < Size; Offset += 1) { + Data = Ptr[Offset]; + MmioWrite8 (MmioAddr + Offset, Data); + } + break; + } + + return EFI_SUCCESS; +} + +/** + Transfer MMIO data to memory. + + @param[in,out] MemBuffer - Destination: Memory address + @param[in] MmioAddr - Source: MMIO address + @param[in] Size - Size for read + + @retval EFI_SUCCESS - MMIO read sucessfully +**/ +EFI_STATUS +OpalPciRead ( + IN OUT VOID *MemBuffer, + IN UINTN MmioAddr, + IN UINTN Size + ) +{ + UINTN Offset; + UINT8 Data; + UINT8 *Ptr; + + // priority has adjusted + switch (Size) { + case 4: + *((UINT32 *)MemBuffer) = PciRead32 (MmioAddr); + break; + + case 2: + *((UINT16 *)MemBuffer) = PciRead16 (MmioAddr); + break; + + case 1: + *((UINT8 *)MemBuffer) = PciRead8 (MmioAddr); + break; + + default: + Ptr = (UINT8 *)MemBuffer; + for (Offset = 0; Offset < Size; Offset += 1) { + Data = PciRead8 (MmioAddr + Offset); + Ptr[Offset] = Data; + } + break; + } + + return EFI_SUCCESS; +} + +/** + Transfer memory data to MMIO. + + @param[in,out] MmioAddr - Destination: MMIO address + @param[in] MemBuffer - Source: Memory address + @param[in] Size - Size for write + + @retval EFI_SUCCESS - MMIO write sucessfully +**/ +EFI_STATUS +OpalPciWrite ( + IN OUT UINTN MmioAddr, + IN VOID *MemBuffer, + IN UINTN Size + ) +{ + UINTN Offset; + UINT8 Data; + UINT8 *Ptr; + + // priority has adjusted + switch (Size) { + case 4: + PciWrite32 (MmioAddr, *((UINT32 *)MemBuffer)); + break; + + case 2: + PciWrite16 (MmioAddr, *((UINT16 *)MemBuffer)); + break; + + case 1: + PciWrite8 (MmioAddr, *((UINT8 *)MemBuffer)); + break; + + default: + Ptr = (UINT8 *)MemBuffer; + for (Offset = 0; Offset < Size; Offset += 1) { + Data = Ptr[Offset]; + PciWrite8 (MmioAddr + Offset, Data); + } + break; + } + + return EFI_SUCCESS; +} + +/** + Get total pages for specific NVME based memory. + + @param[in] BaseMemIndex - The Index of BaseMem (0-based). + + @retval - The page count for specific BaseMem Index + +**/ +UINT32 +NvmeGetBaseMemPages ( + IN UINTN BaseMemIndex + ) +{ + UINT32 Pages; + UINTN Index; + UINT32 PageSizeList[8]; + + PageSizeList[0] = 1; /* Controller Data */ + PageSizeList[1] = 1; /* Identify Data */ + PageSizeList[2] = 1; /* ASQ */ + PageSizeList[3] = 1; /* ACQ */ + PageSizeList[4] = 1; /* SQs */ + PageSizeList[5] = 1; /* CQs */ + PageSizeList[6] = NVME_PRP_SIZE * NVME_CSQ_DEPTH; /* PRPs */ + PageSizeList[7] = 1; /* Security Commands */ + + if (BaseMemIndex > MAX_BASEMEM_COUNT) { + ASSERT (FALSE); + return 0; + } + + Pages = 0; + for (Index = 0; Index < BaseMemIndex; Index++) { + Pages += PageSizeList[Index]; + } + + return Pages; +} + +/** + Wait for NVME controller status to be ready or not. + + @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure. + @param[in] WaitReady - Flag for waitting status ready or not + + @return EFI_SUCCESS - Successfully to wait specific status. + @return others - Fail to wait for specific controller status. + +**/ +STATIC +EFI_STATUS +NvmeWaitController ( + IN NVME_CONTEXT *Nvme, + IN BOOLEAN WaitReady + ) +{ + NVME_CSTS Csts; + EFI_STATUS Status; + UINT32 Index; + UINT8 Timeout; + + // + // Cap.To specifies max delay time in 500ms increments for Csts.Rdy to set after + // Cc.Enable. Loop produces a 1 millisecond delay per itteration, up to 500 * Cap.To. + // + if (Nvme->Cap.To == 0) { + Timeout = 1; + } else { + Timeout = Nvme->Cap.To; + } + + Status = EFI_SUCCESS; + for(Index = (Timeout * 500); Index != 0; --Index) { + MicroSecondDelay (1000); + + // + // Check if the controller is initialized + // + Status = NVME_GET_CSTS (Nvme, &Csts); + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_ERROR, "NVME_GET_CSTS fail, Status = %r\n", Status)); + return Status; + } + + if ((BOOLEAN) Csts.Rdy == WaitReady) { + break; + } + } + + if (Index == 0) { + Status = EFI_TIMEOUT; + } + + return Status; +} + +/** + Disable the Nvm Express controller. + + @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure. + + @return EFI_SUCCESS - Successfully disable the controller. + @return others - Fail to disable the controller. + +**/ +STATIC +EFI_STATUS +NvmeDisableController ( + IN NVME_CONTEXT *Nvme + ) +{ + NVME_CC Cc; + NVME_CSTS Csts; + EFI_STATUS Status; + + Status = NVME_GET_CSTS (Nvme, &Csts); + + /// + /// Read Controller Configuration Register. + /// + Status = NVME_GET_CC (Nvme, &Cc); + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_ERROR, "NVME_GET_CC fail, Status = %r\n", Status)); + goto Done; + } + + if (Cc.En == 1) { + Cc.En = 0; + /// + /// Disable the controller. + /// + Status = NVME_SET_CC (Nvme, &Cc); + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_ERROR, "NVME_SET_CC fail, Status = %r\n", Status)); + goto Done; + } + } + + Status = NvmeWaitController (Nvme, FALSE); + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_ERROR, "NvmeWaitController fail, Status = %r\n", Status)); + goto Done; + } + + return EFI_SUCCESS; + +Done: + DEBUG ((DEBUG_INFO, "NvmeDisableController fail, Status: %r\n", Status)); + return Status; +} + +/** + Enable the Nvm Express controller. + + @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure. + + @return EFI_SUCCESS - Successfully enable the controller. + @return EFI_DEVICE_ERROR - Fail to enable the controller. + @return EFI_TIMEOUT - Fail to enable the controller in given time slot. + +**/ +STATIC +EFI_STATUS +NvmeEnableController ( + IN NVME_CONTEXT *Nvme + ) +{ + NVME_CC Cc; + EFI_STATUS Status; + + // + // Enable the controller + // + ZeroMem (&Cc, sizeof (NVME_CC)); + Cc.En = 1; + Cc.Iosqes = 6; + Cc.Iocqes = 4; + Status = NVME_SET_CC (Nvme, &Cc); + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_ERROR, "NVME_SET_CC fail, Status = %r\n", Status)); + goto Done; + } + + Status = NvmeWaitController (Nvme, TRUE); + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_ERROR, "NvmeWaitController fail, Status = %r\n", Status)); + goto Done; + } + + return EFI_SUCCESS; + +Done: + DEBUG ((DEBUG_INFO, "NvmeEnableController fail, Status: %r\n", Status)); + return Status; +} + +/** + Shutdown the Nvm Express controller. + + @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure. + + @return EFI_SUCCESS - Successfully shutdown the controller. + @return EFI_DEVICE_ERROR - Fail to shutdown the controller. + @return EFI_TIMEOUT - Fail to shutdown the controller in given time slot. + +**/ +STATIC +EFI_STATUS +NvmeShutdownController ( + IN NVME_CONTEXT *Nvme + ) +{ + NVME_CC Cc; + NVME_CSTS Csts; + EFI_STATUS Status; + UINT32 Index; + UINTN Timeout; + + Status = NVME_GET_CC (Nvme, &Cc); + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_ERROR, "NVME_GET_CC fail, Status = %r\n", Status)); + return Status; + } + + Cc.Shn = 1; // Normal shutdown + + Status = NVME_SET_CC (Nvme, &Cc); + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_ERROR, "NVME_SET_CC fail, Status = %r\n", Status)); + return Status; + } + + Timeout = NVME_GENERIC_TIMEOUT/1000; // ms + for(Index = (UINT32)(Timeout); Index != 0; --Index) { + MicroSecondDelay (1000); + + Status = NVME_GET_CSTS (Nvme, &Csts); + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_ERROR, "NVME_GET_CSTS fail, Status = %r\n", Status)); + return Status; + } + + if (Csts.Shst == 2) { // Shutdown processing complete + break; + } + } + + if (Index == 0) { + Status = EFI_TIMEOUT; + } + + return Status; +} + +/** + Check the execution status from a given completion queue entry. + + @param[in] Cq - A pointer to the NVME_CQ item. + +**/ +EFI_STATUS +NvmeCheckCqStatus ( + IN NVME_CQ *Cq + ) +{ + if (Cq->Sct == 0x0 && Cq->Sc == 0x0) { + return EFI_SUCCESS; + } + + DEBUG ((DEBUG_INFO, "Dump NVMe Completion Entry Status from [0x%x]:\n", (UINTN)Cq)); + DEBUG ((DEBUG_INFO, " SQ Identifier : [0x%x], Phase Tag : [%d], Cmd Identifier : [0x%x]\n", Cq->Sqid, Cq->Pt, Cq->Cid)); + DEBUG ((DEBUG_INFO, " NVMe Cmd Execution Result - ")); + + switch (Cq->Sct) { + case 0x0: + switch (Cq->Sc) { + case 0x0: + DEBUG ((DEBUG_INFO, "Successful Completion\n")); + return EFI_SUCCESS; + case 0x1: + DEBUG ((DEBUG_INFO, "Invalid Command Opcode\n")); + break; + case 0x2: + DEBUG ((DEBUG_INFO, "Invalid Field in Command\n")); + break; + case 0x3: + DEBUG ((DEBUG_INFO, "Command ID Conflict\n")); + break; + case 0x4: + DEBUG ((DEBUG_INFO, "Data Transfer Error\n")); + break; + case 0x5: + DEBUG ((DEBUG_INFO, "Commands Aborted due to Power Loss Notification\n")); + break; + case 0x6: + DEBUG ((DEBUG_INFO, "Internal Device Error\n")); + break; + case 0x7: + DEBUG ((DEBUG_INFO, "Command Abort Requested\n")); + break; + case 0x8: + DEBUG ((DEBUG_INFO, "Command Aborted due to SQ Deletion\n")); + break; + case 0x9: + DEBUG ((DEBUG_INFO, "Command Aborted due to Failed Fused Command\n")); + break; + case 0xA: + DEBUG ((DEBUG_INFO, "Command Aborted due to Missing Fused Command\n")); + break; + case 0xB: + DEBUG ((DEBUG_INFO, "Invalid Namespace or Format\n")); + break; + case 0xC: + DEBUG ((DEBUG_INFO, "Command Sequence Error\n")); + break; + case 0xD: + DEBUG ((DEBUG_INFO, "Invalid SGL Last Segment Descriptor\n")); + break; + case 0xE: + DEBUG ((DEBUG_INFO, "Invalid Number of SGL Descriptors\n")); + break; + case 0xF: + DEBUG ((DEBUG_INFO, "Data SGL Length Invalid\n")); + break; + case 0x10: + DEBUG ((DEBUG_INFO, "Metadata SGL Length Invalid\n")); + break; + case 0x11: + DEBUG ((DEBUG_INFO, "SGL Descriptor Type Invalid\n")); + break; + case 0x80: + DEBUG ((DEBUG_INFO, "LBA Out of Range\n")); + break; + case 0x81: + DEBUG ((DEBUG_INFO, "Capacity Exceeded\n")); + break; + case 0x82: + DEBUG ((DEBUG_INFO, "Namespace Not Ready\n")); + break; + case 0x83: + DEBUG ((DEBUG_INFO, "Reservation Conflict\n")); + break; + } + break; + + case 0x1: + switch (Cq->Sc) { + case 0x0: + DEBUG ((DEBUG_INFO, "Completion Queue Invalid\n")); + break; + case 0x1: + DEBUG ((DEBUG_INFO, "Invalid Queue Identifier\n")); + break; + case 0x2: + DEBUG ((DEBUG_INFO, "Maximum Queue Size Exceeded\n")); + break; + case 0x3: + DEBUG ((DEBUG_INFO, "Abort Command Limit Exceeded\n")); + break; + case 0x5: + DEBUG ((DEBUG_INFO, "Asynchronous Event Request Limit Exceeded\n")); + break; + case 0x6: + DEBUG ((DEBUG_INFO, "Invalid Firmware Slot\n")); + break; + case 0x7: + DEBUG ((DEBUG_INFO, "Invalid Firmware Image\n")); + break; + case 0x8: + DEBUG ((DEBUG_INFO, "Invalid Interrupt Vector\n")); + break; + case 0x9: + DEBUG ((DEBUG_INFO, "Invalid Log Page\n")); + break; + case 0xA: + DEBUG ((DEBUG_INFO, "Invalid Format\n")); + break; + case 0xB: + DEBUG ((DEBUG_INFO, "Firmware Application Requires Conventional Reset\n")); + break; + case 0xC: + DEBUG ((DEBUG_INFO, "Invalid Queue Deletion\n")); + break; + case 0xD: + DEBUG ((DEBUG_INFO, "Feature Identifier Not Saveable\n")); + break; + case 0xE: + DEBUG ((DEBUG_INFO, "Feature Not Changeable\n")); + break; + case 0xF: + DEBUG ((DEBUG_INFO, "Feature Not Namespace Specific\n")); + break; + case 0x10: + DEBUG ((DEBUG_INFO, "Firmware Application Requires NVM Subsystem Reset\n")); + break; + case 0x80: + DEBUG ((DEBUG_INFO, "Conflicting Attributes\n")); + break; + case 0x81: + DEBUG ((DEBUG_INFO, "Invalid Protection Information\n")); + break; + case 0x82: + DEBUG ((DEBUG_INFO, "Attempted Write to Read Only Range\n")); + break; + } + break; + + case 0x2: + switch (Cq->Sc) { + case 0x80: + DEBUG ((DEBUG_INFO, "Write Fault\n")); + break; + case 0x81: + DEBUG ((DEBUG_INFO, "Unrecovered Read Error\n")); + break; + case 0x82: + DEBUG ((DEBUG_INFO, "End-to-end Guard Check Error\n")); + break; + case 0x83: + DEBUG ((DEBUG_INFO, "End-to-end Application Tag Check Error\n")); + break; + case 0x84: + DEBUG ((DEBUG_INFO, "End-to-end Reference Tag Check Error\n")); + break; + case 0x85: + DEBUG ((DEBUG_INFO, "Compare Failure\n")); + break; + case 0x86: + DEBUG ((DEBUG_INFO, "Access Denied\n")); + break; + } + break; + + default: + DEBUG ((DEBUG_INFO, "Unknown error\n")); + break; + } + + return EFI_DEVICE_ERROR; +} + +/** + Create PRP lists for Data transfer which is larger than 2 memory pages. + Note here we calcuate the number of required PRP lists and allocate them at one time. + + @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure. + @param[in] SqId - The SQ index for this PRP + @param[in] PhysicalAddr - The physical base address of Data Buffer. + @param[in] Pages - The number of pages to be transfered. + @param[out] PrpListHost - The host base address of PRP lists. + @param[in,out] PrpListNo - The number of PRP List. + + @retval The pointer Value to the first PRP List of the PRP lists. + +**/ +STATIC +UINT64 +NvmeCreatePrpList ( + IN NVME_CONTEXT *Nvme, + IN UINT16 SqId, + IN EFI_PHYSICAL_ADDRESS PhysicalAddr, + IN UINTN Pages, + OUT VOID **PrpListHost, + IN OUT UINTN *PrpListNo + ) +{ + UINTN PrpEntryNo; + UINT64 PrpListBase; + UINTN PrpListIndex; + UINTN PrpEntryIndex; + UINT64 Remainder; + EFI_PHYSICAL_ADDRESS PrpListPhyAddr; + UINTN Bytes; + UINT8 *PrpEntry; + EFI_PHYSICAL_ADDRESS NewPhyAddr; + + /// + /// The number of Prp Entry in a memory page. + /// + PrpEntryNo = EFI_PAGE_SIZE / sizeof (UINT64); + + /// + /// Calculate total PrpList number. + /// + *PrpListNo = (UINTN) DivU64x64Remainder ((UINT64)Pages, (UINT64)PrpEntryNo, &Remainder); + if (Remainder != 0) { + *PrpListNo += 1; + } + + if (*PrpListNo > NVME_PRP_SIZE) { + DEBUG ((DEBUG_INFO, "NvmeCreatePrpList (PhysicalAddr: %lx, Pages: %x) PrpEntryNo: %x\n", + PhysicalAddr, Pages, PrpEntryNo)); + DEBUG ((DEBUG_INFO, "*PrpListNo: %x, Remainder: %lx", *PrpListNo, Remainder)); + ASSERT (FALSE); + } + *PrpListHost = (VOID *)(UINTN) NVME_PRP_BASE (Nvme, SqId); + + Bytes = EFI_PAGES_TO_SIZE (*PrpListNo); + PrpListPhyAddr = (UINT64)(UINTN)(*PrpListHost); + + /// + /// Fill all PRP lists except of last one. + /// + ZeroMem (*PrpListHost, Bytes); + for (PrpListIndex = 0; PrpListIndex < *PrpListNo - 1; ++PrpListIndex) { + PrpListBase = *(UINT64*)PrpListHost + PrpListIndex * EFI_PAGE_SIZE; + + for (PrpEntryIndex = 0; PrpEntryIndex < PrpEntryNo; ++PrpEntryIndex) { + PrpEntry = (UINT8 *)(UINTN) (PrpListBase + PrpEntryIndex * sizeof(UINT64)); + if (PrpEntryIndex != PrpEntryNo - 1) { + /// + /// Fill all PRP entries except of last one. + /// + CopyMem (PrpEntry, (VOID *)(UINTN) (&PhysicalAddr), sizeof (UINT64)); + PhysicalAddr += EFI_PAGE_SIZE; + } else { + /// + /// Fill last PRP entries with next PRP List pointer. + /// + NewPhyAddr = (PrpListPhyAddr + (PrpListIndex + 1) * EFI_PAGE_SIZE); + CopyMem (PrpEntry, (VOID *)(UINTN) (&NewPhyAddr), sizeof (UINT64)); + } + } + } + + /// + /// Fill last PRP list. + /// + PrpListBase = *(UINT64*)PrpListHost + PrpListIndex * EFI_PAGE_SIZE; + for (PrpEntryIndex = 0; PrpEntryIndex < ((Remainder != 0) ? Remainder : PrpEntryNo); ++PrpEntryIndex) { + PrpEntry = (UINT8 *)(UINTN) (PrpListBase + PrpEntryIndex * sizeof(UINT64)); + CopyMem (PrpEntry, (VOID *)(UINTN) (&PhysicalAddr), sizeof (UINT64)); + + PhysicalAddr += EFI_PAGE_SIZE; + } + + return PrpListPhyAddr; +} + +/** + Check whether there are available command slots. + + @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure. + @param[in] Qid - Queue index + + @retval EFI_SUCCESS - Available command slot is found + @retval EFI_NOT_READY - No available command slot is found + @retval EFI_DEVICE_ERROR - Error occurred on device side. + +**/ +EFI_STATUS +NvmeHasFreeCmdSlot ( + IN NVME_CONTEXT *Nvme, + IN UINT8 Qid + ) +{ + return TRUE; +} + +/** + Check whether all command slots are clean. + + @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure. + @param[in] Qid - Queue index + + @retval EFI_SUCCESS - All command slots are clean + @retval EFI_NOT_READY - Not all command slots are clean + @retval EFI_DEVICE_ERROR - Error occurred on device side. + +**/ +EFI_STATUS +NvmeIsAllCmdSlotClean ( + IN NVME_CONTEXT *Nvme, + IN UINT8 Qid + ) +{ + return EFI_SUCCESS; +} + +/** + Waits until all NVME commands completed. + + @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure. + @param[in] Qid - Queue index + + @retval EFI_SUCCESS - All NVME commands have completed + @retval EFI_TIMEOUT - Timeout occured + @retval EFI_NOT_READY - Not all NVME commands have completed + @retval others - Error occurred on device side. +**/ +EFI_STATUS +NvmeWaitAllComplete ( + IN NVME_CONTEXT *Nvme, + IN UINT8 Qid + ) +{ + return EFI_SUCCESS; +} + +/** + Sends an NVM Express Command Packet to an NVM Express controller or namespace. This function supports + both blocking I/O and nonblocking I/O. The blocking I/O functionality is required, and the nonblocking + I/O functionality is optional. + + @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure. + @param[in] NamespaceId - Is a 32 bit Namespace ID to which the Express HCI command packet will be sent. + A Value of 0 denotes the NVM Express controller, a Value of all 0FFh in the namespace + ID specifies that the command packet should be sent to all valid namespaces. + @param[in] NamespaceUuid - Is a 64 bit Namespace UUID to which the Express HCI command packet will be sent. + A Value of 0 denotes the NVM Express controller, a Value of all 0FFh in the namespace + UUID specifies that the command packet should be sent to all valid namespaces. + @param[in,out] Packet - A pointer to the NVM Express HCI Command Packet to send to the NVMe namespace specified + by NamespaceId. + + @retval EFI_SUCCESS - The NVM Express Command Packet was sent by the host. TransferLength bytes were transferred + to, or from DataBuffer. + @retval EFI_NOT_READY - The NVM Express Command Packet could not be sent because the controller is not ready. The caller + may retry again later. + @retval EFI_DEVICE_ERROR - A device error occurred while attempting to send the NVM Express Command Packet. + @retval EFI_INVALID_PARAMETER - Namespace, or the contents of NVM_EXPRESS_PASS_THRU_COMMAND_PACKET are invalid. The NVM + Express Command Packet was not sent, so no additional status information is available. + @retval EFI_UNSUPPORTED - The command described by the NVM Express Command Packet is not supported by the host adapter. + The NVM Express Command Packet was not sent, so no additional status information is available. + @retval EFI_TIMEOUT - A timeout occurred while waiting for the NVM Express Command Packet to execute. + +**/ +EFI_STATUS +NvmePassThru ( + IN NVME_CONTEXT *Nvme, + IN UINT32 NamespaceId, + IN UINT64 NamespaceUuid, + IN OUT NVM_EXPRESS_PASS_THRU_COMMAND_PACKET *Packet + ) +{ + EFI_STATUS Status; + NVME_SQ *Sq; + NVME_CQ *Cq; + UINT8 Qid; + UINT32 Bytes; + UINT32 Offset; + EFI_PHYSICAL_ADDRESS PhyAddr; + VOID *PrpListHost; + UINTN PrpListNo; + UINT32 Timer; + UINTN SqSize; + UINTN CqSize; + + /// + /// check the Data fields in Packet parameter. + /// + if ((Nvme == NULL) || (Packet == NULL)) { + DEBUG ((DEBUG_ERROR, "NvmePassThru, invalid parameter: Nvme(%x)/Packet(%x)\n", + (UINTN)Nvme, (UINTN)Packet)); + return EFI_INVALID_PARAMETER; + } + + if ((Packet->NvmeCmd == NULL) || (Packet->NvmeResponse == NULL)) { + DEBUG ((DEBUG_ERROR, "NvmePassThru, invalid parameter: NvmeCmd(%x)/NvmeResponse(%x)\n", + (UINTN)Packet->NvmeCmd, (UINTN)Packet->NvmeResponse)); + return EFI_INVALID_PARAMETER; + } + + if (Packet->QueueId != NVME_ADMIN_QUEUE && Packet->QueueId != NVME_IO_QUEUE) { + DEBUG ((DEBUG_ERROR, "NvmePassThru, invalid parameter: QueueId(%x)\n", + Packet->QueueId)); + return EFI_INVALID_PARAMETER; + } + + PrpListHost = NULL; + PrpListNo = 0; + Status = EFI_SUCCESS; + + Qid = Packet->QueueId; + Sq = Nvme->SqBuffer[Qid] + Nvme->SqTdbl[Qid].Sqt; + Cq = Nvme->CqBuffer[Qid] + Nvme->CqHdbl[Qid].Cqh; + if (Qid == NVME_ADMIN_QUEUE) { + SqSize = NVME_ASQ_SIZE + 1; + CqSize = NVME_ACQ_SIZE + 1; + } else { + SqSize = NVME_CSQ_DEPTH; + CqSize = NVME_CCQ_DEPTH; + } + + if (Packet->NvmeCmd->Nsid != NamespaceId) { + DEBUG ((DEBUG_ERROR, "NvmePassThru: Nsid mismatch (%x, %x)\n", + Packet->NvmeCmd->Nsid, NamespaceId)); + return EFI_INVALID_PARAMETER; + } + + ZeroMem (Sq, sizeof (NVME_SQ)); + Sq->Opc = Packet->NvmeCmd->Cdw0.Opcode; + Sq->Fuse = Packet->NvmeCmd->Cdw0.FusedOperation; + Sq->Cid = Packet->NvmeCmd->Cdw0.Cid; + Sq->Nsid = Packet->NvmeCmd->Nsid; + + /// + /// Currently we only support PRP for Data transfer, SGL is NOT supported. + /// + ASSERT (Sq->Psdt == 0); + if (Sq->Psdt != 0) { + DEBUG ((DEBUG_ERROR, "NvmePassThru: doesn't support SGL mechanism\n")); + return EFI_UNSUPPORTED; + } + + Sq->Prp[0] = Packet->TransferBuffer; + Sq->Prp[1] = 0; + + if(Packet->MetadataBuffer != (UINT64)(UINTN)NULL) { + Sq->Mptr = Packet->MetadataBuffer; + } + + /// + /// If the Buffer Size spans more than two memory pages (page Size as defined in CC.Mps), + /// then build a PRP list in the second PRP submission queue entry. + /// + Offset = ((UINT32)Sq->Prp[0]) & (EFI_PAGE_SIZE - 1); + Bytes = Packet->TransferLength; + + if ((Offset + Bytes) > (EFI_PAGE_SIZE * 2)) { + /// + /// Create PrpList for remaining Data Buffer. + /// + PhyAddr = (Sq->Prp[0] + EFI_PAGE_SIZE) & ~(EFI_PAGE_SIZE - 1); + Sq->Prp[1] = NvmeCreatePrpList (Nvme, Nvme->SqTdbl[Qid].Sqt, PhyAddr, EFI_SIZE_TO_PAGES(Offset + Bytes) - 1, &PrpListHost, &PrpListNo); + if (Sq->Prp[1] == 0) { + Status = EFI_OUT_OF_RESOURCES; + DEBUG ((DEBUG_ERROR, "NvmeCreatePrpList fail, Status: %r\n", Status)); + goto EXIT; + } + + } else if ((Offset + Bytes) > EFI_PAGE_SIZE) { + Sq->Prp[1] = (Sq->Prp[0] + EFI_PAGE_SIZE) & ~(EFI_PAGE_SIZE - 1); + } + + if(Packet->NvmeCmd->Flags & CDW10_VALID) { + Sq->Payload.Raw.Cdw10 = Packet->NvmeCmd->Cdw10; + } + if(Packet->NvmeCmd->Flags & CDW11_VALID) { + Sq->Payload.Raw.Cdw11 = Packet->NvmeCmd->Cdw11; + } + if(Packet->NvmeCmd->Flags & CDW12_VALID) { + Sq->Payload.Raw.Cdw12 = Packet->NvmeCmd->Cdw12; + } + if(Packet->NvmeCmd->Flags & CDW13_VALID) { + Sq->Payload.Raw.Cdw13 = Packet->NvmeCmd->Cdw13; + } + if(Packet->NvmeCmd->Flags & CDW14_VALID) { + Sq->Payload.Raw.Cdw14 = Packet->NvmeCmd->Cdw14; + } + if(Packet->NvmeCmd->Flags & CDW15_VALID) { + Sq->Payload.Raw.Cdw15 = Packet->NvmeCmd->Cdw15; + } + + /// + /// Ring the submission queue doorbell. + /// + Nvme->SqTdbl[Qid].Sqt++; + if(Nvme->SqTdbl[Qid].Sqt == SqSize) { + Nvme->SqTdbl[Qid].Sqt = 0; + } + Status = NVME_SET_SQTDBL (Nvme, Qid, &Nvme->SqTdbl[Qid]); + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_ERROR, "NVME_SET_SQTDBL fail, Status: %r\n", Status)); + goto EXIT; + } + + /// + /// Wait for completion queue to get filled in. + /// + Status = EFI_TIMEOUT; + Timer = 0; + while (Timer < NVME_CMD_TIMEOUT) { + //DEBUG ((DEBUG_VERBOSE, "Timer: %x, Cq:\n", Timer)); + //DumpMem (Cq, sizeof (NVME_CQ)); + if (Cq->Pt != Nvme->Pt[Qid]) { + Status = EFI_SUCCESS; + break; + } + + MicroSecondDelay (NVME_CMD_WAIT); + Timer += NVME_CMD_WAIT; + } + + Nvme->CqHdbl[Qid].Cqh++; + if (Nvme->CqHdbl[Qid].Cqh == CqSize) { + Nvme->CqHdbl[Qid].Cqh = 0; + Nvme->Pt[Qid] ^= 1; + } + + /// + /// Copy the Respose Queue entry for this command to the callers response Buffer + /// + CopyMem (Packet->NvmeResponse, Cq, sizeof(NVM_EXPRESS_RESPONSE)); + + if (!EFI_ERROR(Status)) { // We still need to check CQ status if no timeout error occured + Status = NvmeCheckCqStatus (Cq); + } + NVME_SET_CQHDBL (Nvme, Qid, &Nvme->CqHdbl[Qid]); + +EXIT: + return Status; +} + +/** + Get identify controller Data. + + @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure. + @param[in] Buffer - The Buffer used to store the identify controller Data. + + @return EFI_SUCCESS - Successfully get the identify controller Data. + @return others - Fail to get the identify controller Data. + +**/ +STATIC +EFI_STATUS +NvmeIdentifyController ( + IN NVME_CONTEXT *Nvme, + IN VOID *Buffer + ) +{ + NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket; + NVM_EXPRESS_COMMAND Command; + NVM_EXPRESS_RESPONSE Response; + EFI_STATUS Status; + + ZeroMem (&CommandPacket, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET)); + ZeroMem (&Command, sizeof(NVM_EXPRESS_COMMAND)); + ZeroMem (&Response, sizeof(NVM_EXPRESS_RESPONSE)); + + Command.Cdw0.Opcode = NVME_ADMIN_IDENTIFY_OPC; + Command.Cdw0.Cid = Nvme->Cid[NVME_ADMIN_QUEUE]++; + // + // According to Nvm Express 1.1 spec Figure 38, When not used, the field shall be cleared to 0h. + // For the Identify command, the Namespace Identifier is only used for the Namespace Data structure. + // + Command.Nsid = 0; + + CommandPacket.NvmeCmd = &Command; + CommandPacket.NvmeResponse = &Response; + CommandPacket.TransferBuffer = (UINT64)(UINTN)Buffer; + CommandPacket.TransferLength = sizeof (NVME_ADMIN_CONTROLLER_DATA); + CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT; + CommandPacket.QueueId = NVME_ADMIN_QUEUE; + // + // Set bit 0 (Cns bit) to 1 to identify a controller + // + Command.Cdw10 = 1; + Command.Flags = CDW10_VALID; + + Status = NvmePassThru ( + Nvme, + NVME_CONTROLLER_ID, + 0, + &CommandPacket + ); + if (!EFI_ERROR (Status)) { + Status = NvmeWaitAllComplete (Nvme, CommandPacket.QueueId); + } + + return Status; +} + +/** + Get specified identify namespace Data. + + @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure. + @param[in] NamespaceId - The specified namespace identifier. + @param[in] Buffer - The Buffer used to store the identify namespace Data. + + @return EFI_SUCCESS - Successfully get the identify namespace Data. + @return others - Fail to get the identify namespace Data. + +**/ +STATIC +EFI_STATUS +NvmeIdentifyNamespace ( + IN NVME_CONTEXT *Nvme, + IN UINT32 NamespaceId, + IN VOID *Buffer + ) +{ + NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket; + NVM_EXPRESS_COMMAND Command; + NVM_EXPRESS_RESPONSE Response; + EFI_STATUS Status; + + ZeroMem (&CommandPacket, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET)); + ZeroMem (&Command, sizeof(NVM_EXPRESS_COMMAND)); + ZeroMem (&Response, sizeof(NVM_EXPRESS_RESPONSE)); + + CommandPacket.NvmeCmd = &Command; + CommandPacket.NvmeResponse = &Response; + + Command.Cdw0.Opcode = NVME_ADMIN_IDENTIFY_OPC; + Command.Cdw0.Cid = Nvme->Cid[NVME_ADMIN_QUEUE]++; + Command.Nsid = NamespaceId; + CommandPacket.TransferBuffer = (UINT64)(UINTN)Buffer; + CommandPacket.TransferLength = sizeof (NVME_ADMIN_NAMESPACE_DATA); + CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT; + CommandPacket.QueueId = NVME_ADMIN_QUEUE; + // + // Set bit 0 (Cns bit) to 1 to identify a namespace + // + CommandPacket.NvmeCmd->Cdw10 = 0; + CommandPacket.NvmeCmd->Flags = CDW10_VALID; + + Status = NvmePassThru ( + Nvme, + NamespaceId, + 0, + &CommandPacket + ); + if (!EFI_ERROR (Status)) { + Status = NvmeWaitAllComplete (Nvme, CommandPacket.QueueId); + } + + return Status; +} + +/** + Get Block Size for specific namespace of NVME. + + @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure. + + @return - Block Size in bytes + +**/ +STATIC +UINT32 +NvmeGetBlockSize ( + IN NVME_CONTEXT *Nvme + ) +{ + UINT32 BlockSize; + UINT32 Lbads; + UINT32 Flbas; + UINT32 LbaFmtIdx; + + Flbas = Nvme->NamespaceData->Flbas; + LbaFmtIdx = Flbas & 3; + Lbads = Nvme->NamespaceData->LbaFormat[LbaFmtIdx].Lbads; + + BlockSize = (UINT32)1 << Lbads; + return BlockSize; +} + +/** + Get last LBA for specific namespace of NVME. + + @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure. + + @return - Last LBA address + +**/ +STATIC +EFI_LBA +NvmeGetLastLba ( + IN NVME_CONTEXT *Nvme + ) +{ + EFI_LBA LastBlock; + LastBlock = Nvme->NamespaceData->Nsze - 1; + return LastBlock; +} + +/** + Create io completion queue. + + @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure. + + @return EFI_SUCCESS - Successfully create io completion queue. + @return others - Fail to create io completion queue. + +**/ +STATIC +EFI_STATUS +NvmeCreateIoCompletionQueue ( + IN NVME_CONTEXT *Nvme + ) +{ + NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket; + NVM_EXPRESS_COMMAND Command; + NVM_EXPRESS_RESPONSE Response; + EFI_STATUS Status; + NVME_ADMIN_CRIOCQ CrIoCq; + + ZeroMem (&CommandPacket, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET)); + ZeroMem (&Command, sizeof(NVM_EXPRESS_COMMAND)); + ZeroMem (&Response, sizeof(NVM_EXPRESS_RESPONSE)); + ZeroMem (&CrIoCq, sizeof(NVME_ADMIN_CRIOCQ)); + + CommandPacket.NvmeCmd = &Command; + CommandPacket.NvmeResponse = &Response; + + Command.Cdw0.Opcode = NVME_ADMIN_CRIOCQ_OPC; + Command.Cdw0.Cid = Nvme->Cid[NVME_ADMIN_QUEUE]++; + CommandPacket.TransferBuffer = (UINT64)(UINTN)Nvme->CqBuffer[NVME_IO_QUEUE]; + CommandPacket.TransferLength = EFI_PAGE_SIZE; + CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT; + CommandPacket.QueueId = NVME_ADMIN_QUEUE; + + CrIoCq.Qid = NVME_IO_QUEUE; + CrIoCq.Qsize = NVME_CCQ_SIZE; + CrIoCq.Pc = 1; + CopyMem (&CommandPacket.NvmeCmd->Cdw10, &CrIoCq, sizeof (NVME_ADMIN_CRIOCQ)); + CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID; + + Status = NvmePassThru ( + Nvme, + NVME_CONTROLLER_ID, + 0, + &CommandPacket + ); + if (!EFI_ERROR (Status)) { + Status = NvmeWaitAllComplete (Nvme, CommandPacket.QueueId); + } + + return Status; +} + +/** + Create io submission queue. + + @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure. + + @return EFI_SUCCESS - Successfully create io submission queue. + @return others - Fail to create io submission queue. + +**/ +STATIC +EFI_STATUS +NvmeCreateIoSubmissionQueue ( + IN NVME_CONTEXT *Nvme + ) +{ + NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket; + NVM_EXPRESS_COMMAND Command; + NVM_EXPRESS_RESPONSE Response; + EFI_STATUS Status; + NVME_ADMIN_CRIOSQ CrIoSq; + + ZeroMem (&CommandPacket, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET)); + ZeroMem (&Command, sizeof(NVM_EXPRESS_COMMAND)); + ZeroMem (&Response, sizeof(NVM_EXPRESS_RESPONSE)); + ZeroMem (&CrIoSq, sizeof(NVME_ADMIN_CRIOSQ)); + + CommandPacket.NvmeCmd = &Command; + CommandPacket.NvmeResponse = &Response; + + Command.Cdw0.Opcode = NVME_ADMIN_CRIOSQ_OPC; + Command.Cdw0.Cid = Nvme->Cid[NVME_ADMIN_QUEUE]++; + CommandPacket.TransferBuffer = (UINT64)(UINTN)Nvme->SqBuffer[NVME_IO_QUEUE]; + CommandPacket.TransferLength = EFI_PAGE_SIZE; + CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT; + CommandPacket.QueueId = NVME_ADMIN_QUEUE; + + CrIoSq.Qid = NVME_IO_QUEUE; + CrIoSq.Qsize = NVME_CSQ_SIZE; + CrIoSq.Pc = 1; + CrIoSq.Cqid = NVME_IO_QUEUE; + CrIoSq.Qprio = 0; + CopyMem (&CommandPacket.NvmeCmd->Cdw10, &CrIoSq, sizeof (NVME_ADMIN_CRIOSQ)); + CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID; + + Status = NvmePassThru ( + Nvme, + NVME_CONTROLLER_ID, + 0, + &CommandPacket + ); + if (!EFI_ERROR (Status)) { + Status = NvmeWaitAllComplete (Nvme, CommandPacket.QueueId); + } + + return Status; +} + +/** + Security send and receive commands. + + @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure. + @param[in] SendCommand - The flag to indicate the command type, TRUE for Send command and FALSE for receive command + @param[in] SecurityProtocol - Security Protocol + @param[in] SpSpecific - Security Protocol Specific + @param[in] TransferLength - Transfer Length of Buffer (in bytes) - always a multiple of 512 + @param[in,out] TransferBuffer - Address of Data to transfer + + @return EFI_SUCCESS - Successfully create io submission queue. + @return others - Fail to send/receive commands. + +**/ +EFI_STATUS +NvmeSecuritySendReceive ( + IN NVME_CONTEXT *Nvme, + IN BOOLEAN SendCommand, + IN UINT8 SecurityProtocol, + IN UINT16 SpSpecific, + IN UINTN TransferLength, + IN OUT VOID *TransferBuffer + ) +{ + NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket; + NVM_EXPRESS_COMMAND Command; + NVM_EXPRESS_RESPONSE Response; + EFI_STATUS Status; + NVME_ADMIN_SECSEND SecSend; + OACS *Oacs; + UINT8 Opcode; + VOID* *SecBuff; + + Oacs = (OACS *)&Nvme->ControllerData->Oacs; + + // + // Verify security bit for Security Send/Receive commands + // + if (Oacs->Security == 0) { + DEBUG ((DEBUG_ERROR, "Security command doesn't support.\n")); + return EFI_NOT_READY; + } + + SecBuff = (VOID *)(UINTN) NVME_SEC_BASE (Nvme); + + // + // Actions for sending security command + // + if (SendCommand) { + CopyMem (SecBuff, TransferBuffer, TransferLength); + } + + ZeroMem (&CommandPacket, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET)); + ZeroMem (&Command, sizeof(NVM_EXPRESS_COMMAND)); + ZeroMem (&Response, sizeof(NVM_EXPRESS_RESPONSE)); + ZeroMem (&SecSend, sizeof(NVME_ADMIN_SECSEND)); + + CommandPacket.NvmeCmd = &Command; + CommandPacket.NvmeResponse = &Response; + + Opcode = (UINT8)(SendCommand ? NVME_ADMIN_SECURITY_SEND_OPC : NVME_ADMIN_SECURITY_RECV_OPC); + Command.Cdw0.Opcode = Opcode; + Command.Cdw0.Cid = Nvme->Cid[NVME_ADMIN_QUEUE]++; + CommandPacket.TransferBuffer = (UINT64)(UINTN)SecBuff; + CommandPacket.TransferLength = (UINT32)TransferLength; + CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT; + CommandPacket.QueueId = NVME_ADMIN_QUEUE; + + SecSend.Spsp = SpSpecific; + SecSend.Secp = SecurityProtocol; + SecSend.Tl = (UINT32)TransferLength; + + CopyMem (&CommandPacket.NvmeCmd->Cdw10, &SecSend, sizeof (NVME_ADMIN_SECSEND)); + CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID; + + Status = NvmePassThru ( + Nvme, + NVME_CONTROLLER_ID, + 0, + &CommandPacket + ); + if (!EFI_ERROR (Status)) { + Status = NvmeWaitAllComplete (Nvme, CommandPacket.QueueId); + } + + // + // Actions for receiving security command + // + if (!SendCommand) { + CopyMem (TransferBuffer, SecBuff, TransferLength); + } + + return Status; +} + +/** + Destroy io completion queue. + + @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure. + + @return EFI_SUCCESS - Successfully destroy io completion queue. + @return others - Fail to destroy io completion queue. + +**/ +STATIC +EFI_STATUS +NvmeDestroyIoCompletionQueue ( + IN NVME_CONTEXT *Nvme + ) +{ + NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket; + NVM_EXPRESS_COMMAND Command; + NVM_EXPRESS_RESPONSE Response; + EFI_STATUS Status; + NVME_ADMIN_DEIOCQ DelIoCq; + + ZeroMem (&CommandPacket, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET)); + ZeroMem (&Command, sizeof(NVM_EXPRESS_COMMAND)); + ZeroMem (&Response, sizeof(NVM_EXPRESS_RESPONSE)); + ZeroMem (&DelIoCq, sizeof(NVME_ADMIN_DEIOCQ)); + + CommandPacket.NvmeCmd = &Command; + CommandPacket.NvmeResponse = &Response; + + Command.Cdw0.Opcode = NVME_ADMIN_DELIOCQ_OPC; + Command.Cdw0.Cid = Nvme->Cid[NVME_ADMIN_QUEUE]++; + CommandPacket.TransferBuffer = (UINT64)(UINTN)Nvme->CqBuffer[NVME_IO_QUEUE]; + CommandPacket.TransferLength = EFI_PAGE_SIZE; + CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT; + CommandPacket.QueueId = NVME_ADMIN_QUEUE; + + DelIoCq.Qid = NVME_IO_QUEUE; + CopyMem (&CommandPacket.NvmeCmd->Cdw10, &DelIoCq, sizeof (NVME_ADMIN_DEIOCQ)); + CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID; + + Status = NvmePassThru ( + Nvme, + NVME_CONTROLLER_ID, + 0, + &CommandPacket + ); + if (!EFI_ERROR (Status)) { + Status = NvmeWaitAllComplete (Nvme, CommandPacket.QueueId); + } + + return Status; +} + +/** + Destroy io submission queue. + + @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure. + + @return EFI_SUCCESS - Successfully destroy io submission queue. + @return others - Fail to destroy io submission queue. + +**/ +STATIC +EFI_STATUS +NvmeDestroyIoSubmissionQueue ( + IN NVME_CONTEXT *Nvme + ) +{ + NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket; + NVM_EXPRESS_COMMAND Command; + NVM_EXPRESS_RESPONSE Response; + EFI_STATUS Status; + NVME_ADMIN_DEIOSQ DelIoSq; + + ZeroMem (&CommandPacket, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET)); + ZeroMem (&Command, sizeof(NVM_EXPRESS_COMMAND)); + ZeroMem (&Response, sizeof(NVM_EXPRESS_RESPONSE)); + ZeroMem (&DelIoSq, sizeof(NVME_ADMIN_DEIOSQ)); + + CommandPacket.NvmeCmd = &Command; + CommandPacket.NvmeResponse = &Response; + + Command.Cdw0.Opcode = NVME_ADMIN_DELIOSQ_OPC; + Command.Cdw0.Cid = Nvme->Cid[NVME_ADMIN_QUEUE]++; + CommandPacket.TransferBuffer = (UINT64)(UINTN)Nvme->SqBuffer[NVME_IO_QUEUE]; + CommandPacket.TransferLength = EFI_PAGE_SIZE; + CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT; + CommandPacket.QueueId = NVME_ADMIN_QUEUE; + + DelIoSq.Qid = NVME_IO_QUEUE; + CopyMem (&CommandPacket.NvmeCmd->Cdw10, &DelIoSq, sizeof (NVME_ADMIN_DEIOSQ)); + CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID; + + Status = NvmePassThru ( + Nvme, + NVME_CONTROLLER_ID, + 0, + &CommandPacket + ); + if (!EFI_ERROR (Status)) { + Status = NvmeWaitAllComplete (Nvme, CommandPacket.QueueId); + } + + return Status; +} + +/** + Allocate transfer-related Data struct which is used at Nvme. + + @param[in] ImageHandle Image handle for this driver image + @param[in] Nvme The pointer to the NVME_CONTEXT Data structure. + + @retval EFI_OUT_OF_RESOURCE The allocation is failure. + @retval EFI_SUCCESS Successful to allocate memory. + +**/ +EFI_STATUS +EFIAPI +NvmeAllocateResource ( + IN EFI_HANDLE ImageHandle, + IN NVME_CONTEXT *Nvme + ) +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS Addr; + UINT32 Size; + + // + // Allocate resources required by NVMe host controller. + // + // NBAR + Size = 0x10000; + Addr = 0xFFFFFFFF; + Status = gDS->AllocateMemorySpace ( + EfiGcdAllocateMaxAddressSearchBottomUp, + EfiGcdMemoryTypeMemoryMappedIo, + 15, // 2^15: 32K Alignment + Size, + &Addr, + ImageHandle, + NULL + ); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + Nvme->Nbar = (UINT32) Addr; + + // DMA Buffer + Size = NVME_MEM_MAX_SIZE; + Addr = 0xFFFFFFFF; + Status = gBS->AllocatePages ( + AllocateMaxAddress, + EfiACPIMemoryNVS, + EFI_SIZE_TO_PAGES (Size), + (EFI_PHYSICAL_ADDRESS *)&Addr + ); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + Nvme->BaseMem = (UINT32) Addr; + + // Clean up DMA Buffer before using + ZeroMem ((VOID *)(UINTN)Addr, NVME_MEM_MAX_SIZE); + + return EFI_SUCCESS; +} + +/** + Free allocated transfer-related Data struct which is used at NVMe. + + @param[in] Nvme The pointer to the NVME_CONTEXT Data structure. + +**/ +VOID +EFIAPI +NvmeFreeResource ( + IN NVME_CONTEXT *Nvme + ) +{ + UINT32 Size; + + // NBAR + if (Nvme->BaseMem != 0) { + Size = 0x10000; + gDS->FreeMemorySpace (Nvme->Nbar, Size); + } + + // DMA Buffer + if (Nvme->Nbar != 0) { + Size = NVME_MEM_MAX_SIZE; + gBS->FreePages ((EFI_PHYSICAL_ADDRESS)(UINTN) Nvme->Nbar, EFI_SIZE_TO_PAGES (Size)); + } +} + + +/** + Initialize the Nvm Express controller. + + @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure. + + @retval EFI_SUCCESS - The NVM Express Controller is initialized successfully. + @retval Others - A device error occurred while initializing the controller. + +**/ +EFI_STATUS +NvmeControllerInit ( + IN NVME_CONTEXT *Nvme + ) +{ + EFI_STATUS Status; + NVME_AQA Aqa; + NVME_ASQ Asq; + NVME_ACQ Acq; + NVME_VER Ver; + + UINT32 MlBAR; + UINT32 MuBAR; + + /// + /// Update PCIE BAR0/1 for NVME device + /// + MlBAR = Nvme->Nbar; + MuBAR = 0; + PciWrite32 (Nvme->PciBase + 0x10, MlBAR); // MLBAR (BAR0) + PciWrite32 (Nvme->PciBase + 0x14, MuBAR); // MUBAR (BAR1) + + /// + /// Enable PCIE decode + /// + PciWrite8 (Nvme->PciBase + NVME_PCIE_PCICMD, 0x6); + + // Version + NVME_GET_VER (Nvme, &Ver); + if (!(Ver.Mjr == 0x0001) && (Ver.Mnr == 0x0000)) { + DEBUG ((DEBUG_INFO, "\n!!!\n!!! NVME Version mismatch for the implementation !!!\n!!!\n")); + } + + /// + /// Read the Controller Capabilities register and verify that the NVM command set is supported + /// + Status = NVME_GET_CAP (Nvme, &Nvme->Cap); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "NVME_GET_CAP fail, Status: %r\n", Status)); + goto Done; + } + + if (Nvme->Cap.Css != 0x01) { + DEBUG ((DEBUG_ERROR, "NvmeControllerInit fail: the controller doesn't support NVMe command set\n")); + Status = EFI_UNSUPPORTED; + goto Done; + } + + /// + /// Currently the driver only supports 4k page Size. + /// + if ((Nvme->Cap.Mpsmin + 12) > EFI_PAGE_SHIFT) { + DEBUG ((DEBUG_ERROR, "NvmeControllerInit fail: only supports 4k page Size\n")); + ASSERT (FALSE); + Status = EFI_UNSUPPORTED; + goto Done; + } + + Nvme->Cid[0] = 0; + Nvme->Cid[1] = 0; + + Nvme->Pt[0] = 0; + Nvme->Pt[1] = 0; + + ZeroMem ((VOID *)(UINTN)(&(Nvme->SqTdbl[0])), sizeof (NVME_SQTDBL) * NVME_MAX_IO_QUEUES); + ZeroMem ((VOID *)(UINTN)(&(Nvme->CqHdbl[0])), sizeof (NVME_CQHDBL) * NVME_MAX_IO_QUEUES); + + ZeroMem ((VOID *)(UINTN)Nvme->BaseMem, NVME_MEM_MAX_SIZE); + + Status = NvmeDisableController (Nvme); + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_ERROR, "NvmeDisableController fail, Status: %r\n", Status)); + goto Done; + } + + /// + /// set number of entries admin submission & completion queues. + /// + Aqa.Asqs = NVME_ASQ_SIZE; + Aqa.Rsvd1 = 0; + Aqa.Acqs = NVME_ACQ_SIZE; + Aqa.Rsvd2 = 0; + + /// + /// Address of admin submission queue. + /// + Asq = (UINT64)(UINTN)(NVME_ASQ_BASE (Nvme) & ~0xFFF); + + /// + /// Address of admin completion queue. + /// + Acq = (UINT64)(UINTN)(NVME_ACQ_BASE (Nvme) & ~0xFFF); + + /// + /// Address of I/O submission & completion queue. + /// + Nvme->SqBuffer[0] = (NVME_SQ *)(UINTN)NVME_ASQ_BASE (Nvme); // NVME_ADMIN_QUEUE + Nvme->CqBuffer[0] = (NVME_CQ *)(UINTN)NVME_ACQ_BASE (Nvme); // NVME_ADMIN_QUEUE + Nvme->SqBuffer[1] = (NVME_SQ *)(UINTN)NVME_SQ_BASE (Nvme, 0); // NVME_IO_QUEUE + Nvme->CqBuffer[1] = (NVME_CQ *)(UINTN)NVME_CQ_BASE (Nvme, 0); // NVME_IO_QUEUE + + DEBUG ((DEBUG_INFO, "BaseMem = [%08X]\n", Nvme->BaseMem)); + DEBUG ((DEBUG_INFO, "Admin Submission Queue Size (Aqa.Asqs) = [%08X]\n", Aqa.Asqs)); + DEBUG ((DEBUG_INFO, "Admin Completion Queue Size (Aqa.Acqs) = [%08X]\n", Aqa.Acqs)); + DEBUG ((DEBUG_INFO, "Admin Submission Queue (SqBuffer[0]) = [%08X]\n", Nvme->SqBuffer[0])); + DEBUG ((DEBUG_INFO, "Admin Completion Queue (CqBuffer[0]) = [%08X]\n", Nvme->CqBuffer[0])); + DEBUG ((DEBUG_INFO, "I/O Submission Queue (SqBuffer[1]) = [%08X]\n", Nvme->SqBuffer[1])); + DEBUG ((DEBUG_INFO, "I/O Completion Queue (CqBuffer[1]) = [%08X]\n", Nvme->CqBuffer[1])); + + /// + /// Program admin queue attributes. + /// + Status = NVME_SET_AQA (Nvme, &Aqa); + if (EFI_ERROR(Status)) { + goto Done; + } + + /// + /// Program admin submission queue address. + /// + Status = NVME_SET_ASQ (Nvme, &Asq); + if (EFI_ERROR(Status)) { + goto Done; + } + + /// + /// Program admin completion queue address. + /// + Status = NVME_SET_ACQ (Nvme, &Acq); + if (EFI_ERROR(Status)) { + goto Done; + } + + Status = NvmeEnableController (Nvme); + if (EFI_ERROR(Status)) { + goto Done; + } + + /// + /// Create one I/O completion queue. + /// + Status = NvmeCreateIoCompletionQueue (Nvme); + if (EFI_ERROR(Status)) { + goto Done; + } + + /// + /// Create one I/O Submission queue. + /// + Status = NvmeCreateIoSubmissionQueue (Nvme); + if (EFI_ERROR(Status)) { + goto Done; + } + + /// + /// Get current Identify Controller Data + /// + Nvme->ControllerData = (NVME_ADMIN_CONTROLLER_DATA *)(UINTN) NVME_CONTROL_DATA_BASE (Nvme); + Status = NvmeIdentifyController (Nvme, Nvme->ControllerData); + if (EFI_ERROR(Status)) { + goto Done; + } + + /// + /// Dump NvmExpress Identify Controller Data + /// + Nvme->ControllerData->Sn[19] = 0; + Nvme->ControllerData->Mn[39] = 0; + //NvmeDumpIdentifyController (Nvme->ControllerData); + + /// + /// Get current Identify Namespace Data + /// + Nvme->NamespaceData = (NVME_ADMIN_NAMESPACE_DATA *)NVME_NAMESPACE_DATA_BASE (Nvme); + Status = NvmeIdentifyNamespace (Nvme, Nvme->Nsid, Nvme->NamespaceData); + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_ERROR, "NvmeIdentifyNamespace fail, Status = %r\n", Status)); + goto Done; + } + + /// + /// Dump NvmExpress Identify Namespace Data + /// + if (Nvme->NamespaceData->Ncap == 0) { + DEBUG ((DEBUG_ERROR, "Invalid Namespace, Ncap: %lx\n", Nvme->NamespaceData->Ncap)); + Status = EFI_DEVICE_ERROR; + goto Done; + } + + Nvme->BlockSize = NvmeGetBlockSize (Nvme); + Nvme->LastBlock = NvmeGetLastLba (Nvme); + + Nvme->State = NvmeStatusInit; + + return EFI_SUCCESS; + +Done: + return Status; +} + +/** + Un-initialize the Nvm Express controller. + + @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure. + + @retval EFI_SUCCESS - The NVM Express Controller is un-initialized successfully. + @retval Others - A device error occurred while un-initializing the controller. + +**/ +EFI_STATUS +NvmeControllerExit ( + IN NVME_CONTEXT *Nvme + ) +{ + EFI_STATUS Status; + + Status = EFI_SUCCESS; + if (Nvme->State == NvmeStatusInit || Nvme->State == NvmeStatusMax) { + /// + /// Destroy I/O Submission queue. + /// + Status = NvmeDestroyIoSubmissionQueue (Nvme); + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_ERROR, "NvmeDestroyIoSubmissionQueue fail, Status = %r\n", Status)); + return Status; + } + + /// + /// Destroy I/O completion queue. + /// + Status = NvmeDestroyIoCompletionQueue (Nvme); + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_ERROR, "NvmeDestroyIoCompletionQueue fail, Status = %r\n", Status)); + return Status; + } + + Status = NvmeShutdownController (Nvme); + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_ERROR, "NvmeShutdownController fail, Status: %r\n", Status)); + } + } + + /// + /// Disable PCIE decode + /// + PciWrite8 (Nvme->PciBase + NVME_PCIE_PCICMD, 0x0); + PciWrite32 (Nvme->PciBase + 0x10, 0); // MLBAR (BAR0) + PciWrite32 (Nvme->PciBase + 0x14, 0); // MUBAR (BAR1) + + Nvme->State = NvmeStatusUnknown; + return Status; +} + +/** + Read sector Data from the NVMe device. + + @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure. + @param[in,out] Buffer - The Buffer used to store the Data read from the device. + @param[in] Lba - The start block number. + @param[in] Blocks - Total block number to be read. + + @retval EFI_SUCCESS - Datum are read from the device. + @retval Others - Fail to read all the datum. + +**/ +EFI_STATUS +NvmeReadSectors ( + IN NVME_CONTEXT *Nvme, + IN OUT UINT64 Buffer, + IN UINT64 Lba, + IN UINT32 Blocks + ) +{ + UINT32 Bytes; + NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket; + NVM_EXPRESS_COMMAND Command; + NVM_EXPRESS_RESPONSE Response; + EFI_STATUS Status; + UINT32 BlockSize; + + BlockSize = Nvme->BlockSize; + Bytes = Blocks * BlockSize; + + ZeroMem (&CommandPacket, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET)); + ZeroMem (&Command, sizeof(NVM_EXPRESS_COMMAND)); + ZeroMem (&Response, sizeof(NVM_EXPRESS_RESPONSE)); + + CommandPacket.NvmeCmd = &Command; + CommandPacket.NvmeResponse = &Response; + + CommandPacket.NvmeCmd->Cdw0.Opcode = NVME_IO_READ_OPC; + CommandPacket.NvmeCmd->Cdw0.Cid = Nvme->Cid[NVME_IO_QUEUE]++; + CommandPacket.NvmeCmd->Nsid = Nvme->Nsid; + CommandPacket.TransferBuffer = Buffer; + + CommandPacket.TransferLength = Bytes; + CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT; + CommandPacket.QueueId = NVME_IO_QUEUE; + + CommandPacket.NvmeCmd->Cdw10 = (UINT32)Lba; + CommandPacket.NvmeCmd->Cdw11 = (UINT32)(RShiftU64 (Lba, 32)); + CommandPacket.NvmeCmd->Cdw12 = (Blocks - 1) & 0xFFFF; + + CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID | CDW12_VALID; + + Status = NvmePassThru ( + Nvme, + Nvme->Nsid, + 0, + &CommandPacket + ); + + return Status; +} + +/** + Write sector Data to the NVMe device. + + @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure. + @param[in] Buffer - The Buffer to be written into the device. + @param[in] Lba - The start block number. + @param[in] Blocks - Total block number to be written. + + @retval EFI_SUCCESS - Datum are written into the Buffer. + @retval Others - Fail to write all the datum. + +**/ +EFI_STATUS +NvmeWriteSectors ( + IN NVME_CONTEXT *Nvme, + IN UINT64 Buffer, + IN UINT64 Lba, + IN UINT32 Blocks + ) +{ + NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket; + NVM_EXPRESS_COMMAND Command; + NVM_EXPRESS_RESPONSE Response; + EFI_STATUS Status; + UINT32 Bytes; + UINT32 BlockSize; + + BlockSize = Nvme->BlockSize; + Bytes = Blocks * BlockSize; + + ZeroMem (&CommandPacket, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET)); + ZeroMem (&Command, sizeof(NVM_EXPRESS_COMMAND)); + ZeroMem (&Response, sizeof(NVM_EXPRESS_RESPONSE)); + + CommandPacket.NvmeCmd = &Command; + CommandPacket.NvmeResponse = &Response; + + CommandPacket.NvmeCmd->Cdw0.Opcode = NVME_IO_WRITE_OPC; + CommandPacket.NvmeCmd->Cdw0.Cid = Nvme->Cid[NVME_IO_QUEUE]++; + CommandPacket.NvmeCmd->Nsid = Nvme->Nsid; + CommandPacket.TransferBuffer = Buffer; + + CommandPacket.TransferLength = Bytes; + CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT; + CommandPacket.QueueId = NVME_IO_QUEUE; + + CommandPacket.NvmeCmd->Cdw10 = (UINT32)Lba; + CommandPacket.NvmeCmd->Cdw11 = (UINT32)(RShiftU64 (Lba, 32)); + CommandPacket.NvmeCmd->Cdw12 = (Blocks - 1) & 0xFFFF; + + CommandPacket.MetadataBuffer = (UINT64)(UINTN)NULL; + CommandPacket.MetadataLength = 0; + + CommandPacket.NvmeCmd->Flags = CDW10_VALID | CDW11_VALID | CDW12_VALID; + + Status = NvmePassThru ( + Nvme, + Nvme->Nsid, + 0, + &CommandPacket + ); + + return Status; +} + +/** + Flushes all modified Data to the device. + + @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure. + + @retval EFI_SUCCESS - Datum are written into the Buffer. + @retval Others - Fail to write all the datum. + +**/ +EFI_STATUS +NvmeFlush ( + IN NVME_CONTEXT *Nvme + ) +{ + NVM_EXPRESS_PASS_THRU_COMMAND_PACKET CommandPacket; + NVM_EXPRESS_COMMAND Command; + NVM_EXPRESS_RESPONSE Response; + EFI_STATUS Status; + + ZeroMem (&CommandPacket, sizeof(NVM_EXPRESS_PASS_THRU_COMMAND_PACKET)); + ZeroMem (&Command, sizeof(NVM_EXPRESS_COMMAND)); + ZeroMem (&Response, sizeof(NVM_EXPRESS_RESPONSE)); + + CommandPacket.NvmeCmd = &Command; + CommandPacket.NvmeResponse = &Response; + + CommandPacket.NvmeCmd->Cdw0.Opcode = NVME_IO_FLUSH_OPC; + CommandPacket.NvmeCmd->Cdw0.Cid = Nvme->Cid[NVME_IO_QUEUE]++; + CommandPacket.NvmeCmd->Nsid = Nvme->Nsid; + CommandPacket.CommandTimeout = NVME_GENERIC_TIMEOUT; + CommandPacket.QueueId = NVME_IO_QUEUE; + + Status = NvmePassThru ( + Nvme, + Nvme->Nsid, + 0, + &CommandPacket + ); + if (!EFI_ERROR (Status)) { + Status = NvmeWaitAllComplete (Nvme, CommandPacket.QueueId); + } + + return Status; +} + +/** + Read some blocks from the device. + + @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure. + @param[out] Buffer - The Buffer used to store the Data read from the device. + @param[in] Lba - The start block number. + @param[in] Blocks - Total block number to be read. + + @retval EFI_SUCCESS - Datum are read from the device. + @retval Others - Fail to read all the datum. + +**/ +EFI_STATUS +NvmeRead ( + IN NVME_CONTEXT *Nvme, + OUT UINT64 Buffer, + IN UINT64 Lba, + IN UINTN Blocks + ) +{ + EFI_STATUS Status; + UINT32 BlockSize; + UINT32 MaxTransferBlocks; + + ASSERT (Blocks <= NVME_MAX_SECTORS); + Status = EFI_SUCCESS; + BlockSize = Nvme->BlockSize; + if (Nvme->ControllerData->Mdts != 0) { + MaxTransferBlocks = (1 << (Nvme->ControllerData->Mdts)) * (1 << (Nvme->Cap.Mpsmin + 12)) / BlockSize; + } else { + MaxTransferBlocks = 1024; + } + + while (Blocks > 0) { + if (Blocks > MaxTransferBlocks) { + Status = NvmeReadSectors (Nvme, Buffer, Lba, MaxTransferBlocks); + + Blocks -= MaxTransferBlocks; + Buffer += (MaxTransferBlocks * BlockSize); + Lba += MaxTransferBlocks; + } else { + Status = NvmeReadSectors (Nvme, Buffer, Lba, (UINT32) Blocks); + Blocks = 0; + } + + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_ERROR, "NvmeRead fail, Status = %r\n", Status)); + break; + } + } + + return Status; +} + +/** + Write some blocks to the device. + + @param[in] Nvme - The pointer to the NVME_CONTEXT Data structure. + @param[in] Buffer - The Buffer to be written into the device. + @param[in] Lba - The start block number. + @param[in] Blocks - Total block number to be written. + + @retval EFI_SUCCESS - Datum are written into the Buffer. + @retval Others - Fail to write all the datum. + +**/ +EFI_STATUS +NvmeWrite ( + IN NVME_CONTEXT *Nvme, + IN UINT64 Buffer, + IN UINT64 Lba, + IN UINTN Blocks + ) +{ + EFI_STATUS Status; + UINT32 BlockSize; + UINT32 MaxTransferBlocks; + + ASSERT (Blocks <= NVME_MAX_SECTORS); + Status = EFI_SUCCESS; + BlockSize = Nvme->BlockSize; + + if (Nvme->ControllerData->Mdts != 0) { + MaxTransferBlocks = (1 << (Nvme->ControllerData->Mdts)) * (1 << (Nvme->Cap.Mpsmin + 12)) / BlockSize; + } else { + MaxTransferBlocks = 1024; + } + + while (Blocks > 0) { + if (Blocks > MaxTransferBlocks) { + Status = NvmeWriteSectors (Nvme, Buffer, Lba, MaxTransferBlocks); + + Blocks -= MaxTransferBlocks; + Buffer += (MaxTransferBlocks * BlockSize); + Lba += MaxTransferBlocks; + } else { + Status = NvmeWriteSectors (Nvme, Buffer, Lba, (UINT32) Blocks); + Blocks = 0; + } + + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_ERROR, "NvmeWrite fail, Status = %r\n", Status)); + break; + } + } + + return Status; +} diff --git a/Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalNvmeMode.h b/Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalNvmeMode.h new file mode 100644 index 0000000000..bfa4f10413 --- /dev/null +++ b/Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalNvmeMode.h @@ -0,0 +1,456 @@ +/** @file + Header file for NVMe function definitions + +Copyright (c) 2016, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +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.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ +#ifndef __OPAL_PASSWORD_NVME_REG_H__ +#define __OPAL_PASSWORD_NVME_REG_H__ + +// +// PCI Header for PCIe root port configuration +// +#define NVME_PCIE_PCICMD 0x04 +#define NVME_PCIE_BNUM 0x18 +#define NVME_PCIE_SEC_BNUM 0x19 +#define NVME_PCIE_IOBL 0x1C +#define NVME_PCIE_MBL 0x20 +#define NVME_PCIE_PMBL 0x24 +#define NVME_PCIE_PMBU32 0x28 +#define NVME_PCIE_PMLU32 0x2C +#define NVME_PCIE_INTR 0x3C + +// +// NVMe related definitions +// +#define PCI_CLASS_MASS_STORAGE_NVM 0x08 // mass storage sub-class non-volatile memory. +#define PCI_IF_NVMHCI 0x02 // mass storage programming interface NVMHCI. + +#define NVME_ASQ_SIZE 1 // Number of admin submission queue entries, which is 0-based +#define NVME_ACQ_SIZE 1 // Number of admin completion queue entries, which is 0-based + +#define NVME_CSQ_SIZE 63 // Number of I/O submission queue entries, which is 0-based +#define NVME_CCQ_SIZE 63 // Number of I/O completion queue entries, which is 0-based + +#define NVME_MAX_IO_QUEUES 2 // Number of I/O queues supported by the driver, 1 for AQ, 1 for CQ + +#define NVME_CSQ_DEPTH (NVME_CSQ_SIZE+1) +#define NVME_CCQ_DEPTH (NVME_CCQ_SIZE+1) +#define NVME_PRP_SIZE (4) // Pages of PRP list + +#define NVME_CONTROLLER_ID 0 + +// +// Time out Value for Nvme transaction execution +// +#define NVME_GENERIC_TIMEOUT 5000000 ///< us +#define NVME_CMD_WAIT 100 ///< us +#define NVME_CMD_TIMEOUT 20000000 ///< us + + + +#define NVME_MEM_MAX_SIZE \ + (( \ + 1 /* Controller Data */ + \ + 1 /* Identify Data */ + \ + 1 /* ASQ */ + \ + 1 /* ACQ */ + \ + 1 /* SQs */ + \ + 1 /* CQs */ + \ + NVME_PRP_SIZE * NVME_CSQ_DEPTH /* PRPs */ \ + ) * EFI_PAGE_SIZE) + + +// +// controller register offsets +// +#define NVME_CAP_OFFSET 0x0000 // Controller Capabilities +#define NVME_VER_OFFSET 0x0008 // Version +#define NVME_INTMS_OFFSET 0x000c // Interrupt Mask Set +#define NVME_INTMC_OFFSET 0x0010 // Interrupt Mask Clear +#define NVME_CC_OFFSET 0x0014 // Controller Configuration +#define NVME_CSTS_OFFSET 0x001c // Controller Status +#define NVME_AQA_OFFSET 0x0024 // Admin Queue Attributes +#define NVME_ASQ_OFFSET 0x0028 // Admin Submission Queue Base Address +#define NVME_ACQ_OFFSET 0x0030 // Admin Completion Queue Base Address +#define NVME_SQ0_OFFSET 0x1000 // Submission Queue 0 (admin) Tail Doorbell +#define NVME_CQ0_OFFSET 0x1004 // Completion Queue 0 (admin) Head Doorbell + +// +// These register offsets are defined as 0x1000 + (N * (4 << CAP.DSTRD)) +// Get the doorbell stride bit shift Value from the controller capabilities. +// +#define NVME_SQTDBL_OFFSET(QID, DSTRD) 0x1000 + ((2 * (QID)) * (4 << (DSTRD))) // Submission Queue y (NVM) Tail Doorbell +#define NVME_CQHDBL_OFFSET(QID, DSTRD) 0x1000 + (((2 * (QID)) + 1) * (4 << (DSTRD))) // Completion Queue y (NVM) Head Doorbell + + +#pragma pack(1) + +// +// 3.1.1 Offset 00h: CAP - Controller Capabilities +// +typedef struct { + UINT16 Mqes; // Maximum Queue Entries Supported + UINT8 Cqr:1; // Contiguous Queues Required + UINT8 Ams:2; // Arbitration Mechanism Supported + UINT8 Rsvd1:5; + UINT8 To; // Timeout + UINT16 Dstrd:4; + UINT16 Rsvd2:1; + UINT16 Css:4; // Command Sets Supported + UINT16 Rsvd3:7; + UINT8 Mpsmin:4; + UINT8 Mpsmax:4; + UINT8 Rsvd4; +} NVME_CAP; + +// +// 3.1.2 Offset 08h: VS - Version +// +typedef struct { + UINT16 Mnr; // Minor version number + UINT16 Mjr; // Major version number +} NVME_VER; + +// +// 3.1.5 Offset 14h: CC - Controller Configuration +// +typedef struct { + UINT16 En:1; // Enable + UINT16 Rsvd1:3; + UINT16 Css:3; // Command Set Selected + UINT16 Mps:4; // Memory Page Size + UINT16 Ams:3; // Arbitration Mechanism Selected + UINT16 Shn:2; // Shutdown Notification + UINT8 Iosqes:4; // I/O Submission Queue Entry Size + UINT8 Iocqes:4; // I/O Completion Queue Entry Size + UINT8 Rsvd2; +} NVME_CC; + +// +// 3.1.6 Offset 1Ch: CSTS - Controller Status +// +typedef struct { + UINT32 Rdy:1; // Ready + UINT32 Cfs:1; // Controller Fatal Status + UINT32 Shst:2; // Shutdown Status + UINT32 Nssro:1; // NVM Subsystem Reset Occurred + UINT32 Rsvd1:27; +} NVME_CSTS; + +// +// 3.1.8 Offset 24h: AQA - Admin Queue Attributes +// +typedef struct { + UINT16 Asqs:12; // Submission Queue Size + UINT16 Rsvd1:4; + UINT16 Acqs:12; // Completion Queue Size + UINT16 Rsvd2:4; +} NVME_AQA; + +// +// 3.1.9 Offset 28h: ASQ - Admin Submission Queue Base Address +// +#define NVME_ASQ UINT64 + +// +// 3.1.10 Offset 30h: ACQ - Admin Completion Queue Base Address +// +#define NVME_ACQ UINT64 + +// +// 3.1.11 Offset (1000h + ((2y) * (4 << CAP.DSTRD))): SQyTDBL - Submission Queue y Tail Doorbell +// +typedef struct { + UINT16 Sqt; + UINT16 Rsvd1; +} NVME_SQTDBL; + +// +// 3.1.12 Offset (1000h + ((2y + 1) * (4 << CAP.DSTRD))): CQyHDBL - Completion Queue y Head Doorbell +// +typedef struct { + UINT16 Cqh; + UINT16 Rsvd1; +} NVME_CQHDBL; + +// +// NVM command set structures +// +// Read Command +// +typedef struct { + // + // CDW 10, 11 + // + UINT64 Slba; /* Starting Sector Address */ + // + // CDW 12 + // + UINT16 Nlb; /* Number of Sectors */ + UINT16 Rsvd1:10; + UINT16 Prinfo:4; /* Protection Info Check */ + UINT16 Fua:1; /* Force Unit Access */ + UINT16 Lr:1; /* Limited Retry */ + // + // CDW 13 + // + UINT32 Af:4; /* Access Frequency */ + UINT32 Al:2; /* Access Latency */ + UINT32 Sr:1; /* Sequential Request */ + UINT32 In:1; /* Incompressible */ + UINT32 Rsvd2:24; + // + // CDW 14 + // + UINT32 Eilbrt; /* Expected Initial Logical Block Reference Tag */ + // + // CDW 15 + // + UINT16 Elbat; /* Expected Logical Block Application Tag */ + UINT16 Elbatm; /* Expected Logical Block Application Tag Mask */ +} NVME_READ; + +// +// Write Command +// +typedef struct { + // + // CDW 10, 11 + // + UINT64 Slba; /* Starting Sector Address */ + // + // CDW 12 + // + UINT16 Nlb; /* Number of Sectors */ + UINT16 Rsvd1:10; + UINT16 Prinfo:4; /* Protection Info Check */ + UINT16 Fua:1; /* Force Unit Access */ + UINT16 Lr:1; /* Limited Retry */ + // + // CDW 13 + // + UINT32 Af:4; /* Access Frequency */ + UINT32 Al:2; /* Access Latency */ + UINT32 Sr:1; /* Sequential Request */ + UINT32 In:1; /* Incompressible */ + UINT32 Rsvd2:24; + // + // CDW 14 + // + UINT32 Ilbrt; /* Initial Logical Block Reference Tag */ + // + // CDW 15 + // + UINT16 Lbat; /* Logical Block Application Tag */ + UINT16 Lbatm; /* Logical Block Application Tag Mask */ +} NVME_WRITE; + +// +// Flush +// +typedef struct { + // + // CDW 10 + // + UINT32 Flush; /* Flush */ +} NVME_FLUSH; + +// +// Write Uncorrectable command +// +typedef struct { + // + // CDW 10, 11 + // + UINT64 Slba; /* Starting LBA */ + // + // CDW 12 + // + UINT32 Nlb:16; /* Number of Logical Blocks */ + UINT32 Rsvd1:16; +} NVME_WRITE_UNCORRECTABLE; + +// +// Write Zeroes command +// +typedef struct { + // + // CDW 10, 11 + // + UINT64 Slba; /* Starting LBA */ + // + // CDW 12 + // + UINT16 Nlb; /* Number of Logical Blocks */ + UINT16 Rsvd1:10; + UINT16 Prinfo:4; /* Protection Info Check */ + UINT16 Fua:1; /* Force Unit Access */ + UINT16 Lr:1; /* Limited Retry */ + // + // CDW 13 + // + UINT32 Rsvd2; + // + // CDW 14 + // + UINT32 Ilbrt; /* Initial Logical Block Reference Tag */ + // + // CDW 15 + // + UINT16 Lbat; /* Logical Block Application Tag */ + UINT16 Lbatm; /* Logical Block Application Tag Mask */ +} NVME_WRITE_ZEROES; + +// +// Compare command +// +typedef struct { + // + // CDW 10, 11 + // + UINT64 Slba; /* Starting LBA */ + // + // CDW 12 + // + UINT16 Nlb; /* Number of Logical Blocks */ + UINT16 Rsvd1:10; + UINT16 Prinfo:4; /* Protection Info Check */ + UINT16 Fua:1; /* Force Unit Access */ + UINT16 Lr:1; /* Limited Retry */ + // + // CDW 13 + // + UINT32 Rsvd2; + // + // CDW 14 + // + UINT32 Eilbrt; /* Expected Initial Logical Block Reference Tag */ + // + // CDW 15 + // + UINT16 Elbat; /* Expected Logical Block Application Tag */ + UINT16 Elbatm; /* Expected Logical Block Application Tag Mask */ +} NVME_COMPARE; + +typedef union { + NVME_READ Read; + NVME_WRITE Write; + NVME_FLUSH Flush; + NVME_WRITE_UNCORRECTABLE WriteUncorrectable; + NVME_WRITE_ZEROES WriteZeros; + NVME_COMPARE Compare; +} NVME_CMD; + +typedef struct { + UINT16 Mp; /* Maximum Power */ + UINT8 Rsvd1; /* Reserved as of Nvm Express 1.1 Spec */ + UINT8 Mps:1; /* Max Power Scale */ + UINT8 Nops:1; /* Non-Operational State */ + UINT8 Rsvd2:6; /* Reserved as of Nvm Express 1.1 Spec */ + UINT32 Enlat; /* Entry Latency */ + UINT32 Exlat; /* Exit Latency */ + UINT8 Rrt:5; /* Relative Read Throughput */ + UINT8 Rsvd3:3; /* Reserved as of Nvm Express 1.1 Spec */ + UINT8 Rrl:5; /* Relative Read Leatency */ + UINT8 Rsvd4:3; /* Reserved as of Nvm Express 1.1 Spec */ + UINT8 Rwt:5; /* Relative Write Throughput */ + UINT8 Rsvd5:3; /* Reserved as of Nvm Express 1.1 Spec */ + UINT8 Rwl:5; /* Relative Write Leatency */ + UINT8 Rsvd6:3; /* Reserved as of Nvm Express 1.1 Spec */ + UINT8 Rsvd7[16]; /* Reserved as of Nvm Express 1.1 Spec */ +} NVME_PSDESCRIPTOR; + +// +// Identify Controller Data +// +typedef struct { + // + // Controller Capabilities and Features 0-255 + // + UINT16 Vid; /* PCI Vendor ID */ + UINT16 Ssvid; /* PCI sub-system vendor ID */ + UINT8 Sn[20]; /* Produce serial number */ + + UINT8 Mn[40]; /* Proeduct model number */ + UINT8 Fr[8]; /* Firmware Revision */ + UINT8 Rab; /* Recommended Arbitration Burst */ + UINT8 Ieee_oiu[3]; /* Organization Unique Identifier */ + UINT8 Cmic; /* Multi-interface Capabilities */ + UINT8 Mdts; /* Maximum Data Transfer Size */ + UINT8 Cntlid[2]; /* Controller ID */ + UINT8 Rsvd1[176]; /* Reserved as of Nvm Express 1.1 Spec */ + // + // Admin Command Set Attributes + // + UINT16 Oacs; /* Optional Admin Command Support */ + UINT8 Acl; /* Abort Command Limit */ + UINT8 Aerl; /* Async Event Request Limit */ + UINT8 Frmw; /* Firmware updates */ + UINT8 Lpa; /* Log Page Attributes */ + UINT8 Elpe; /* Error Log Page Entries */ + UINT8 Npss; /* Number of Power States Support */ + UINT8 Avscc; /* Admin Vendor Specific Command Configuration */ + UINT8 Apsta; /* Autonomous Power State Transition Attributes */ + UINT8 Rsvd2[246]; /* Reserved as of Nvm Express 1.1 Spec */ + // + // NVM Command Set Attributes + // + UINT8 Sqes; /* Submission Queue Entry Size */ + UINT8 Cqes; /* Completion Queue Entry Size */ + UINT16 Rsvd3; /* Reserved as of Nvm Express 1.1 Spec */ + UINT32 Nn; /* Number of Namespaces */ + UINT16 Oncs; /* Optional NVM Command Support */ + UINT16 Fuses; /* Fused Operation Support */ + UINT8 Fna; /* Format NVM Attributes */ + UINT8 Vwc; /* Volatile Write Cache */ + UINT16 Awun; /* Atomic Write Unit Normal */ + UINT16 Awupf; /* Atomic Write Unit Power Fail */ + UINT8 Nvscc; /* NVM Vendor Specific Command Configuration */ + UINT8 Rsvd4; /* Reserved as of Nvm Express 1.1 Spec */ + UINT16 Acwu; /* Atomic Compare & Write Unit */ + UINT16 Rsvd5; /* Reserved as of Nvm Express 1.1 Spec */ + UINT32 Sgls; /* SGL Support */ + UINT8 Rsvd6[164]; /* Reserved as of Nvm Express 1.1 Spec */ + // + // I/O Command set Attributes + // + UINT8 Rsvd7[1344]; /* Reserved as of Nvm Express 1.1 Spec */ + // + // Power State Descriptors + // + NVME_PSDESCRIPTOR PsDescriptor[32]; + + UINT8 VendorData[1024]; /* Vendor specific Data */ +} NVME_ADMIN_CONTROLLER_DATA; + +typedef struct { + UINT16 Security : 1; /* supports security send/receive commands */ + UINT16 Format : 1; /* supports format nvm command */ + UINT16 Firmware : 1; /* supports firmware activate/download commands */ + UINT16 Oacs_rsvd : 13; + } OACS; // optional admin command support: NVME_ADMIN_CONTROLLER_DATA.Oacs + +typedef struct { + UINT16 Ms; /* Metadata Size */ + UINT8 Lbads; /* LBA Data Size */ + UINT8 Rp:2; /* Relative Performance */ + #define LBAF_RP_BEST 00b + #define LBAF_RP_BETTER 01b + #define LBAF_RP_GOOD 10b + #define LBAF_RP_DEGRADED 11b + UINT8 Rsvd1:6; /* Reserved as of Nvm Express 1.1 Spec */ +} NVME_LBAFORMAT; + +// +// Identify Namespace Data +// +typedef struct { + // + // NVM Command Set Specific + // + UINT64 Nsze; /* Namespace Size (total number of blocks in formatted namespace) */ + UINT64 Ncap; /* Namespace Capacity (max number of logical blocks) */ + UINT64 Nuse; /* Namespace Utilization */ + UINT8 Nsfeat; /* Namespace Features */ + UINT8 Nlbaf; /* Number of LBA Formats */ + UINT8 Flbas; /* Formatted LBA Size */ + UINT8 Mc; /* Metadata Capabilities */ + UINT8 Dpc; /* End-to-end Data Protection capabilities */ + UINT8 Dps; /* End-to-end Data Protection Type Settings */ + UINT8 Nmic; /* Namespace Multi-path I/O and Namespace Sharing Capabilities */ + UINT8 Rescap; /* Reservation Capabilities */ + UINT8 Rsvd1[88]; /* Reserved as of Nvm Express 1.1 Spec */ + UINT64 Eui64; /* IEEE Extended Unique Identifier */ + // + // LBA Format + // + NVME_LBAFORMAT LbaFormat[16]; + + UINT8 Rsvd2[192]; /* Reserved as of Nvm Express 1.1 Spec */ + UINT8 VendorData[3712]; /* Vendor specific Data */ +} NVME_ADMIN_NAMESPACE_DATA; + +// +// NvmExpress Admin Identify Cmd +// +typedef struct { + // + // CDW 10 + // + UINT32 Cns:2; + UINT32 Rsvd1:30; +} NVME_ADMIN_IDENTIFY; + +// +// NvmExpress Admin Create I/O Completion Queue +// +typedef struct { + // + // CDW 10 + // + UINT32 Qid:16; /* Queue Identifier */ + UINT32 Qsize:16; /* Queue Size */ + + // + // CDW 11 + // + UINT32 Pc:1; /* Physically Contiguous */ + UINT32 Ien:1; /* Interrupts Enabled */ + UINT32 Rsvd1:14; /* reserved as of Nvm Express 1.1 Spec */ + UINT32 Iv:16; /* Interrupt Vector */ +} NVME_ADMIN_CRIOCQ; + +// +// NvmExpress Admin Create I/O Submission Queue +// +typedef struct { + // + // CDW 10 + // + UINT32 Qid:16; /* Queue Identifier */ + UINT32 Qsize:16; /* Queue Size */ + + // + // CDW 11 + // + UINT32 Pc:1; /* Physically Contiguous */ + UINT32 Qprio:2; /* Queue Priority */ + UINT32 Rsvd1:13; /* Reserved as of Nvm Express 1.1 Spec */ + UINT32 Cqid:16; /* Completion Queue ID */ +} NVME_ADMIN_CRIOSQ; + +// +// NvmExpress Admin Delete I/O Completion Queue +// +typedef struct { + // + // CDW 10 + // + UINT16 Qid; + UINT16 Rsvd1; +} NVME_ADMIN_DEIOCQ; + +// +// NvmExpress Admin Delete I/O Submission Queue +// +typedef struct { + // + // CDW 10 + // + UINT16 Qid; + UINT16 Rsvd1; +} NVME_ADMIN_DEIOSQ; + +// +// NvmExpress Admin Security Send +// +typedef struct { + // + // CDW 10 + // + UINT32 Resv:8; /* Reserve */ + UINT32 Spsp:16; /* SP Specific */ + UINT32 Secp:8; /* Security Protocol */ + + // + // CDW 11 + // + UINT32 Tl; /* Transfer Length */ +} NVME_ADMIN_SECSEND; + +// +// NvmExpress Admin Abort Command +// +typedef struct { + // + // CDW 10 + // + UINT32 Sqid:16; /* Submission Queue identifier */ + UINT32 Cid:16; /* Command Identifier */ +} NVME_ADMIN_ABORT; + +// +// NvmExpress Admin Firmware Activate Command +// +typedef struct { + // + // CDW 10 + // + UINT32 Fs:3; /* Submission Queue identifier */ + UINT32 Aa:2; /* Command Identifier */ + UINT32 Rsvd1:27; +} NVME_ADMIN_FIRMWARE_ACTIVATE; + +// +// NvmExpress Admin Firmware Image Download Command +// +typedef struct { + // + // CDW 10 + // + UINT32 Numd; /* Number of Dwords */ + // + // CDW 11 + // + UINT32 Ofst; /* Offset */ +} NVME_ADMIN_FIRMWARE_IMAGE_DOWNLOAD; + +// +// NvmExpress Admin Get Features Command +// +typedef struct { + // + // CDW 10 + // + UINT32 Fid:8; /* Feature Identifier */ + UINT32 Sel:3; /* Select */ + UINT32 Rsvd1:21; +} NVME_ADMIN_GET_FEATURES; + +// +// NvmExpress Admin Get Log Page Command +// +typedef struct { + // + // CDW 10 + // + UINT32 Lid:8; /* Log Page Identifier */ + #define LID_ERROR_INFO + #define LID_SMART_INFO + #define LID_FW_SLOT_INFO + UINT32 Rsvd1:8; + UINT32 Numd:12; /* Number of Dwords */ + UINT32 Rsvd2:4; /* Reserved as of Nvm Express 1.1 Spec */ +} NVME_ADMIN_GET_LOG_PAGE; + +// +// NvmExpress Admin Set Features Command +// +typedef struct { + // + // CDW 10 + // + UINT32 Fid:8; /* Feature Identifier */ + UINT32 Rsvd1:23; + UINT32 Sv:1; /* Save */ +} NVME_ADMIN_SET_FEATURES; + +// +// NvmExpress Admin Format NVM Command +// +typedef struct { + // + // CDW 10 + // + UINT32 Lbaf:4; /* LBA Format */ + UINT32 Ms:1; /* Metadata Settings */ + UINT32 Pi:3; /* Protection Information */ + UINT32 Pil:1; /* Protection Information Location */ + UINT32 Ses:3; /* Secure Erase Settings */ + UINT32 Rsvd1:20; +} NVME_ADMIN_FORMAT_NVM; + +// +// NvmExpress Admin Security Receive Command +// +typedef struct { + // + // CDW 10 + // + UINT32 Rsvd1:8; + UINT32 Spsp:16; /* SP Specific */ + UINT32 Secp:8; /* Security Protocol */ + // + // CDW 11 + // + UINT32 Al; /* Allocation Length */ +} NVME_ADMIN_SECURITY_RECEIVE; + +// +// NvmExpress Admin Security Send Command +// +typedef struct { + // + // CDW 10 + // + UINT32 Rsvd1:8; + UINT32 Spsp:16; /* SP Specific */ + UINT32 Secp:8; /* Security Protocol */ + // + // CDW 11 + // + UINT32 Tl; /* Transfer Length */ +} NVME_ADMIN_SECURITY_SEND; + +typedef union { + NVME_ADMIN_IDENTIFY Identify; + NVME_ADMIN_CRIOCQ CrIoCq; + NVME_ADMIN_CRIOSQ CrIoSq; + NVME_ADMIN_DEIOCQ DeIoCq; + NVME_ADMIN_DEIOSQ DeIoSq; + NVME_ADMIN_ABORT Abort; + NVME_ADMIN_FIRMWARE_ACTIVATE Activate; + NVME_ADMIN_FIRMWARE_IMAGE_DOWNLOAD FirmwareImageDownload; + NVME_ADMIN_GET_FEATURES GetFeatures; + NVME_ADMIN_GET_LOG_PAGE GetLogPage; + NVME_ADMIN_SET_FEATURES SetFeatures; + NVME_ADMIN_FORMAT_NVM FormatNvm; + NVME_ADMIN_SECURITY_RECEIVE SecurityReceive; + NVME_ADMIN_SECURITY_SEND SecuritySend; +} NVME_ADMIN_CMD; + +typedef struct { + UINT32 Cdw10; + UINT32 Cdw11; + UINT32 Cdw12; + UINT32 Cdw13; + UINT32 Cdw14; + UINT32 Cdw15; +} NVME_RAW; + +typedef union { + NVME_ADMIN_CMD Admin; // Union of Admin commands + NVME_CMD Nvm; // Union of Nvm commands + NVME_RAW Raw; +} NVME_PAYLOAD; + +// +// Submission Queue +// +typedef struct { + // + // CDW 0, Common to all comnmands + // + UINT8 Opc; // Opcode + UINT8 Fuse:2; // Fused Operation + UINT8 Rsvd1:5; + UINT8 Psdt:1; // PRP or SGL for Data Transfer + UINT16 Cid; // Command Identifier + + // + // CDW 1 + // + UINT32 Nsid; // Namespace Identifier + + // + // CDW 2,3 + // + UINT64 Rsvd2; + + // + // CDW 4,5 + // + UINT64 Mptr; // Metadata Pointer + + // + // CDW 6-9 + // + UINT64 Prp[2]; // First and second PRP entries + + NVME_PAYLOAD Payload; + +} NVME_SQ; + +// +// Completion Queue +// +typedef struct { + // + // CDW 0 + // + UINT32 Dword0; + // + // CDW 1 + // + UINT32 Rsvd1; + // + // CDW 2 + // + UINT16 Sqhd; // Submission Queue Head Pointer + UINT16 Sqid; // Submission Queue Identifier + // + // CDW 3 + // + UINT16 Cid; // Command Identifier + UINT16 Pt:1; // Phase Tag + UINT16 Sc:8; // Status Code + UINT16 Sct:3; // Status Code Type + UINT16 Rsvd2:2; + UINT16 Mo:1; // More + UINT16 Dnr:1; // Retry +} NVME_CQ; + +// +// Nvm Express Admin cmd opcodes +// +#define NVME_ADMIN_DELIOSQ_OPC 0 +#define NVME_ADMIN_CRIOSQ_OPC 1 +#define NVME_ADMIN_DELIOCQ_OPC 4 +#define NVME_ADMIN_CRIOCQ_OPC 5 +#define NVME_ADMIN_IDENTIFY_OPC 6 +#define NVME_ADMIN_SECURITY_SEND_OPC 0x81 +#define NVME_ADMIN_SECURITY_RECV_OPC 0x82 + +#define NVME_IO_FLUSH_OPC 0 +#define NVME_IO_WRITE_OPC 1 +#define NVME_IO_READ_OPC 2 + +// +// Offset from the beginning of private Data queue Buffer +// +#define NVME_ASQ_BUF_OFFSET EFI_PAGE_SIZE + +#pragma pack() + +#endif + diff --git a/Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalPasswordSmm.c b/Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalPasswordSmm.c new file mode 100644 index 0000000000..2f2a1d9c13 --- /dev/null +++ b/Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalPasswordSmm.c @@ -0,0 +1,1139 @@ +/** @file + Opal password smm driver which is used to support Opal security feature at s3 path. + +Copyright (c) 2016, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "OpalPasswordSmm.h" + +#define SMM_SIZE_ALLOC_BYTES (512) +#define RESPONSE_SIZE (200) + +#define PCI_CLASS_MASS_STORAGE_AHCI (0x06) + +#define OPAL_PCIE_ROOTPORT_SAVESIZE (0x40) +#define STORE_INVALID_ROOTPORT_INDEX ((UINT8) -1) +#define OPAL_DEVICE_TYPE_SATA 0x1 +#define OPAL_DEVICE_TYPE_NVME 0x2 +#define OPAL_DEVICE_TYPE_UNKNOWN 0xFF + +// +// To unlock the Intel SATA controller at S3 Resume, restored the following registers. +// +const OPAL_HC_PCI_REGISTER_SAVE mSataHcRegisterSaveTemplate[] = { + {0x9, S3BootScriptWidthUint8}, + {0x10, S3BootScriptWidthUint32}, + {0x14, S3BootScriptWidthUint32}, + {0x18, S3BootScriptWidthUint32}, + {0x1C, S3BootScriptWidthUint32}, + {0x20, S3BootScriptWidthUint32}, + {0x24, S3BootScriptWidthUint32}, + {0x3c, S3BootScriptWidthUint8}, + {0x3d, S3BootScriptWidthUint8}, + {0x40, S3BootScriptWidthUint16}, + {0x42, S3BootScriptWidthUint16}, + {0x92, S3BootScriptWidthUint16}, + {0x94, S3BootScriptWidthUint32}, + {0x9C, S3BootScriptWidthUint32}, + {0x4, S3BootScriptWidthUint16}, +}; + + +UINT8 mSwSmiValue; +LIST_ENTRY *mOpalDeviceList; +LIST_ENTRY mSmmDeviceList = INITIALIZE_LIST_HEAD_VARIABLE (mSmmDeviceList); + +BOOLEAN mSendBlockSID = FALSE; + +// AHCI +UINT32 mAhciBar = 0; +EFI_AHCI_REGISTERS mAhciRegisters; +VOID *mBuffer = NULL; // DMA can not read/write Data to smram, so we pre-allocates Buffer from AcpiNVS. +// +// NVME +NVME_CONTEXT mNvmeContext; + +EFI_GCD_MEMORY_SPACE_DESCRIPTOR *mGcdMemSpace = NULL; +UINTN mNumberOfDescriptors = 0; + +/** + Add new bridge node or nvme device info to the device list. + + @param[in] BusNum The bus number. + @param[in] DevNum The device number. + @param[in] FuncNum The function number. + @param[in] Dev The device which need to add device node info. + +**/ +VOID +AddPciDeviceNode ( + UINT32 BusNum, + UINT32 DevNum, + UINT32 FuncNum, + OPAL_SMM_DEVICE *Dev + ) +{ + UINT8 *DevList; + PCI_DEVICE *DeviceNode; + + DevList = AllocateZeroPool (sizeof (PCI_DEVICE) + Dev->Length); + ASSERT (DevList != NULL); + + if (Dev->Length != 0) { + CopyMem (DevList, Dev->PciBridgeNode, Dev->Length); + FreePool (Dev->PciBridgeNode); + } + + DeviceNode = (PCI_DEVICE *) (DevList + Dev->Length); + + DeviceNode->BusNum = BusNum; + DeviceNode->DevNum = DevNum; + DeviceNode->FuncNum = FuncNum; + + Dev->Length += sizeof (PCI_DEVICE); + Dev->PciBridgeNode = (PCI_DEVICE *)DevList; +} + +/** + Extract device info from the input device path. + + @param[in] DevicePath Device path info for the device. + @param[in,out] Dev The device which new inputed. + +**/ +VOID +ExtractDeviceInfoFromDevicePath ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + IN OUT OPAL_SMM_DEVICE *Dev + ) +{ + EFI_DEVICE_PATH_PROTOCOL *TmpDevPath; + EFI_DEVICE_PATH_PROTOCOL *TmpDevPath2; + PCI_DEVICE_PATH *PciDevPath; + SATA_DEVICE_PATH *SataDevPath; + NVME_NAMESPACE_DEVICE_PATH *NvmeDevPath; + UINTN BusNum; + + TmpDevPath = DevicePath; + Dev->DeviceType = OPAL_DEVICE_TYPE_UNKNOWN; + + while (!IsDevicePathEnd(TmpDevPath)) { + if (TmpDevPath->Type == MESSAGING_DEVICE_PATH && TmpDevPath->SubType == MSG_SATA_DP) { + // + // SATA + // + SataDevPath = ( SATA_DEVICE_PATH* )TmpDevPath; + Dev->SataPort = SataDevPath->HBAPortNumber; + Dev->SataPortMultiplierPort = SataDevPath->PortMultiplierPortNumber; + Dev->DeviceType = OPAL_DEVICE_TYPE_SATA; + break; + } else if (TmpDevPath->Type == MESSAGING_DEVICE_PATH && TmpDevPath->SubType == MSG_NVME_NAMESPACE_DP) { + // + // NVMe + // + NvmeDevPath = ( NVME_NAMESPACE_DEVICE_PATH* )TmpDevPath; + Dev->NvmeNamespaceId = NvmeDevPath->NamespaceId; + Dev->DeviceType = OPAL_DEVICE_TYPE_NVME; + break; + } + TmpDevPath = NextDevicePathNode (TmpDevPath); + } + + // + // Get bridge node info for the nvme device. + // + BusNum = 0; + TmpDevPath = DevicePath; + TmpDevPath2 = NextDevicePathNode (DevicePath); + while (!IsDevicePathEnd(TmpDevPath2)) { + if (TmpDevPath->Type == HARDWARE_DEVICE_PATH && TmpDevPath->SubType == HW_PCI_DP) { + PciDevPath = (PCI_DEVICE_PATH *) TmpDevPath; + if ((TmpDevPath2->Type == MESSAGING_DEVICE_PATH && TmpDevPath2->SubType == MSG_NVME_NAMESPACE_DP)|| + (TmpDevPath2->Type == MESSAGING_DEVICE_PATH && TmpDevPath2->SubType == MSG_SATA_DP)) { + Dev->BusNum = (UINT32)BusNum; + Dev->DevNum = PciDevPath->Device; + Dev->FuncNum = PciDevPath->Function; + } else { + AddPciDeviceNode((UINT32)BusNum, PciDevPath->Device, PciDevPath->Function, Dev); + if (TmpDevPath2->Type == HARDWARE_DEVICE_PATH && TmpDevPath2->SubType == HW_PCI_DP) { + BusNum = PciRead8 (PCI_LIB_ADDRESS (BusNum, PciDevPath->Device, PciDevPath->Function, NVME_PCIE_SEC_BNUM)); + } + } + } + + TmpDevPath = NextDevicePathNode (TmpDevPath); + TmpDevPath2 = NextDevicePathNode (TmpDevPath2); + } +} + +/** + + The function returns whether or not the device is Opal Locked. + TRUE means that the device is partially or fully locked. + This will perform a Level 0 Discovery and parse the locking feature descriptor + + @param[in] OpalDev Opal object to determine if locked + @param[out] BlockSidSupported Whether device support BlockSid feature. + +**/ +BOOLEAN +IsOpalDeviceLocked( + OPAL_SMM_DEVICE *OpalDev, + BOOLEAN *BlockSidSupported + ) +{ + OPAL_SESSION Session; + OPAL_DISK_SUPPORT_ATTRIBUTE SupportedAttributes; + TCG_LOCKING_FEATURE_DESCRIPTOR LockingFeature; + UINT16 OpalBaseComId; + TCG_RESULT Ret; + + Session.Sscp = &OpalDev->Sscp; + Session.MediaId = 0; + + Ret = OpalGetSupportedAttributesInfo (&Session, &SupportedAttributes, &OpalBaseComId); + if (Ret != TcgResultSuccess) { + return FALSE; + } + + OpalDev->OpalBaseComId = OpalBaseComId; + Session.OpalBaseComId = OpalBaseComId; + *BlockSidSupported = SupportedAttributes.BlockSid == 1 ? TRUE : FALSE; + + Ret = OpalGetLockingInfo(&Session, &LockingFeature); + if (Ret != TcgResultSuccess) { + return FALSE; + } + + return OpalDeviceLocked (&SupportedAttributes, &LockingFeature); +} + +/** + Save/Restore RootPort configuration space. + + @param[in] DeviceNode - The device node. + @param[in] SaveAction - TRUE: Save, FALSE: Restore + @param[in,out] PcieConfBufferList - Configuration space data buffer for save/restore + + @retval - PCIE base address of this RootPort +**/ +UINTN +SaveRestoreRootportConfSpace ( + IN OPAL_SMM_DEVICE *DeviceNode, + IN BOOLEAN SaveAction, + IN OUT UINT8 **PcieConfBufferList + ) +{ + UINTN RpBase; + UINTN Length; + PCI_DEVICE *DevNode; + UINT8 *StorePcieConfData; + UINTN Index; + + Length = 0; + Index = 0; + RpBase = 0; + + while (Length < DeviceNode->Length) { + DevNode = (PCI_DEVICE *)((UINT8*)DeviceNode->PciBridgeNode + Length); + RpBase = PCI_LIB_ADDRESS (DevNode->BusNum, DevNode->DevNum, DevNode->FuncNum, 0x0); + + if (PcieConfBufferList != NULL) { + if (SaveAction) { + StorePcieConfData = (UINT8 *) AllocateZeroPool (OPAL_PCIE_ROOTPORT_SAVESIZE); + ASSERT (StorePcieConfData != NULL); + OpalPciRead (StorePcieConfData, RpBase, OPAL_PCIE_ROOTPORT_SAVESIZE); + PcieConfBufferList[Index] = StorePcieConfData; + } else { + // Skip PCIe Command & Status registers + StorePcieConfData = PcieConfBufferList[Index]; + OpalPciWrite (RpBase, StorePcieConfData, 4); + OpalPciWrite (RpBase + 8, StorePcieConfData + 8, OPAL_PCIE_ROOTPORT_SAVESIZE - 8); + + FreePool (StorePcieConfData); + } + } + + Length += sizeof (PCI_DEVICE); + Index ++; + } + + return RpBase; +} + +/** + Configure RootPort for downstream PCIe NAND devices. + + @param[in] RpBase - PCIe configuration space address of this RootPort + @param[in] BusNumber - Bus number + @param[in] MemoryBase - Memory base address + @param[in] MemoryLength - Memory size + +**/ +VOID +ConfigureRootPortForPcieNand ( + IN UINTN RpBase, + IN UINTN BusNumber, + IN UINT32 MemoryBase, + IN UINT32 MemoryLength + ) +{ + UINT32 MemoryLimit; + + DEBUG ((DEBUG_INFO, "ConfigureRootPortForPcieNand, BusNumber: %x, MemoryBase: %x, MemoryLength: %x\n", + BusNumber, MemoryBase, MemoryLength)); + + if (MemoryLength == 0) { + MemoryLimit = MemoryBase; + } else { + MemoryLimit = MemoryBase + MemoryLength + 0xFFFFF; // 1M + } + + /// + /// Configue PCIE configuration space for RootPort + /// + PciWrite8 (RpBase + NVME_PCIE_BNUM + 1, (UINT8) BusNumber); // Secondary Bus Number registers + PciWrite8 (RpBase + NVME_PCIE_BNUM + 2, (UINT8) BusNumber); // Subordinate Bus Number registers + PciWrite8 (RpBase + NVME_PCIE_IOBL, 0xFF); // I/O Base registers + PciWrite8 (RpBase + NVME_PCIE_IOBL + 1, 0x00); // I/O Limit registers + PciWrite16 (RpBase + NVME_PCIE_MBL, (UINT16) RShiftU64 ((UINTN)MemoryBase, 16)); // Memory Base register + PciWrite16 (RpBase + NVME_PCIE_MBL + 2, (UINT16) RShiftU64 ((UINTN)MemoryLimit, 16)); // Memory Limit register + PciWrite16 (RpBase + NVME_PCIE_PMBL, 0xFFFF); // Prefetchable Memory Base registers + PciWrite16 (RpBase + NVME_PCIE_PMBL + 2, 0x0000); // Prefetchable Memory Limit registers + PciWrite32 (RpBase + NVME_PCIE_PMBU32, 0xFFFFFFFF); // Prefetchable Memory Upper Base registers + PciWrite32 (RpBase + NVME_PCIE_PMLU32, 0x00000000); // Prefetchable Memory Upper Limit registers +} + + +/** + Dispatch function for a Software SMI handler. + + @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister(). + @param[in] RegisterContext Points to an optional handler context which was specified when the + handler was registered. + @param[in, out] CommBuffer A pointer to a collection of Data in memory that will + be conveyed from a non-SMM environment into an SMM environment. + @param[in, out] CommBufferSize The Size of the CommBuffer. + + @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers + should still be called. + @retval Others Other execution results. +**/ +EFI_STATUS +EFIAPI +SmmUnlockOpalPassword ( + IN EFI_HANDLE DispatchHandle, + IN CONST VOID *RegisterContext, + IN OUT VOID *CommBuffer, + IN OUT UINTN *CommBufferSize + ) +{ + EFI_STATUS Status; + OPAL_SMM_DEVICE *OpalDev; + LIST_ENTRY *Entry; + UINT8 BaseClassCode; + UINT8 SubClassCode; + UINT8 ProgInt; + TCG_RESULT Result; + UINT8 SataCmdSt; + UINT8 *StorePcieConfDataList[16]; + UINTN RpBase; + UINTN MemoryBase; + UINTN MemoryLength; + OPAL_SESSION Session; + BOOLEAN BlockSidSupport; + + ZeroMem (StorePcieConfDataList, sizeof (StorePcieConfDataList)); + Status = EFI_DEVICE_ERROR; + + // + // try to unlock all locked hdd disks. + // + for (Entry = mSmmDeviceList.ForwardLink; Entry != &mSmmDeviceList; Entry = Entry->ForwardLink) { + OpalDev = BASE_CR(Entry, OPAL_SMM_DEVICE, Link); + + RpBase = 0; + SataCmdSt = 0; + + /// + /// Configure RootPort for PCIe AHCI/NVME devices. + /// + if (OpalDev->DeviceType == OPAL_DEVICE_TYPE_NVME) { + /// + /// Save original RootPort configuration space to heap + /// + RpBase = SaveRestoreRootportConfSpace ( + OpalDev, + TRUE, + StorePcieConfDataList + ); + MemoryBase = mNvmeContext.Nbar; + MemoryLength = 0; + ConfigureRootPortForPcieNand (RpBase, OpalDev->BusNum, (UINT32) MemoryBase, (UINT32) MemoryLength); + + /// + /// Enable PCIE decode for RootPort + /// + SataCmdSt = PciRead8 (RpBase + NVME_PCIE_PCICMD); + PciWrite8 (RpBase + NVME_PCIE_PCICMD, 0x6); + } else { + SataCmdSt = PciRead8 (PCI_LIB_ADDRESS (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum, NVME_PCIE_PCICMD)); + PciWrite8 (PCI_LIB_ADDRESS (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum, NVME_PCIE_PCICMD), 0x6); + } + + BaseClassCode = PciRead8 (PCI_LIB_ADDRESS (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum, 0x0B)); + SubClassCode = PciRead8 (PCI_LIB_ADDRESS (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum, 0x0A)); + ProgInt = PciRead8 (PCI_LIB_ADDRESS (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum, 0x09)); + if (BaseClassCode != PCI_CLASS_MASS_STORAGE) { + Status = EFI_INVALID_PARAMETER; + break; + } + + Status = EFI_DEVICE_ERROR; + if (OpalDev->DeviceType == OPAL_DEVICE_TYPE_SATA) { + if ((SubClassCode == PCI_CLASS_MASS_STORAGE_AHCI) || (SubClassCode == PCI_CLASS_MASS_STORAGE_RAID)) { + Status = GetAhciBaseAddress (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "GetAhciBaseAddress error, Status: %r\n", Status)); + goto done; + } + Status = AhciModeInitialize ((UINT8)OpalDev->SataPort); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "AhciModeInitialize error, Status: %r\n", Status)); + goto done; + } + } else { + DEBUG ((DEBUG_ERROR, "SubClassCode not support for SATA device\n")); + } + } else if (OpalDev->DeviceType == OPAL_DEVICE_TYPE_NVME) { + if (SubClassCode == PCI_CLASS_MASS_STORAGE_NVM) { + if (ProgInt != PCI_IF_NVMHCI) { + DEBUG ((DEBUG_ERROR, "PI not support, skipped\n")); + Status = EFI_NOT_FOUND; + goto done; + } + + mNvmeContext.PciBase = PCI_LIB_ADDRESS (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum, 0x0); + mNvmeContext.NvmeInitWaitTime = 0; + mNvmeContext.Nsid = OpalDev->NvmeNamespaceId; + Status = NvmeControllerInit (&mNvmeContext); + } else { + DEBUG ((DEBUG_ERROR, "SubClassCode not support for NVME device\n")); + } + } else { + DEBUG ((DEBUG_ERROR, "Invalid Devicetype\n")); + goto done; + } + + Status = EFI_DEVICE_ERROR; + BlockSidSupport = FALSE; + if (IsOpalDeviceLocked (OpalDev, &BlockSidSupport)) { + ZeroMem(&Session, sizeof(Session)); + Session.Sscp = &OpalDev->Sscp; + Session.MediaId = 0; + Session.OpalBaseComId = OpalDev->OpalBaseComId; + + Result = OpalSupportUnlock (&Session, OpalDev->Password, OpalDev->PasswordLength, NULL); + if (Result == TcgResultSuccess) { + Status = EFI_SUCCESS; + } + } + + if (mSendBlockSID && BlockSidSupport) { + Result = OpalBlockSid (&Session, TRUE); + if (Result != TcgResultSuccess) { + break; + } + } + + if (OpalDev->DeviceType == OPAL_DEVICE_TYPE_NVME) { + if (SubClassCode == PCI_CLASS_MASS_STORAGE_NVM) { + Status = NvmeControllerExit (&mNvmeContext); + } + } + +done: + if (OpalDev->DeviceType == OPAL_DEVICE_TYPE_NVME) { + ASSERT (RpBase != 0); + PciWrite8 (RpBase + NVME_PCIE_PCICMD, 0); + RpBase = SaveRestoreRootportConfSpace ( + OpalDev, + FALSE, // restore + StorePcieConfDataList + ); + PciWrite8 (RpBase + NVME_PCIE_PCICMD, SataCmdSt); + } else { + PciWrite8 (PCI_LIB_ADDRESS (OpalDev->BusNum, OpalDev->DevNum, OpalDev->FuncNum, NVME_PCIE_PCICMD), SataCmdSt); + } + + if (EFI_ERROR (Status)) { + break; + } + } + + return Status; +} + +/** + The function extracts device information from OpalDeviceList and creat SmmDeviceList used for S3. + + @param[in] OpalDeviceList Opal device list created at POST which contains the information of OPAL_DISK_AND_PASSWORD_INFO + @param[in,out] SmmDeviceList Opal Smm device list to be created and used for unlocking devices at S3 resume. + + @retval EFI_SUCCESS Create SmmDeviceList successfully. + @retval Others Other execution results. +**/ +EFI_STATUS +CreateSmmDeviceList ( + IN LIST_ENTRY *OpalDeviceList, + IN OUT LIST_ENTRY *SmmDeviceList + ) +{ + LIST_ENTRY *Entry; + OPAL_DISK_AND_PASSWORD_INFO *PciDev; + OPAL_SMM_DEVICE *SmmDev; + + for (Entry = OpalDeviceList->ForwardLink; Entry != OpalDeviceList; Entry = Entry->ForwardLink) { + PciDev = BASE_CR (Entry, OPAL_DISK_AND_PASSWORD_INFO, Link); + + SmmDev = AllocateZeroPool (sizeof (OPAL_SMM_DEVICE)); + if (SmmDev == NULL) { + return EFI_OUT_OF_RESOURCES; + } + SmmDev->Signature = OPAL_SMM_DEVICE_SIGNATURE; + + ExtractDeviceInfoFromDevicePath(&PciDev->OpalDevicePath, SmmDev); + + SmmDev->PasswordLength = PciDev->PasswordLength; + CopyMem(&(SmmDev->Password), PciDev->Password, OPAL_PASSWORD_MAX_LENGTH); + + SmmDev->Sscp.ReceiveData = SecurityReceiveData; + SmmDev->Sscp.SendData = SecuritySendData; + + DEBUG ((DEBUG_INFO, "Opal SMM: Insert device node to SmmDeviceList:\n")); + DEBUG ((DEBUG_INFO, "DeviceType:%x, Bus:%d, Dev:%d, Fun:%d\n", \ + SmmDev->DeviceType, SmmDev->BusNum, SmmDev->DevNum, SmmDev->FuncNum)); + DEBUG ((DEBUG_INFO, "SataPort:%x, MultiplierPort:%x, NvmeNamespaceId:%x\n", \ + SmmDev->SataPort, SmmDev->SataPortMultiplierPort, SmmDev->NvmeNamespaceId)); + + InsertHeadList (SmmDeviceList, &SmmDev->Link); + } + + return EFI_SUCCESS; +} + +/** + Main entry point for an SMM handler dispatch or communicate-based callback. + + @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister(). + @param[in] Context Points to an optional handler context which was specified when the + handler was registered. + @param[in,out] CommBuffer A pointer to a collection of Data in memory that will + be conveyed from a non-SMM environment into an SMM environment. + @param[in,out] CommBufferSize The Size of the CommBuffer. + + @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers + should still be called. + @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has been quiesced but other handlers should + still be called. + @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other handlers should still + be called. + @retval EFI_INTERRUPT_PENDING The interrupt could not be quiesced. +**/ +EFI_STATUS +EFIAPI +S3SleepEntryCallBack ( + IN EFI_HANDLE DispatchHandle, + IN CONST VOID *Context OPTIONAL, + IN OUT VOID *CommBuffer OPTIONAL, + IN OUT UINTN *CommBufferSize OPTIONAL + ) +{ + UINTN Bus; + UINTN Device; + UINTN Function; + UINTN Index; + EFI_STATUS Status; + LIST_ENTRY *Entry; + UINTN Offset; + UINT64 Address; + S3_BOOT_SCRIPT_LIB_WIDTH Width; + UINT32 Data; + OPAL_HC_PCI_REGISTER_SAVE *HcRegisterSaveListPtr; + UINTN Count; + OPAL_SMM_DEVICE *SmmDev; + + Data = 0; + Status = EFI_SUCCESS; + + mOpalDeviceList = OpalSupportGetOpalDeviceList(); + if (IsListEmpty (mOpalDeviceList)) { + // + // No Opal enabled device. Do nothing. + // + return EFI_SUCCESS; + } + + if (IsListEmpty (&mSmmDeviceList)) { + // + // mSmmDeviceList for S3 is empty, creat it by mOpalDeviceList. + // + Status = CreateSmmDeviceList (mOpalDeviceList, &mSmmDeviceList); + if (EFI_ERROR (Status)) { + return Status; + } + } + + // + // Go through SmmDeviceList to save register data for S3 + // + for (Entry = mSmmDeviceList.ForwardLink; Entry != &mSmmDeviceList; Entry = Entry->ForwardLink) { + SmmDev = BASE_CR (Entry, OPAL_SMM_DEVICE, Link); + + if (SmmDev->DeviceType == OPAL_DEVICE_TYPE_NVME) { + continue; + } + + // + // Save register Data for S3. Sata controller only. + // + Bus = SmmDev->BusNum; + Device = SmmDev->DevNum; + Function = SmmDev->FuncNum; + + ASSERT (SmmDev->DeviceType == OPAL_DEVICE_TYPE_SATA); + HcRegisterSaveListPtr = (OPAL_HC_PCI_REGISTER_SAVE *) mSataHcRegisterSaveTemplate; + Count = sizeof (mSataHcRegisterSaveTemplate) / sizeof (OPAL_HC_PCI_REGISTER_SAVE); + + for (Index = 0; Index < Count; Index += 1) { + Offset = HcRegisterSaveListPtr[Index].Address; + Width = HcRegisterSaveListPtr[Index].Width; + + switch (Width) { + case S3BootScriptWidthUint8: + Data = (UINT32)PciRead8 (PCI_LIB_ADDRESS(Bus,Device,Function,Offset)); + break; + case S3BootScriptWidthUint16: + Data = (UINT32)PciRead16 (PCI_LIB_ADDRESS(Bus,Device,Function,Offset)); + break; + case S3BootScriptWidthUint32: + Data = PciRead32 (PCI_LIB_ADDRESS(Bus,Device,Function,Offset)); + break; + default: + ASSERT (FALSE); + break; + } + + Address = S3_BOOT_SCRIPT_LIB_PCI_ADDRESS (Bus, Device, Function, Offset); + Status = S3BootScriptSavePciCfgWrite (Width, Address, 1, &Data); + if (EFI_ERROR (Status)) { + return Status; + } + } + } + + Status = S3BootScriptSaveIoWrite (S3BootScriptWidthUint8, 0xB2, 1, &mSwSmiValue); + ASSERT_EFI_ERROR (Status); + + return Status; +} + +/** + OpalPassword Notification for SMM EndOfDxe protocol. + + @param[in] Protocol Points to the protocol's unique identifier. + @param[in] Interface Points to the interface instance. + @param[in] Handle The handle on which the interface was installed. + + @retval EFI_SUCCESS Notification runs successfully. +**/ +EFI_STATUS +EFIAPI +OpalPasswordEndOfDxeNotification ( + IN CONST EFI_GUID *Protocol, + IN VOID *Interface, + IN EFI_HANDLE Handle + ) +{ + UINTN NumberOfDescriptors; + EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemSpaceMap; + EFI_STATUS Status; + + Status = gDS->GetMemorySpaceMap (&NumberOfDescriptors, &MemSpaceMap); + if (EFI_ERROR (Status)) { + return Status; + } + + mGcdMemSpace = AllocateCopyPool (NumberOfDescriptors * sizeof (EFI_GCD_MEMORY_SPACE_DESCRIPTOR), MemSpaceMap); + if (EFI_ERROR (Status)) { + gBS->FreePool (MemSpaceMap); + return Status; + } + + mNumberOfDescriptors = NumberOfDescriptors; + gBS->FreePool (MemSpaceMap); + + return EFI_SUCCESS; +} + +/** + Main entry for this driver. + + @param ImageHandle Image handle this driver. + @param SystemTable Pointer to SystemTable. + + @retval EFI_SUCESS This function always complete successfully. + +**/ +EFI_STATUS +EFIAPI +OpalPasswordSmmInit ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_SMM_SW_DISPATCH2_PROTOCOL *SwDispatch; + EFI_SMM_SX_DISPATCH2_PROTOCOL *SxDispatch; + EFI_HANDLE SwHandle; + EFI_SMM_SW_REGISTER_CONTEXT Context; + EFI_HANDLE S3SleepEntryHandle; + EFI_SMM_SX_REGISTER_CONTEXT EntryRegisterContext; + EFI_SMM_VARIABLE_PROTOCOL *SmmVariable; + OPAL_EXTRA_INFO_VAR OpalExtraInfo; + UINTN DataSize; + EFI_EVENT EndOfDxeEvent; + EFI_PHYSICAL_ADDRESS Address; + + mBuffer = NULL; + SwHandle = NULL; + S3SleepEntryHandle = NULL; + ZeroMem (&mNvmeContext, sizeof (NVME_CONTEXT)); + + Status = gSmst->SmmLocateProtocol ( + &gEfiSmmSwDispatch2ProtocolGuid, + NULL, + (VOID **)&SwDispatch + ); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + DEBUG((DEBUG_ERROR, " SmmLocateProtocol gEfiSmmSwDispatch2ProtocolGuid fail, Status: %r\n", Status)); + return Status; + } + + Status = gSmst->SmmLocateProtocol ( + &gEfiSmmSxDispatch2ProtocolGuid, + NULL, + (VOID **)&SxDispatch + ); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + DEBUG((DEBUG_ERROR, " SmmLocateProtocol gEfiSmmSxDispatch2ProtocolGuid fail, Status: %r\n", Status)); + return Status; + } + + // + // Preallocate a 512 bytes Buffer to perform trusted I/O. + // Assume this is big enough for unlock commands + // It's because DMA can not access smmram stack at the cmd execution. + // + Address = 0xFFFFFFFF; + Status = gBS->AllocatePages ( + AllocateMaxAddress, + EfiACPIMemoryNVS, + EFI_SIZE_TO_PAGES (SMM_SIZE_ALLOC_BYTES), + &Address + ); + if (EFI_ERROR (Status)) { + DEBUG((DEBUG_ERROR, " AllocatePages for SATA DAM fail, Status: %r\n", Status)); + return EFI_OUT_OF_RESOURCES; + } + + mBuffer = (VOID *)(UINTN)Address; + ZeroMem ((VOID *)(UINTN)mBuffer, SMM_SIZE_ALLOC_BYTES); + + // + // Preallocate resource for AHCI transfer descriptor. + // + Status = AhciAllocateResource (); + if (EFI_ERROR (Status)) { + DEBUG((DEBUG_ERROR, " AhciAllocateResource fail, Status: %r\n", Status)); + Status = EFI_OUT_OF_RESOURCES; + goto EXIT; + } + + // + // Preallocate resource for NVMe configuration space. + // + Status = NvmeAllocateResource (ImageHandle, &mNvmeContext); + if (EFI_ERROR (Status)) { + DEBUG((DEBUG_ERROR, " NvmeAllocateResource fail, Status: %r\n", Status)); + Status = EFI_OUT_OF_RESOURCES; + goto EXIT; + } + + // + // Register a S3 entry callback function to store ATA host controller context to boot script. + // These boot scripts would be invoked at S3 path to recovery ATA host controller h/w context + // for executing HDD unlock cmd. + // + EntryRegisterContext.Type = SxS3; + EntryRegisterContext.Phase = SxEntry; + Status = SxDispatch->Register ( + SxDispatch, + S3SleepEntryCallBack, + &EntryRegisterContext, + &S3SleepEntryHandle + ); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + goto EXIT; + } + + // + // Register Opal password smm unlock handler + // + Context.SwSmiInputValue = (UINTN) -1; + Status = SwDispatch->Register ( + SwDispatch, + SmmUnlockOpalPassword, + &Context, + &SwHandle + ); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + DEBUG((DEBUG_ERROR, " SwDispatch->Register fail, Status: %r\n", Status)); + goto EXIT; + } + + // + // trigger smi to unlock hdd if it's locked. + // + mSwSmiValue = (UINT8) Context.SwSmiInputValue; + + // + // Create event to record GCD descriptors at end of dxe for judging AHCI/NVMe PCI Bar + // is in MMIO space to avoid attack. + // + Status = gSmst->SmmRegisterProtocolNotify (&gEfiSmmEndOfDxeProtocolGuid, OpalPasswordEndOfDxeNotification, &EndOfDxeEvent); + if (EFI_ERROR (Status)) { + DEBUG((DEBUG_ERROR, "OpalPasswordSmm: Register SmmEndOfDxe fail, Status: %r\n", Status)); + goto EXIT; + } + Status = gSmst->SmmLocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID**)&SmmVariable); + if (!EFI_ERROR (Status)) { + DataSize = sizeof (OPAL_EXTRA_INFO_VAR); + Status = SmmVariable->SmmGetVariable ( + OPAL_EXTRA_INFO_VAR_NAME, + &gOpalExtraInfoVariableGuid, + NULL, + &DataSize, + &OpalExtraInfo + ); + if (!EFI_ERROR (Status)) { + mSendBlockSID = OpalExtraInfo.EnableBlockSid; + } + } + + return EFI_SUCCESS; + +EXIT: + if (S3SleepEntryHandle != NULL) { + SxDispatch->UnRegister (SxDispatch, S3SleepEntryHandle); + } + + AhciFreeResource (); + + NvmeFreeResource (&mNvmeContext); + + if (mBuffer != NULL) { + gBS->FreePages ((EFI_PHYSICAL_ADDRESS)(UINTN) mBuffer, EFI_SIZE_TO_PAGES (SMM_SIZE_ALLOC_BYTES)); + } + + return Status; +} + +/** + Provide Io action support. + + @param[in] SmmDev the opal device need to perform trust io. + @param[in] IoType OPAL_IO_TYPE indicating whether to perform a Trusted Send or Trusted Receive. + @param[in] SecurityProtocol Security Protocol + @param[in] SpSpecific Security Protocol Specific + @param[in] TransferLength Transfer Length of Buffer (in bytes) - always a multiple of 512 + @param[in] Buffer Address of Data to transfer + + @retval TcgResultSuccess Perform the io action success. + @retval TcgResultFailure Perform the io action failed. + +**/ +EFI_STATUS +PerformTrustedIo ( + OPAL_SMM_DEVICE *SmmDev, + OPAL_IO_TYPE IoType, + UINT8 SecurityProtocol, + UINT16 SpSpecific, + UINTN TransferLength, + VOID *Buffer + ) +{ + EFI_STATUS Status; + UINTN BufferSizeBlocks; + EFI_ATA_COMMAND_BLOCK AtaCommandBlock; + + Status = EFI_DEVICE_ERROR; + if (SmmDev->DeviceType == OPAL_DEVICE_TYPE_SATA) { + BufferSizeBlocks = TransferLength / 512; + + ZeroMem( &AtaCommandBlock, sizeof( EFI_ATA_COMMAND_BLOCK ) ); + AtaCommandBlock.AtaCommand = ( IoType == OpalSend ) ? ATA_COMMAND_TRUSTED_SEND : ATA_COMMAND_TRUSTED_RECEIVE; + AtaCommandBlock.AtaSectorCount = ( UINT8 )BufferSizeBlocks; + AtaCommandBlock.AtaSectorNumber = ( UINT8 )( BufferSizeBlocks >> 8 ); + AtaCommandBlock.AtaFeatures = SecurityProtocol; + AtaCommandBlock.AtaCylinderLow = ( UINT8 )( SpSpecific >> 8 ); + AtaCommandBlock.AtaCylinderHigh = ( UINT8 )( SpSpecific ); + AtaCommandBlock.AtaDeviceHead = ATA_DEVICE_LBA; + + + ZeroMem( mBuffer, HDD_PAYLOAD ); + ASSERT( TransferLength <= HDD_PAYLOAD ); + + if (IoType == OpalSend) { + CopyMem( mBuffer, Buffer, TransferLength ); + } + + Status = AhciPioTransfer( + &mAhciRegisters, + (UINT8) SmmDev->SataPort, + (UINT8) SmmDev->SataPortMultiplierPort, + NULL, + 0, + ( IoType == OpalSend ) ? FALSE : TRUE, // i/o direction + &AtaCommandBlock, + NULL, + mBuffer, + (UINT32)TransferLength, + ATA_TIMEOUT + ); + + if (IoType == OpalRecv) { + CopyMem( Buffer, mBuffer, TransferLength ); + } + } else if (SmmDev->DeviceType == OPAL_DEVICE_TYPE_NVME) { + Status = NvmeSecuritySendReceive ( + &mNvmeContext, + IoType == OpalSend, + SecurityProtocol, + SwapBytes16(SpSpecific), + TransferLength, + Buffer + ); + } else { + DEBUG((DEBUG_ERROR, "DeviceType(%x) not support.\n", SmmDev->DeviceType)); + } + + return Status; +} + +/** + Send a security protocol command to a device that receives data and/or the result + of one or more commands sent by SendData. + + The ReceiveData function sends a security protocol command to the given MediaId. + The security protocol command sent is defined by SecurityProtocolId and contains + the security protocol specific data SecurityProtocolSpecificData. The function + returns the data from the security protocol command in PayloadBuffer. + + For devices supporting the SCSI command set, the security protocol command is sent + using the SECURITY PROTOCOL IN command defined in SPC-4. + + For devices supporting the ATA command set, the security protocol command is sent + using one of the TRUSTED RECEIVE commands defined in ATA8-ACS if PayloadBufferSize + is non-zero. + + If the PayloadBufferSize is zero, the security protocol command is sent using the + Trusted Non-Data command defined in ATA8-ACS. + + If PayloadBufferSize is too small to store the available data from the security + protocol command, the function shall copy PayloadBufferSize bytes into the + PayloadBuffer and return EFI_WARN_BUFFER_TOO_SMALL. + + If PayloadBuffer or PayloadTransferSize is NULL and PayloadBufferSize is non-zero, + the function shall return EFI_INVALID_PARAMETER. + + If the given MediaId does not support security protocol commands, the function shall + return EFI_UNSUPPORTED. If there is no media in the device, the function returns + EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the device, + the function returns EFI_MEDIA_CHANGED. + + If the security protocol fails to complete within the Timeout period, the function + shall return EFI_TIMEOUT. + + If the security protocol command completes without an error, the function shall + return EFI_SUCCESS. If the security protocol command completes with an error, the + function shall return EFI_DEVICE_ERROR. + + @param This Indicates a pointer to the calling context. + @param MediaId ID of the medium to receive data from. + @param Timeout The timeout, in 100ns units, to use for the execution + of the security protocol command. A Timeout value of 0 + means that this function will wait indefinitely for the + security protocol command to execute. If Timeout is greater + than zero, then this function will return EFI_TIMEOUT + if the time required to execute the receive data command + is greater than Timeout. + @param SecurityProtocolId The value of the "Security Protocol" parameter of + the security protocol command to be sent. + @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter + of the security protocol command to be sent. + @param PayloadBufferSize Size in bytes of the payload data buffer. + @param PayloadBuffer A pointer to a destination buffer to store the security + protocol command specific payload data for the security + protocol command. The caller is responsible for having + either implicit or explicit ownership of the buffer. + @param PayloadTransferSize A pointer to a buffer to store the size in bytes of the + data written to the payload data buffer. + + @retval EFI_SUCCESS The security protocol command completed successfully. + @retval EFI_WARN_BUFFER_TOO_SMALL The PayloadBufferSize was too small to store the available + data from the device. The PayloadBuffer contains the truncated data. + @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands. + @retval EFI_DEVICE_ERROR The security protocol command completed with an error. + @retval EFI_NO_MEDIA There is no media in the device. + @retval EFI_MEDIA_CHANGED The MediaId is not for the current media. + @retval EFI_INVALID_PARAMETER The PayloadBuffer or PayloadTransferSize is NULL and + PayloadBufferSize is non-zero. + @retval EFI_TIMEOUT A timeout occurred while waiting for the security + protocol command to execute. + +**/ +EFI_STATUS +EFIAPI +SecurityReceiveData ( + IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This, + IN UINT32 MediaId, + IN UINT64 Timeout, + IN UINT8 SecurityProtocolId, + IN UINT16 SecurityProtocolSpecificData, + IN UINTN PayloadBufferSize, + OUT VOID *PayloadBuffer, + OUT UINTN *PayloadTransferSize + ) +{ + OPAL_SMM_DEVICE *SmmDev; + + SmmDev = OPAL_SMM_DEVICE_FROM_THIS (This); + if (SmmDev == NULL) { + return EFI_DEVICE_ERROR; + } + + return PerformTrustedIo ( + SmmDev, + OpalRecv, + SecurityProtocolId, + SecurityProtocolSpecificData, + PayloadBufferSize, + PayloadBuffer + ); +} + +/** + Send a security protocol command to a device. + + The SendData function sends a security protocol command containing the payload + PayloadBuffer to the given MediaId. The security protocol command sent is + defined by SecurityProtocolId and contains the security protocol specific data + SecurityProtocolSpecificData. If the underlying protocol command requires a + specific padding for the command payload, the SendData function shall add padding + bytes to the command payload to satisfy the padding requirements. + + For devices supporting the SCSI command set, the security protocol command is sent + using the SECURITY PROTOCOL OUT command defined in SPC-4. + + For devices supporting the ATA command set, the security protocol command is sent + using one of the TRUSTED SEND commands defined in ATA8-ACS if PayloadBufferSize + is non-zero. If the PayloadBufferSize is zero, the security protocol command is + sent using the Trusted Non-Data command defined in ATA8-ACS. + + If PayloadBuffer is NULL and PayloadBufferSize is non-zero, the function shall + return EFI_INVALID_PARAMETER. + + If the given MediaId does not support security protocol commands, the function + shall return EFI_UNSUPPORTED. If there is no media in the device, the function + returns EFI_NO_MEDIA. If the MediaId is not the ID for the current media in the + device, the function returns EFI_MEDIA_CHANGED. + + If the security protocol fails to complete within the Timeout period, the function + shall return EFI_TIMEOUT. + + If the security protocol command completes without an error, the function shall return + EFI_SUCCESS. If the security protocol command completes with an error, the function + shall return EFI_DEVICE_ERROR. + + @param This Indicates a pointer to the calling context. + @param MediaId ID of the medium to receive data from. + @param Timeout The timeout, in 100ns units, to use for the execution + of the security protocol command. A Timeout value of 0 + means that this function will wait indefinitely for the + security protocol command to execute. If Timeout is greater + than zero, then this function will return EFI_TIMEOUT + if the time required to execute the send data command + is greater than Timeout. + @param SecurityProtocolId The value of the "Security Protocol" parameter of + the security protocol command to be sent. + @param SecurityProtocolSpecificData The value of the "Security Protocol Specific" parameter + of the security protocol command to be sent. + @param PayloadBufferSize Size in bytes of the payload data buffer. + @param PayloadBuffer A pointer to a destination buffer to store the security + protocol command specific payload data for the security + protocol command. + + @retval EFI_SUCCESS The security protocol command completed successfully. + @retval EFI_UNSUPPORTED The given MediaId does not support security protocol commands. + @retval EFI_DEVICE_ERROR The security protocol command completed with an error. + @retval EFI_NO_MEDIA There is no media in the device. + @retval EFI_MEDIA_CHANGED The MediaId is not for the current media. + @retval EFI_INVALID_PARAMETER The PayloadBuffer is NULL and PayloadBufferSize is non-zero. + @retval EFI_TIMEOUT A timeout occurred while waiting for the security + protocol command to execute. + +**/ +EFI_STATUS +EFIAPI +SecuritySendData ( + IN EFI_STORAGE_SECURITY_COMMAND_PROTOCOL *This, + IN UINT32 MediaId, + IN UINT64 Timeout, + IN UINT8 SecurityProtocolId, + IN UINT16 SecurityProtocolSpecificData, + IN UINTN PayloadBufferSize, + IN VOID *PayloadBuffer + ) +{ + OPAL_SMM_DEVICE *SmmDev; + + SmmDev = OPAL_SMM_DEVICE_FROM_THIS (This); + if (SmmDev == NULL) { + return EFI_DEVICE_ERROR; + } + + return PerformTrustedIo ( + SmmDev, + OpalSend, + SecurityProtocolId, + SecurityProtocolSpecificData, + PayloadBufferSize, + PayloadBuffer + ); + +} + diff --git a/Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalPasswordSmm.h b/Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalPasswordSmm.h new file mode 100644 index 0000000000..ab31a6bfe7 --- /dev/null +++ b/Core/SecurityPkg/Tcg/Opal/OpalPasswordSmm/OpalPasswordSmm.h @@ -0,0 +1,300 @@ +/** @file + Opal password smm driver which is used to support Opal security feature at s3 path. + +Copyright (c) 2016, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#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.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# 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.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include +#include +#include +#include + +/** + This interface returns whether TPM physical presence needs be locked or not. + + @param[in] PeiServices The pointer to the PEI Services Table. + + @retval TRUE The TPM physical presence should be locked. + @retval FALSE The TPM physical presence cannot be locked. + +**/ +BOOLEAN +EFIAPI +LockTpmPhysicalPresence ( + IN CONST EFI_PEI_SERVICES **PeiServices + ); + +// +// Gobal defintions for lock physical presence PPI and its descriptor. +// +PEI_LOCK_PHYSICAL_PRESENCE_PPI mLockPhysicalPresencePpi = { + LockTpmPhysicalPresence +}; + +EFI_PEI_PPI_DESCRIPTOR mLockPhysicalPresencePpiList = { + EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, + &gPeiLockPhysicalPresencePpiGuid, + &mLockPhysicalPresencePpi +}; + +/** + This interface returns whether TPM physical presence needs be locked or not. + + @param[in] PeiServices The pointer to the PEI Services Table. + + @retval TRUE The TPM physical presence should be locked. + @retval FALSE The TPM physical presence cannot be locked. + +**/ +BOOLEAN +EFIAPI +LockTpmPhysicalPresence ( + IN CONST EFI_PEI_SERVICES **PeiServices + ) +{ + EFI_STATUS Status; + EFI_PEI_READ_ONLY_VARIABLE2_PPI *Variable; + UINTN DataSize; + EFI_PHYSICAL_PRESENCE TcgPpData; + + // + // The CRTM has sensed the physical presence assertion of the user. For example, + // the user has pressed the startup button or inserted a USB dongle. The details + // of the implementation are vendor-specific. Here we read a PCD value to indicate + // whether operator physical presence. + // + if (!PcdGetBool (PcdTpmPhysicalPresence)) { + return TRUE; + } + + // + // Check the pending TPM requests. Lock TPM physical presence if there is no TPM + // request. + // + Status = PeiServicesLocatePpi ( + &gEfiPeiReadOnlyVariable2PpiGuid, + 0, + NULL, + (VOID **)&Variable + ); + if (!EFI_ERROR (Status)) { + DataSize = sizeof (EFI_PHYSICAL_PRESENCE); + Status = Variable->GetVariable ( + Variable, + PHYSICAL_PRESENCE_VARIABLE, + &gEfiPhysicalPresenceGuid, + NULL, + &DataSize, + &TcgPpData + ); + if (!EFI_ERROR (Status)) { + if (TcgPpData.PPRequest != 0) { + return FALSE; + } + } + } + + // + // Lock TPM physical presence by default. + // + return TRUE; +} + +/** + Entry point of this module. + + It installs lock physical presence PPI. + + @param[in] FileHandle Handle of the file being invoked. + @param[in] PeiServices Describes the list of possible PEI Services. + + @return Status of install lock physical presence PPI. + +**/ +EFI_STATUS +EFIAPI +PeimEntry ( + IN EFI_PEI_FILE_HANDLE FileHandle, + IN CONST EFI_PEI_SERVICES **PeiServices + ) +{ + return PeiServicesInstallPpi (&mLockPhysicalPresencePpiList); +} diff --git a/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.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = PhysicalPresencePei + MODULE_UNI_FILE = PhysicalPresencePei.uni + FILE_GUID = 4FE772E8-FE3E-4086-B638-8C493C490488 + MODULE_TYPE = PEIM + VERSION_STRING = 1.0 + + ENTRY_POINT = PeimEntry + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF +# + +[Sources] + PhysicalPresencePei.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + PeimEntryPoint + PeiServicesLib + +[Ppis] + gPeiLockPhysicalPresencePpiGuid ## PRODUCES + gEfiPeiReadOnlyVariable2PpiGuid ## CONSUMES + +[Guids] + gEfiPhysicalPresenceGuid ## SOMETIMES_CONSUMES ## Variable:L"PhysicalPresence" + +[Pcd] + gEfiSecurityPkgTokenSpaceGuid.PcdTpmPhysicalPresence ## SOMETIMES_CONSUMES + +[Depex] + gEfiPeiMemoryDiscoveredPpiGuid AND + gEfiPeiReadOnlyVariable2PpiGuid AND + gPeiTpmInitializedPpiGuid + +[UserExtensions.TianoCore."ExtraFiles"] + PhysicalPresencePeiExtra.uni + \ No newline at end of file diff --git a/Core/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePei.uni b/Core/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePei.uni new file mode 100644 index 0000000000..8f701f6260 --- /dev/null +++ b/Core/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePei.uni @@ -0,0 +1,23 @@ +// /** @file +// Produces a PPI to indicate whether to lock TPM in PEI phase +// +// This module produces PEI_LOCK_PHYSICAL_PRESENCE_PPI to indicate whether +// TPM physical presence needs to be locked. It can be replaced by a +// platform specific module. +// +// Copyright (c) 2005 - 2014, Intel Corporation. All rights reserved.
+// +// This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// **/ + + +#string STR_MODULE_ABSTRACT #language en-US "Produces a PPI to indicate whether to lock TPM in PEI phase" + +#string STR_MODULE_DESCRIPTION #language en-US "This module produces PEI_LOCK_PHYSICAL_PRESENCE_PPI to indicate whether TPM physical presence needs to be locked. It can be replaced by a platform-specific module." + diff --git a/Core/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePeiExtra.uni b/Core/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePeiExtra.uni new file mode 100644 index 0000000000..0fb38dba82 --- /dev/null +++ b/Core/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePeiExtra.uni @@ -0,0 +1,19 @@ +// /** @file +// PhysicalPresencePei Localized Strings and Content +// +// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.
+// +// This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// **/ + +#string STR_PROPERTIES_MODULE_NAME +#language en-US +"Physical Presence PEI" + + diff --git a/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2Config.vfr b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2Config.vfr new file mode 100644 index 0000000000..1d44c99109 --- /dev/null +++ b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2Config.vfr @@ -0,0 +1,250 @@ +/** @file + VFR file used by the TCG2 configuration component. + +Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "Tcg2ConfigNvData.h" + +formset + guid = TCG2_CONFIG_FORM_SET_GUID, + title = STRING_TOKEN(STR_TCG2_TITLE), + help = STRING_TOKEN(STR_TCG2_HELP), + classguid = EFI_HII_PLATFORM_SETUP_FORMSET_GUID, + + efivarstore TCG2_CONFIGURATION_INFO, + varid = TCG2_CONFIGURATION_INFO_VARSTORE_ID, + attribute = 0x02, // EFI variable attribures EFI_VARIABLE_BOOTSERVICE_ACCESS + name = TCG2_CONFIGURATION_INFO, + guid = TCG2_CONFIG_FORM_SET_GUID; + + efivarstore TCG2_CONFIGURATION, + varid = TCG2_CONFIGURATION_VARSTORE_ID, + attribute = 0x03, // EFI variable attribures EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE + name = TCG2_CONFIGURATION, + guid = TCG2_CONFIG_FORM_SET_GUID; + + efivarstore TCG2_VERSION, + varid = TCG2_VERSION_VARSTORE_ID, + attribute = 0x03, // EFI variable attribures EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE + name = TCG2_VERSION, + guid = TCG2_CONFIG_FORM_SET_GUID; + + form formid = TCG2_CONFIGURATION_FORM_ID, + title = STRING_TOKEN(STR_TCG2_TITLE); + + subtitle text = STRING_TOKEN(STR_NULL); + + text + help = STRING_TOKEN(STR_TCG2_DEVICE_STATE_HELP), + text = STRING_TOKEN(STR_TCG2_DEVICE_STATE_PROMPT), + text = STRING_TOKEN(STR_TCG2_DEVICE_STATE_CONTENT); + + oneof varid = TCG2_CONFIGURATION.TpmDevice, + questionid = KEY_TPM_DEVICE, + prompt = STRING_TOKEN(STR_TCG2_DEVICE_PROMPT), + help = STRING_TOKEN(STR_TCG2_DEVICE_HELP), + flags = INTERACTIVE, + option text = STRING_TOKEN(STR_TCG2_TPM_1_2), value = TPM_DEVICE_1_2, flags = DEFAULT | MANUFACTURING | RESET_REQUIRED; + option text = STRING_TOKEN(STR_TCG2_TPM_2_0_DTPM), value = TPM_DEVICE_2_0_DTPM, flags = RESET_REQUIRED; + endoneof; + + suppressif ideqvallist TCG2_CONFIGURATION.TpmDevice == TPM_DEVICE_NULL TPM_DEVICE_1_2; + + subtitle text = STRING_TOKEN(STR_NULL); + + text + help = STRING_TOKEN(STR_TPM2_ACPI_HID_HELP), + text = STRING_TOKEN(STR_TPM2_ACPI_HID_PROMPT), + text = STRING_TOKEN(STR_TPM2_ACPI_HID_CONTENT); + + text + help = STRING_TOKEN(STR_TPM2_ACPI_REVISION_STATE_HELP), + text = STRING_TOKEN(STR_TPM2_ACPI_REVISION_STATE_PROMPT), + text = STRING_TOKEN(STR_TPM2_ACPI_REVISION_STATE_CONTENT); + + oneof varid = TCG2_VERSION.Tpm2AcpiTableRev, + questionid = KEY_TPM2_ACPI_REVISION, + prompt = STRING_TOKEN(STR_TPM2_ACPI_REVISION_PROMPT), + help = STRING_TOKEN(STR_TPM2_ACPI_REVISION_HELP), + flags = INTERACTIVE, + option text = STRING_TOKEN(STR_TPM2_ACPI_REVISION_3), value = TPM2_ACPI_REVISION_3, flags = RESET_REQUIRED; + option text = STRING_TOKEN(STR_TPM2_ACPI_REVISION_4), value = TPM2_ACPI_REVISION_4, flags = DEFAULT | MANUFACTURING | RESET_REQUIRED; + endoneof; + + subtitle text = STRING_TOKEN(STR_NULL); + + text + help = STRING_TOKEN(STR_TCG2_DEVICE_INTERFACE_STATE_HELP), + text = STRING_TOKEN(STR_TCG2_DEVICE_INTERFACE_STATE_PROMPT), + text = STRING_TOKEN(STR_TCG2_DEVICE_INTERFACE_STATE_CONTENT); + + text + help = STRING_TOKEN(STR_TCG2_DEVICE_INTERFACE_CAPABILITY_HELP), + text = STRING_TOKEN(STR_TCG2_DEVICE_INTERFACE_CAPABILITY_PROMPT), + text = STRING_TOKEN(STR_TCG2_DEVICE_INTERFACE_CAPABILITY_CONTENT); + + suppressif ideqval TCG2_CONFIGURATION_INFO.TpmDeviceInterfacePtpFifoSupported == 0 + OR ideqval TCG2_CONFIGURATION_INFO.TpmDeviceInterfacePtpCrbSupported == 0; + oneof varid = TCG2_CONFIGURATION_INFO.TpmDeviceInterfaceAttempt, + questionid = KEY_TPM_DEVICE_INTERFACE, + prompt = STRING_TOKEN(STR_TCG2_DEVICE_INTERFACE_PROMPT), + help = STRING_TOKEN(STR_TCG2_DEVICE_INTERFACE_HELP), + flags = INTERACTIVE, + option text = STRING_TOKEN(STR_TCG2_DEVICE_INTERFACE_TIS), value = TPM_DEVICE_INTERFACE_TIS, flags = RESET_REQUIRED; + option text = STRING_TOKEN(STR_TCG2_DEVICE_INTERFACE_PTP_FIFO), value = TPM_DEVICE_INTERFACE_PTP_FIFO, flags = RESET_REQUIRED; + option text = STRING_TOKEN(STR_TCG2_DEVICE_INTERFACE_PTP_CRB), value = TPM_DEVICE_INTERFACE_PTP_CRB, flags = DEFAULT | MANUFACTURING | RESET_REQUIRED; + endoneof; + endif; + + endif; + + subtitle text = STRING_TOKEN(STR_NULL); + + suppressif ideqvallist TCG2_CONFIGURATION.TpmDevice == TPM_DEVICE_NULL TPM_DEVICE_1_2; + text + help = STRING_TOKEN(STR_TPM2_ACTIVE_HASH_ALGO_HELP), + text = STRING_TOKEN(STR_TPM2_ACTIVE_HASH_ALGO), + text = STRING_TOKEN(STR_TPM2_ACTIVE_HASH_ALGO_CONTENT); + text + help = STRING_TOKEN(STR_TPM2_SUPPORTED_HASH_ALGO_HELP), + text = STRING_TOKEN(STR_TPM2_SUPPORTED_HASH_ALGO), + text = STRING_TOKEN(STR_TPM2_SUPPORTED_HASH_ALGO_CONTENT); + text + help = STRING_TOKEN(STR_BIOS_HASH_ALGO_HELP), + text = STRING_TOKEN(STR_BIOS_HASH_ALGO), + text = STRING_TOKEN(STR_BIOS_HASH_ALGO_CONTENT); + + subtitle text = STRING_TOKEN(STR_NULL); + subtitle text = STRING_TOKEN(STR_TCG2_PP_OPERATION); + + text + help = STRING_TOKEN(STR_TCG2_PPI_VERSION_STATE_HELP), + text = STRING_TOKEN(STR_TCG2_PPI_VERSION_STATE_PROMPT), + text = STRING_TOKEN(STR_TCG2_PPI_VERSION_STATE_CONTENT); + + oneof varid = TCG2_VERSION.PpiVersion, + questionid = KEY_TCG2_PPI_VERSION, + prompt = STRING_TOKEN(STR_TCG2_PPI_VERSION_PROMPT), + help = STRING_TOKEN(STR_TCG2_PPI_VERSION_HELP), + flags = INTERACTIVE, + option text = STRING_TOKEN(STR_TCG2_PPI_VERSION_1_2), value = TCG2_PPI_VERSION_1_2, flags = RESET_REQUIRED; + option text = STRING_TOKEN(STR_TCG2_PPI_VERSION_1_3), value = TCG2_PPI_VERSION_1_3, flags = DEFAULT | MANUFACTURING | RESET_REQUIRED; + endoneof; + + oneof name = Tpm2Operation, + questionid = KEY_TPM2_OPERATION, + prompt = STRING_TOKEN(STR_TCG2_OPERATION), + help = STRING_TOKEN(STR_TCG2_OPERATION_HELP), + flags = INTERACTIVE | NUMERIC_SIZE_1, + option text = STRING_TOKEN(STR_TCG2_NO_ACTION), value = TCG2_PHYSICAL_PRESENCE_NO_ACTION, flags = DEFAULT | MANUFACTURING | RESET_REQUIRED; + option text = STRING_TOKEN(STR_TCG2_ENABLE), value = TCG2_PHYSICAL_PRESENCE_ENABLE, flags = RESET_REQUIRED; + option text = STRING_TOKEN(STR_TCG2_DISABLE), value = TCG2_PHYSICAL_PRESENCE_DISABLE, flags = RESET_REQUIRED; + option text = STRING_TOKEN(STR_TCG2_CLEAR), value = TCG2_PHYSICAL_PRESENCE_CLEAR, flags = RESET_REQUIRED; + option text = STRING_TOKEN(STR_TCG2_SET_PCD_BANKS), value = TCG2_PHYSICAL_PRESENCE_SET_PCR_BANKS, flags = RESET_REQUIRED; + option text = STRING_TOKEN(STR_TCG2_CHANGE_EPS), value = TCG2_PHYSICAL_PRESENCE_CHANGE_EPS, flags = RESET_REQUIRED; + option text = STRING_TOKEN(STR_TCG2_LOG_ALL_DIGESTS), value = TCG2_PHYSICAL_PRESENCE_LOG_ALL_DIGESTS, flags = RESET_REQUIRED; + option text = STRING_TOKEN(STR_TCG2_DISABLE_ENDORSEMENT_ENABLE_STORAGE_HIERARCHY), value = TCG2_PHYSICAL_PRESENCE_DISABLE_ENDORSEMENT_ENABLE_STORAGE_HIERARCHY, flags = RESET_REQUIRED; + endoneof; + + suppressif NOT questionref(Tpm2Operation) == TCG2_PHYSICAL_PRESENCE_SET_PCR_BANKS; + numeric name = Tpm2OperationParameter, + questionid = KEY_TPM2_OPERATION_PARAMETER, + prompt = STRING_TOKEN(STR_TCG2_OPERATION_PARAMETER), + help = STRING_TOKEN(STR_TCG2_OPERATION_PARAMETER_HELP), + flags = DISPLAY_UINT_HEX | INTERACTIVE | NUMERIC_SIZE_4, + minimum = 0, + maximum = 0xFFFFFFFF, + step = 0, + default = 0, + endnumeric; + endif; + + subtitle text = STRING_TOKEN(STR_NULL); + subtitle text = STRING_TOKEN(STR_TCG2_CONFIGURATION); + + text + help = STRING_TOKEN(STR_TCG2_SUPPORTED_EVENT_LOG_FORMAT_HELP), + text = STRING_TOKEN(STR_TCG2_SUPPORTED_EVENT_LOG_FORMAT), + text = STRING_TOKEN(STR_TCG2_SUPPORTED_EVENT_LOG_FORMAT_CONTENT); + + text + help = STRING_TOKEN(STR_TCG2_HASH_ALGO_BITMAP_HELP), + text = STRING_TOKEN(STR_TCG2_HASH_ALGO_BITMAP), + text = STRING_TOKEN(STR_TCG2_HASH_ALGO_BITMAP_CONTENT); + + text + help = STRING_TOKEN(STR_TCG2_NUMBER_OF_PCR_BANKS_HELP), + text = STRING_TOKEN(STR_TCG2_NUMBER_OF_PCR_BANKS), + text = STRING_TOKEN(STR_TCG2_NUMBER_OF_PCR_BANKS_CONTENT); + + text + help = STRING_TOKEN(STR_TCG2_ACTIVE_PCR_BANKS_HELP), + text = STRING_TOKEN(STR_TCG2_ACTIVE_PCR_BANKS), + text = STRING_TOKEN(STR_TCG2_ACTIVE_PCR_BANKS_CONTENT); + + subtitle text = STRING_TOKEN(STR_NULL); + + suppressif ideqval TCG2_CONFIGURATION_INFO.Sha1Supported == 0; + checkbox name = TCG2ActivatePCRBank0, + questionid = KEY_TPM2_PCR_BANKS_REQUEST_0, + prompt = STRING_TOKEN(STR_TCG2_PCR_BANK_SHA1), + help = STRING_TOKEN(STR_TCG2_PCR_BANK_SHA1_HELP), + flags = INTERACTIVE | RESET_REQUIRED, + default = 1, + endcheckbox; + endif; + + suppressif ideqval TCG2_CONFIGURATION_INFO.Sha256Supported == 0; + checkbox name = TCG2ActivatePCRBank1, + questionid = KEY_TPM2_PCR_BANKS_REQUEST_1, + prompt = STRING_TOKEN(STR_TCG2_PCR_BANK_SHA256), + help = STRING_TOKEN(STR_TCG2_PCR_BANK_SHA256_HELP), + flags = INTERACTIVE | RESET_REQUIRED, + default = 0, + endcheckbox; + endif; + + suppressif ideqval TCG2_CONFIGURATION_INFO.Sha384Supported == 0; + checkbox name = TCG2ActivatePCRBank2, + questionid = KEY_TPM2_PCR_BANKS_REQUEST_2, + prompt = STRING_TOKEN(STR_TCG2_PCR_BANK_SHA384), + help = STRING_TOKEN(STR_TCG2_PCR_BANK_SHA384_HELP), + flags = INTERACTIVE | RESET_REQUIRED, + default = 0, + endcheckbox; + endif; + + suppressif ideqval TCG2_CONFIGURATION_INFO.Sha512Supported == 0; + checkbox name = TCG2ActivatePCRBank3, + questionid = KEY_TPM2_PCR_BANKS_REQUEST_3, + prompt = STRING_TOKEN(STR_TCG2_PCR_BANK_SHA512), + help = STRING_TOKEN(STR_TCG2_PCR_BANK_SHA512_HELP), + flags = INTERACTIVE | RESET_REQUIRED, + default = 0, + endcheckbox; + endif; + + suppressif ideqval TCG2_CONFIGURATION_INFO.Sm3Supported == 0; + checkbox name = TCG2ActivatePCRBank4, + questionid = KEY_TPM2_PCR_BANKS_REQUEST_4, + prompt = STRING_TOKEN(STR_TCG2_PCR_BANK_SM3_256), + help = STRING_TOKEN(STR_TCG2_PCR_BANK_SM3_256_HELP), + flags = INTERACTIVE | RESET_REQUIRED, + default = 0, + endcheckbox; + endif; + + endif; + + endform; + +endformset; diff --git a/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDriver.c b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDriver.c new file mode 100644 index 0000000000..9c590dcb74 --- /dev/null +++ b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDriver.c @@ -0,0 +1,461 @@ +/** @file + The module entry point for Tcg2 configuration module. + +Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "Tcg2ConfigImpl.h" + +extern TPM_INSTANCE_ID mTpmInstanceId[TPM_DEVICE_MAX + 1]; + +/** + Update default PCR banks data. + + @param[in] HiiPackage HII Package. + @param[in] HiiPackageSize HII Package size. + @param[in] PCRBanks PCR Banks data. + +**/ +VOID +UpdateDefaultPCRBanks ( + IN VOID *HiiPackage, + IN UINTN HiiPackageSize, + IN UINT32 PCRBanks + ) +{ + EFI_HII_PACKAGE_HEADER *HiiPackageHeader; + EFI_IFR_OP_HEADER *IfrOpCodeHeader; + EFI_IFR_CHECKBOX *IfrCheckBox; + EFI_IFR_DEFAULT *IfrDefault; + + HiiPackageHeader = (EFI_HII_PACKAGE_HEADER *)HiiPackage; + + switch (HiiPackageHeader->Type) { + case EFI_HII_PACKAGE_FORMS: + IfrOpCodeHeader = (EFI_IFR_OP_HEADER *)(HiiPackageHeader + 1); + while ((UINTN)IfrOpCodeHeader < (UINTN)HiiPackageHeader + HiiPackageHeader->Length) { + switch (IfrOpCodeHeader->OpCode) { + case EFI_IFR_CHECKBOX_OP: + IfrCheckBox = (EFI_IFR_CHECKBOX *)IfrOpCodeHeader; + if ((IfrCheckBox->Question.QuestionId >= KEY_TPM2_PCR_BANKS_REQUEST_0) && (IfrCheckBox->Question.QuestionId <= KEY_TPM2_PCR_BANKS_REQUEST_4)) { + IfrDefault = (EFI_IFR_DEFAULT *)(IfrCheckBox + 1); + ASSERT (IfrDefault->Header.OpCode == EFI_IFR_DEFAULT_OP); + ASSERT (IfrDefault->Type == EFI_IFR_TYPE_BOOLEAN); + IfrDefault->Value.b = (BOOLEAN)((PCRBanks >> (IfrCheckBox->Question.QuestionId - KEY_TPM2_PCR_BANKS_REQUEST_0)) & 0x1); + } + break; + } + IfrOpCodeHeader = (EFI_IFR_OP_HEADER *)((UINTN)IfrOpCodeHeader + IfrOpCodeHeader->Length); + } + break; + } + return ; +} + +/** + Initialize TCG2 version information. + + This function will initialize efi varstore configuration data for + TCG2_VERSION_NAME variable, check the value of related PCD with + the variable value and set string for the version state content + according to the PCD value. + + @param[in] PrivateData Points to TCG2 configuration private data. + +**/ +VOID +InitializeTcg2VersionInfo ( + IN TCG2_CONFIG_PRIVATE_DATA *PrivateData + ) +{ + EFI_STATUS Status; + EFI_STRING ConfigRequestHdr; + BOOLEAN ActionFlag; + TCG2_VERSION Tcg2Version; + UINTN DataSize; + UINT64 PcdTcg2PpiVersion; + UINT8 PcdTpm2AcpiTableRev; + + // + // Get the PCD value before initializing efi varstore configuration data. + // + PcdTcg2PpiVersion = 0; + CopyMem ( + &PcdTcg2PpiVersion, + PcdGetPtr (PcdTcgPhysicalPresenceInterfaceVer), + AsciiStrSize ((CHAR8 *) PcdGetPtr (PcdTcgPhysicalPresenceInterfaceVer)) + ); + + PcdTpm2AcpiTableRev = PcdGet8 (PcdTpm2AcpiTableRev); + + // + // Initialize efi varstore configuration data. + // + ZeroMem (&Tcg2Version, sizeof (Tcg2Version)); + ConfigRequestHdr = HiiConstructConfigHdr ( + &gTcg2ConfigFormSetGuid, + TCG2_VERSION_NAME, + PrivateData->DriverHandle + ); + ASSERT (ConfigRequestHdr != NULL); + DataSize = sizeof (Tcg2Version); + Status = gRT->GetVariable ( + TCG2_VERSION_NAME, + &gTcg2ConfigFormSetGuid, + NULL, + &DataSize, + &Tcg2Version + ); + if (!EFI_ERROR (Status)) { + // + // EFI variable does exist and validate current setting. + // + ActionFlag = HiiValidateSettings (ConfigRequestHdr); + if (!ActionFlag) { + // + // Current configuration is invalid, reset to defaults. + // + ActionFlag = HiiSetToDefaults (ConfigRequestHdr, EFI_HII_DEFAULT_CLASS_STANDARD); + ASSERT (ActionFlag); + // + // Get the default values from variable. + // + DataSize = sizeof (Tcg2Version); + Status = gRT->GetVariable ( + TCG2_VERSION_NAME, + &gTcg2ConfigFormSetGuid, + NULL, + &DataSize, + &Tcg2Version + ); + ASSERT_EFI_ERROR (Status); + } + } else { + // + // EFI variable doesn't exist or variable size is not expected. + // + + // + // Store zero data Buffer Storage to EFI variable. + // + Status = gRT->SetVariable ( + TCG2_VERSION_NAME, + &gTcg2ConfigFormSetGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, + sizeof (Tcg2Version), + &Tcg2Version + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Tcg2ConfigDriver: Fail to set TCG2_VERSION_NAME\n")); + return; + } else { + // + // Build this variable based on default values stored in IFR. + // + ActionFlag = HiiSetToDefaults (ConfigRequestHdr, EFI_HII_DEFAULT_CLASS_STANDARD); + ASSERT (ActionFlag); + // + // Get the default values from variable. + // + DataSize = sizeof (Tcg2Version); + Status = gRT->GetVariable ( + TCG2_VERSION_NAME, + &gTcg2ConfigFormSetGuid, + NULL, + &DataSize, + &Tcg2Version + ); + ASSERT_EFI_ERROR (Status); + if (PcdTcg2PpiVersion != Tcg2Version.PpiVersion) { + DEBUG ((DEBUG_WARN, "WARNING: PcdTcgPhysicalPresenceInterfaceVer default value is not same with the default value in VFR\n")); + DEBUG ((DEBUG_WARN, "WARNING: The default value in VFR has be chosen\n")); + } + if (PcdTpm2AcpiTableRev != Tcg2Version.Tpm2AcpiTableRev) { + DEBUG ((DEBUG_WARN, "WARNING: PcdTpm2AcpiTableRev default value is not same with the default value in VFR\n")); + DEBUG ((DEBUG_WARN, "WARNING: The default value in VFR has be chosen\n")); + } + } + } + FreePool (ConfigRequestHdr); + + // + // Get the PCD value again. + // If the PCD value is not equal to the value in variable, + // the PCD is not DynamicHii type and does not map to the setup option. + // + PcdTcg2PpiVersion = 0; + CopyMem ( + &PcdTcg2PpiVersion, + PcdGetPtr (PcdTcgPhysicalPresenceInterfaceVer), + AsciiStrSize ((CHAR8 *) PcdGetPtr (PcdTcgPhysicalPresenceInterfaceVer)) + ); + if (PcdTcg2PpiVersion != Tcg2Version.PpiVersion) { + DEBUG ((DEBUG_WARN, "WARNING: PcdTcgPhysicalPresenceInterfaceVer is not DynamicHii type and does not map to TCG2_VERSION.PpiVersion\n")); + DEBUG ((DEBUG_WARN, "WARNING: The TCG2 PPI version configuring from setup page will not work\n")); + } + + switch (PcdTcg2PpiVersion) { + case TCG2_PPI_VERSION_1_2: + HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_TCG2_PPI_VERSION_STATE_CONTENT), L"1.2", NULL); + break; + case TCG2_PPI_VERSION_1_3: + HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_TCG2_PPI_VERSION_STATE_CONTENT), L"1.3", NULL); + break; + default: + ASSERT (FALSE); + break; + } + + // + // Get the PcdTpm2AcpiTableRev value again. + // If the PCD value is not equal to the value in variable, + // the PCD is not DynamicHii type and does not map to TCG2_VERSION Variable. + // + PcdTpm2AcpiTableRev = PcdGet8 (PcdTpm2AcpiTableRev); + if (PcdTpm2AcpiTableRev != Tcg2Version.Tpm2AcpiTableRev) { + DEBUG ((DEBUG_WARN, "WARNING: PcdTpm2AcpiTableRev is not DynamicHii type and does not map to TCG2_VERSION.Tpm2AcpiTableRev\n")); + DEBUG ((DEBUG_WARN, "WARNING: The Tpm2 ACPI Revision configuring from setup page will not work\n")); + } + + switch (PcdTpm2AcpiTableRev) { + case EFI_TPM2_ACPI_TABLE_REVISION_3: + HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_TPM2_ACPI_REVISION_STATE_CONTENT), L"Rev 3", NULL); + break; + case EFI_TPM2_ACPI_TABLE_REVISION_4: + HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_TPM2_ACPI_REVISION_STATE_CONTENT), L"Rev 4", NULL); + break; + default: + ASSERT (FALSE); + break; + } +} + +/** + The entry point for Tcg2 configuration driver. + + @param[in] ImageHandle The image handle of the driver. + @param[in] SystemTable The system table. + + @retval EFI_ALREADY_STARTED The driver already exists in system. + @retval EFI_OUT_OF_RESOURCES Fail to execute entry point due to lack of resources. + @retval EFI_SUCCES All the related protocols are installed on the driver. + @retval Others Fail to install protocols as indicated. + +**/ +EFI_STATUS +EFIAPI +Tcg2ConfigDriverEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + TCG2_CONFIG_PRIVATE_DATA *PrivateData; + TCG2_CONFIGURATION Tcg2Configuration; + TCG2_DEVICE_DETECTION Tcg2DeviceDetection; + UINTN Index; + UINTN DataSize; + EDKII_VARIABLE_LOCK_PROTOCOL *VariableLockProtocol; + UINT32 CurrentActivePCRBanks; + + Status = gBS->OpenProtocol ( + ImageHandle, + &gEfiCallerIdGuid, + NULL, + ImageHandle, + ImageHandle, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); + if (!EFI_ERROR (Status)) { + return EFI_ALREADY_STARTED; + } + + // + // Create a private data structure. + // + PrivateData = AllocateCopyPool (sizeof (TCG2_CONFIG_PRIVATE_DATA), &mTcg2ConfigPrivateDateTemplate); + ASSERT (PrivateData != NULL); + mTcg2ConfigPrivateDate = PrivateData; + // + // Install private GUID. + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &ImageHandle, + &gEfiCallerIdGuid, + PrivateData, + NULL + ); + ASSERT_EFI_ERROR (Status); + + Status = gBS->LocateProtocol (&gEfiTcg2ProtocolGuid, NULL, (VOID **) &PrivateData->Tcg2Protocol); + ASSERT_EFI_ERROR (Status); + + PrivateData->ProtocolCapability.Size = sizeof(PrivateData->ProtocolCapability); + Status = PrivateData->Tcg2Protocol->GetCapability ( + PrivateData->Tcg2Protocol, + &PrivateData->ProtocolCapability + ); + ASSERT_EFI_ERROR (Status); + + DataSize = sizeof(Tcg2Configuration); + Status = gRT->GetVariable ( + TCG2_STORAGE_NAME, + &gTcg2ConfigFormSetGuid, + NULL, + &DataSize, + &Tcg2Configuration + ); + if (EFI_ERROR (Status)) { + // + // Variable not ready, set default value + // + Tcg2Configuration.TpmDevice = TPM_DEVICE_DEFAULT; + } + + // + // Validation + // + if ((Tcg2Configuration.TpmDevice > TPM_DEVICE_MAX) || (Tcg2Configuration.TpmDevice < TPM_DEVICE_MIN)) { + Tcg2Configuration.TpmDevice = TPM_DEVICE_DEFAULT; + } + + // + // Set value for Tcg2CurrentActivePCRBanks + // Search Tcg2ConfigBin[] and update default value there + // + Status = PrivateData->Tcg2Protocol->GetActivePcrBanks (PrivateData->Tcg2Protocol, &CurrentActivePCRBanks); + ASSERT_EFI_ERROR (Status); + PrivateData->PCRBanksDesired = CurrentActivePCRBanks; + UpdateDefaultPCRBanks (Tcg2ConfigBin + sizeof(UINT32), ReadUnaligned32((UINT32 *)Tcg2ConfigBin) - sizeof(UINT32), CurrentActivePCRBanks); + + // + // Sync data from PCD to variable, so that we do not need detect again in S3 phase. + // + Tcg2DeviceDetection.TpmDeviceDetected = TPM_DEVICE_NULL; + for (Index = 0; Index < sizeof(mTpmInstanceId)/sizeof(mTpmInstanceId[0]); Index++) { + if (CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &mTpmInstanceId[Index].TpmInstanceGuid)) { + Tcg2DeviceDetection.TpmDeviceDetected = mTpmInstanceId[Index].TpmDevice; + break; + } + } + + PrivateData->TpmDeviceDetected = Tcg2DeviceDetection.TpmDeviceDetected; + Tcg2Configuration.TpmDevice = Tcg2DeviceDetection.TpmDeviceDetected; + + // + // Save to variable so platform driver can get it. + // + Status = gRT->SetVariable ( + TCG2_DEVICE_DETECTION_NAME, + &gTcg2ConfigFormSetGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, + sizeof(Tcg2DeviceDetection), + &Tcg2DeviceDetection + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Tcg2ConfigDriver: Fail to set TCG2_DEVICE_DETECTION_NAME\n")); + Status = gRT->SetVariable ( + TCG2_DEVICE_DETECTION_NAME, + &gTcg2ConfigFormSetGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, + 0, + NULL + ); + ASSERT_EFI_ERROR (Status); + } + + // + // Save to variable so platform driver can get it. + // + Status = gRT->SetVariable ( + TCG2_STORAGE_NAME, + &gTcg2ConfigFormSetGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, + sizeof(Tcg2Configuration), + &Tcg2Configuration + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Tcg2ConfigDriver: Fail to set TCG2_STORAGE_NAME\n")); + } + + // + // We should lock Tcg2DeviceDetection, because it contains information needed at S3. + // + Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **)&VariableLockProtocol); + if (!EFI_ERROR (Status)) { + Status = VariableLockProtocol->RequestToLock ( + VariableLockProtocol, + TCG2_DEVICE_DETECTION_NAME, + &gTcg2ConfigFormSetGuid + ); + ASSERT_EFI_ERROR (Status); + } + + // + // Install Tcg2 configuration form + // + Status = InstallTcg2ConfigForm (PrivateData); + if (EFI_ERROR (Status)) { + goto ErrorExit; + } + + InitializeTcg2VersionInfo (PrivateData); + + return EFI_SUCCESS; + +ErrorExit: + if (PrivateData != NULL) { + UninstallTcg2ConfigForm (PrivateData); + } + + return Status; +} + +/** + Unload the Tcg2 configuration form. + + @param[in] ImageHandle The driver's image handle. + + @retval EFI_SUCCESS The Tcg2 configuration form is unloaded. + @retval Others Failed to unload the form. + +**/ +EFI_STATUS +EFIAPI +Tcg2ConfigDriverUnload ( + IN EFI_HANDLE ImageHandle + ) +{ + EFI_STATUS Status; + TCG2_CONFIG_PRIVATE_DATA *PrivateData; + + Status = gBS->HandleProtocol ( + ImageHandle, + &gEfiCallerIdGuid, + (VOID **) &PrivateData + ); + if (EFI_ERROR (Status)) { + return Status; + } + + ASSERT (PrivateData->Signature == TCG2_CONFIG_PRIVATE_DATA_SIGNATURE); + + gBS->UninstallMultipleProtocolInterfaces ( + &ImageHandle, + &gEfiCallerIdGuid, + PrivateData, + NULL + ); + + UninstallTcg2ConfigForm (PrivateData); + + return EFI_SUCCESS; +} diff --git a/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDxe.inf b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDxe.inf new file mode 100644 index 0000000000..38fa331701 --- /dev/null +++ b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDxe.inf @@ -0,0 +1,91 @@ +## @file +# TPM device configuration for TPM 2.0 +# +# By this module, user may select TPM device, clear TPM state, etc. +# NOTE: This module is only for reference only, each platform should have its own setup page. +# +# Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = Tcg2ConfigDxe + MODULE_UNI_FILE = Tcg2ConfigDxe.uni + FILE_GUID = 4D9CBEF0-15A0-4D0C-83DB-5213E710C23F + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = Tcg2ConfigDriverEntryPoint + UNLOAD_IMAGE = Tcg2ConfigDriverUnload + +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + Tcg2ConfigDriver.c + Tcg2ConfigImpl.c + Tcg2ConfigImpl.h + Tcg2Config.vfr + Tcg2ConfigStrings.uni + Tcg2ConfigNvData.h + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + MemoryAllocationLib + UefiLib + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + UefiDriverEntryPoint + UefiHiiServicesLib + DebugLib + HiiLib + PcdLib + PrintLib + Tpm2DeviceLib + Tpm2CommandLib + Tcg2PhysicalPresenceLib + IoLib + +[Guids] + ## PRODUCES ## HII + ## SOMETIMES_PRODUCES ## Variable:L"TCG2_CONFIGURATION" + ## SOMETIMES_CONSUMES ## Variable:L"TCG2_CONFIGURATION" + ## PRODUCES ## Variable:L"TCG2_DEVICE_DETECTION" + ## SOMETIMES_CONSUMES ## Variable:L"TCG2_DEVICE_DETECTION" + gTcg2ConfigFormSetGuid + +[Protocols] + gEfiHiiConfigAccessProtocolGuid ## PRODUCES + gEfiDevicePathProtocolGuid ## PRODUCES + gEdkiiVariableLockProtocolGuid ## SOMETIMES_CONSUMES + gEfiTcg2ProtocolGuid ## CONSUMES + +[Pcd] + gEfiSecurityPkgTokenSpaceGuid.PcdTpmInstanceGuid ## CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdTcg2HashAlgorithmBitmap ## CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdTpmBaseAddress ## CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdTcgPhysicalPresenceInterfaceVer ## CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdTpm2AcpiTableRev ## CONSUMES + +[Depex] + gEfiTcg2ProtocolGuid AND + gEfiHiiConfigRoutingProtocolGuid AND + gEfiHiiDatabaseProtocolGuid AND + gEfiVariableArchProtocolGuid AND + gEfiVariableWriteArchProtocolGuid + +[UserExtensions.TianoCore."ExtraFiles"] + Tcg2ConfigDxeExtra.uni diff --git a/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDxe.uni b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDxe.uni new file mode 100644 index 0000000000..ee7219ee5b --- /dev/null +++ b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDxe.uni @@ -0,0 +1,22 @@ +// /** @file +// TPM device configuration for TPM 2.0 +// +// By this module, user may select TPM device, clear TPM state, etc. +// NOTE: This module is only for reference only, each platform should have its own setup page. +// +// Copyright (c) 2015, Intel Corporation. All rights reserved.
+// +// This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// **/ + + +#string STR_MODULE_ABSTRACT #language en-US "TPM device configuration for TPM 2.0" + +#string STR_MODULE_DESCRIPTION #language en-US "By this module, user may select TPM device, clear TPM state, etc. NOTE: This module is only for reference only, each platform should have its own setup page." + diff --git a/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDxeExtra.uni b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDxeExtra.uni new file mode 100644 index 0000000000..37f81e17bd --- /dev/null +++ b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDxeExtra.uni @@ -0,0 +1,19 @@ +// /** @file +// Tcg2ConfigDxe Localized Strings and Content +// +// Copyright (c) 2015, Intel Corporation. All rights reserved.
+// +// This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// **/ + +#string STR_PROPERTIES_MODULE_NAME +#language en-US +"TCG2 (Trusted Computing Group) Configuration DXE" + + diff --git a/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigImpl.c b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigImpl.c new file mode 100644 index 0000000000..b3a849e918 --- /dev/null +++ b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigImpl.c @@ -0,0 +1,1032 @@ +/** @file + HII Config Access protocol implementation of TCG2 configuration module. + NOTE: This module is only for reference only, each platform should have its own setup page. + +Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE 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 +#include +#include +#include + +#include + +#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 + format. + @param[out] Progress On return, points to a character in the Request + string. Points to the string's null terminator if + request was successful. Points to the most recent + '&' before the first failing name/value pair (or + the beginning of the string if the failure is in + the first name/value pair) if the request was not + successful. + @param[out] Results A null-terminated Unicode string in + format which has all values filled + in for the names in the Request string. String to + be allocated by the called function. + + @retval EFI_SUCCESS The Results is filled with the requested values. + @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results. + @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name. + @retval EFI_NOT_FOUND Routing data doesn't match any storage in this + driver. + +**/ +EFI_STATUS +EFIAPI +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 + format. + @param[out] Progress A pointer to a string filled in with the offset of + the most recent '&' before the first failing + name/value pair (or the beginning of the string if + the failure is in the first name/value pair) or + the terminating NULL if all was successful. + + @retval EFI_SUCCESS The Results is processed successfully. + @retval EFI_INVALID_PARAMETER Configuration is NULL. + @retval EFI_NOT_FOUND Routing data doesn't match any storage in this + driver. + +**/ +EFI_STATUS +EFIAPI +Tcg2RouteConfig ( + IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, + IN CONST EFI_STRING Configuration, + OUT EFI_STRING *Progress + ) +{ + if (Configuration == NULL || Progress == NULL) { + return EFI_INVALID_PARAMETER; + } + + return EFI_NOT_FOUND; +} + +/** + Get HID string of TPM2 ACPI device object + + @param[in] Hid Points to HID String Buffer. + @param[in] Size HID String size in bytes. Must >= TPM_HID_ACPI_SIZE + + @return HID String get status. + +**/ +EFI_STATUS +GetTpm2HID( + CHAR8 *Hid, + UINTN Size + ) +{ + EFI_STATUS Status; + UINT32 ManufacturerID; + UINT32 FirmwareVersion1; + UINT32 FirmwareVersion2; + BOOLEAN PnpHID; + + PnpHID = TRUE; + + ZeroMem(Hid, Size); + + // + // Get Manufacturer ID + // + Status = Tpm2GetCapabilityManufactureID(&ManufacturerID); + if (!EFI_ERROR(Status)) { + DEBUG((DEBUG_INFO, "TPM_PT_MANUFACTURER 0x%08x\n", ManufacturerID)); + // + // ManufacturerID defined in TCG Vendor ID Registry + // may tailed with 0x00 or 0x20 + // + if ((ManufacturerID >> 24) == 0x00 || ((ManufacturerID >> 24) == 0x20)) { + // + // HID containing PNP ID "NNN####" + // NNN is uppercase letter for Vendor ID specified by manufacturer + // + CopyMem(Hid, &ManufacturerID, 3); + } else { + // + // HID containing ACP ID "NNNN####" + // NNNN is uppercase letter for Vendor ID specified by manufacturer + // + CopyMem(Hid, &ManufacturerID, 4); + PnpHID = FALSE; + } + } else { + DEBUG ((DEBUG_ERROR, "Get TPM_PT_MANUFACTURER failed %x!\n", Status)); + ASSERT(FALSE); + return Status; + } + + Status = Tpm2GetCapabilityFirmwareVersion(&FirmwareVersion1, &FirmwareVersion2); + if (!EFI_ERROR(Status)) { + DEBUG((DEBUG_INFO, "TPM_PT_FIRMWARE_VERSION_1 0x%x\n", FirmwareVersion1)); + DEBUG((DEBUG_INFO, "TPM_PT_FIRMWARE_VERSION_2 0x%x\n", FirmwareVersion2)); + // + // #### is Firmware Version 1 + // + if (PnpHID) { + AsciiSPrint(Hid + 3, TPM_HID_PNP_SIZE - 3, "%02d%02d", ((FirmwareVersion1 & 0xFFFF0000) >> 16), (FirmwareVersion1 & 0x0000FFFF)); + } else { + AsciiSPrint(Hid + 4, TPM_HID_ACPI_SIZE - 4, "%02d%02d", ((FirmwareVersion1 & 0xFFFF0000) >> 16), (FirmwareVersion1 & 0x0000FFFF)); + } + + } else { + DEBUG ((DEBUG_ERROR, "Get TPM_PT_FIRMWARE_VERSION_X failed %x!\n", Status)); + ASSERT(FALSE); + return Status; + } + + return EFI_SUCCESS; +} + +/** + This function processes the results of changes in configuration + for TCG2 version information. + + @param[in] Action Specifies the type of action taken by the browser. + ASSERT if the Action is not EFI_BROWSER_ACTION_SUBMITTED. + @param[in] QuestionId A unique value which is sent to the original + exporting driver so that it can identify the type + of data to expect. + @param[in] Type The type of value for the question. + @param[in] Value A pointer to the data being sent to the original + exporting driver. + + @retval EFI_SUCCESS The callback successfully handled the action. + +**/ +EFI_STATUS +Tcg2VersionInfoCallback ( + IN EFI_BROWSER_ACTION Action, + IN EFI_QUESTION_ID QuestionId, + IN UINT8 Type, + IN EFI_IFR_TYPE_VALUE *Value + ) +{ + EFI_INPUT_KEY Key; + UINT64 PcdTcg2PpiVersion; + UINT8 PcdTpm2AcpiTableRev; + + ASSERT (Action == EFI_BROWSER_ACTION_SUBMITTED); + + if (QuestionId == KEY_TCG2_PPI_VERSION) { + // + // Get the PCD value after EFI_BROWSER_ACTION_SUBMITTED, + // the SetVariable to TCG2_VERSION_NAME should have been done. + // If the PCD value is not equal to the value set to variable, + // the PCD is not DynamicHii type and does not map to the setup option. + // + PcdTcg2PpiVersion = 0; + CopyMem ( + &PcdTcg2PpiVersion, + PcdGetPtr (PcdTcgPhysicalPresenceInterfaceVer), + AsciiStrSize ((CHAR8 *) PcdGetPtr (PcdTcgPhysicalPresenceInterfaceVer)) + ); + if (PcdTcg2PpiVersion != Value->u64) { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"WARNING: PcdTcgPhysicalPresenceInterfaceVer is not DynamicHii type and does not map to this option!", + L"The version configuring by this setup option will not work!", + NULL + ); + } + } else if (QuestionId == KEY_TPM2_ACPI_REVISION){ + // + // Get the PCD value after EFI_BROWSER_ACTION_SUBMITTED, + // the SetVariable to TCG2_VERSION_NAME should have been done. + // If the PCD value is not equal to the value set to variable, + // the PCD is not DynamicHii type and does not map to the setup option. + // + PcdTpm2AcpiTableRev = PcdGet8 (PcdTpm2AcpiTableRev); + + if (PcdTpm2AcpiTableRev != Value->u8) { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"WARNING: PcdTpm2AcpiTableRev is not DynamicHii type and does not map to this option!", + L"The Revision configuring by this setup option will not work!", + NULL + ); + } + } + + return EFI_SUCCESS; +} + +/** + This function processes the results of changes in configuration. + + @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + @param[in] Action Specifies the type of action taken by the browser. + @param[in] QuestionId A unique value which is sent to the original + exporting driver so that it can identify the type + of data to expect. + @param[in] Type The type of value for the question. + @param[in] Value A pointer to the data being sent to the original + exporting driver. + @param[out] ActionRequest On return, points to the action requested by the + callback function. + + @retval EFI_SUCCESS The callback successfully handled the action. + @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the + variable and its data. + @retval EFI_DEVICE_ERROR The variable could not be saved. + @retval EFI_UNSUPPORTED The specified Action is not supported by the + callback. + +**/ +EFI_STATUS +EFIAPI +Tcg2Callback ( + IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, + IN EFI_BROWSER_ACTION Action, + IN EFI_QUESTION_ID QuestionId, + IN UINT8 Type, + IN EFI_IFR_TYPE_VALUE *Value, + OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest + ) +{ + EFI_STATUS Status; + EFI_INPUT_KEY Key; + CHAR8 HidStr[16]; + CHAR16 UnHidStr[16]; + TCG2_CONFIG_PRIVATE_DATA *Private; + + if ((This == NULL) || (Value == NULL) || (ActionRequest == NULL)) { + return EFI_INVALID_PARAMETER; + } + + Private = TCG2_CONFIG_PRIVATE_DATA_FROM_THIS (This); + + if (Action == EFI_BROWSER_ACTION_FORM_OPEN) { + // + // Update TPM2 HID info + // + if (QuestionId == KEY_TPM_DEVICE) { + Status = GetTpm2HID(HidStr, 16); + + if (EFI_ERROR(Status)) { + // + // Fail to get TPM2 HID + // + HiiSetString (Private->HiiHandle, STRING_TOKEN (STR_TPM2_ACPI_HID_CONTENT), L"Unknown", NULL); + } else { + AsciiStrToUnicodeStrS(HidStr, UnHidStr, 16); + HiiSetString (Private->HiiHandle, STRING_TOKEN (STR_TPM2_ACPI_HID_CONTENT), UnHidStr, NULL); + } + } + return EFI_SUCCESS; + } + + if (Action == EFI_BROWSER_ACTION_CHANGING) { + if (QuestionId == KEY_TPM_DEVICE_INTERFACE) { + Status = SetPtpInterface ((VOID *) (UINTN) PcdGet64 (PcdTpmBaseAddress), Value->u8); + if (EFI_ERROR (Status)) { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Error: Fail to set PTP interface!", + NULL + ); + return EFI_DEVICE_ERROR; + } + } + } + + if (Action == EFI_BROWSER_ACTION_CHANGED) { + if (QuestionId == KEY_TPM_DEVICE) { + return EFI_SUCCESS; + } + if (QuestionId == KEY_TPM2_OPERATION) { + return SaveTcg2PpRequest (Value->u8); + } + if (QuestionId == KEY_TPM2_OPERATION_PARAMETER) { + return SaveTcg2PpRequestParameter (Value->u32); + } + if ((QuestionId >= KEY_TPM2_PCR_BANKS_REQUEST_0) && (QuestionId <= KEY_TPM2_PCR_BANKS_REQUEST_4)) { + return SaveTcg2PCRBanksRequest (QuestionId - KEY_TPM2_PCR_BANKS_REQUEST_0, Value->b); + } + } + + if (Action == EFI_BROWSER_ACTION_SUBMITTED) { + if (QuestionId == KEY_TCG2_PPI_VERSION || QuestionId == KEY_TPM2_ACPI_REVISION) { + return Tcg2VersionInfoCallback (Action, QuestionId, Type, Value); + } + } + + return EFI_UNSUPPORTED; +} + +/** + Append Buffer With TpmAlgHash. + + @param[in] Buffer Buffer to be appended. + @param[in] BufferSize Size of buffer. + @param[in] TpmAlgHash TpmAlgHash. + +**/ +VOID +AppendBufferWithTpmAlgHash ( + IN UINT16 *Buffer, + IN UINTN BufferSize, + IN UINT32 TpmAlgHash + ) +{ + switch (TpmAlgHash) { + case TPM_ALG_SHA1: + if (Buffer[0] != 0) { + StrCatS (Buffer, BufferSize / sizeof (CHAR16), L", "); + } + StrCatS (Buffer, BufferSize / sizeof (CHAR16), L"SHA1"); + break; + case TPM_ALG_SHA256: + if (Buffer[0] != 0) { + StrCatS (Buffer, BufferSize / sizeof (CHAR16), L", "); + } + StrCatS (Buffer, BufferSize / sizeof (CHAR16), L"SHA256"); + break; + case TPM_ALG_SHA384: + if (Buffer[0] != 0) { + StrCatS (Buffer, BufferSize / sizeof (CHAR16), L", "); + } + StrCatS (Buffer, BufferSize / sizeof (CHAR16), L"SHA384"); + break; + case TPM_ALG_SHA512: + if (Buffer[0] != 0) { + StrCatS (Buffer, BufferSize / sizeof (CHAR16), L", "); + } + StrCatS (Buffer, BufferSize / sizeof (CHAR16), L"SHA512"); + break; + case TPM_ALG_SM3_256: + if (Buffer[0] != 0) { + StrCatS (Buffer, BufferSize / sizeof (CHAR16), L", "); + } + StrCatS (Buffer, BufferSize / sizeof (CHAR16), L"SM3_256"); + break; + } +} + +/** + Fill Buffer With BootHashAlg. + + @param[in] Buffer Buffer to be filled. + @param[in] BufferSize Size of buffer. + @param[in] BootHashAlg BootHashAlg. + +**/ +VOID +FillBufferWithBootHashAlg ( + IN UINT16 *Buffer, + IN UINTN BufferSize, + IN UINT32 BootHashAlg + ) +{ + Buffer[0] = 0; + if ((BootHashAlg & EFI_TCG2_BOOT_HASH_ALG_SHA1) != 0) { + if (Buffer[0] != 0) { + StrCatS (Buffer, BufferSize / sizeof (CHAR16), L", "); + } + StrCatS (Buffer, BufferSize / sizeof (CHAR16), L"SHA1"); + } + if ((BootHashAlg & EFI_TCG2_BOOT_HASH_ALG_SHA256) != 0) { + if (Buffer[0] != 0) { + StrCatS (Buffer, BufferSize / sizeof (CHAR16), L", "); + } + StrCatS (Buffer, BufferSize / sizeof (CHAR16), L"SHA256"); + } + if ((BootHashAlg & EFI_TCG2_BOOT_HASH_ALG_SHA384) != 0) { + if (Buffer[0] != 0) { + StrCatS (Buffer, BufferSize / sizeof (CHAR16), L", "); + } + StrCatS (Buffer, BufferSize / sizeof (CHAR16), L"SHA384"); + } + if ((BootHashAlg & EFI_TCG2_BOOT_HASH_ALG_SHA512) != 0) { + if (Buffer[0] != 0) { + StrCatS (Buffer, BufferSize / sizeof (CHAR16), L", "); + } + StrCatS (Buffer, BufferSize / sizeof (CHAR16), L"SHA512"); + } + if ((BootHashAlg & EFI_TCG2_BOOT_HASH_ALG_SM3_256) != 0) { + if (Buffer[0] != 0) { + StrCatS (Buffer, BufferSize / sizeof (CHAR16), L", "); + } + StrCatS (Buffer, BufferSize / sizeof (CHAR16), L"SM3_256"); + } +} + +/** + Set ConfigInfo according to TpmAlgHash. + + @param[in,out] Tcg2ConfigInfo TCG2 config info. + @param[in] TpmAlgHash TpmAlgHash. + +**/ +VOID +SetConfigInfo ( + IN OUT TCG2_CONFIGURATION_INFO *Tcg2ConfigInfo, + IN UINT32 TpmAlgHash + ) +{ + switch (TpmAlgHash) { + case TPM_ALG_SHA1: + Tcg2ConfigInfo->Sha1Supported = TRUE; + break; + case TPM_ALG_SHA256: + Tcg2ConfigInfo->Sha256Supported = TRUE; + break; + case TPM_ALG_SHA384: + Tcg2ConfigInfo->Sha384Supported = TRUE; + break; + case TPM_ALG_SHA512: + Tcg2ConfigInfo->Sha512Supported = TRUE; + break; + case TPM_ALG_SM3_256: + Tcg2ConfigInfo->Sm3Supported = TRUE; + break; + } +} + +/** + Fill Buffer With TCG2EventLogFormat. + + @param[in] Buffer Buffer to be filled. + @param[in] BufferSize Size of buffer. + @param[in] TCG2EventLogFormat TCG2EventLogFormat. + +**/ +VOID +FillBufferWithTCG2EventLogFormat ( + IN UINT16 *Buffer, + IN UINTN BufferSize, + IN UINT32 TCG2EventLogFormat + ) +{ + Buffer[0] = 0; + if ((TCG2EventLogFormat & EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2) != 0) { + if (Buffer[0] != 0) { + StrCatS (Buffer, BufferSize / sizeof (CHAR16), L", "); + } + StrCatS (Buffer, BufferSize / sizeof (CHAR16), L"TCG_1_2"); + } + if ((TCG2EventLogFormat & EFI_TCG2_EVENT_LOG_FORMAT_TCG_2) != 0) { + if (Buffer[0] != 0) { + StrCatS (Buffer, BufferSize / sizeof (CHAR16), L", "); + } + StrCatS (Buffer, BufferSize / sizeof (CHAR16), L"TCG_2"); + } + if ((TCG2EventLogFormat & (~EFI_TCG2_EVENT_LOG_FORMAT_ALL)) != 0) { + if (Buffer[0] != 0) { + StrCatS (Buffer, BufferSize / sizeof (CHAR16), L", "); + } + StrCatS (Buffer, BufferSize / sizeof (CHAR16), L"UNKNOWN"); + } +} + +/** + This function publish the TCG2 configuration Form for TPM device. + + @param[in, out] PrivateData Points to TCG2 configuration private data. + + @retval EFI_SUCCESS HII Form is installed for this network device. + @retval EFI_OUT_OF_RESOURCES Not enough resource for HII Form installation. + @retval Others Other errors as indicated. + +**/ +EFI_STATUS +InstallTcg2ConfigForm ( + IN OUT TCG2_CONFIG_PRIVATE_DATA *PrivateData + ) +{ + EFI_STATUS Status; + EFI_HII_HANDLE HiiHandle; + EFI_HANDLE DriverHandle; + EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess; + UINTN Index; + TPML_PCR_SELECTION Pcrs; + CHAR16 TempBuffer[1024]; + TCG2_CONFIGURATION_INFO Tcg2ConfigInfo; + UINT8 TpmDeviceInterfaceDetected; + + DriverHandle = NULL; + ConfigAccess = &PrivateData->ConfigAccess; + Status = gBS->InstallMultipleProtocolInterfaces ( + &DriverHandle, + &gEfiDevicePathProtocolGuid, + &mTcg2HiiVendorDevicePath, + &gEfiHiiConfigAccessProtocolGuid, + ConfigAccess, + NULL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + PrivateData->DriverHandle = DriverHandle; + + // + // Publish the HII package list + // + HiiHandle = HiiAddPackages ( + &gTcg2ConfigFormSetGuid, + DriverHandle, + Tcg2ConfigDxeStrings, + Tcg2ConfigBin, + NULL + ); + if (HiiHandle == NULL) { + gBS->UninstallMultipleProtocolInterfaces ( + DriverHandle, + &gEfiDevicePathProtocolGuid, + &mTcg2HiiVendorDevicePath, + &gEfiHiiConfigAccessProtocolGuid, + ConfigAccess, + NULL + ); + + return EFI_OUT_OF_RESOURCES; + } + + PrivateData->HiiHandle = HiiHandle; + + // + // Update static data + // + switch (PrivateData->TpmDeviceDetected) { + case TPM_DEVICE_NULL: + HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_TCG2_DEVICE_STATE_CONTENT), L"Not Found", NULL); + break; + case TPM_DEVICE_1_2: + HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_TCG2_DEVICE_STATE_CONTENT), L"TPM 1.2", NULL); + break; + case TPM_DEVICE_2_0_DTPM: + HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_TCG2_DEVICE_STATE_CONTENT), L"TPM 2.0", NULL); + break; + default: + HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_TCG2_DEVICE_STATE_CONTENT), L"Unknown", NULL); + break; + } + + ZeroMem (&Tcg2ConfigInfo, sizeof(Tcg2ConfigInfo)); + Status = Tpm2GetCapabilityPcrs (&Pcrs); + if (EFI_ERROR (Status)) { + HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_TPM2_ACTIVE_HASH_ALGO_CONTENT), L"[Unknown]", NULL); + HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_TPM2_SUPPORTED_HASH_ALGO_CONTENT), L"[Unknown]", NULL); + } else { + TempBuffer[0] = 0; + for (Index = 0; Index < Pcrs.count; Index++) { + if (!IsZeroBuffer (Pcrs.pcrSelections[Index].pcrSelect, Pcrs.pcrSelections[Index].sizeofSelect)) { + AppendBufferWithTpmAlgHash (TempBuffer, sizeof(TempBuffer), Pcrs.pcrSelections[Index].hash); + } + } + HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_TPM2_ACTIVE_HASH_ALGO_CONTENT), TempBuffer, NULL); + + TempBuffer[0] = 0; + for (Index = 0; Index < Pcrs.count; Index++) { + AppendBufferWithTpmAlgHash (TempBuffer, sizeof(TempBuffer), Pcrs.pcrSelections[Index].hash); + SetConfigInfo (&Tcg2ConfigInfo, Pcrs.pcrSelections[Index].hash); + } + HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_TPM2_SUPPORTED_HASH_ALGO_CONTENT), TempBuffer, NULL); + } + + FillBufferWithBootHashAlg (TempBuffer, sizeof(TempBuffer), PcdGet32 (PcdTcg2HashAlgorithmBitmap)); + HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_BIOS_HASH_ALGO_CONTENT), TempBuffer, NULL); + + // + // Tcg2 Capability + // + FillBufferWithTCG2EventLogFormat (TempBuffer, sizeof(TempBuffer), PrivateData->ProtocolCapability.SupportedEventLogs); + HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_TCG2_SUPPORTED_EVENT_LOG_FORMAT_CONTENT), TempBuffer, NULL); + + FillBufferWithBootHashAlg (TempBuffer, sizeof(TempBuffer), PrivateData->ProtocolCapability.HashAlgorithmBitmap); + HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_TCG2_HASH_ALGO_BITMAP_CONTENT), TempBuffer, NULL); + + UnicodeSPrint (TempBuffer, sizeof (TempBuffer), L"%d", PrivateData->ProtocolCapability.NumberOfPCRBanks); + HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_TCG2_NUMBER_OF_PCR_BANKS_CONTENT), TempBuffer, NULL); + + FillBufferWithBootHashAlg (TempBuffer, sizeof(TempBuffer), PrivateData->ProtocolCapability.ActivePcrBanks); + HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_TCG2_ACTIVE_PCR_BANKS_CONTENT), TempBuffer, NULL); + + // + // Update TPM device interface type + // + if (PrivateData->TpmDeviceDetected == TPM_DEVICE_2_0_DTPM) { + TpmDeviceInterfaceDetected = GetPtpInterface ((VOID *) (UINTN) PcdGet64 (PcdTpmBaseAddress)); + switch (TpmDeviceInterfaceDetected) { + case TPM_DEVICE_INTERFACE_TIS: + HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_TCG2_DEVICE_INTERFACE_STATE_CONTENT), L"TIS", NULL); + break; + case TPM_DEVICE_INTERFACE_PTP_FIFO: + HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_TCG2_DEVICE_INTERFACE_STATE_CONTENT), L"PTP FIFO", NULL); + break; + case TPM_DEVICE_INTERFACE_PTP_CRB: + HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_TCG2_DEVICE_INTERFACE_STATE_CONTENT), L"PTP CRB", NULL); + break; + default: + HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_TCG2_DEVICE_INTERFACE_STATE_CONTENT), L"Unknown", NULL); + break; + } + + Tcg2ConfigInfo.TpmDeviceInterfaceAttempt = TpmDeviceInterfaceDetected; + switch (TpmDeviceInterfaceDetected) { + case TPM_DEVICE_INTERFACE_TIS: + Tcg2ConfigInfo.TpmDeviceInterfacePtpFifoSupported = FALSE; + Tcg2ConfigInfo.TpmDeviceInterfacePtpCrbSupported = FALSE; + HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_TCG2_DEVICE_INTERFACE_CAPABILITY_CONTENT), L"TIS", NULL); + break; + case TPM_DEVICE_INTERFACE_PTP_FIFO: + case TPM_DEVICE_INTERFACE_PTP_CRB: + Tcg2ConfigInfo.TpmDeviceInterfacePtpFifoSupported = IsPtpFifoSupported((VOID *) (UINTN) PcdGet64 (PcdTpmBaseAddress)); + Tcg2ConfigInfo.TpmDeviceInterfacePtpCrbSupported = IsPtpCrbSupported((VOID *) (UINTN) PcdGet64 (PcdTpmBaseAddress)); + TempBuffer[0] = 0; + if (Tcg2ConfigInfo.TpmDeviceInterfacePtpFifoSupported) { + if (TempBuffer[0] != 0) { + StrCatS (TempBuffer, sizeof(TempBuffer) / sizeof (CHAR16), L", "); + } + StrCatS (TempBuffer, sizeof(TempBuffer) / sizeof (CHAR16), L"PTP FIFO"); + } + if (Tcg2ConfigInfo.TpmDeviceInterfacePtpCrbSupported) { + if (TempBuffer[0] != 0) { + StrCatS (TempBuffer, sizeof(TempBuffer) / sizeof (CHAR16), L", "); + } + StrCatS (TempBuffer, sizeof(TempBuffer) / sizeof (CHAR16), L"PTP CRB"); + } + HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_TCG2_DEVICE_INTERFACE_CAPABILITY_CONTENT), TempBuffer, NULL); + break; + default: + Tcg2ConfigInfo.TpmDeviceInterfacePtpFifoSupported = FALSE; + Tcg2ConfigInfo.TpmDeviceInterfacePtpCrbSupported = FALSE; + HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_TCG2_DEVICE_INTERFACE_CAPABILITY_CONTENT), L"Unknown", NULL); + break; + } + } + + // + // Set ConfigInfo, to control the check box. + // + Status = gRT->SetVariable ( + TCG2_STORAGE_INFO_NAME, + &gTcg2ConfigFormSetGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS, + sizeof(Tcg2ConfigInfo), + &Tcg2ConfigInfo + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Tcg2ConfigDriver: Fail to set TCG2_STORAGE_INFO_NAME\n")); + } + + return EFI_SUCCESS; +} + +/** + This function removes TCG2 configuration Form. + + @param[in, out] PrivateData Points to TCG2 configuration private data. + +**/ +VOID +UninstallTcg2ConfigForm ( + IN OUT TCG2_CONFIG_PRIVATE_DATA *PrivateData + ) +{ + // + // Uninstall HII package list + // + if (PrivateData->HiiHandle != NULL) { + HiiRemovePackages (PrivateData->HiiHandle); + PrivateData->HiiHandle = NULL; + } + + // + // Uninstall HII Config Access Protocol + // + if (PrivateData->DriverHandle != NULL) { + gBS->UninstallMultipleProtocolInterfaces ( + PrivateData->DriverHandle, + &gEfiDevicePathProtocolGuid, + &mTcg2HiiVendorDevicePath, + &gEfiHiiConfigAccessProtocolGuid, + &PrivateData->ConfigAccess, + NULL + ); + PrivateData->DriverHandle = NULL; + } + + FreePool (PrivateData); +} diff --git a/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigImpl.h b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigImpl.h new file mode 100644 index 0000000000..504212baa8 --- /dev/null +++ b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigImpl.h @@ -0,0 +1,201 @@ +/** @file + The header file of HII Config Access protocol implementation of TCG2 + configuration module. + +Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +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 + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "Tcg2ConfigNvData.h" + +// +// Tool generated IFR binary data and String package data +// +extern UINT8 Tcg2ConfigBin[]; +extern UINT8 Tcg2ConfigDxeStrings[]; + +/// +/// HII specific Vendor Device Path definition. +/// +typedef struct { + VENDOR_DEVICE_PATH VendorDevicePath; + EFI_DEVICE_PATH_PROTOCOL End; +} HII_VENDOR_DEVICE_PATH; + +typedef struct { + UINTN Signature; + + EFI_HII_CONFIG_ACCESS_PROTOCOL ConfigAccess; + EFI_HII_HANDLE HiiHandle; + EFI_HANDLE DriverHandle; + + UINT8 TpmDeviceDetected; + EFI_TCG2_PROTOCOL *Tcg2Protocol; + EFI_TCG2_BOOT_SERVICE_CAPABILITY ProtocolCapability; + UINT32 PCRBanksDesired; +} TCG2_CONFIG_PRIVATE_DATA; + +extern TCG2_CONFIG_PRIVATE_DATA mTcg2ConfigPrivateDateTemplate; +extern TCG2_CONFIG_PRIVATE_DATA *mTcg2ConfigPrivateDate; +#define TCG2_CONFIG_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('T', 'r', 'E', 'D') +#define TCG2_CONFIG_PRIVATE_DATA_FROM_THIS(a) CR (a, TCG2_CONFIG_PRIVATE_DATA, ConfigAccess, TCG2_CONFIG_PRIVATE_DATA_SIGNATURE) + +#define TPM_HID_PNP_SIZE 8 +#define TPM_HID_ACPI_SIZE 9 + +/** + This function publish the TCG2 configuration Form for TPM device. + + @param[in, out] PrivateData Points to TCG2 configuration private data. + + @retval EFI_SUCCESS HII Form is installed for this network device. + @retval EFI_OUT_OF_RESOURCES Not enough resource for HII Form installation. + @retval Others Other errors as indicated. + +**/ +EFI_STATUS +InstallTcg2ConfigForm ( + IN OUT TCG2_CONFIG_PRIVATE_DATA *PrivateData + ); + +/** + This function removes TCG2 configuration Form. + + @param[in, out] PrivateData Points to TCG2 configuration private data. + +**/ +VOID +UninstallTcg2ConfigForm ( + IN OUT TCG2_CONFIG_PRIVATE_DATA *PrivateData + ); + +/** + This function allows a caller to extract the current configuration for one + or more named elements from the target driver. + + @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + @param[in] Request A null-terminated Unicode string in + format. + @param[out] Progress On return, points to a character in the Request + string. Points to the string's null terminator if + request was successful. Points to the most recent + '&' before the first failing name/value pair (or + the beginning of the string if the failure is in + the first name/value pair) if the request was not + successful. + @param[out] Results A null-terminated Unicode string in + format which has all values filled + in for the names in the Request string. String to + be allocated by the called function. + + @retval EFI_SUCCESS The Results is filled with the requested values. + @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results. + @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name. + @retval EFI_NOT_FOUND Routing data doesn't match any storage in this + driver. + +**/ +EFI_STATUS +EFIAPI +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 + format. + @param[out] Progress A pointer to a string filled in with the offset of + the most recent '&' before the first failing + name/value pair (or the beginning of the string if + the failure is in the first name/value pair) or + the terminating NULL if all was successful. + + @retval EFI_SUCCESS The Results is processed successfully. + @retval EFI_INVALID_PARAMETER Configuration is NULL. + @retval EFI_NOT_FOUND Routing data doesn't match any storage in this + driver. + +**/ +EFI_STATUS +EFIAPI +Tcg2RouteConfig ( + IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, + IN CONST EFI_STRING Configuration, + OUT EFI_STRING *Progress + ); + +/** + This function processes the results of changes in configuration. + + @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + @param[in] Action Specifies the type of action taken by the browser. + @param[in] QuestionId A unique value which is sent to the original + exporting driver so that it can identify the type + of data to expect. + @param[in] Type The type of value for the question. + @param[in] Value A pointer to the data being sent to the original + exporting driver. + @param[out] ActionRequest On return, points to the action requested by the + callback function. + + @retval EFI_SUCCESS The callback successfully handled the action. + @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the + variable and its data. + @retval EFI_DEVICE_ERROR The variable could not be saved. + @retval EFI_UNSUPPORTED The specified Action is not supported by the + callback. + +**/ +EFI_STATUS +EFIAPI +Tcg2Callback ( + IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, + IN EFI_BROWSER_ACTION Action, + IN EFI_QUESTION_ID QuestionId, + IN UINT8 Type, + IN EFI_IFR_TYPE_VALUE *Value, + OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest + ); + +#endif diff --git a/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigNvData.h b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigNvData.h new file mode 100644 index 0000000000..5960446421 --- /dev/null +++ b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigNvData.h @@ -0,0 +1,129 @@ +/** @file + Header file for NV data structure definition. + +Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +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 +#include +#include + +// +// BUGBUG: In order to pass VfrCompiler, we have to redefine below MACRO, which already in . +// +#ifndef __TCG2_H__ +#define EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2 0x00000001 +#define EFI_TCG2_EVENT_LOG_FORMAT_TCG_2 0x00000002 +#endif +#define EFI_TCG2_EVENT_LOG_FORMAT_ALL (EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2 | EFI_TCG2_EVENT_LOG_FORMAT_TCG_2) + +#define TCG2_CONFIGURATION_VARSTORE_ID 0x0001 +#define TCG2_CONFIGURATION_INFO_VARSTORE_ID 0x0002 +#define TCG2_VERSION_VARSTORE_ID 0x0003 +#define TCG2_CONFIGURATION_FORM_ID 0x0001 + +#define KEY_TPM_DEVICE 0x2000 +#define KEY_TPM2_OPERATION 0x2001 +#define KEY_TPM2_OPERATION_PARAMETER 0x2002 +#define KEY_TPM2_PCR_BANKS_REQUEST_0 0x2003 +#define KEY_TPM2_PCR_BANKS_REQUEST_1 0x2004 +#define KEY_TPM2_PCR_BANKS_REQUEST_2 0x2005 +#define KEY_TPM2_PCR_BANKS_REQUEST_3 0x2006 +#define KEY_TPM2_PCR_BANKS_REQUEST_4 0x2007 +#define KEY_TPM_DEVICE_INTERFACE 0x2008 +#define KEY_TCG2_PPI_VERSION 0x2009 +#define KEY_TPM2_ACPI_REVISION 0x200A + +#define TPM_DEVICE_NULL 0 +#define TPM_DEVICE_1_2 1 +#define TPM_DEVICE_2_0_DTPM 2 +#define TPM_DEVICE_MIN TPM_DEVICE_1_2 +#define TPM_DEVICE_MAX TPM_DEVICE_2_0_DTPM +#define TPM_DEVICE_DEFAULT TPM_DEVICE_1_2 + +#define TPM2_ACPI_REVISION_3 3 +#define TPM2_ACPI_REVISION_4 4 + +#define TPM_DEVICE_INTERFACE_TIS 0 +#define TPM_DEVICE_INTERFACE_PTP_FIFO 1 +#define TPM_DEVICE_INTERFACE_PTP_CRB 2 +#define TPM_DEVICE_INTERFACE_MAX TPM_DEVICE_INTERFACE_PTP_FIFO +#define TPM_DEVICE_INTERFACE_DEFAULT TPM_DEVICE_INTERFACE_PTP_CRB + +#define TCG2_PROTOCOL_VERSION_DEFAULT 0x0001 +#define EFI_TCG2_EVENT_LOG_FORMAT_DEFAULT EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2 + +#define TCG2_PPI_VERSION_1_2 0x322E31 // "1.2" +#define TCG2_PPI_VERSION_1_3 0x332E31 // "1.3" + +// +// Nv Data structure referenced by IFR, TPM device user desired +// +typedef struct { + UINT8 TpmDevice; +} TCG2_CONFIGURATION; + +typedef struct { + UINT64 PpiVersion; + UINT8 Tpm2AcpiTableRev; +} TCG2_VERSION; + +typedef struct { + BOOLEAN Sha1Supported; + BOOLEAN Sha256Supported; + BOOLEAN Sha384Supported; + BOOLEAN Sha512Supported; + BOOLEAN Sm3Supported; + UINT8 TpmDeviceInterfaceAttempt; + BOOLEAN TpmDeviceInterfacePtpFifoSupported; + BOOLEAN TpmDeviceInterfacePtpCrbSupported; +} TCG2_CONFIGURATION_INFO; + +// +// Variable saved for S3, TPM detected, only valid in S3 path. +// This variable is ReadOnly. +// +typedef struct { + UINT8 TpmDeviceDetected; +} TCG2_DEVICE_DETECTION; + +#define TCG2_STORAGE_NAME L"TCG2_CONFIGURATION" +#define TCG2_STORAGE_INFO_NAME L"TCG2_CONFIGURATION_INFO" +#define TCG2_DEVICE_DETECTION_NAME L"TCG2_DEVICE_DETECTION" +#define TCG2_VERSION_NAME L"TCG2_VERSION" + +#define TPM_INSTANCE_ID_LIST { \ + {TPM_DEVICE_INTERFACE_NONE, TPM_DEVICE_NULL}, \ + {TPM_DEVICE_INTERFACE_TPM12, TPM_DEVICE_1_2}, \ + {TPM_DEVICE_INTERFACE_TPM20_DTPM, TPM_DEVICE_2_0_DTPM}, \ +} + +// +// BUGBUG: In order to pass VfrCompiler, we have to redefine GUID here. +// +#ifndef __BASE_H__ +typedef struct { + UINT32 Data1; + UINT16 Data2; + UINT16 Data3; + UINT8 Data4[8]; +} GUID; +#endif + +typedef struct { + GUID TpmInstanceGuid; + UINT8 TpmDevice; +} TPM_INSTANCE_ID; + +#endif diff --git a/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPei.inf b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPei.inf new file mode 100644 index 0000000000..8dd0b63e48 --- /dev/null +++ b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPei.inf @@ -0,0 +1,77 @@ +## @file +# Set TPM device type +# +# This module initializes TPM device type based on variable and detection. +# NOTE: This module is only for reference only, each platform should have its own setup page. +# +# Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = Tcg2ConfigPei + MODULE_UNI_FILE = Tcg2ConfigPei.uni + FILE_GUID = EADD5061-93EF-4CCC-8450-F78A7F0820F0 + MODULE_TYPE = PEIM + VERSION_STRING = 1.0 + ENTRY_POINT = Tcg2ConfigPeimEntryPoint + +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# +# [BootMode] +# S3_RESUME ## SOMETIMES_CONSUMES +# + +[Sources] + Tcg2ConfigPeim.c + Tcg2ConfigNvData.h + TpmDetection.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + MemoryAllocationLib + PeiServicesLib + PeimEntryPoint + DebugLib + PcdLib + TimerLib + Tpm12CommandLib + Tpm12DeviceLib + +[Guids] + ## SOMETIMES_CONSUMES ## Variable:L"TCG2_CONFIGURATION" + ## SOMETIMES_CONSUMES ## Variable:L"TCG2_DEVICE_DETECTION" + gTcg2ConfigFormSetGuid + gEfiTpmDeviceSelectedGuid ## PRODUCES ## GUID # Used as a PPI GUID + gEfiTpmDeviceInstanceNoneGuid ## SOMETIMES_CONSUMES ## GUID # TPM device identifier + +[Ppis] + gEfiPeiReadOnlyVariable2PpiGuid ## CONSUMES + gPeiTpmInitializationDonePpiGuid ## SOMETIMES_PRODUCES + +[Pcd] + gEfiSecurityPkgTokenSpaceGuid.PcdTpmInstanceGuid ## PRODUCES + gEfiSecurityPkgTokenSpaceGuid.PcdTpmInitializationPolicy ## PRODUCES + gEfiSecurityPkgTokenSpaceGuid.PcdTpmAutoDetection ## CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdTpmBaseAddress ## SOMETIMES_CONSUMES + +[Depex] + gEfiPeiMasterBootModePpiGuid AND + gEfiPeiReadOnlyVariable2PpiGuid + +[UserExtensions.TianoCore."ExtraFiles"] + Tcg2ConfigPeiExtra.uni diff --git a/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPei.uni b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPei.uni new file mode 100644 index 0000000000..02eaf8faad --- /dev/null +++ b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPei.uni @@ -0,0 +1,23 @@ +// /** @file +// Set TPM device type +// +// This module initializes TPM device type based on variable and detection. +// NOTE: This module is only for reference only, each platform should have its own setup page. +// +// Copyright (c) 2015, Intel Corporation. All rights reserved.
+// +// This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// **/ + + +#string STR_MODULE_ABSTRACT #language en-US "Set TPM device type" + +#string STR_MODULE_DESCRIPTION #language en-US "This module initializes TPM device type based on variable and detection.\n" + "NOTE: This module is only for reference only, each platform should have its own setup page." + diff --git a/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPeiExtra.uni b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPeiExtra.uni new file mode 100644 index 0000000000..37f81e17bd --- /dev/null +++ b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPeiExtra.uni @@ -0,0 +1,19 @@ +// /** @file +// Tcg2ConfigDxe Localized Strings and Content +// +// Copyright (c) 2015, Intel Corporation. All rights reserved.
+// +// This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// **/ + +#string STR_PROPERTIES_MODULE_NAME +#language en-US +"TCG2 (Trusted Computing Group) Configuration DXE" + + diff --git a/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPeim.c b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPeim.c new file mode 100644 index 0000000000..004c7efe70 --- /dev/null +++ b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPeim.c @@ -0,0 +1,159 @@ +/** @file + The module entry point for Tcg2 configuration module. + +Copyright (c) 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + + +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "Tcg2ConfigNvData.h" + +TPM_INSTANCE_ID mTpmInstanceId[] = TPM_INSTANCE_ID_LIST; + +CONST EFI_PEI_PPI_DESCRIPTOR gTpmSelectedPpi = { + (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gEfiTpmDeviceSelectedGuid, + NULL +}; + +EFI_PEI_PPI_DESCRIPTOR mTpmInitializationDonePpiList = { + EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, + &gPeiTpmInitializationDonePpiGuid, + NULL +}; + +/** + This routine check both SetupVariable and real TPM device, and return final TpmDevice configuration. + + @param SetupTpmDevice TpmDevice configuration in setup driver + + @return TpmDevice configuration +**/ +UINT8 +DetectTpmDevice ( + IN UINT8 SetupTpmDevice + ); + +/** + The entry point for Tcg2 configuration driver. + + @param FileHandle Handle of the file being invoked. + @param PeiServices Describes the list of possible PEI Services. + + @retval EFI_SUCCES Convert variable to PCD successfully. + @retval Others Fail to convert variable to PCD. +**/ +EFI_STATUS +EFIAPI +Tcg2ConfigPeimEntryPoint ( + IN EFI_PEI_FILE_HANDLE FileHandle, + IN CONST EFI_PEI_SERVICES **PeiServices + ) +{ + UINTN Size; + EFI_STATUS Status; + EFI_STATUS Status2; + EFI_PEI_READ_ONLY_VARIABLE2_PPI *VariablePpi; + TCG2_CONFIGURATION Tcg2Configuration; + UINTN Index; + UINT8 TpmDevice; + + Status = PeiServicesLocatePpi (&gEfiPeiReadOnlyVariable2PpiGuid, 0, NULL, (VOID **) &VariablePpi); + ASSERT_EFI_ERROR (Status); + + Size = sizeof(Tcg2Configuration); + Status = VariablePpi->GetVariable ( + VariablePpi, + TCG2_STORAGE_NAME, + &gTcg2ConfigFormSetGuid, + NULL, + &Size, + &Tcg2Configuration + ); + if (EFI_ERROR (Status)) { + // + // Variable not ready, set default value + // + Tcg2Configuration.TpmDevice = TPM_DEVICE_DEFAULT; + } + + // + // Validation + // + if ((Tcg2Configuration.TpmDevice > TPM_DEVICE_MAX) || (Tcg2Configuration.TpmDevice < TPM_DEVICE_MIN)) { + Tcg2Configuration.TpmDevice = TPM_DEVICE_DEFAULT; + } + + // + // Although we have SetupVariable info, we still need detect TPM device manually. + // + DEBUG ((EFI_D_INFO, "Tcg2Configuration.TpmDevice from Setup: %x\n", Tcg2Configuration.TpmDevice)); + + if (PcdGetBool (PcdTpmAutoDetection)) { + TpmDevice = DetectTpmDevice (Tcg2Configuration.TpmDevice); + DEBUG ((EFI_D_INFO, "TpmDevice final: %x\n", TpmDevice)); + if (TpmDevice != TPM_DEVICE_NULL) { + Tcg2Configuration.TpmDevice = TpmDevice; + } + } else { + TpmDevice = Tcg2Configuration.TpmDevice; + } + + // + // Convert variable to PCD. + // This is work-around because there is no gurantee DynamicHiiPcd can return correct value in DXE phase. + // Using DynamicPcd instead. + // + // NOTE: Tcg2Configuration variable contains the desired TpmDevice type, + // while PcdTpmInstanceGuid PCD contains the real detected TpmDevice type + // + for (Index = 0; Index < sizeof(mTpmInstanceId)/sizeof(mTpmInstanceId[0]); Index++) { + if (TpmDevice == mTpmInstanceId[Index].TpmDevice) { + Size = sizeof(mTpmInstanceId[Index].TpmInstanceGuid); + Status = PcdSetPtrS (PcdTpmInstanceGuid, &Size, &mTpmInstanceId[Index].TpmInstanceGuid); + ASSERT_EFI_ERROR (Status); + DEBUG ((EFI_D_INFO, "TpmDevice PCD: %g\n", &mTpmInstanceId[Index].TpmInstanceGuid)); + break; + } + } + + // + // Selection done + // + Status = PeiServicesInstallPpi (&gTpmSelectedPpi); + ASSERT_EFI_ERROR (Status); + + // + // Even if no TPM is selected or detected, we still need intall TpmInitializationDonePpi. + // Because TcgPei or Tcg2Pei will not run, but we still need a way to notify other driver. + // Other driver can know TPM initialization state by TpmInitializedPpi. + // + if (CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceNoneGuid)) { + Status2 = PeiServicesInstallPpi (&mTpmInitializationDonePpiList); + ASSERT_EFI_ERROR (Status2); + } + + return Status; +} diff --git a/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigStrings.uni b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigStrings.uni new file mode 100644 index 0000000000..a7d62bcbe6 --- /dev/null +++ b/Core/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigStrings.uni @@ -0,0 +1,138 @@ +/** @file + String definitions for TCG2 configuration form. + +Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#langdef en-US "English" + +#string STR_TCG2_TITLE #language en-US "TCG2 Configuration" +#string STR_TCG2_HELP #language en-US "Press to select TCG2 Setup options." + +#string STR_TCG2_DEVICE_STATE_PROMPT #language en-US "Current TPM Device" +#string STR_TCG2_DEVICE_STATE_HELP #language en-US "Current TPM Device: Disable, TPM1.2, or TPM2.0" +#string STR_TCG2_DEVICE_STATE_CONTENT #language en-US "" + +#string STR_TCG2_DEVICE_PROMPT #language en-US "Attempt TPM Device" +#string STR_TCG2_DEVICE_HELP #language en-US "Attempt TPM Device: TPM1.2, or TPM2.0" +#string STR_TCG2_DEVICE_CONTENT #language en-US "" + +#string STR_TCG2_PPI_VERSION_STATE_PROMPT #language en-US "Current PPI Version" +#string STR_TCG2_PPI_VERSION_STATE_HELP #language en-US "Current PPI Version: 1.2 or 1.3" +#string STR_TCG2_PPI_VERSION_STATE_CONTENT #language en-US "" + +#string STR_TCG2_PPI_VERSION_PROMPT #language en-US "Attempt PPI Version" +#string STR_TCG2_PPI_VERSION_HELP #language en-US "Attempt PPI Version: 1.2 or 1.3\n" + "PcdTcgPhysicalPresenceInterfaceVer needs to be DynamicHii type and map to this option\n" + "Otherwise the version configuring by this setup option will not work" + +#string STR_TPM2_ACPI_HID_PROMPT #language en-US "HID from TPM2 ACPI Table" +#string STR_TPM2_ACPI_HID_HELP #language en-US "HID from TPM2 ACPI Table: ManufacturerID + FirmwareVersion_1" +#string STR_TPM2_ACPI_HID_CONTENT #language en-US "" + +#string STR_TPM2_ACPI_REVISION_STATE_PROMPT #language en-US "Current Rev of TPM2 ACPI Table" +#string STR_TPM2_ACPI_REVISION_STATE_HELP #language en-US "Current Rev of TPM2 ACPI Table: Rev 3 or Rev 4" +#string STR_TPM2_ACPI_REVISION_STATE_CONTENT #language en-US "" + +#string STR_TPM2_ACPI_REVISION_PROMPT #language en-US "Attempt Rev of TPM2 ACPI Table" +#string STR_TPM2_ACPI_REVISION_HELP #language en-US "Rev 3 or Rev 4 (Rev 4 is defined in TCG ACPI Spec 00.37)" + "PcdTpm2AcpiTableRev needs to be DynamicHii type and map to this option\n" + "Otherwise the version configuring by this setup option will not work" + +#string STR_TCG2_DEVICE_INTERFACE_STATE_PROMPT #language en-US "Current TPM Device Interface" +#string STR_TCG2_DEVICE_INTERFACE_STATE_HELP #language en-US "Current TPM Device Interface: TIS, PTP FIFO, PTP CRB" +#string STR_TCG2_DEVICE_INTERFACE_STATE_CONTENT #language en-US "" + +#string STR_TCG2_DEVICE_INTERFACE_CAPABILITY_PROMPT #language en-US "PTP TPM Device Interface Capability" +#string STR_TCG2_DEVICE_INTERFACE_CAPABILITY_HELP #language en-US "PTP TPM Device Interface Capability: PTP FIFO, PTP CRB" +#string STR_TCG2_DEVICE_INTERFACE_CAPABILITY_CONTENT #language en-US "" + +#string STR_TCG2_DEVICE_INTERFACE_PROMPT #language en-US "Attempt PTP TPM Device Interface" +#string STR_TCG2_DEVICE_INTERFACE_HELP #language en-US "Attempt PTP TPM Device Interface: PTP FIFO, PTP CRB" +#string STR_TCG2_DEVICE_INTERFACE_CONTENT #language en-US "" + +#string STR_TCG2_DEVICE_INTERFACE_TIS #language en-US "TIS" +#string STR_TCG2_DEVICE_INTERFACE_PTP_FIFO #language en-US "PTP FIFO" +#string STR_TCG2_DEVICE_INTERFACE_PTP_CRB #language en-US "PTP CRB" + +#string STR_TCG2_PP_OPERATION #language en-US "TPM2 Physical Presence Operation" + +#string STR_TCG2_OPERATION #language en-US "TPM2 Operation" +#string STR_TCG2_OPERATION_HELP #language en-US "Select one of the supported operation to change TPM2 state." + +#string STR_TCG2_NO_ACTION #language en-US "No Action" +#string STR_TCG2_ENABLE #language en-US "TPM2 HierarchyControl (TPM_RH_OWNER YES, TPM_RH_ENDORSEMENT YES)" +#string STR_TCG2_DISABLE #language en-US "TPM2 HierarchyControl (TPM_RH_OWNER NO, TPM_RH_ENDORSEMENT NO)" +#string STR_TCG2_CLEAR #language en-US "TPM2 ClearControl(NO) + Clear" +#string STR_TCG2_SET_PCD_BANKS #language en-US "TPM2 PCR_Allocate(Algorithm IDs)" +#string STR_TCG2_CHANGE_EPS #language en-US "TPM2 ChangeEPS" +#string STR_TCG2_LOG_ALL_DIGESTS #language en-US "TCG2 LogAllDigests" +#string STR_TCG2_DISABLE_ENDORSEMENT_ENABLE_STORAGE_HIERARCHY #language en-US "TPM2 HierarchyControl (TPM_RH_OWNER NO, TPM_RH_ENDORSEMENT YES)" + +#string STR_TCG2_OPERATION_PARAMETER #language en-US "TPM2 Operation Parameter" +#string STR_TCG2_OPERATION_PARAMETER_HELP #language en-US "Additional TPM2 Operation Parameter need be sent with Operation Code (required for SetPCRBanks)" + +#string STR_TCG2_TPM_1_2 #language en-US "TPM 1.2" +#string STR_TCG2_TPM_2_0_DTPM #language en-US "TPM 2.0" + +#string STR_TPM2_ACPI_REVISION_3 #language en-US "Rev 3" +#string STR_TPM2_ACPI_REVISION_4 #language en-US "Rev 4" + +#string STR_TCG2_PPI_VERSION_1_2 #language en-US "1.2" +#string STR_TCG2_PPI_VERSION_1_3 #language en-US "1.3" + +#string STR_TPM2_ACTIVE_HASH_ALGO #language en-US "TPM2 Active PCR Hash Algorithm" +#string STR_TPM2_ACTIVE_HASH_ALGO_HELP #language en-US "TPM2 Active PCR Hash Algorithm: SHA1, SHA256, SHA384, SHA512, SM3_256" +#string STR_TPM2_ACTIVE_HASH_ALGO_CONTENT #language en-US "" + +#string STR_TPM2_SUPPORTED_HASH_ALGO #language en-US "TPM2 Hardware Supported Hash Algorithm" +#string STR_TPM2_SUPPORTED_HASH_ALGO_HELP #language en-US "TPM2 Hardware Supported Hash Algorithm: SHA1, SHA256, SHA384, SHA512, SM3_256" +#string STR_TPM2_SUPPORTED_HASH_ALGO_CONTENT #language en-US "" + +#string STR_BIOS_HASH_ALGO #language en-US "BIOS Supported Hash Algorithm" +#string STR_BIOS_HASH_ALGO_HELP #language en-US "BIOS Supported Hash Algorithm: SHA1, SHA256, SHA384, SHA512, SM3_256" +#string STR_BIOS_HASH_ALGO_CONTENT #language en-US "" + +#string STR_TCG2_CONFIGURATION #language en-US "TCG2 Protocol Configuration" + +#string STR_TCG2_PROTOCOL_VERSION #language en-US "TCG2 Protocol Version" +#string STR_TCG2_PROTOCOL_VERSION_HELP #language en-US "TCG2 Protocol Version: 1.0 or 1.1" +#string STR_TCG2_PROTOCOL_VERSION_1_0 #language en-US "1.0" +#string STR_TCG2_PROTOCOL_VERSION_1_1 #language en-US "1.1" + +#string STR_TCG2_SUPPORTED_EVENT_LOG_FORMAT #language en-US "Supported Event Log Format" +#string STR_TCG2_SUPPORTED_EVENT_LOG_FORMAT_HELP #language en-US "TCG2 Supported Event Log Format: TCG_1_2, TCG_2" +#string STR_TCG2_SUPPORTED_EVENT_LOG_FORMAT_CONTENT #language en-US "" + +#string STR_TCG2_HASH_ALGO_BITMAP #language en-US "Hash Algorithm Bitmap" +#string STR_TCG2_HASH_ALGO_BITMAP_HELP #language en-US "TCG2 Supported Hash Algorithm Bitmap: SHA1, SHA256, SHA384, SHA512" +#string STR_TCG2_HASH_ALGO_BITMAP_CONTENT #language en-US "" + +#string STR_TCG2_NUMBER_OF_PCR_BANKS #language en-US "Number of PCR Banks" +#string STR_TCG2_NUMBER_OF_PCR_BANKS_HELP #language en-US "TCG2 Number of PCR Banks" +#string STR_TCG2_NUMBER_OF_PCR_BANKS_CONTENT #language en-US "" + +#string STR_TCG2_ACTIVE_PCR_BANKS #language en-US "Active PCR Banks" +#string STR_TCG2_ACTIVE_PCR_BANKS_HELP #language en-US "TCG2 Active PCR Banks: SHA1, SHA256, SHA384, SHA512" +#string STR_TCG2_ACTIVE_PCR_BANKS_CONTENT #language en-US "" + +#string STR_TCG2_PCR_BANK_SHA1 #language en-US " PCR Bank: SHA1" +#string STR_TCG2_PCR_BANK_SHA1_HELP #language en-US "TCG2 Request PCR Bank: SHA1" +#string STR_TCG2_PCR_BANK_SHA256 #language en-US " PCR Bank: SHA256" +#string STR_TCG2_PCR_BANK_SHA256_HELP #language en-US "TCG2 Request PCR Bank: SHA256" +#string STR_TCG2_PCR_BANK_SHA384 #language en-US " PCR Bank: SHA384" +#string STR_TCG2_PCR_BANK_SHA384_HELP #language en-US "TCG2 Request PCR Bank: SHA384" +#string STR_TCG2_PCR_BANK_SHA512 #language en-US " PCR Bank: SHA512" +#string STR_TCG2_PCR_BANK_SHA512_HELP #language en-US "TCG2 Request PCR Bank: SHA512" +#string STR_TCG2_PCR_BANK_SM3_256 #language en-US " PCR Bank: SM3_256" +#string STR_TCG2_PCR_BANK_SM3_256_HELP #language en-US "TCG2 Request PCR Bank: SM3_256" + +#string STR_NULL #language en-US "" diff --git a/Core/SecurityPkg/Tcg/Tcg2Config/TpmDetection.c b/Core/SecurityPkg/Tcg/Tcg2Config/TpmDetection.c new file mode 100644 index 0000000000..7e6ca44205 --- /dev/null +++ b/Core/SecurityPkg/Tcg/Tcg2Config/TpmDetection.c @@ -0,0 +1,105 @@ +/** @file + TPM1.2/dTPM2.0 auto detection. + +Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Tcg2ConfigNvData.h" + +/** + This routine check both SetupVariable and real TPM device, and return final TpmDevice configuration. + + @param SetupTpmDevice TpmDevice configuration in setup driver + + @return TpmDevice configuration +**/ +UINT8 +DetectTpmDevice ( + IN UINT8 SetupTpmDevice + ) +{ + EFI_STATUS Status; + EFI_BOOT_MODE BootMode; + TCG2_DEVICE_DETECTION Tcg2DeviceDetection; + EFI_PEI_READ_ONLY_VARIABLE2_PPI *VariablePpi; + UINTN Size; + + Status = PeiServicesGetBootMode (&BootMode); + ASSERT_EFI_ERROR (Status); + + // + // In S3, we rely on normal boot Detection, because we save to ReadOnly Variable in normal boot. + // + if (BootMode == BOOT_ON_S3_RESUME) { + DEBUG ((EFI_D_INFO, "DetectTpmDevice: S3 mode\n")); + + Status = PeiServicesLocatePpi (&gEfiPeiReadOnlyVariable2PpiGuid, 0, NULL, (VOID **) &VariablePpi); + ASSERT_EFI_ERROR (Status); + + Size = sizeof(TCG2_DEVICE_DETECTION); + ZeroMem (&Tcg2DeviceDetection, sizeof(Tcg2DeviceDetection)); + Status = VariablePpi->GetVariable ( + VariablePpi, + TCG2_DEVICE_DETECTION_NAME, + &gTcg2ConfigFormSetGuid, + NULL, + &Size, + &Tcg2DeviceDetection + ); + if (!EFI_ERROR (Status) && + (Tcg2DeviceDetection.TpmDeviceDetected >= TPM_DEVICE_MIN) && + (Tcg2DeviceDetection.TpmDeviceDetected <= TPM_DEVICE_MAX)) { + DEBUG ((EFI_D_ERROR, "TpmDevice from DeviceDetection: %x\n", Tcg2DeviceDetection.TpmDeviceDetected)); + return Tcg2DeviceDetection.TpmDeviceDetected; + } + } + + DEBUG ((EFI_D_INFO, "DetectTpmDevice:\n")); + + // dTPM available and not disabled by setup + // We need check if it is TPM1.2 or TPM2.0 + // So try TPM1.2 command at first + + Status = Tpm12RequestUseTpm (); + if (EFI_ERROR (Status)) { + // + // dTPM not available + // + return TPM_DEVICE_NULL; + } + + if (BootMode == BOOT_ON_S3_RESUME) { + Status = Tpm12Startup (TPM_ST_STATE); + } else { + Status = Tpm12Startup (TPM_ST_CLEAR); + } + if (EFI_ERROR (Status)) { + return TPM_DEVICE_2_0_DTPM; + } + + // NO initialization needed again. + Status = PcdSet8S (PcdTpmInitializationPolicy, 0); + ASSERT_EFI_ERROR (Status); + return TPM_DEVICE_1_2; +} diff --git a/Core/SecurityPkg/Tcg/Tcg2Dxe/MeasureBootPeCoff.c b/Core/SecurityPkg/Tcg/Tcg2Dxe/MeasureBootPeCoff.c new file mode 100644 index 0000000000..8ee34a702e --- /dev/null +++ b/Core/SecurityPkg/Tcg/Tcg2Dxe/MeasureBootPeCoff.c @@ -0,0 +1,427 @@ +/** @file + This module implements measuring PeCoff image for Tcg2 Protocol. + + Caution: This file requires additional review when modified. + This driver will have external input - PE/COFF image. + This external input must be validated carefully to avoid security issue like + buffer overflow, integer overflow. + +Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +UINTN mTcg2DxeImageSize = 0; + +/** + Reads contents of a PE/COFF image in memory buffer. + + Caution: This function may receive untrusted input. + PE/COFF image is external input, so this function will make sure the PE/COFF image content + read is within the image buffer. + + @param FileHandle Pointer to the file handle to read the PE/COFF image. + @param FileOffset Offset into the PE/COFF image to begin the read operation. + @param ReadSize On input, the size in bytes of the requested read operation. + On output, the number of bytes actually read. + @param Buffer Output buffer that contains the data read from the PE/COFF image. + + @retval EFI_SUCCESS The specified portion of the PE/COFF image was read and the size +**/ +EFI_STATUS +EFIAPI +Tcg2DxeImageRead ( + IN VOID *FileHandle, + IN UINTN FileOffset, + IN OUT UINTN *ReadSize, + OUT VOID *Buffer + ) +{ + UINTN EndPosition; + + if (FileHandle == NULL || ReadSize == NULL || Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (MAX_ADDRESS - FileOffset < *ReadSize) { + return EFI_INVALID_PARAMETER; + } + + EndPosition = FileOffset + *ReadSize; + if (EndPosition > mTcg2DxeImageSize) { + *ReadSize = (UINT32)(mTcg2DxeImageSize - FileOffset); + } + + if (FileOffset >= mTcg2DxeImageSize) { + *ReadSize = 0; + } + + CopyMem (Buffer, (UINT8 *)((UINTN) FileHandle + FileOffset), *ReadSize); + + return EFI_SUCCESS; +} + +/** + Measure PE image into TPM log based on the authenticode image hashing in + PE/COFF Specification 8.0 Appendix A. + + Caution: This function may receive untrusted input. + PE/COFF image is external input, so this function will validate its data structure + within this image buffer before use. + + Notes: PE/COFF image is checked by BasePeCoffLib PeCoffLoaderGetImageInfo(). + + @param[in] PCRIndex TPM PCR index + @param[in] ImageAddress Start address of image buffer. + @param[in] ImageSize Image size + @param[out] DigestList Digeest list of this image. + + @retval EFI_SUCCESS Successfully measure image. + @retval EFI_OUT_OF_RESOURCES No enough resource to measure image. + @retval other error value +**/ +EFI_STATUS +MeasurePeImageAndExtend ( + IN UINT32 PCRIndex, + IN EFI_PHYSICAL_ADDRESS ImageAddress, + IN UINTN ImageSize, + OUT TPML_DIGEST_VALUES *DigestList + ) +{ + EFI_STATUS Status; + EFI_IMAGE_DOS_HEADER *DosHdr; + UINT32 PeCoffHeaderOffset; + EFI_IMAGE_SECTION_HEADER *Section; + UINT8 *HashBase; + UINTN HashSize; + UINTN SumOfBytesHashed; + EFI_IMAGE_SECTION_HEADER *SectionHeader; + UINTN Index; + UINTN Pos; + UINT16 Magic; + EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr; + UINT32 NumberOfRvaAndSizes; + UINT32 CertSize; + HASH_HANDLE HashHandle; + PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; + + HashHandle = 0xFFFFFFFF; // Know bad value + + Status = EFI_UNSUPPORTED; + SectionHeader = NULL; + + // + // Check PE/COFF image + // + ZeroMem (&ImageContext, sizeof (ImageContext)); + ImageContext.Handle = (VOID *) (UINTN) ImageAddress; + mTcg2DxeImageSize = ImageSize; + ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) Tcg2DxeImageRead; + + // + // Get information about the image being loaded + // + Status = PeCoffLoaderGetImageInfo (&ImageContext); + if (EFI_ERROR (Status)) { + // + // The information can't be got from the invalid PeImage + // + DEBUG ((DEBUG_INFO, "Tcg2Dxe: PeImage invalid. Cannot retrieve image information.\n")); + goto Finish; + } + + DosHdr = (EFI_IMAGE_DOS_HEADER *) (UINTN) ImageAddress; + PeCoffHeaderOffset = 0; + if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) { + PeCoffHeaderOffset = DosHdr->e_lfanew; + } + + Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINT8 *) (UINTN) ImageAddress + PeCoffHeaderOffset); + if (Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) { + Status = EFI_UNSUPPORTED; + goto Finish; + } + + // + // PE/COFF Image Measurement + // + // NOTE: The following codes/steps are based upon the authenticode image hashing in + // PE/COFF Specification 8.0 Appendix A. + // + // + + // 1. Load the image header into memory. + + // 2. Initialize a SHA hash context. + + Status = HashStart (&HashHandle); + if (EFI_ERROR (Status)) { + goto Finish; + } + + // + // Measuring PE/COFF Image Header; + // But CheckSum field and SECURITY data directory (certificate) are excluded + // + if (Hdr.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + // + // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value + // in the PE/COFF Header. If the MachineType is Itanium(IA64) and the + // Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC + // then override the magic value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC + // + Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC; + } else { + // + // Get the magic value from the PE/COFF Optional Header + // + Magic = Hdr.Pe32->OptionalHeader.Magic; + } + + // + // 3. Calculate the distance from the base of the image header to the image checksum address. + // 4. Hash the image header from its base to beginning of the image checksum. + // + HashBase = (UINT8 *) (UINTN) ImageAddress; + if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + // + // Use PE32 offset + // + NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes; + HashSize = (UINTN) (&Hdr.Pe32->OptionalHeader.CheckSum) - (UINTN) HashBase; + } else { + // + // Use PE32+ offset + // + NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes; + HashSize = (UINTN) (&Hdr.Pe32Plus->OptionalHeader.CheckSum) - (UINTN) HashBase; + } + + Status = HashUpdate (HashHandle, HashBase, HashSize); + if (EFI_ERROR (Status)) { + goto Finish; + } + + // + // 5. Skip over the image checksum (it occupies a single ULONG). + // + if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) { + // + // 6. Since there is no Cert Directory in optional header, hash everything + // from the end of the checksum to the end of image header. + // + if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + // + // Use PE32 offset. + // + HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.CheckSum + sizeof (UINT32); + HashSize = Hdr.Pe32->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress); + } else { + // + // Use PE32+ offset. + // + HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32); + HashSize = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress); + } + + if (HashSize != 0) { + Status = HashUpdate (HashHandle, HashBase, HashSize); + if (EFI_ERROR (Status)) { + goto Finish; + } + } + } else { + // + // 7. Hash everything from the end of the checksum to the start of the Cert Directory. + // + if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + // + // Use PE32 offset + // + HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.CheckSum + sizeof (UINT32); + HashSize = (UINTN) (&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - (UINTN) HashBase; + } else { + // + // Use PE32+ offset + // + HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32); + HashSize = (UINTN) (&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - (UINTN) HashBase; + } + + if (HashSize != 0) { + Status = HashUpdate (HashHandle, HashBase, HashSize); + if (EFI_ERROR (Status)) { + goto Finish; + } + } + + // + // 8. Skip over the Cert Directory. (It is sizeof(IMAGE_DATA_DIRECTORY) bytes.) + // 9. Hash everything from the end of the Cert Directory to the end of image header. + // + if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + // + // Use PE32 offset + // + HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]; + HashSize = Hdr.Pe32->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress); + } else { + // + // Use PE32+ offset + // + HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]; + HashSize = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress); + } + + if (HashSize != 0) { + Status = HashUpdate (HashHandle, HashBase, HashSize); + if (EFI_ERROR (Status)) { + goto Finish; + } + } + } + + // + // 10. Set the SUM_OF_BYTES_HASHED to the size of the header + // + if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + // + // Use PE32 offset + // + SumOfBytesHashed = Hdr.Pe32->OptionalHeader.SizeOfHeaders; + } else { + // + // Use PE32+ offset + // + SumOfBytesHashed = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders; + } + + // + // 11. Build a temporary table of pointers to all the IMAGE_SECTION_HEADER + // structures in the image. The 'NumberOfSections' field of the image + // header indicates how big the table should be. Do not include any + // IMAGE_SECTION_HEADERs in the table whose 'SizeOfRawData' field is zero. + // + SectionHeader = (EFI_IMAGE_SECTION_HEADER *) AllocateZeroPool (sizeof (EFI_IMAGE_SECTION_HEADER) * Hdr.Pe32->FileHeader.NumberOfSections); + if (SectionHeader == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Finish; + } + + // + // 12. Using the 'PointerToRawData' in the referenced section headers as + // a key, arrange the elements in the table in ascending order. In other + // words, sort the section headers according to the disk-file offset of + // the section. + // + Section = (EFI_IMAGE_SECTION_HEADER *) ( + (UINT8 *) (UINTN) ImageAddress + + PeCoffHeaderOffset + + sizeof(UINT32) + + sizeof(EFI_IMAGE_FILE_HEADER) + + Hdr.Pe32->FileHeader.SizeOfOptionalHeader + ); + for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) { + Pos = Index; + while ((Pos > 0) && (Section->PointerToRawData < SectionHeader[Pos - 1].PointerToRawData)) { + CopyMem (&SectionHeader[Pos], &SectionHeader[Pos - 1], sizeof(EFI_IMAGE_SECTION_HEADER)); + Pos--; + } + CopyMem (&SectionHeader[Pos], Section, sizeof(EFI_IMAGE_SECTION_HEADER)); + Section += 1; + } + + // + // 13. Walk through the sorted table, bring the corresponding section + // into memory, and hash the entire section (using the 'SizeOfRawData' + // field in the section header to determine the amount of data to hash). + // 14. Add the section's 'SizeOfRawData' to SUM_OF_BYTES_HASHED . + // 15. Repeat steps 13 and 14 for all the sections in the sorted table. + // + for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) { + Section = (EFI_IMAGE_SECTION_HEADER *) &SectionHeader[Index]; + if (Section->SizeOfRawData == 0) { + continue; + } + HashBase = (UINT8 *) (UINTN) ImageAddress + Section->PointerToRawData; + HashSize = (UINTN) Section->SizeOfRawData; + + Status = HashUpdate (HashHandle, HashBase, HashSize); + if (EFI_ERROR (Status)) { + goto Finish; + } + + SumOfBytesHashed += HashSize; + } + + // + // 16. If the file size is greater than SUM_OF_BYTES_HASHED, there is extra + // data in the file that needs to be added to the hash. This data begins + // at file offset SUM_OF_BYTES_HASHED and its length is: + // FileSize - (CertDirectory->Size) + // + if (ImageSize > SumOfBytesHashed) { + HashBase = (UINT8 *) (UINTN) ImageAddress + SumOfBytesHashed; + + if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) { + CertSize = 0; + } else { + if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + // + // Use PE32 offset. + // + CertSize = Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size; + } else { + // + // Use PE32+ offset. + // + CertSize = Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size; + } + } + + if (ImageSize > CertSize + SumOfBytesHashed) { + HashSize = (UINTN) (ImageSize - CertSize - SumOfBytesHashed); + + Status = HashUpdate (HashHandle, HashBase, HashSize); + if (EFI_ERROR (Status)) { + goto Finish; + } + } else if (ImageSize < CertSize + SumOfBytesHashed) { + Status = EFI_UNSUPPORTED; + goto Finish; + } + } + + // + // 17. Finalize the SHA hash. + // + Status = HashCompleteAndExtend (HashHandle, PCRIndex, NULL, 0, DigestList); + if (EFI_ERROR (Status)) { + goto Finish; + } + +Finish: + if (SectionHeader != NULL) { + FreePool (SectionHeader); + } + + return Status; +} diff --git a/Core/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c b/Core/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c new file mode 100644 index 0000000000..c2c52e32b8 --- /dev/null +++ b/Core/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c @@ -0,0 +1,2621 @@ +/** @file + This module implements Tcg2 Protocol. + +Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.
+(C) Copyright 2016 Hewlett Packard Enterprise Development LP
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PERF_ID_TCG2_DXE 0x3120 + +typedef struct { + CHAR16 *VariableName; + EFI_GUID *VendorGuid; +} VARIABLE_TYPE; + +#define TCG2_DEFAULT_MAX_COMMAND_SIZE 0x1000 +#define TCG2_DEFAULT_MAX_RESPONSE_SIZE 0x1000 + +typedef struct { + EFI_GUID *EventGuid; + EFI_TCG2_EVENT_LOG_FORMAT LogFormat; +} TCG2_EVENT_INFO_STRUCT; + +TCG2_EVENT_INFO_STRUCT mTcg2EventInfo[] = { + {&gTcgEventEntryHobGuid, EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2}, + {&gTcgEvent2EntryHobGuid, EFI_TCG2_EVENT_LOG_FORMAT_TCG_2}, +}; + +#define TCG_EVENT_LOG_AREA_COUNT_MAX 2 + +typedef struct { + EFI_TCG2_EVENT_LOG_FORMAT EventLogFormat; + EFI_PHYSICAL_ADDRESS Lasa; + UINT64 Laml; + UINTN EventLogSize; + UINT8 *LastEvent; + BOOLEAN EventLogStarted; + BOOLEAN EventLogTruncated; +} TCG_EVENT_LOG_AREA_STRUCT; + +typedef struct _TCG_DXE_DATA { + EFI_TCG2_BOOT_SERVICE_CAPABILITY BsCap; + TCG_EVENT_LOG_AREA_STRUCT EventLogAreaStruct[TCG_EVENT_LOG_AREA_COUNT_MAX]; + BOOLEAN GetEventLogCalled[TCG_EVENT_LOG_AREA_COUNT_MAX]; + TCG_EVENT_LOG_AREA_STRUCT FinalEventLogAreaStruct[TCG_EVENT_LOG_AREA_COUNT_MAX]; + EFI_TCG2_FINAL_EVENTS_TABLE *FinalEventsTable[TCG_EVENT_LOG_AREA_COUNT_MAX]; +} TCG_DXE_DATA; + +TCG_DXE_DATA mTcgDxeData = { + { + sizeof (EFI_TCG2_BOOT_SERVICE_CAPABILITY), // Size + { 1, 1 }, // StructureVersion + { 1, 1 }, // ProtocolVersion + EFI_TCG2_BOOT_HASH_ALG_SHA1, // HashAlgorithmBitmap + EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2, // SupportedEventLogs + TRUE, // TPMPresentFlag + TCG2_DEFAULT_MAX_COMMAND_SIZE, // MaxCommandSize + TCG2_DEFAULT_MAX_RESPONSE_SIZE, // MaxResponseSize + 0, // ManufacturerID + 0, // NumberOfPCRBanks + 0, // ActivePcrBanks + }, +}; + +UINTN mBootAttempts = 0; +CHAR16 mBootVarName[] = L"BootOrder"; + +VARIABLE_TYPE mVariableType[] = { + {EFI_SECURE_BOOT_MODE_NAME, &gEfiGlobalVariableGuid}, + {EFI_PLATFORM_KEY_NAME, &gEfiGlobalVariableGuid}, + {EFI_KEY_EXCHANGE_KEY_NAME, &gEfiGlobalVariableGuid}, + {EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid}, + {EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid}, +}; + +EFI_HANDLE mImageHandle; + +/** + Measure PE image into TPM log based on the authenticode image hashing in + PE/COFF Specification 8.0 Appendix A. + + Caution: This function may receive untrusted input. + PE/COFF image is external input, so this function will validate its data structure + within this image buffer before use. + + Notes: PE/COFF image is checked by BasePeCoffLib PeCoffLoaderGetImageInfo(). + + @param[in] PCRIndex TPM PCR index + @param[in] ImageAddress Start address of image buffer. + @param[in] ImageSize Image size + @param[out] DigestList Digeest list of this image. + + @retval EFI_SUCCESS Successfully measure image. + @retval EFI_OUT_OF_RESOURCES No enough resource to measure image. + @retval other error value +**/ +EFI_STATUS +MeasurePeImageAndExtend ( + IN UINT32 PCRIndex, + IN EFI_PHYSICAL_ADDRESS ImageAddress, + IN UINTN ImageSize, + OUT TPML_DIGEST_VALUES *DigestList + ); + +/** + + This function dump raw data. + + @param Data raw data + @param Size raw data size + +**/ +VOID +InternalDumpData ( + IN UINT8 *Data, + IN UINTN Size + ) +{ + UINTN Index; + for (Index = 0; Index < Size; Index++) { + DEBUG ((EFI_D_INFO, "%02x", (UINTN)Data[Index])); + } +} + +/** + + This function initialize TCG_PCR_EVENT2_HDR for EV_NO_ACTION Event Type other than EFI Specification ID event + The behavior is defined by TCG PC Client PFP Spec. Section 9.3.4 EV_NO_ACTION Event Types + + @param[in, out] NoActionEvent Event Header of EV_NO_ACTION Event + @param[in] EventSize Event Size of the EV_NO_ACTION Event + +**/ +VOID +InitNoActionEvent ( + IN OUT TCG_PCR_EVENT2_HDR *NoActionEvent, + IN UINT32 EventSize + ) +{ + UINT32 DigestListCount; + TPMI_ALG_HASH HashAlgId; + UINT8 *DigestBuffer; + + DigestBuffer = (UINT8 *)NoActionEvent->Digests.digests; + DigestListCount = 0; + + NoActionEvent->PCRIndex = 0; + NoActionEvent->EventType = EV_NO_ACTION; + + // + // Set Hash count & hashAlg accordingly, while Digest.digests[n].digest to all 0 + // + ZeroMem (&NoActionEvent->Digests, sizeof(NoActionEvent->Digests)); + + if ((mTcgDxeData.BsCap.ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SHA1) != 0) { + HashAlgId = TPM_ALG_SHA1; + CopyMem (DigestBuffer, &HashAlgId, sizeof(TPMI_ALG_HASH)); + DigestBuffer += sizeof(TPMI_ALG_HASH) + GetHashSizeFromAlgo (HashAlgId); + DigestListCount++; + } + + if ((mTcgDxeData.BsCap.ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SHA256) != 0) { + HashAlgId = TPM_ALG_SHA256; + CopyMem (DigestBuffer, &HashAlgId, sizeof(TPMI_ALG_HASH)); + DigestBuffer += sizeof(TPMI_ALG_HASH) + GetHashSizeFromAlgo (HashAlgId); + DigestListCount++; + } + + if ((mTcgDxeData.BsCap.ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SHA384) != 0) { + HashAlgId = TPM_ALG_SHA384; + CopyMem (DigestBuffer, &HashAlgId, sizeof(TPMI_ALG_HASH)); + DigestBuffer += sizeof(TPMI_ALG_HASH) + GetHashSizeFromAlgo (HashAlgId); + DigestListCount++; + } + + if ((mTcgDxeData.BsCap.ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SHA512) != 0) { + HashAlgId = TPM_ALG_SHA512; + CopyMem (DigestBuffer, &HashAlgId, sizeof(TPMI_ALG_HASH)); + DigestBuffer += sizeof(TPMI_ALG_HASH) + GetHashSizeFromAlgo (HashAlgId); + DigestListCount++; + } + + if ((mTcgDxeData.BsCap.ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SM3_256) != 0) { + HashAlgId = TPM_ALG_SM3_256; + CopyMem (DigestBuffer, &HashAlgId, sizeof(TPMI_ALG_HASH)); + DigestBuffer += sizeof(TPMI_ALG_HASH) + GetHashSizeFromAlgo (HashAlgId); + DigestListCount++; + } + + // + // Set Digests Count + // + WriteUnaligned32 ((UINT32 *)&NoActionEvent->Digests.count, DigestListCount); + + // + // Set Event Size + // + WriteUnaligned32((UINT32 *)DigestBuffer, EventSize); +} + +/** + + This function dump raw data with colume format. + + @param Data raw data + @param Size raw data size + +**/ +VOID +InternalDumpHex ( + IN UINT8 *Data, + IN UINTN Size + ) +{ + UINTN Index; + UINTN Count; + UINTN Left; + +#define COLUME_SIZE (16 * 2) + + Count = Size / COLUME_SIZE; + Left = Size % COLUME_SIZE; + for (Index = 0; Index < Count; Index++) { + DEBUG ((EFI_D_INFO, "%04x: ", Index * COLUME_SIZE)); + InternalDumpData (Data + Index * COLUME_SIZE, COLUME_SIZE); + DEBUG ((EFI_D_INFO, "\n")); + } + + if (Left != 0) { + DEBUG ((EFI_D_INFO, "%04x: ", Index * COLUME_SIZE)); + InternalDumpData (Data + Index * COLUME_SIZE, Left); + DEBUG ((EFI_D_INFO, "\n")); + } +} + +/** + Get All processors EFI_CPU_LOCATION in system. LocationBuf is allocated inside the function + Caller is responsible to free LocationBuf. + + @param[out] LocationBuf Returns Processor Location Buffer. + @param[out] Num Returns processor number. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_UNSUPPORTED MpService protocol not found. + +**/ +EFI_STATUS +GetProcessorsCpuLocation ( + OUT EFI_CPU_PHYSICAL_LOCATION **LocationBuf, + OUT UINTN *Num + ) +{ + EFI_STATUS Status; + EFI_MP_SERVICES_PROTOCOL *MpProtocol; + UINTN ProcessorNum; + UINTN EnabledProcessorNum; + EFI_PROCESSOR_INFORMATION ProcessorInfo; + EFI_CPU_PHYSICAL_LOCATION *ProcessorLocBuf; + UINTN Index; + + Status = gBS->LocateProtocol (&gEfiMpServiceProtocolGuid, NULL, (VOID **) &MpProtocol); + if (EFI_ERROR (Status)) { + // + // MP protocol is not installed + // + return EFI_UNSUPPORTED; + } + + Status = MpProtocol->GetNumberOfProcessors( + MpProtocol, + &ProcessorNum, + &EnabledProcessorNum + ); + if (EFI_ERROR(Status)){ + return Status; + } + + Status = gBS->AllocatePool( + EfiBootServicesData, + sizeof(EFI_CPU_PHYSICAL_LOCATION) * ProcessorNum, + (VOID **) &ProcessorLocBuf + ); + if (EFI_ERROR(Status)){ + return Status; + } + + // + // Get each processor Location info + // + for (Index = 0; Index < ProcessorNum; Index++) { + Status = MpProtocol->GetProcessorInfo( + MpProtocol, + Index, + &ProcessorInfo + ); + if (EFI_ERROR(Status)){ + FreePool(ProcessorLocBuf); + return Status; + } + + // + // Get all Processor Location info & measure + // + CopyMem( + &ProcessorLocBuf[Index], + &ProcessorInfo.Location, + sizeof(EFI_CPU_PHYSICAL_LOCATION) + ); + } + + *LocationBuf = ProcessorLocBuf; + *Num = ProcessorNum; + + return Status; +} + +/** + The EFI_TCG2_PROTOCOL GetCapability function call provides protocol + capability information and state information. + + @param[in] This Indicates the calling context + @param[in, out] ProtocolCapability The caller allocates memory for a EFI_TCG2_BOOT_SERVICE_CAPABILITY + structure and sets the size field to the size of the structure allocated. + The callee fills in the fields with the EFI protocol capability information + and the current EFI TCG2 state information up to the number of fields which + fit within the size of the structure passed in. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR The command was unsuccessful. + The ProtocolCapability variable will not be populated. + @retval EFI_INVALID_PARAMETER One or more of the parameters are incorrect. + The ProtocolCapability variable will not be populated. + @retval EFI_BUFFER_TOO_SMALL The ProtocolCapability variable is too small to hold the full response. + It will be partially populated (required Size field will be set). +**/ +EFI_STATUS +EFIAPI +Tcg2GetCapability ( + IN EFI_TCG2_PROTOCOL *This, + IN OUT EFI_TCG2_BOOT_SERVICE_CAPABILITY *ProtocolCapability + ) +{ + DEBUG ((DEBUG_VERBOSE, "Tcg2GetCapability ...\n")); + + if ((This == NULL) || (ProtocolCapability == NULL)) { + return EFI_INVALID_PARAMETER; + } + + DEBUG ((DEBUG_VERBOSE, "Size - 0x%x\n", ProtocolCapability->Size)); + DEBUG ((DEBUG_VERBOSE, " 1.1 - 0x%x, 1.0 - 0x%x\n", sizeof(EFI_TCG2_BOOT_SERVICE_CAPABILITY), sizeof(TREE_BOOT_SERVICE_CAPABILITY_1_0))); + + if (ProtocolCapability->Size < mTcgDxeData.BsCap.Size) { + // + // Handle the case that firmware support 1.1 but OS only support 1.0. + // + if ((mTcgDxeData.BsCap.ProtocolVersion.Major > 0x01) || + ((mTcgDxeData.BsCap.ProtocolVersion.Major == 0x01) && ((mTcgDxeData.BsCap.ProtocolVersion.Minor > 0x00)))) { + if (ProtocolCapability->Size >= sizeof(TREE_BOOT_SERVICE_CAPABILITY_1_0)) { + CopyMem (ProtocolCapability, &mTcgDxeData.BsCap, sizeof(TREE_BOOT_SERVICE_CAPABILITY_1_0)); + ProtocolCapability->Size = sizeof(TREE_BOOT_SERVICE_CAPABILITY_1_0); + ProtocolCapability->StructureVersion.Major = 1; + ProtocolCapability->StructureVersion.Minor = 0; + ProtocolCapability->ProtocolVersion.Major = 1; + ProtocolCapability->ProtocolVersion.Minor = 0; + DEBUG ((EFI_D_ERROR, "TreeGetCapability (Compatible) - %r\n", EFI_SUCCESS)); + return EFI_SUCCESS; + } + } + ProtocolCapability->Size = mTcgDxeData.BsCap.Size; + return EFI_BUFFER_TOO_SMALL; + } + + CopyMem (ProtocolCapability, &mTcgDxeData.BsCap, mTcgDxeData.BsCap.Size); + DEBUG ((DEBUG_VERBOSE, "Tcg2GetCapability - %r\n", EFI_SUCCESS)); + return EFI_SUCCESS; +} + +/** + This function dump PCR event. + + @param[in] EventHdr TCG PCR event structure. +**/ +VOID +DumpEvent ( + IN TCG_PCR_EVENT_HDR *EventHdr + ) +{ + UINTN Index; + + DEBUG ((EFI_D_INFO, " Event:\n")); + DEBUG ((EFI_D_INFO, " PCRIndex - %d\n", EventHdr->PCRIndex)); + DEBUG ((EFI_D_INFO, " EventType - 0x%08x\n", EventHdr->EventType)); + DEBUG ((EFI_D_INFO, " Digest - ")); + for (Index = 0; Index < sizeof(TCG_DIGEST); Index++) { + DEBUG ((EFI_D_INFO, "%02x ", EventHdr->Digest.digest[Index])); + } + DEBUG ((EFI_D_INFO, "\n")); + DEBUG ((EFI_D_INFO, " EventSize - 0x%08x\n", EventHdr->EventSize)); + InternalDumpHex ((UINT8 *)(EventHdr + 1), EventHdr->EventSize); +} + +/** + This function dump TCG_EfiSpecIDEventStruct. + + @param[in] TcgEfiSpecIdEventStruct A pointer to TCG_EfiSpecIDEventStruct. +**/ +VOID +DumpTcgEfiSpecIdEventStruct ( + IN TCG_EfiSpecIDEventStruct *TcgEfiSpecIdEventStruct + ) +{ + TCG_EfiSpecIdEventAlgorithmSize *DigestSize; + UINTN Index; + UINT8 *VendorInfoSize; + UINT8 *VendorInfo; + UINT32 NumberOfAlgorithms; + + DEBUG ((EFI_D_INFO, " TCG_EfiSpecIDEventStruct:\n")); + DEBUG ((EFI_D_INFO, " signature - '")); + for (Index = 0; Index < sizeof(TcgEfiSpecIdEventStruct->signature); Index++) { + DEBUG ((EFI_D_INFO, "%c", TcgEfiSpecIdEventStruct->signature[Index])); + } + DEBUG ((EFI_D_INFO, "'\n")); + DEBUG ((EFI_D_INFO, " platformClass - 0x%08x\n", TcgEfiSpecIdEventStruct->platformClass)); + DEBUG ((EFI_D_INFO, " specVersion - %d.%d%d\n", TcgEfiSpecIdEventStruct->specVersionMajor, TcgEfiSpecIdEventStruct->specVersionMinor, TcgEfiSpecIdEventStruct->specErrata)); + DEBUG ((EFI_D_INFO, " uintnSize - 0x%02x\n", TcgEfiSpecIdEventStruct->uintnSize)); + + CopyMem (&NumberOfAlgorithms, TcgEfiSpecIdEventStruct + 1, sizeof(NumberOfAlgorithms)); + DEBUG ((EFI_D_INFO, " NumberOfAlgorithms - 0x%08x\n", NumberOfAlgorithms)); + + DigestSize = (TCG_EfiSpecIdEventAlgorithmSize *)((UINT8 *)TcgEfiSpecIdEventStruct + sizeof(*TcgEfiSpecIdEventStruct) + sizeof(NumberOfAlgorithms)); + for (Index = 0; Index < NumberOfAlgorithms; Index++) { + DEBUG ((EFI_D_INFO, " digest(%d)\n", Index)); + DEBUG ((EFI_D_INFO, " algorithmId - 0x%04x\n", DigestSize[Index].algorithmId)); + DEBUG ((EFI_D_INFO, " digestSize - 0x%04x\n", DigestSize[Index].digestSize)); + } + VendorInfoSize = (UINT8 *)&DigestSize[NumberOfAlgorithms]; + DEBUG ((EFI_D_INFO, " VendorInfoSize - 0x%02x\n", *VendorInfoSize)); + VendorInfo = VendorInfoSize + 1; + DEBUG ((EFI_D_INFO, " VendorInfo - ")); + for (Index = 0; Index < *VendorInfoSize; Index++) { + DEBUG ((EFI_D_INFO, "%02x ", VendorInfo[Index])); + } + DEBUG ((EFI_D_INFO, "\n")); +} + +/** + This function get size of TCG_EfiSpecIDEventStruct. + + @param[in] TcgEfiSpecIdEventStruct A pointer to TCG_EfiSpecIDEventStruct. +**/ +UINTN +GetTcgEfiSpecIdEventStructSize ( + IN TCG_EfiSpecIDEventStruct *TcgEfiSpecIdEventStruct + ) +{ + TCG_EfiSpecIdEventAlgorithmSize *DigestSize; + UINT8 *VendorInfoSize; + UINT32 NumberOfAlgorithms; + + CopyMem (&NumberOfAlgorithms, TcgEfiSpecIdEventStruct + 1, sizeof(NumberOfAlgorithms)); + + DigestSize = (TCG_EfiSpecIdEventAlgorithmSize *)((UINT8 *)TcgEfiSpecIdEventStruct + sizeof(*TcgEfiSpecIdEventStruct) + sizeof(NumberOfAlgorithms)); + VendorInfoSize = (UINT8 *)&DigestSize[NumberOfAlgorithms]; + return sizeof(TCG_EfiSpecIDEventStruct) + sizeof(UINT32) + (NumberOfAlgorithms * sizeof(TCG_EfiSpecIdEventAlgorithmSize)) + sizeof(UINT8) + (*VendorInfoSize); +} + +/** + This function dump PCR event 2. + + @param[in] TcgPcrEvent2 TCG PCR event 2 structure. +**/ +VOID +DumpEvent2 ( + IN TCG_PCR_EVENT2 *TcgPcrEvent2 + ) +{ + UINTN Index; + UINT32 DigestIndex; + UINT32 DigestCount; + TPMI_ALG_HASH HashAlgo; + UINT32 DigestSize; + UINT8 *DigestBuffer; + UINT32 EventSize; + UINT8 *EventBuffer; + + DEBUG ((EFI_D_INFO, " Event:\n")); + DEBUG ((EFI_D_INFO, " PCRIndex - %d\n", TcgPcrEvent2->PCRIndex)); + DEBUG ((EFI_D_INFO, " EventType - 0x%08x\n", TcgPcrEvent2->EventType)); + + DEBUG ((EFI_D_INFO, " DigestCount: 0x%08x\n", TcgPcrEvent2->Digest.count)); + + DigestCount = TcgPcrEvent2->Digest.count; + HashAlgo = TcgPcrEvent2->Digest.digests[0].hashAlg; + DigestBuffer = (UINT8 *)&TcgPcrEvent2->Digest.digests[0].digest; + for (DigestIndex = 0; DigestIndex < DigestCount; DigestIndex++) { + DEBUG ((EFI_D_INFO, " HashAlgo : 0x%04x\n", HashAlgo)); + DEBUG ((EFI_D_INFO, " Digest(%d): ", DigestIndex)); + DigestSize = GetHashSizeFromAlgo (HashAlgo); + for (Index = 0; Index < DigestSize; Index++) { + DEBUG ((EFI_D_INFO, "%02x ", DigestBuffer[Index])); + } + DEBUG ((EFI_D_INFO, "\n")); + // + // Prepare next + // + CopyMem (&HashAlgo, DigestBuffer + DigestSize, sizeof(TPMI_ALG_HASH)); + DigestBuffer = DigestBuffer + DigestSize + sizeof(TPMI_ALG_HASH); + } + DEBUG ((EFI_D_INFO, "\n")); + DigestBuffer = DigestBuffer - sizeof(TPMI_ALG_HASH); + + CopyMem (&EventSize, DigestBuffer, sizeof(TcgPcrEvent2->EventSize)); + DEBUG ((EFI_D_INFO, " EventSize - 0x%08x\n", EventSize)); + EventBuffer = DigestBuffer + sizeof(TcgPcrEvent2->EventSize); + InternalDumpHex (EventBuffer, EventSize); +} + +/** + This function returns size of TCG PCR event 2. + + @param[in] TcgPcrEvent2 TCG PCR event 2 structure. + + @return size of TCG PCR event 2. +**/ +UINTN +GetPcrEvent2Size ( + IN TCG_PCR_EVENT2 *TcgPcrEvent2 + ) +{ + UINT32 DigestIndex; + UINT32 DigestCount; + TPMI_ALG_HASH HashAlgo; + UINT32 DigestSize; + UINT8 *DigestBuffer; + UINT32 EventSize; + UINT8 *EventBuffer; + + DigestCount = TcgPcrEvent2->Digest.count; + HashAlgo = TcgPcrEvent2->Digest.digests[0].hashAlg; + DigestBuffer = (UINT8 *)&TcgPcrEvent2->Digest.digests[0].digest; + for (DigestIndex = 0; DigestIndex < DigestCount; DigestIndex++) { + DigestSize = GetHashSizeFromAlgo (HashAlgo); + // + // Prepare next + // + CopyMem (&HashAlgo, DigestBuffer + DigestSize, sizeof(TPMI_ALG_HASH)); + DigestBuffer = DigestBuffer + DigestSize + sizeof(TPMI_ALG_HASH); + } + DigestBuffer = DigestBuffer - sizeof(TPMI_ALG_HASH); + + CopyMem (&EventSize, DigestBuffer, sizeof(TcgPcrEvent2->EventSize)); + EventBuffer = DigestBuffer + sizeof(TcgPcrEvent2->EventSize); + + return (UINTN)EventBuffer + EventSize - (UINTN)TcgPcrEvent2; +} + +/** + This function dump event log. + + @param[in] EventLogFormat The type of the event log for which the information is requested. + @param[in] EventLogLocation A pointer to the memory address of the event log. + @param[in] EventLogLastEntry If the Event Log contains more than one entry, this is a pointer to the + address of the start of the last entry in the event log in memory. + @param[in] FinalEventsTable A pointer to the memory address of the final event table. +**/ +VOID +DumpEventLog ( + IN EFI_TCG2_EVENT_LOG_FORMAT EventLogFormat, + IN EFI_PHYSICAL_ADDRESS EventLogLocation, + IN EFI_PHYSICAL_ADDRESS EventLogLastEntry, + IN EFI_TCG2_FINAL_EVENTS_TABLE *FinalEventsTable + ) +{ + TCG_PCR_EVENT_HDR *EventHdr; + TCG_PCR_EVENT2 *TcgPcrEvent2; + TCG_EfiSpecIDEventStruct *TcgEfiSpecIdEventStruct; + UINTN NumberOfEvents; + + DEBUG ((EFI_D_INFO, "EventLogFormat: (0x%x)\n", EventLogFormat)); + + switch (EventLogFormat) { + case EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2: + EventHdr = (TCG_PCR_EVENT_HDR *)(UINTN)EventLogLocation; + while ((UINTN)EventHdr <= EventLogLastEntry) { + DumpEvent (EventHdr); + EventHdr = (TCG_PCR_EVENT_HDR *)((UINTN)EventHdr + sizeof(TCG_PCR_EVENT_HDR) + EventHdr->EventSize); + } + if (FinalEventsTable == NULL) { + DEBUG ((EFI_D_INFO, "FinalEventsTable: NOT FOUND\n")); + } else { + DEBUG ((EFI_D_INFO, "FinalEventsTable: (0x%x)\n", FinalEventsTable)); + DEBUG ((EFI_D_INFO, " Version: (0x%x)\n", FinalEventsTable->Version)); + DEBUG ((EFI_D_INFO, " NumberOfEvents: (0x%x)\n", FinalEventsTable->NumberOfEvents)); + + EventHdr = (TCG_PCR_EVENT_HDR *)(UINTN)(FinalEventsTable + 1); + for (NumberOfEvents = 0; NumberOfEvents < FinalEventsTable->NumberOfEvents; NumberOfEvents++) { + DumpEvent (EventHdr); + EventHdr = (TCG_PCR_EVENT_HDR *)((UINTN)EventHdr + sizeof(TCG_PCR_EVENT_HDR) + EventHdr->EventSize); + } + } + break; + case EFI_TCG2_EVENT_LOG_FORMAT_TCG_2: + // + // Dump first event + // + EventHdr = (TCG_PCR_EVENT_HDR *)(UINTN)EventLogLocation; + DumpEvent (EventHdr); + + TcgEfiSpecIdEventStruct = (TCG_EfiSpecIDEventStruct *)(EventHdr + 1); + DumpTcgEfiSpecIdEventStruct (TcgEfiSpecIdEventStruct); + + TcgPcrEvent2 = (TCG_PCR_EVENT2 *)((UINTN)TcgEfiSpecIdEventStruct + GetTcgEfiSpecIdEventStructSize (TcgEfiSpecIdEventStruct)); + while ((UINTN)TcgPcrEvent2 <= EventLogLastEntry) { + DumpEvent2 (TcgPcrEvent2); + TcgPcrEvent2 = (TCG_PCR_EVENT2 *)((UINTN)TcgPcrEvent2 + GetPcrEvent2Size (TcgPcrEvent2)); + } + + if (FinalEventsTable == NULL) { + DEBUG ((EFI_D_INFO, "FinalEventsTable: NOT FOUND\n")); + } else { + DEBUG ((EFI_D_INFO, "FinalEventsTable: (0x%x)\n", FinalEventsTable)); + DEBUG ((EFI_D_INFO, " Version: (0x%x)\n", FinalEventsTable->Version)); + DEBUG ((EFI_D_INFO, " NumberOfEvents: (0x%x)\n", FinalEventsTable->NumberOfEvents)); + + TcgPcrEvent2 = (TCG_PCR_EVENT2 *)(UINTN)(FinalEventsTable + 1); + for (NumberOfEvents = 0; NumberOfEvents < FinalEventsTable->NumberOfEvents; NumberOfEvents++) { + DumpEvent2 (TcgPcrEvent2); + TcgPcrEvent2 = (TCG_PCR_EVENT2 *)((UINTN)TcgPcrEvent2 + GetPcrEvent2Size (TcgPcrEvent2)); + } + } + break; + } + + return ; +} + +/** + The EFI_TCG2_PROTOCOL Get Event Log function call allows a caller to + retrieve the address of a given event log and its last entry. + + @param[in] This Indicates the calling context + @param[in] EventLogFormat The type of the event log for which the information is requested. + @param[out] EventLogLocation A pointer to the memory address of the event log. + @param[out] EventLogLastEntry If the Event Log contains more than one entry, this is a pointer to the + address of the start of the last entry in the event log in memory. + @param[out] EventLogTruncated If the Event Log is missing at least one entry because an event would + have exceeded the area allocated for events, this value is set to TRUE. + Otherwise, the value will be FALSE and the Event Log will be complete. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_INVALID_PARAMETER One or more of the parameters are incorrect + (e.g. asking for an event log whose format is not supported). +**/ +EFI_STATUS +EFIAPI +Tcg2GetEventLog ( + IN EFI_TCG2_PROTOCOL *This, + IN EFI_TCG2_EVENT_LOG_FORMAT EventLogFormat, + OUT EFI_PHYSICAL_ADDRESS *EventLogLocation, + OUT EFI_PHYSICAL_ADDRESS *EventLogLastEntry, + OUT BOOLEAN *EventLogTruncated + ) +{ + UINTN Index; + + DEBUG ((EFI_D_INFO, "Tcg2GetEventLog ... (0x%x)\n", EventLogFormat)); + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + for (Index = 0; Index < sizeof(mTcg2EventInfo)/sizeof(mTcg2EventInfo[0]); Index++) { + if (EventLogFormat == mTcg2EventInfo[Index].LogFormat) { + break; + } + } + + if (Index == sizeof(mTcg2EventInfo)/sizeof(mTcg2EventInfo[0])) { + return EFI_INVALID_PARAMETER; + } + + if ((mTcg2EventInfo[Index].LogFormat & mTcgDxeData.BsCap.SupportedEventLogs) == 0) { + return EFI_INVALID_PARAMETER; + } + + if (!mTcgDxeData.BsCap.TPMPresentFlag) { + if (EventLogLocation != NULL) { + *EventLogLocation = 0; + } + if (EventLogLastEntry != NULL) { + *EventLogLastEntry = 0; + } + if (EventLogTruncated != NULL) { + *EventLogTruncated = FALSE; + } + return EFI_SUCCESS; + } + + if (EventLogLocation != NULL) { + *EventLogLocation = mTcgDxeData.EventLogAreaStruct[Index].Lasa; + DEBUG ((EFI_D_INFO, "Tcg2GetEventLog (EventLogLocation - %x)\n", *EventLogLocation)); + } + + if (EventLogLastEntry != NULL) { + if (!mTcgDxeData.EventLogAreaStruct[Index].EventLogStarted) { + *EventLogLastEntry = (EFI_PHYSICAL_ADDRESS)(UINTN)0; + } else { + *EventLogLastEntry = (EFI_PHYSICAL_ADDRESS)(UINTN)mTcgDxeData.EventLogAreaStruct[Index].LastEvent; + } + DEBUG ((EFI_D_INFO, "Tcg2GetEventLog (EventLogLastEntry - %x)\n", *EventLogLastEntry)); + } + + if (EventLogTruncated != NULL) { + *EventLogTruncated = mTcgDxeData.EventLogAreaStruct[Index].EventLogTruncated; + DEBUG ((EFI_D_INFO, "Tcg2GetEventLog (EventLogTruncated - %x)\n", *EventLogTruncated)); + } + + DEBUG ((EFI_D_INFO, "Tcg2GetEventLog - %r\n", EFI_SUCCESS)); + + // Dump Event Log for debug purpose + if ((EventLogLocation != NULL) && (EventLogLastEntry != NULL)) { + DumpEventLog (EventLogFormat, *EventLogLocation, *EventLogLastEntry, mTcgDxeData.FinalEventsTable[Index]); + } + + // + // All events generated after the invocation of EFI_TCG2_GET_EVENT_LOG SHALL be stored + // in an instance of an EFI_CONFIGURATION_TABLE named by the VendorGuid of EFI_TCG2_FINAL_EVENTS_TABLE_GUID. + // + mTcgDxeData.GetEventLogCalled[Index] = TRUE; + + return EFI_SUCCESS; +} + +/** + Add a new entry to the Event Log. + + @param[in, out] EventLogPtr Pointer to the Event Log data. + @param[in, out] LogSize Size of the Event Log. + @param[in] MaxSize Maximum size of the Event Log. + @param[in] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR/TCG_PCR_EVENT_EX data structure. + @param[in] NewEventHdrSize New event header size. + @param[in] NewEventData Pointer to the new event data. + @param[in] NewEventSize New event data size. + + @retval EFI_SUCCESS The new event log entry was added. + @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event. + +**/ +EFI_STATUS +TcgCommLogEvent ( + IN OUT UINT8 **EventLogPtr, + IN OUT UINTN *LogSize, + IN UINTN MaxSize, + IN VOID *NewEventHdr, + IN UINT32 NewEventHdrSize, + IN UINT8 *NewEventData, + IN UINT32 NewEventSize + ) +{ + UINTN NewLogSize; + + if (NewEventSize > MAX_ADDRESS - NewEventHdrSize) { + return EFI_OUT_OF_RESOURCES; + } + + NewLogSize = NewEventHdrSize + NewEventSize; + + if (NewLogSize > MAX_ADDRESS - *LogSize) { + return EFI_OUT_OF_RESOURCES; + } + + if (NewLogSize + *LogSize > MaxSize) { + DEBUG ((EFI_D_INFO, " MaxSize - 0x%x\n", MaxSize)); + DEBUG ((EFI_D_INFO, " NewLogSize - 0x%x\n", NewLogSize)); + DEBUG ((EFI_D_INFO, " LogSize - 0x%x\n", *LogSize)); + DEBUG ((EFI_D_INFO, "TcgCommLogEvent - %r\n", EFI_OUT_OF_RESOURCES)); + return EFI_OUT_OF_RESOURCES; + } + + *EventLogPtr += *LogSize; + *LogSize += NewLogSize; + CopyMem (*EventLogPtr, NewEventHdr, NewEventHdrSize); + CopyMem ( + *EventLogPtr + NewEventHdrSize, + NewEventData, + NewEventSize + ); + return EFI_SUCCESS; +} + +/** + Add a new entry to the Event Log. + + @param[in] EventLogFormat The type of the event log for which the information is requested. + @param[in] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR/TCG_PCR_EVENT_EX data structure. + @param[in] NewEventHdrSize New event header size. + @param[in] NewEventData Pointer to the new event data. + @param[in] NewEventSize New event data size. + + @retval EFI_SUCCESS The new event log entry was added. + @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event. + +**/ +EFI_STATUS +TcgDxeLogEvent ( + IN EFI_TCG2_EVENT_LOG_FORMAT EventLogFormat, + IN VOID *NewEventHdr, + IN UINT32 NewEventHdrSize, + IN UINT8 *NewEventData, + IN UINT32 NewEventSize + ) +{ + EFI_STATUS Status; + UINTN Index; + TCG_EVENT_LOG_AREA_STRUCT *EventLogAreaStruct; + + for (Index = 0; Index < sizeof(mTcg2EventInfo)/sizeof(mTcg2EventInfo[0]); Index++) { + if (EventLogFormat == mTcg2EventInfo[Index].LogFormat) { + break; + } + } + + if (Index == sizeof(mTcg2EventInfo)/sizeof(mTcg2EventInfo[0])) { + return EFI_INVALID_PARAMETER; + } + + // + // Record to normal event log + // + EventLogAreaStruct = &mTcgDxeData.EventLogAreaStruct[Index]; + + if (EventLogAreaStruct->EventLogTruncated) { + return EFI_VOLUME_FULL; + } + + EventLogAreaStruct->LastEvent = (UINT8*)(UINTN)EventLogAreaStruct->Lasa; + Status = TcgCommLogEvent ( + &EventLogAreaStruct->LastEvent, + &EventLogAreaStruct->EventLogSize, + (UINTN)EventLogAreaStruct->Laml, + NewEventHdr, + NewEventHdrSize, + NewEventData, + NewEventSize + ); + + if (Status == EFI_OUT_OF_RESOURCES) { + EventLogAreaStruct->EventLogTruncated = TRUE; + return EFI_VOLUME_FULL; + } else if (Status == EFI_SUCCESS) { + EventLogAreaStruct->EventLogStarted = TRUE; + } + + // + // If GetEventLog is called, record to FinalEventsTable, too. + // + if (mTcgDxeData.GetEventLogCalled[Index]) { + if (mTcgDxeData.FinalEventsTable[Index] == NULL) { + // + // no need for FinalEventsTable + // + return EFI_SUCCESS; + } + EventLogAreaStruct = &mTcgDxeData.FinalEventLogAreaStruct[Index]; + + if (EventLogAreaStruct->EventLogTruncated) { + return EFI_VOLUME_FULL; + } + + EventLogAreaStruct->LastEvent = (UINT8*)(UINTN)EventLogAreaStruct->Lasa; + Status = TcgCommLogEvent ( + &EventLogAreaStruct->LastEvent, + &EventLogAreaStruct->EventLogSize, + (UINTN)EventLogAreaStruct->Laml, + NewEventHdr, + NewEventHdrSize, + NewEventData, + NewEventSize + ); + if (Status == EFI_OUT_OF_RESOURCES) { + EventLogAreaStruct->EventLogTruncated = TRUE; + return EFI_VOLUME_FULL; + } else if (Status == EFI_SUCCESS) { + EventLogAreaStruct->EventLogStarted = TRUE; + // + // Increase the NumberOfEvents in FinalEventsTable + // + (mTcgDxeData.FinalEventsTable[Index])->NumberOfEvents ++; + DEBUG ((EFI_D_INFO, "FinalEventsTable->NumberOfEvents - 0x%x\n", (mTcgDxeData.FinalEventsTable[Index])->NumberOfEvents)); + DEBUG ((EFI_D_INFO, " Size - 0x%x\n", (UINTN)EventLogAreaStruct->EventLogSize)); + } + } + + return Status; +} + +/** + Get TPML_DIGEST_VALUES compact binary buffer size. + + @param[in] DigestListBin TPML_DIGEST_VALUES compact binary buffer. + + @return TPML_DIGEST_VALUES compact binary buffer size. +**/ +UINT32 +GetDigestListBinSize ( + IN VOID *DigestListBin + ) +{ + UINTN Index; + UINT16 DigestSize; + UINT32 TotalSize; + UINT32 Count; + TPMI_ALG_HASH HashAlg; + + Count = ReadUnaligned32 (DigestListBin); + TotalSize = sizeof(Count); + DigestListBin = (UINT8 *)DigestListBin + sizeof(Count); + for (Index = 0; Index < Count; Index++) { + HashAlg = ReadUnaligned16 (DigestListBin); + TotalSize += sizeof(HashAlg); + DigestListBin = (UINT8 *)DigestListBin + sizeof(HashAlg); + + DigestSize = GetHashSizeFromAlgo (HashAlg); + TotalSize += DigestSize; + DigestListBin = (UINT8 *)DigestListBin + DigestSize; + } + + return TotalSize; +} + +/** + Copy TPML_DIGEST_VALUES compact binary into a buffer + + @param[in,out] Buffer Buffer to hold copied TPML_DIGEST_VALUES compact binary. + @param[in] DigestListBin TPML_DIGEST_VALUES compact binary buffer. + @param[in] HashAlgorithmMask HASH bits corresponding to the desired digests to copy. + @param[out] HashAlgorithmMaskCopied Pointer to HASH bits corresponding to the digests copied. + + @return The end of buffer to hold TPML_DIGEST_VALUES compact binary. +**/ +VOID * +CopyDigestListBinToBuffer ( + IN OUT VOID *Buffer, + IN VOID *DigestListBin, + IN UINT32 HashAlgorithmMask, + OUT UINT32 *HashAlgorithmMaskCopied + ) +{ + UINTN Index; + UINT16 DigestSize; + UINT32 Count; + TPMI_ALG_HASH HashAlg; + UINT32 DigestListCount; + UINT32 *DigestListCountPtr; + + DigestListCountPtr = (UINT32 *) Buffer; + DigestListCount = 0; + (*HashAlgorithmMaskCopied) = 0; + + Count = ReadUnaligned32 (DigestListBin); + Buffer = (UINT8 *)Buffer + sizeof(Count); + DigestListBin = (UINT8 *)DigestListBin + sizeof(Count); + for (Index = 0; Index < Count; Index++) { + HashAlg = ReadUnaligned16 (DigestListBin); + DigestListBin = (UINT8 *)DigestListBin + sizeof(HashAlg); + DigestSize = GetHashSizeFromAlgo (HashAlg); + + if (IsHashAlgSupportedInHashAlgorithmMask(HashAlg, HashAlgorithmMask)) { + CopyMem (Buffer, &HashAlg, sizeof(HashAlg)); + Buffer = (UINT8 *)Buffer + sizeof(HashAlg); + CopyMem (Buffer, DigestListBin, DigestSize); + Buffer = (UINT8 *)Buffer + DigestSize; + DigestListCount++; + (*HashAlgorithmMaskCopied) |= GetHashMaskFromAlgo (HashAlg); + } else { + DEBUG ((DEBUG_ERROR, "WARNING: CopyDigestListBinToBuffer Event log has HashAlg unsupported by PCR bank (0x%x)\n", HashAlg)); + } + DigestListBin = (UINT8 *)DigestListBin + DigestSize; + } + WriteUnaligned32 (DigestListCountPtr, DigestListCount); + + return Buffer; +} + +/** + Add a new entry to the Event Log. + + @param[in] DigestList A list of digest. + @param[in,out] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR data structure. + @param[in] NewEventData Pointer to the new event data. + + @retval EFI_SUCCESS The new event log entry was added. + @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event. +**/ +EFI_STATUS +TcgDxeLogHashEvent ( + IN TPML_DIGEST_VALUES *DigestList, + IN OUT TCG_PCR_EVENT_HDR *NewEventHdr, + IN UINT8 *NewEventData + ) +{ + EFI_STATUS Status; + EFI_TPL OldTpl; + UINTN Index; + EFI_STATUS RetStatus; + TCG_PCR_EVENT2 TcgPcrEvent2; + UINT8 *DigestBuffer; + UINT32 *EventSizePtr; + + DEBUG ((EFI_D_INFO, "SupportedEventLogs - 0x%08x\n", mTcgDxeData.BsCap.SupportedEventLogs)); + + RetStatus = EFI_SUCCESS; + for (Index = 0; Index < sizeof(mTcg2EventInfo)/sizeof(mTcg2EventInfo[0]); Index++) { + if ((mTcgDxeData.BsCap.SupportedEventLogs & mTcg2EventInfo[Index].LogFormat) != 0) { + DEBUG ((EFI_D_INFO, " LogFormat - 0x%08x\n", mTcg2EventInfo[Index].LogFormat)); + switch (mTcg2EventInfo[Index].LogFormat) { + case EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2: + Status = GetDigestFromDigestList (TPM_ALG_SHA1, DigestList, &NewEventHdr->Digest); + if (!EFI_ERROR (Status)) { + // + // Enter critical region + // + OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL); + Status = TcgDxeLogEvent ( + mTcg2EventInfo[Index].LogFormat, + NewEventHdr, + sizeof(TCG_PCR_EVENT_HDR), + NewEventData, + NewEventHdr->EventSize + ); + if (Status != EFI_SUCCESS) { + RetStatus = Status; + } + gBS->RestoreTPL (OldTpl); + // + // Exit critical region + // + } + break; + case EFI_TCG2_EVENT_LOG_FORMAT_TCG_2: + ZeroMem (&TcgPcrEvent2, sizeof(TcgPcrEvent2)); + TcgPcrEvent2.PCRIndex = NewEventHdr->PCRIndex; + TcgPcrEvent2.EventType = NewEventHdr->EventType; + DigestBuffer = (UINT8 *)&TcgPcrEvent2.Digest; + EventSizePtr = CopyDigestListToBuffer (DigestBuffer, DigestList, mTcgDxeData.BsCap.ActivePcrBanks); + CopyMem (EventSizePtr, &NewEventHdr->EventSize, sizeof(NewEventHdr->EventSize)); + + // + // Enter critical region + // + OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL); + Status = TcgDxeLogEvent ( + mTcg2EventInfo[Index].LogFormat, + &TcgPcrEvent2, + sizeof(TcgPcrEvent2.PCRIndex) + sizeof(TcgPcrEvent2.EventType) + GetDigestListBinSize (DigestBuffer) + sizeof(TcgPcrEvent2.EventSize), + NewEventData, + NewEventHdr->EventSize + ); + if (Status != EFI_SUCCESS) { + RetStatus = Status; + } + gBS->RestoreTPL (OldTpl); + // + // Exit critical region + // + break; + } + } + } + + return RetStatus; +} + +/** + Do a hash operation on a data buffer, extend a specific TPM PCR with the hash result, + and add an entry to the Event Log. + + @param[in] Flags Bitmap providing additional information. + @param[in] HashData Physical address of the start of the data buffer + to be hashed, extended, and logged. + @param[in] HashDataLen The length, in bytes, of the buffer referenced by HashData + @param[in, out] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR data structure. + @param[in] NewEventData Pointer to the new event data. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event. + @retval EFI_DEVICE_ERROR The command was unsuccessful. + +**/ +EFI_STATUS +TcgDxeHashLogExtendEvent ( + IN UINT64 Flags, + IN UINT8 *HashData, + IN UINT64 HashDataLen, + IN OUT TCG_PCR_EVENT_HDR *NewEventHdr, + IN UINT8 *NewEventData + ) +{ + EFI_STATUS Status; + TPML_DIGEST_VALUES DigestList; + + if (!mTcgDxeData.BsCap.TPMPresentFlag) { + return EFI_DEVICE_ERROR; + } + + Status = HashAndExtend ( + NewEventHdr->PCRIndex, + HashData, + (UINTN)HashDataLen, + &DigestList + ); + if (!EFI_ERROR (Status)) { + if ((Flags & EFI_TCG2_EXTEND_ONLY) == 0) { + Status = TcgDxeLogHashEvent (&DigestList, NewEventHdr, NewEventData); + } + } + + if (Status == EFI_DEVICE_ERROR) { + DEBUG ((EFI_D_ERROR, "TcgDxeHashLogExtendEvent - %r. Disable TPM.\n", Status)); + mTcgDxeData.BsCap.TPMPresentFlag = FALSE; + REPORT_STATUS_CODE ( + EFI_ERROR_CODE | EFI_ERROR_MINOR, + (PcdGet32 (PcdStatusCodeSubClassTpmDevice) | EFI_P_EC_INTERFACE_ERROR) + ); + } + + return Status; +} + +/** + The EFI_TCG2_PROTOCOL HashLogExtendEvent function call provides callers with + an opportunity to extend and optionally log events without requiring + knowledge of actual TPM commands. + The extend operation will occur even if this function cannot create an event + log entry (e.g. due to the event log being full). + + @param[in] This Indicates the calling context + @param[in] Flags Bitmap providing additional information. + @param[in] DataToHash Physical address of the start of the data buffer to be hashed. + @param[in] DataToHashLen The length in bytes of the buffer referenced by DataToHash. + @param[in] Event Pointer to data buffer containing information about the event. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR The command was unsuccessful. + @retval EFI_VOLUME_FULL The extend operation occurred, but the event could not be written to one or more event logs. + @retval EFI_INVALID_PARAMETER One or more of the parameters are incorrect. + @retval EFI_UNSUPPORTED The PE/COFF image type is not supported. +**/ +EFI_STATUS +EFIAPI +Tcg2HashLogExtendEvent ( + IN EFI_TCG2_PROTOCOL *This, + IN UINT64 Flags, + IN EFI_PHYSICAL_ADDRESS DataToHash, + IN UINT64 DataToHashLen, + IN EFI_TCG2_EVENT *Event + ) +{ + EFI_STATUS Status; + TCG_PCR_EVENT_HDR NewEventHdr; + TPML_DIGEST_VALUES DigestList; + + DEBUG ((DEBUG_VERBOSE, "Tcg2HashLogExtendEvent ...\n")); + + if ((This == NULL) || (DataToHash == 0) || (Event == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if (!mTcgDxeData.BsCap.TPMPresentFlag) { + return EFI_DEVICE_ERROR; + } + + if (Event->Size < Event->Header.HeaderSize + sizeof(UINT32)) { + return EFI_INVALID_PARAMETER; + } + + if (Event->Header.PCRIndex > MAX_PCR_INDEX) { + return EFI_INVALID_PARAMETER; + } + + NewEventHdr.PCRIndex = Event->Header.PCRIndex; + NewEventHdr.EventType = Event->Header.EventType; + NewEventHdr.EventSize = Event->Size - sizeof(UINT32) - Event->Header.HeaderSize; + if ((Flags & PE_COFF_IMAGE) != 0) { + Status = MeasurePeImageAndExtend ( + NewEventHdr.PCRIndex, + DataToHash, + (UINTN)DataToHashLen, + &DigestList + ); + if (!EFI_ERROR (Status)) { + if ((Flags & EFI_TCG2_EXTEND_ONLY) == 0) { + Status = TcgDxeLogHashEvent (&DigestList, &NewEventHdr, Event->Event); + } + } + if (Status == EFI_DEVICE_ERROR) { + DEBUG ((EFI_D_ERROR, "MeasurePeImageAndExtend - %r. Disable TPM.\n", Status)); + mTcgDxeData.BsCap.TPMPresentFlag = FALSE; + REPORT_STATUS_CODE ( + EFI_ERROR_CODE | EFI_ERROR_MINOR, + (PcdGet32 (PcdStatusCodeSubClassTpmDevice) | EFI_P_EC_INTERFACE_ERROR) + ); + } + } else { + Status = TcgDxeHashLogExtendEvent ( + Flags, + (UINT8 *) (UINTN) DataToHash, + DataToHashLen, + &NewEventHdr, + Event->Event + ); + } + DEBUG ((DEBUG_VERBOSE, "Tcg2HashLogExtendEvent - %r\n", Status)); + return Status; +} + +/** + This service enables the sending of commands to the TPM. + + @param[in] This Indicates the calling context + @param[in] InputParameterBlockSize Size of the TPM input parameter block. + @param[in] InputParameterBlock Pointer to the TPM input parameter block. + @param[in] OutputParameterBlockSize Size of the TPM output parameter block. + @param[in] OutputParameterBlock Pointer to the TPM output parameter block. + + @retval EFI_SUCCESS The command byte stream was successfully sent to the device and a response was successfully received. + @retval EFI_DEVICE_ERROR The command was not successfully sent to the device or a response was not successfully received from the device. + @retval EFI_INVALID_PARAMETER One or more of the parameters are incorrect. + @retval EFI_BUFFER_TOO_SMALL The output parameter block is too small. +**/ +EFI_STATUS +EFIAPI +Tcg2SubmitCommand ( + IN EFI_TCG2_PROTOCOL *This, + IN UINT32 InputParameterBlockSize, + IN UINT8 *InputParameterBlock, + IN UINT32 OutputParameterBlockSize, + IN UINT8 *OutputParameterBlock + ) +{ + EFI_STATUS Status; + + DEBUG ((EFI_D_INFO, "Tcg2SubmitCommand ...\n")); + + if ((This == NULL) || + (InputParameterBlockSize == 0) || (InputParameterBlock == NULL) || + (OutputParameterBlockSize == 0) || (OutputParameterBlock == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if (!mTcgDxeData.BsCap.TPMPresentFlag) { + return EFI_DEVICE_ERROR; + } + + if (InputParameterBlockSize > mTcgDxeData.BsCap.MaxCommandSize) { + return EFI_INVALID_PARAMETER; + } + if (OutputParameterBlockSize > mTcgDxeData.BsCap.MaxResponseSize) { + return EFI_INVALID_PARAMETER; + } + + Status = Tpm2SubmitCommand ( + InputParameterBlockSize, + InputParameterBlock, + &OutputParameterBlockSize, + OutputParameterBlock + ); + DEBUG ((EFI_D_INFO, "Tcg2SubmitCommand - %r\n", Status)); + return Status; +} + +/** + This service returns the currently active PCR banks. + + @param[in] This Indicates the calling context + @param[out] ActivePcrBanks Pointer to the variable receiving the bitmap of currently active PCR banks. + + @retval EFI_SUCCESS The bitmap of active PCR banks was stored in the ActivePcrBanks parameter. + @retval EFI_INVALID_PARAMETER One or more of the parameters are incorrect. +**/ +EFI_STATUS +EFIAPI +Tcg2GetActivePCRBanks ( + IN EFI_TCG2_PROTOCOL *This, + OUT UINT32 *ActivePcrBanks + ) +{ + if (ActivePcrBanks == NULL) { + return EFI_INVALID_PARAMETER; + } + *ActivePcrBanks = mTcgDxeData.BsCap.ActivePcrBanks; + return EFI_SUCCESS; +} + +/** + This service sets the currently active PCR banks. + + @param[in] This Indicates the calling context + @param[in] ActivePcrBanks Bitmap of the requested active PCR banks. At least one bit SHALL be set. + + @retval EFI_SUCCESS The bitmap in ActivePcrBank parameter is already active. + @retval EFI_INVALID_PARAMETER One or more of the parameters are incorrect. +**/ +EFI_STATUS +EFIAPI +Tcg2SetActivePCRBanks ( + IN EFI_TCG2_PROTOCOL *This, + IN UINT32 ActivePcrBanks + ) +{ + EFI_STATUS Status; + UINT32 ReturnCode; + + DEBUG ((EFI_D_INFO, "Tcg2SetActivePCRBanks ... (0x%x)\n", ActivePcrBanks)); + + if (ActivePcrBanks == 0) { + return EFI_INVALID_PARAMETER; + } + if ((ActivePcrBanks & (~mTcgDxeData.BsCap.HashAlgorithmBitmap)) != 0) { + return EFI_INVALID_PARAMETER; + } + if (ActivePcrBanks == mTcgDxeData.BsCap.ActivePcrBanks) { + // + // Need clear previous SET_PCR_BANKS setting + // + ReturnCode = Tcg2PhysicalPresenceLibSubmitRequestToPreOSFunction (TCG2_PHYSICAL_PRESENCE_NO_ACTION, 0); + } else { + ReturnCode = Tcg2PhysicalPresenceLibSubmitRequestToPreOSFunction (TCG2_PHYSICAL_PRESENCE_SET_PCR_BANKS, ActivePcrBanks); + } + + if (ReturnCode == TCG_PP_SUBMIT_REQUEST_TO_PREOS_SUCCESS) { + Status = EFI_SUCCESS; + } else if (ReturnCode == TCG_PP_SUBMIT_REQUEST_TO_PREOS_GENERAL_FAILURE) { + Status = EFI_OUT_OF_RESOURCES; + } else if (ReturnCode == TCG_PP_SUBMIT_REQUEST_TO_PREOS_NOT_IMPLEMENTED) { + Status = EFI_UNSUPPORTED; + } else { + Status = EFI_DEVICE_ERROR; + } + + DEBUG ((EFI_D_INFO, "Tcg2SetActivePCRBanks - %r\n", Status)); + + return Status; +} + +/** + This service retrieves the result of a previous invocation of SetActivePcrBanks. + + @param[in] This Indicates the calling context + @param[out] OperationPresent Non-zero value to indicate a SetActivePcrBank operation was invoked during the last boot. + @param[out] Response The response from the SetActivePcrBank request. + + @retval EFI_SUCCESS The result value could be returned. + @retval EFI_INVALID_PARAMETER One or more of the parameters are incorrect. +**/ +EFI_STATUS +EFIAPI +Tcg2GetResultOfSetActivePcrBanks ( + IN EFI_TCG2_PROTOCOL *This, + OUT UINT32 *OperationPresent, + OUT UINT32 *Response + ) +{ + UINT32 ReturnCode; + + if ((OperationPresent == NULL) || (Response == NULL)) { + return EFI_INVALID_PARAMETER; + } + + ReturnCode = Tcg2PhysicalPresenceLibReturnOperationResponseToOsFunction (OperationPresent, Response); + if (ReturnCode == TCG_PP_RETURN_TPM_OPERATION_RESPONSE_SUCCESS) { + return EFI_SUCCESS; + } else { + return EFI_UNSUPPORTED; + } +} + +EFI_TCG2_PROTOCOL mTcg2Protocol = { + Tcg2GetCapability, + Tcg2GetEventLog, + Tcg2HashLogExtendEvent, + Tcg2SubmitCommand, + Tcg2GetActivePCRBanks, + Tcg2SetActivePCRBanks, + Tcg2GetResultOfSetActivePcrBanks, +}; + +/** + Initialize the Event Log and log events passed from the PEI phase. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_OUT_OF_RESOURCES Out of memory. + +**/ +EFI_STATUS +SetupEventLog ( + VOID + ) +{ + EFI_STATUS Status; + VOID *TcgEvent; + EFI_PEI_HOB_POINTERS GuidHob; + EFI_PHYSICAL_ADDRESS Lasa; + UINTN Index; + VOID *DigestListBin; + TPML_DIGEST_VALUES TempDigestListBin; + UINT32 DigestListBinSize; + UINT8 *Event; + UINT32 EventSize; + UINT32 *EventSizePtr; + UINT32 HashAlgorithmMaskCopied; + TCG_EfiSpecIDEventStruct *TcgEfiSpecIdEventStruct; + UINT8 TempBuf[sizeof(TCG_EfiSpecIDEventStruct) + sizeof(UINT32) + (HASH_COUNT * sizeof(TCG_EfiSpecIdEventAlgorithmSize)) + sizeof(UINT8)]; + TCG_PCR_EVENT_HDR SpecIdEvent; + TCG_PCR_EVENT2_HDR NoActionEvent; + TCG_EfiSpecIdEventAlgorithmSize *DigestSize; + TCG_EfiSpecIdEventAlgorithmSize *TempDigestSize; + UINT8 *VendorInfoSize; + UINT32 NumberOfAlgorithms; + TCG_EfiStartupLocalityEvent StartupLocalityEvent; + + DEBUG ((EFI_D_INFO, "SetupEventLog\n")); + + // + // 1. Create Log Area + // + for (Index = 0; Index < sizeof(mTcg2EventInfo)/sizeof(mTcg2EventInfo[0]); Index++) { + if ((mTcgDxeData.BsCap.SupportedEventLogs & mTcg2EventInfo[Index].LogFormat) != 0) { + mTcgDxeData.EventLogAreaStruct[Index].EventLogFormat = mTcg2EventInfo[Index].LogFormat; + Status = gBS->AllocatePages ( + AllocateAnyPages, + EfiBootServicesData, + EFI_SIZE_TO_PAGES (PcdGet32 (PcdTcgLogAreaMinLen)), + &Lasa + ); + if (EFI_ERROR (Status)) { + return Status; + } + mTcgDxeData.EventLogAreaStruct[Index].Lasa = Lasa; + mTcgDxeData.EventLogAreaStruct[Index].Laml = PcdGet32 (PcdTcgLogAreaMinLen); + // + // To initialize them as 0xFF is recommended + // because the OS can know the last entry for that. + // + SetMem ((VOID *)(UINTN)Lasa, PcdGet32 (PcdTcgLogAreaMinLen), 0xFF); + // + // Create first entry for Log Header Entry Data + // + if (mTcg2EventInfo[Index].LogFormat != EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2) { + // + // TcgEfiSpecIdEventStruct + // + TcgEfiSpecIdEventStruct = (TCG_EfiSpecIDEventStruct *)TempBuf; + CopyMem (TcgEfiSpecIdEventStruct->signature, TCG_EfiSpecIDEventStruct_SIGNATURE_03, sizeof(TcgEfiSpecIdEventStruct->signature)); + TcgEfiSpecIdEventStruct->platformClass = PcdGet8 (PcdTpmPlatformClass); + TcgEfiSpecIdEventStruct->specVersionMajor = TCG_EfiSpecIDEventStruct_SPEC_VERSION_MAJOR_TPM2; + TcgEfiSpecIdEventStruct->specVersionMinor = TCG_EfiSpecIDEventStruct_SPEC_VERSION_MINOR_TPM2; + TcgEfiSpecIdEventStruct->specErrata = TCG_EfiSpecIDEventStruct_SPEC_ERRATA_TPM2; + TcgEfiSpecIdEventStruct->uintnSize = sizeof(UINTN)/sizeof(UINT32); + NumberOfAlgorithms = 0; + DigestSize = (TCG_EfiSpecIdEventAlgorithmSize *)((UINT8 *)TcgEfiSpecIdEventStruct + sizeof(*TcgEfiSpecIdEventStruct) + sizeof(NumberOfAlgorithms)); + if ((mTcgDxeData.BsCap.ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SHA1) != 0) { + TempDigestSize = DigestSize; + TempDigestSize += NumberOfAlgorithms; + TempDigestSize->algorithmId = TPM_ALG_SHA1; + TempDigestSize->digestSize = SHA1_DIGEST_SIZE; + NumberOfAlgorithms++; + } + if ((mTcgDxeData.BsCap.ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SHA256) != 0) { + TempDigestSize = DigestSize; + TempDigestSize += NumberOfAlgorithms; + TempDigestSize->algorithmId = TPM_ALG_SHA256; + TempDigestSize->digestSize = SHA256_DIGEST_SIZE; + NumberOfAlgorithms++; + } + if ((mTcgDxeData.BsCap.ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SHA384) != 0) { + TempDigestSize = DigestSize; + TempDigestSize += NumberOfAlgorithms; + TempDigestSize->algorithmId = TPM_ALG_SHA384; + TempDigestSize->digestSize = SHA384_DIGEST_SIZE; + NumberOfAlgorithms++; + } + if ((mTcgDxeData.BsCap.ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SHA512) != 0) { + TempDigestSize = DigestSize; + TempDigestSize += NumberOfAlgorithms; + TempDigestSize->algorithmId = TPM_ALG_SHA512; + TempDigestSize->digestSize = SHA512_DIGEST_SIZE; + NumberOfAlgorithms++; + } + if ((mTcgDxeData.BsCap.ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SM3_256) != 0) { + TempDigestSize = DigestSize; + TempDigestSize += NumberOfAlgorithms; + TempDigestSize->algorithmId = TPM_ALG_SM3_256; + TempDigestSize->digestSize = SM3_256_DIGEST_SIZE; + NumberOfAlgorithms++; + } + CopyMem (TcgEfiSpecIdEventStruct + 1, &NumberOfAlgorithms, sizeof(NumberOfAlgorithms)); + TempDigestSize = DigestSize; + TempDigestSize += NumberOfAlgorithms; + VendorInfoSize = (UINT8 *)TempDigestSize; + *VendorInfoSize = 0; + + SpecIdEvent.PCRIndex = 0; + SpecIdEvent.EventType = EV_NO_ACTION; + ZeroMem (&SpecIdEvent.Digest, sizeof(SpecIdEvent.Digest)); + SpecIdEvent.EventSize = (UINT32)GetTcgEfiSpecIdEventStructSize (TcgEfiSpecIdEventStruct); + + // + // Log TcgEfiSpecIdEventStruct as the first Event. Event format is TCG_PCR_EVENT. + // TCG EFI Protocol Spec. Section 5.3 Event Log Header + // TCG PC Client PFP spec. Section 9.2 Measurement Event Entries and Log + // + Status = TcgDxeLogEvent ( + mTcg2EventInfo[Index].LogFormat, + &SpecIdEvent, + sizeof(SpecIdEvent), + (UINT8 *)TcgEfiSpecIdEventStruct, + SpecIdEvent.EventSize + ); + + // + // EfiStartupLocalityEvent. Event format is TCG_PCR_EVENT2 + // + GuidHob.Guid = GetFirstGuidHob (&gTpm2StartupLocalityHobGuid); + if (GuidHob.Guid != NULL) { + // + // Get Locality Indicator from StartupLocality HOB + // + StartupLocalityEvent.StartupLocality = *(UINT8 *)(GET_GUID_HOB_DATA (GuidHob.Guid)); + CopyMem (StartupLocalityEvent.Signature, TCG_EfiStartupLocalityEvent_SIGNATURE, sizeof(StartupLocalityEvent.Signature)); + DEBUG ((DEBUG_INFO, "SetupEventLog: Set Locality from HOB into StartupLocalityEvent 0x%02x\n", StartupLocalityEvent.StartupLocality)); + + // + // Initialize StartupLocalityEvent + // + InitNoActionEvent(&NoActionEvent, sizeof(StartupLocalityEvent)); + + // + // Log EfiStartupLocalityEvent as the second Event + // TCG PC Client PFP spec. Section 9.3.4.3 Startup Locality Event + // + Status = TcgDxeLogEvent ( + mTcg2EventInfo[Index].LogFormat, + &NoActionEvent, + sizeof(NoActionEvent.PCRIndex) + sizeof(NoActionEvent.EventType) + GetDigestListBinSize (&NoActionEvent.Digests) + sizeof(NoActionEvent.EventSize), + (UINT8 *)&StartupLocalityEvent, + sizeof(StartupLocalityEvent) + ); + + } + } + } + } + + // + // 2. Create Final Log Area + // + for (Index = 0; Index < sizeof(mTcg2EventInfo)/sizeof(mTcg2EventInfo[0]); Index++) { + if ((mTcgDxeData.BsCap.SupportedEventLogs & mTcg2EventInfo[Index].LogFormat) != 0) { + if (mTcg2EventInfo[Index].LogFormat == EFI_TCG2_EVENT_LOG_FORMAT_TCG_2) { + Status = gBS->AllocatePages ( + AllocateAnyPages, + EfiACPIMemoryNVS, + EFI_SIZE_TO_PAGES (PcdGet32 (PcdTcg2FinalLogAreaLen)), + &Lasa + ); + if (EFI_ERROR (Status)) { + return Status; + } + SetMem ((VOID *)(UINTN)Lasa, PcdGet32 (PcdTcg2FinalLogAreaLen), 0xFF); + + // + // Initialize + // + mTcgDxeData.FinalEventsTable[Index] = (VOID *)(UINTN)Lasa; + (mTcgDxeData.FinalEventsTable[Index])->Version = EFI_TCG2_FINAL_EVENTS_TABLE_VERSION; + (mTcgDxeData.FinalEventsTable[Index])->NumberOfEvents = 0; + + mTcgDxeData.FinalEventLogAreaStruct[Index].EventLogFormat = mTcg2EventInfo[Index].LogFormat; + mTcgDxeData.FinalEventLogAreaStruct[Index].Lasa = Lasa + sizeof(EFI_TCG2_FINAL_EVENTS_TABLE); + mTcgDxeData.FinalEventLogAreaStruct[Index].Laml = PcdGet32 (PcdTcg2FinalLogAreaLen) - sizeof(EFI_TCG2_FINAL_EVENTS_TABLE); + mTcgDxeData.FinalEventLogAreaStruct[Index].EventLogSize = 0; + mTcgDxeData.FinalEventLogAreaStruct[Index].LastEvent = (VOID *)(UINTN)mTcgDxeData.FinalEventLogAreaStruct[Index].Lasa; + mTcgDxeData.FinalEventLogAreaStruct[Index].EventLogStarted = FALSE; + mTcgDxeData.FinalEventLogAreaStruct[Index].EventLogTruncated = FALSE; + + // + // Install to configuration table for EFI_TCG2_EVENT_LOG_FORMAT_TCG_2 + // + Status = gBS->InstallConfigurationTable (&gEfiTcg2FinalEventsTableGuid, (VOID *)mTcgDxeData.FinalEventsTable[Index]); + if (EFI_ERROR (Status)) { + return Status; + } + } else { + // + // No need to handle EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2 + // + mTcgDxeData.FinalEventsTable[Index] = NULL; + mTcgDxeData.FinalEventLogAreaStruct[Index].EventLogFormat = mTcg2EventInfo[Index].LogFormat; + mTcgDxeData.FinalEventLogAreaStruct[Index].Lasa = 0; + mTcgDxeData.FinalEventLogAreaStruct[Index].Laml = 0; + mTcgDxeData.FinalEventLogAreaStruct[Index].EventLogSize = 0; + mTcgDxeData.FinalEventLogAreaStruct[Index].LastEvent = 0; + mTcgDxeData.FinalEventLogAreaStruct[Index].EventLogStarted = FALSE; + mTcgDxeData.FinalEventLogAreaStruct[Index].EventLogTruncated = FALSE; + } + } + } + + // + // 3. Sync data from PEI to DXE + // + Status = EFI_SUCCESS; + for (Index = 0; Index < sizeof(mTcg2EventInfo)/sizeof(mTcg2EventInfo[0]); Index++) { + if ((mTcgDxeData.BsCap.SupportedEventLogs & mTcg2EventInfo[Index].LogFormat) != 0) { + GuidHob.Raw = GetHobList (); + Status = EFI_SUCCESS; + while (!EFI_ERROR (Status) && + (GuidHob.Raw = GetNextGuidHob (mTcg2EventInfo[Index].EventGuid, GuidHob.Raw)) != NULL) { + TcgEvent = AllocateCopyPool (GET_GUID_HOB_DATA_SIZE (GuidHob.Guid), GET_GUID_HOB_DATA (GuidHob.Guid)); + ASSERT (TcgEvent != NULL); + GuidHob.Raw = GET_NEXT_HOB (GuidHob); + switch (mTcg2EventInfo[Index].LogFormat) { + case EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2: + Status = TcgDxeLogEvent ( + mTcg2EventInfo[Index].LogFormat, + TcgEvent, + sizeof(TCG_PCR_EVENT_HDR), + ((TCG_PCR_EVENT*)TcgEvent)->Event, + ((TCG_PCR_EVENT_HDR*)TcgEvent)->EventSize + ); + break; + case EFI_TCG2_EVENT_LOG_FORMAT_TCG_2: + DigestListBin = (UINT8 *)TcgEvent + sizeof(TCG_PCRINDEX) + sizeof(TCG_EVENTTYPE); + DigestListBinSize = GetDigestListBinSize (DigestListBin); + // + // Save event size. + // + CopyMem (&EventSize, (UINT8 *)DigestListBin + DigestListBinSize, sizeof(UINT32)); + Event = (UINT8 *)DigestListBin + DigestListBinSize + sizeof(UINT32); + // + // Filter inactive digest in the event2 log from PEI HOB. + // + CopyMem (&TempDigestListBin, DigestListBin, GetDigestListBinSize (DigestListBin)); + EventSizePtr = CopyDigestListBinToBuffer ( + DigestListBin, + &TempDigestListBin, + mTcgDxeData.BsCap.ActivePcrBanks, + &HashAlgorithmMaskCopied + ); + if (HashAlgorithmMaskCopied != mTcgDxeData.BsCap.ActivePcrBanks) { + DEBUG (( + DEBUG_ERROR, + "ERROR: The event2 log includes digest hash mask 0x%x, but required digest hash mask is 0x%x\n", + HashAlgorithmMaskCopied, + mTcgDxeData.BsCap.ActivePcrBanks + )); + } + // + // Restore event size. + // + CopyMem (EventSizePtr, &EventSize, sizeof(UINT32)); + DigestListBinSize = GetDigestListBinSize (DigestListBin); + + Status = TcgDxeLogEvent ( + mTcg2EventInfo[Index].LogFormat, + TcgEvent, + sizeof(TCG_PCRINDEX) + sizeof(TCG_EVENTTYPE) + DigestListBinSize + sizeof(UINT32), + Event, + EventSize + ); + break; + } + FreePool (TcgEvent); + } + } + } + + return Status; +} + +/** + Measure and log an action string, and extend the measurement result into PCR[PCRIndex]. + + @param[in] PCRIndex PCRIndex to extend + @param[in] String A specific string that indicates an Action event. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR The operation was unsuccessful. + +**/ +EFI_STATUS +TcgMeasureAction ( + IN TPM_PCRINDEX PCRIndex, + IN CHAR8 *String + ) +{ + TCG_PCR_EVENT_HDR TcgEvent; + + TcgEvent.PCRIndex = PCRIndex; + TcgEvent.EventType = EV_EFI_ACTION; + TcgEvent.EventSize = (UINT32)AsciiStrLen (String); + return TcgDxeHashLogExtendEvent ( + 0, + (UINT8*)String, + TcgEvent.EventSize, + &TcgEvent, + (UINT8 *) String + ); +} + +/** + Measure and log EFI handoff tables, and extend the measurement result into PCR[1]. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR The operation was unsuccessful. + +**/ +EFI_STATUS +MeasureHandoffTables ( + VOID + ) +{ + EFI_STATUS Status; + TCG_PCR_EVENT_HDR TcgEvent; + EFI_HANDOFF_TABLE_POINTERS HandoffTables; + UINTN ProcessorNum; + EFI_CPU_PHYSICAL_LOCATION *ProcessorLocBuf; + + ProcessorLocBuf = NULL; + Status = EFI_SUCCESS; + + if (PcdGet8 (PcdTpmPlatformClass) == TCG_PLATFORM_TYPE_SERVER) { + // + // Tcg Server spec. + // Measure each processor EFI_CPU_PHYSICAL_LOCATION with EV_TABLE_OF_DEVICES to PCR[1] + // + Status = GetProcessorsCpuLocation(&ProcessorLocBuf, &ProcessorNum); + + if (!EFI_ERROR(Status)){ + TcgEvent.PCRIndex = 1; + TcgEvent.EventType = EV_TABLE_OF_DEVICES; + TcgEvent.EventSize = sizeof (HandoffTables); + + HandoffTables.NumberOfTables = 1; + HandoffTables.TableEntry[0].VendorGuid = gEfiMpServiceProtocolGuid; + HandoffTables.TableEntry[0].VendorTable = ProcessorLocBuf; + + Status = TcgDxeHashLogExtendEvent ( + 0, + (UINT8*)(UINTN)ProcessorLocBuf, + sizeof(EFI_CPU_PHYSICAL_LOCATION) * ProcessorNum, + &TcgEvent, + (UINT8*)&HandoffTables + ); + + FreePool(ProcessorLocBuf); + } + } + + return Status; +} + +/** + Measure and log Separator event, and extend the measurement result into a specific PCR. + + @param[in] PCRIndex PCR index. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR The operation was unsuccessful. + +**/ +EFI_STATUS +MeasureSeparatorEvent ( + IN TPM_PCRINDEX PCRIndex + ) +{ + TCG_PCR_EVENT_HDR TcgEvent; + UINT32 EventData; + + DEBUG ((EFI_D_INFO, "MeasureSeparatorEvent Pcr - %x\n", PCRIndex)); + + EventData = 0; + TcgEvent.PCRIndex = PCRIndex; + TcgEvent.EventType = EV_SEPARATOR; + TcgEvent.EventSize = (UINT32)sizeof (EventData); + return TcgDxeHashLogExtendEvent ( + 0, + (UINT8 *)&EventData, + sizeof (EventData), + &TcgEvent, + (UINT8 *)&EventData + ); +} + +/** + Measure and log an EFI variable, and extend the measurement result into a specific PCR. + + @param[in] PCRIndex PCR Index. + @param[in] EventType Event type. + @param[in] VarName A Null-terminated string that is the name of the vendor's variable. + @param[in] VendorGuid A unique identifier for the vendor. + @param[in] VarData The content of the variable data. + @param[in] VarSize The size of the variable data. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_OUT_OF_RESOURCES Out of memory. + @retval EFI_DEVICE_ERROR The operation was unsuccessful. + +**/ +EFI_STATUS +MeasureVariable ( + IN TPM_PCRINDEX PCRIndex, + IN TCG_EVENTTYPE EventType, + IN CHAR16 *VarName, + IN EFI_GUID *VendorGuid, + IN VOID *VarData, + IN UINTN VarSize + ) +{ + EFI_STATUS Status; + TCG_PCR_EVENT_HDR TcgEvent; + UINTN VarNameLength; + UEFI_VARIABLE_DATA *VarLog; + + DEBUG ((EFI_D_INFO, "Tcg2Dxe: MeasureVariable (Pcr - %x, EventType - %x, ", (UINTN)PCRIndex, (UINTN)EventType)); + DEBUG ((EFI_D_INFO, "VariableName - %s, VendorGuid - %g)\n", VarName, VendorGuid)); + + VarNameLength = StrLen (VarName); + TcgEvent.PCRIndex = PCRIndex; + TcgEvent.EventType = EventType; + + TcgEvent.EventSize = (UINT32)(sizeof (*VarLog) + VarNameLength * sizeof (*VarName) + VarSize + - sizeof (VarLog->UnicodeName) - sizeof (VarLog->VariableData)); + + VarLog = (UEFI_VARIABLE_DATA *)AllocatePool (TcgEvent.EventSize); + if (VarLog == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + VarLog->VariableName = *VendorGuid; + VarLog->UnicodeNameLength = VarNameLength; + VarLog->VariableDataLength = VarSize; + CopyMem ( + VarLog->UnicodeName, + VarName, + VarNameLength * sizeof (*VarName) + ); + if (VarSize != 0 && VarData != NULL) { + CopyMem ( + (CHAR16 *)VarLog->UnicodeName + VarNameLength, + VarData, + VarSize + ); + } + + if (EventType == EV_EFI_VARIABLE_DRIVER_CONFIG) { + // + // Digest is the event data (UEFI_VARIABLE_DATA) + // + Status = TcgDxeHashLogExtendEvent ( + 0, + (UINT8*)VarLog, + TcgEvent.EventSize, + &TcgEvent, + (UINT8*)VarLog + ); + } else { + ASSERT (VarData != NULL); + Status = TcgDxeHashLogExtendEvent ( + 0, + (UINT8*)VarData, + VarSize, + &TcgEvent, + (UINT8*)VarLog + ); + } + FreePool (VarLog); + return Status; +} + +/** + Read then Measure and log an EFI variable, and extend the measurement result into a specific PCR. + + @param[in] PCRIndex PCR Index. + @param[in] EventType Event type. + @param[in] VarName A Null-terminated string that is the name of the vendor's variable. + @param[in] VendorGuid A unique identifier for the vendor. + @param[out] VarSize The size of the variable data. + @param[out] VarData Pointer to the content of the variable. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_OUT_OF_RESOURCES Out of memory. + @retval EFI_DEVICE_ERROR The operation was unsuccessful. + +**/ +EFI_STATUS +ReadAndMeasureVariable ( + IN TPM_PCRINDEX PCRIndex, + IN TCG_EVENTTYPE EventType, + IN CHAR16 *VarName, + IN EFI_GUID *VendorGuid, + OUT UINTN *VarSize, + OUT VOID **VarData + ) +{ + EFI_STATUS Status; + + Status = GetVariable2 (VarName, VendorGuid, VarData, VarSize); + if (EventType == EV_EFI_VARIABLE_DRIVER_CONFIG) { + if (EFI_ERROR (Status)) { + // + // It is valid case, so we need handle it. + // + *VarData = NULL; + *VarSize = 0; + } + } else { + // + // if status error, VarData is freed and set NULL by GetVariable2 + // + if (EFI_ERROR (Status)) { + return EFI_NOT_FOUND; + } + } + + Status = MeasureVariable ( + PCRIndex, + EventType, + VarName, + VendorGuid, + *VarData, + *VarSize + ); + return Status; +} + +/** + Read then Measure and log an EFI boot variable, and extend the measurement result into PCR[1]. +according to TCG PC Client PFP spec 0021 Section 2.4.4.2 + + @param[in] VarName A Null-terminated string that is the name of the vendor's variable. + @param[in] VendorGuid A unique identifier for the vendor. + @param[out] VarSize The size of the variable data. + @param[out] VarData Pointer to the content of the variable. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_OUT_OF_RESOURCES Out of memory. + @retval EFI_DEVICE_ERROR The operation was unsuccessful. + +**/ +EFI_STATUS +ReadAndMeasureBootVariable ( + IN CHAR16 *VarName, + IN EFI_GUID *VendorGuid, + OUT UINTN *VarSize, + OUT VOID **VarData + ) +{ + return ReadAndMeasureVariable ( + 1, + EV_EFI_VARIABLE_BOOT, + VarName, + VendorGuid, + VarSize, + VarData + ); +} + +/** + Read then Measure and log an EFI Secure variable, and extend the measurement result into PCR[7]. + + @param[in] VarName A Null-terminated string that is the name of the vendor's variable. + @param[in] VendorGuid A unique identifier for the vendor. + @param[out] VarSize The size of the variable data. + @param[out] VarData Pointer to the content of the variable. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_OUT_OF_RESOURCES Out of memory. + @retval EFI_DEVICE_ERROR The operation was unsuccessful. + +**/ +EFI_STATUS +ReadAndMeasureSecureVariable ( + IN CHAR16 *VarName, + IN EFI_GUID *VendorGuid, + OUT UINTN *VarSize, + OUT VOID **VarData + ) +{ + return ReadAndMeasureVariable ( + 7, + EV_EFI_VARIABLE_DRIVER_CONFIG, + VarName, + VendorGuid, + VarSize, + VarData + ); +} + +/** + Measure and log all EFI boot variables, and extend the measurement result into a specific PCR. + + The EFI boot variables are BootOrder and Boot#### variables. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_OUT_OF_RESOURCES Out of memory. + @retval EFI_DEVICE_ERROR The operation was unsuccessful. + +**/ +EFI_STATUS +MeasureAllBootVariables ( + VOID + ) +{ + EFI_STATUS Status; + UINT16 *BootOrder; + UINTN BootCount; + UINTN Index; + VOID *BootVarData; + UINTN Size; + + Status = ReadAndMeasureBootVariable ( + mBootVarName, + &gEfiGlobalVariableGuid, + &BootCount, + (VOID **) &BootOrder + ); + if (Status == EFI_NOT_FOUND || BootOrder == NULL) { + return EFI_SUCCESS; + } + + if (EFI_ERROR (Status)) { + // + // BootOrder can't be NULL if status is not EFI_NOT_FOUND + // + FreePool (BootOrder); + return Status; + } + + BootCount /= sizeof (*BootOrder); + for (Index = 0; Index < BootCount; Index++) { + UnicodeSPrint (mBootVarName, sizeof (mBootVarName), L"Boot%04x", BootOrder[Index]); + Status = ReadAndMeasureBootVariable ( + mBootVarName, + &gEfiGlobalVariableGuid, + &Size, + &BootVarData + ); + if (!EFI_ERROR (Status)) { + FreePool (BootVarData); + } + } + + FreePool (BootOrder); + return EFI_SUCCESS; +} + +/** + Measure and log all EFI Secure variables, and extend the measurement result into a specific PCR. + + The EFI boot variables are BootOrder and Boot#### variables. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_OUT_OF_RESOURCES Out of memory. + @retval EFI_DEVICE_ERROR The operation was unsuccessful. + +**/ +EFI_STATUS +MeasureAllSecureVariables ( + VOID + ) +{ + EFI_STATUS Status; + VOID *Data; + UINTN DataSize; + UINTN Index; + + Status = EFI_NOT_FOUND; + for (Index = 0; Index < sizeof(mVariableType)/sizeof(mVariableType[0]); Index++) { + Status = ReadAndMeasureSecureVariable ( + mVariableType[Index].VariableName, + mVariableType[Index].VendorGuid, + &DataSize, + &Data + ); + if (!EFI_ERROR (Status)) { + if (Data != NULL) { + FreePool (Data); + } + } + } + + // + // Measure DBT if present and not empty + // + Status = GetVariable2 (EFI_IMAGE_SECURITY_DATABASE2, &gEfiImageSecurityDatabaseGuid, &Data, &DataSize); + if (!EFI_ERROR(Status)) { + Status = MeasureVariable ( + 7, + EV_EFI_VARIABLE_DRIVER_CONFIG, + EFI_IMAGE_SECURITY_DATABASE2, + &gEfiImageSecurityDatabaseGuid, + Data, + DataSize + ); + FreePool(Data); + } else { + DEBUG((DEBUG_INFO, "Skip measuring variable %s since it's deleted\n", EFI_IMAGE_SECURITY_DATABASE2)); + } + + return EFI_SUCCESS; +} + +/** + Measure and log launch of FirmwareDebugger, and extend the measurement result into a specific PCR. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_OUT_OF_RESOURCES Out of memory. + @retval EFI_DEVICE_ERROR The operation was unsuccessful. + +**/ +EFI_STATUS +MeasureLaunchOfFirmwareDebugger ( + VOID + ) +{ + TCG_PCR_EVENT_HDR TcgEvent; + + TcgEvent.PCRIndex = 7; + TcgEvent.EventType = EV_EFI_ACTION; + TcgEvent.EventSize = sizeof(FIRMWARE_DEBUGGER_EVENT_STRING) - 1; + return TcgDxeHashLogExtendEvent ( + 0, + (UINT8 *)FIRMWARE_DEBUGGER_EVENT_STRING, + sizeof(FIRMWARE_DEBUGGER_EVENT_STRING) - 1, + &TcgEvent, + (UINT8 *)FIRMWARE_DEBUGGER_EVENT_STRING + ); +} + +/** + Measure and log all Secure Boot Policy, and extend the measurement result into a specific PCR. + + Platform firmware adhering to the policy must therefore measure the following values into PCR[7]: (in order listed) + - The contents of the SecureBoot variable + - The contents of the PK variable + - The contents of the KEK variable + - The contents of the EFI_IMAGE_SECURITY_DATABASE variable + - The contents of the EFI_IMAGE_SECURITY_DATABASE1 variable + - Separator + - Entries in the EFI_IMAGE_SECURITY_DATABASE that are used to validate EFI Drivers or EFI Boot Applications in the boot path + + NOTE: Because of the above, UEFI variables PK, KEK, EFI_IMAGE_SECURITY_DATABASE, + EFI_IMAGE_SECURITY_DATABASE1 and SecureBoot SHALL NOT be measured into PCR[3]. + + @param[in] Event Event whose notification function is being invoked + @param[in] Context Pointer to the notification function's context +**/ +VOID +EFIAPI +MeasureSecureBootPolicy ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + VOID *Protocol; + + Status = gBS->LocateProtocol (&gEfiVariableWriteArchProtocolGuid, NULL, (VOID **)&Protocol); + if (EFI_ERROR (Status)) { + return; + } + + if (PcdGetBool (PcdFirmwareDebuggerInitialized)) { + Status = MeasureLaunchOfFirmwareDebugger (); + DEBUG ((EFI_D_INFO, "MeasureLaunchOfFirmwareDebugger - %r\n", Status)); + } + + Status = MeasureAllSecureVariables (); + DEBUG ((EFI_D_INFO, "MeasureAllSecureVariables - %r\n", Status)); + + // + // We need measure Separator(7) here, because this event must be between SecureBootPolicy (Configure) + // and ImageVerification (Authority) + // There might be a case that we need measure UEFI image from DriverOrder, besides BootOrder. So + // the Authority measurement happen before ReadToBoot event. + // + Status = MeasureSeparatorEvent (7); + DEBUG ((EFI_D_INFO, "MeasureSeparatorEvent - %r\n", Status)); + return ; +} + +/** + Ready to Boot Event notification handler. + + Sequence of OS boot events is measured in this event notification handler. + + @param[in] Event Event whose notification function is being invoked + @param[in] Context Pointer to the notification function's context + +**/ +VOID +EFIAPI +OnReadyToBoot ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + TPM_PCRINDEX PcrIndex; + + PERF_START_EX (mImageHandle, "EventRec", "Tcg2Dxe", 0, PERF_ID_TCG2_DXE); + if (mBootAttempts == 0) { + + // + // Measure handoff tables. + // + Status = MeasureHandoffTables (); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "HOBs not Measured. Error!\n")); + } + + // + // Measure BootOrder & Boot#### variables. + // + Status = MeasureAllBootVariables (); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Boot Variables not Measured. Error!\n")); + } + + // + // 1. This is the first boot attempt. + // + Status = TcgMeasureAction ( + 4, + EFI_CALLING_EFI_APPLICATION + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "%a not Measured. Error!\n", EFI_CALLING_EFI_APPLICATION)); + } + + // + // 2. Draw a line between pre-boot env and entering post-boot env. + // PCR[7] is already done. + // + for (PcrIndex = 0; PcrIndex < 7; PcrIndex++) { + Status = MeasureSeparatorEvent (PcrIndex); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Separator Event not Measured. Error!\n")); + } + } + + // + // 3. Measure GPT. It would be done in SAP driver. + // + + // + // 4. Measure PE/COFF OS loader. It would be done in SAP driver. + // + + // + // 5. Read & Measure variable. BootOrder already measured. + // + } else { + // + // 6. Not first attempt, meaning a return from last attempt + // + Status = TcgMeasureAction ( + 4, + EFI_RETURNING_FROM_EFI_APPLICATOIN + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "%a not Measured. Error!\n", EFI_RETURNING_FROM_EFI_APPLICATOIN)); + } + + // + // 7. Next boot attempt, measure "Calling EFI Application from Boot Option" again + // TCG PC Client PFP spec Section 2.4.4.5 Step 4 + // + Status = TcgMeasureAction ( + 4, + EFI_CALLING_EFI_APPLICATION + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "%a not Measured. Error!\n", EFI_CALLING_EFI_APPLICATION)); + } + } + + DEBUG ((EFI_D_INFO, "TPM2 Tcg2Dxe Measure Data when ReadyToBoot\n")); + // + // Increase boot attempt counter. + // + mBootAttempts++; + PERF_END_EX (mImageHandle, "EventRec", "Tcg2Dxe", 0, PERF_ID_TCG2_DXE + 1); +} + +/** + Exit Boot Services Event notification handler. + + Measure invocation and success of ExitBootServices. + + @param[in] Event Event whose notification function is being invoked + @param[in] Context Pointer to the notification function's context + +**/ +VOID +EFIAPI +OnExitBootServices ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + + // + // Measure invocation of ExitBootServices, + // + Status = TcgMeasureAction ( + 5, + EFI_EXIT_BOOT_SERVICES_INVOCATION + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "%a not Measured. Error!\n", EFI_EXIT_BOOT_SERVICES_INVOCATION)); + } + + // + // Measure success of ExitBootServices + // + Status = TcgMeasureAction ( + 5, + EFI_EXIT_BOOT_SERVICES_SUCCEEDED + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "%a not Measured. Error!\n", EFI_EXIT_BOOT_SERVICES_SUCCEEDED)); + } +} + +/** + Exit Boot Services Failed Event notification handler. + + Measure Failure of ExitBootServices. + + @param[in] Event Event whose notification function is being invoked + @param[in] Context Pointer to the notification function's context + +**/ +VOID +EFIAPI +OnExitBootServicesFailed ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + + // + // Measure Failure of ExitBootServices, + // + Status = TcgMeasureAction ( + 5, + EFI_EXIT_BOOT_SERVICES_FAILED + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "%a not Measured. Error!\n", EFI_EXIT_BOOT_SERVICES_FAILED)); + } + +} + +/** + The function install Tcg2 protocol. + + @retval EFI_SUCCESS Tcg2 protocol is installed. + @retval other Some error occurs. +**/ +EFI_STATUS +InstallTcg2 ( + VOID + ) +{ + EFI_STATUS Status; + EFI_HANDLE Handle; + + Handle = NULL; + Status = gBS->InstallMultipleProtocolInterfaces ( + &Handle, + &gEfiTcg2ProtocolGuid, + &mTcg2Protocol, + NULL + ); + return Status; +} + +/** + The driver's entry point. It publishes EFI Tcg2 Protocol. + + @param[in] ImageHandle The firmware allocated handle for the EFI image. + @param[in] SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The entry point is executed successfully. + @retval other Some error occurs when executing this entry point. +**/ +EFI_STATUS +EFIAPI +DriverEntry ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_EVENT Event; + VOID *Registration; + UINT32 MaxCommandSize; + UINT32 MaxResponseSize; + UINTN Index; + EFI_TCG2_EVENT_ALGORITHM_BITMAP TpmHashAlgorithmBitmap; + UINT32 ActivePCRBanks; + UINT32 NumberOfPCRBanks; + + mImageHandle = ImageHandle; + + if (CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceNoneGuid) || + CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceTpm12Guid)){ + DEBUG ((DEBUG_INFO, "No TPM2 instance required!\n")); + return EFI_UNSUPPORTED; + } + + if (GetFirstGuidHob (&gTpmErrorHobGuid) != NULL) { + DEBUG ((EFI_D_ERROR, "TPM2 error!\n")); + return EFI_DEVICE_ERROR; + } + + Status = Tpm2RequestUseTpm (); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "TPM2 not detected!\n")); + return Status; + } + + // + // Fill information + // + ASSERT (TCG_EVENT_LOG_AREA_COUNT_MAX == sizeof(mTcg2EventInfo)/sizeof(mTcg2EventInfo[0])); + + mTcgDxeData.BsCap.Size = sizeof(EFI_TCG2_BOOT_SERVICE_CAPABILITY); + mTcgDxeData.BsCap.ProtocolVersion.Major = 1; + mTcgDxeData.BsCap.ProtocolVersion.Minor = 1; + mTcgDxeData.BsCap.StructureVersion.Major = 1; + mTcgDxeData.BsCap.StructureVersion.Minor = 1; + + DEBUG ((EFI_D_INFO, "Tcg2.ProtocolVersion - %02x.%02x\n", mTcgDxeData.BsCap.ProtocolVersion.Major, mTcgDxeData.BsCap.ProtocolVersion.Minor)); + DEBUG ((EFI_D_INFO, "Tcg2.StructureVersion - %02x.%02x\n", mTcgDxeData.BsCap.StructureVersion.Major, mTcgDxeData.BsCap.StructureVersion.Minor)); + + Status = Tpm2GetCapabilityManufactureID (&mTcgDxeData.BsCap.ManufacturerID); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Tpm2GetCapabilityManufactureID fail!\n")); + } else { + DEBUG ((EFI_D_INFO, "Tpm2GetCapabilityManufactureID - %08x\n", mTcgDxeData.BsCap.ManufacturerID)); + } + + DEBUG_CODE ( + UINT32 FirmwareVersion1; + UINT32 FirmwareVersion2; + + Status = Tpm2GetCapabilityFirmwareVersion (&FirmwareVersion1, &FirmwareVersion2); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Tpm2GetCapabilityFirmwareVersion fail!\n")); + } else { + DEBUG ((EFI_D_INFO, "Tpm2GetCapabilityFirmwareVersion - %08x %08x\n", FirmwareVersion1, FirmwareVersion2)); + } + ); + + Status = Tpm2GetCapabilityMaxCommandResponseSize (&MaxCommandSize, &MaxResponseSize); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Tpm2GetCapabilityMaxCommandResponseSize fail!\n")); + } else { + mTcgDxeData.BsCap.MaxCommandSize = (UINT16)MaxCommandSize; + mTcgDxeData.BsCap.MaxResponseSize = (UINT16)MaxResponseSize; + DEBUG ((EFI_D_INFO, "Tpm2GetCapabilityMaxCommandResponseSize - %08x, %08x\n", MaxCommandSize, MaxResponseSize)); + } + + // + // Get supported PCR and current Active PCRs + // + Status = Tpm2GetCapabilitySupportedAndActivePcrs (&TpmHashAlgorithmBitmap, &ActivePCRBanks); + ASSERT_EFI_ERROR (Status); + + mTcgDxeData.BsCap.HashAlgorithmBitmap = TpmHashAlgorithmBitmap & PcdGet32 (PcdTcg2HashAlgorithmBitmap); + mTcgDxeData.BsCap.ActivePcrBanks = ActivePCRBanks & PcdGet32 (PcdTcg2HashAlgorithmBitmap); + + // + // Need calculate NumberOfPCRBanks here, because HashAlgorithmBitmap might be removed by PCD. + // + NumberOfPCRBanks = 0; + for (Index = 0; Index < 32; Index++) { + if ((mTcgDxeData.BsCap.HashAlgorithmBitmap & (1u << Index)) != 0) { + NumberOfPCRBanks++; + } + } + + if (PcdGet32 (PcdTcg2NumberOfPCRBanks) == 0) { + mTcgDxeData.BsCap.NumberOfPCRBanks = NumberOfPCRBanks; + } else { + mTcgDxeData.BsCap.NumberOfPCRBanks = PcdGet32 (PcdTcg2NumberOfPCRBanks); + if (PcdGet32 (PcdTcg2NumberOfPCRBanks) > NumberOfPCRBanks) { + DEBUG ((EFI_D_ERROR, "ERROR: PcdTcg2NumberOfPCRBanks(0x%x) > NumberOfPCRBanks(0x%x)\n", PcdGet32 (PcdTcg2NumberOfPCRBanks), NumberOfPCRBanks)); + mTcgDxeData.BsCap.NumberOfPCRBanks = NumberOfPCRBanks; + } + } + + mTcgDxeData.BsCap.SupportedEventLogs = EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2 | EFI_TCG2_EVENT_LOG_FORMAT_TCG_2; + if ((mTcgDxeData.BsCap.ActivePcrBanks & EFI_TCG2_BOOT_HASH_ALG_SHA1) == 0) { + // + // No need to expose TCG1.2 event log if SHA1 bank does not exist. + // + mTcgDxeData.BsCap.SupportedEventLogs &= ~EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2; + } + + DEBUG ((EFI_D_INFO, "Tcg2.SupportedEventLogs - 0x%08x\n", mTcgDxeData.BsCap.SupportedEventLogs)); + DEBUG ((EFI_D_INFO, "Tcg2.HashAlgorithmBitmap - 0x%08x\n", mTcgDxeData.BsCap.HashAlgorithmBitmap)); + DEBUG ((EFI_D_INFO, "Tcg2.NumberOfPCRBanks - 0x%08x\n", mTcgDxeData.BsCap.NumberOfPCRBanks)); + DEBUG ((EFI_D_INFO, "Tcg2.ActivePcrBanks - 0x%08x\n", mTcgDxeData.BsCap.ActivePcrBanks)); + + if (mTcgDxeData.BsCap.TPMPresentFlag) { + // + // Setup the log area and copy event log from hob list to it + // + Status = SetupEventLog (); + ASSERT_EFI_ERROR (Status); + + // + // Measure handoff tables, Boot#### variables etc. + // + Status = EfiCreateEventReadyToBootEx ( + TPL_CALLBACK, + OnReadyToBoot, + NULL, + &Event + ); + + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + OnExitBootServices, + NULL, + &gEfiEventExitBootServicesGuid, + &Event + ); + + // + // Measure Exit Boot Service failed + // + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + OnExitBootServicesFailed, + NULL, + &gEventExitBootServicesFailedGuid, + &Event + ); + + // + // Create event callback, because we need access variable on SecureBootPolicyVariable + // We should use VariableWriteArch instead of VariableArch, because Variable driver + // may update SecureBoot value based on last setting. + // + EfiCreateProtocolNotifyEvent (&gEfiVariableWriteArchProtocolGuid, TPL_CALLBACK, MeasureSecureBootPolicy, NULL, &Registration); + } + + // + // Install Tcg2Protocol + // + Status = InstallTcg2 (); + DEBUG ((EFI_D_INFO, "InstallTcg2 - %r\n", Status)); + + return Status; +} diff --git a/Core/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.inf b/Core/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.inf new file mode 100644 index 0000000000..8efc4e3aad --- /dev/null +++ b/Core/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.inf @@ -0,0 +1,112 @@ +## @file +# Produces Tcg2 protocol and measure boot environment +# This module will produce Tcg2 protocol and measure boot environment. +# +# Caution: This module requires additional review when modified. +# This driver will have external input - PE/COFF image. +# This external input must be validated carefully to avoid security issue like +# buffer overflow, integer overflow. +# +# Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = Tcg2Dxe + MODULE_UNI_FILE = Tcg2Dxe.uni + FILE_GUID = FDFF263D-5F68-4591-87BA-B768F445A9AF + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = DriverEntry + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF +# + +[Sources] + Tcg2Dxe.c + MeasureBootPeCoff.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + SecurityPkg/SecurityPkg.dec + CryptoPkg/CryptoPkg.dec + +[LibraryClasses] + MemoryAllocationLib + BaseLib + UefiBootServicesTableLib + HobLib + UefiDriverEntryPoint + UefiRuntimeServicesTableLib + BaseMemoryLib + DebugLib + Tpm2CommandLib + PrintLib + UefiLib + Tpm2DeviceLib + HashLib + PerformanceLib + ReportStatusCodeLib + Tcg2PhysicalPresenceLib + PeCoffLib + +[Guids] + ## SOMETIMES_CONSUMES ## Variable:L"SecureBoot" + ## SOMETIMES_CONSUMES ## Variable:L"PK" + ## SOMETIMES_CONSUMES ## Variable:L"KEK" + ## SOMETIMES_CONSUMES ## Variable:L"BootXXXX" + gEfiGlobalVariableGuid + + ## SOMETIMES_CONSUMES ## Variable:L"db" + ## SOMETIMES_CONSUMES ## Variable:L"dbx" + gEfiImageSecurityDatabaseGuid + + gTcgEventEntryHobGuid ## SOMETIMES_CONSUMES ## HOB + gTpmErrorHobGuid ## SOMETIMES_CONSUMES ## HOB + gEfiEventExitBootServicesGuid ## CONSUMES ## Event + gEventExitBootServicesFailedGuid ## SOMETIMES_CONSUMES ## Event + gEfiTpmDeviceInstanceNoneGuid ## SOMETIMES_CONSUMES ## GUID # TPM device identifier + gEfiTpmDeviceInstanceTpm12Guid ## SOMETIMES_CONSUMES ## GUID # TPM device identifier + + gTcgEvent2EntryHobGuid ## SOMETIMES_CONSUMES ## HOB + gTpm2StartupLocalityHobGuid ## SOMETIMES_CONSUMES ## HOB + +[Protocols] + gEfiTcg2ProtocolGuid ## PRODUCES + gEfiTcg2FinalEventsTableGuid ## PRODUCES + gEfiAcpiTableProtocolGuid ## NOTIFY + gEfiMpServiceProtocolGuid ## SOMETIMES_CONSUMES + gEfiVariableWriteArchProtocolGuid ## NOTIFY + +[Pcd] + gEfiSecurityPkgTokenSpaceGuid.PcdTpmPlatformClass ## SOMETIMES_CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdFirmwareDebuggerInitialized ## SOMETIMES_CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdTpmInstanceGuid ## CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdTpmBaseAddress ## SOMETIMES_CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemId ## SOMETIMES_CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemTableId ## SOMETIMES_CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemRevision ## SOMETIMES_CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorId ## SOMETIMES_CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorRevision ## SOMETIMES_CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdStatusCodeSubClassTpmDevice ## SOMETIMES_CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdTcg2HashAlgorithmBitmap ## CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdTcg2NumberOfPCRBanks ## CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdTcgLogAreaMinLen ## CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdTcg2FinalLogAreaLen ## CONSUMES + +[Depex] + TRUE + +[UserExtensions.TianoCore."ExtraFiles"] + Tcg2DxeExtra.uni diff --git a/Core/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.uni b/Core/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.uni new file mode 100644 index 0000000000..dadcd1a79e --- /dev/null +++ b/Core/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.uni @@ -0,0 +1,26 @@ +// /** @file +// Produces TCG2 protocol and measure boot environment +// +// This module will produce TCG2 protocol and measure boot environment. +// +// Caution: This module requires additional review when modified. +// This driver will have external input - PE/COFF image. +// This external input must be validated carefully to avoid security issue like +// buffer overflow, integer overflow. +// +// Copyright (c) 2015, Intel Corporation. All rights reserved.
+// +// This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// **/ + + +#string STR_MODULE_ABSTRACT #language en-US "Produces TCG2 protocol and measure boot environment" + +#string STR_MODULE_DESCRIPTION #language en-US "This module will produce TCG2 protocol and measure boot environment." + diff --git a/Core/SecurityPkg/Tcg/Tcg2Dxe/Tcg2DxeExtra.uni b/Core/SecurityPkg/Tcg/Tcg2Dxe/Tcg2DxeExtra.uni new file mode 100644 index 0000000000..1cd59a33a3 --- /dev/null +++ b/Core/SecurityPkg/Tcg/Tcg2Dxe/Tcg2DxeExtra.uni @@ -0,0 +1,17 @@ +// /** @file +// Tcg2Dxe Localized Strings and Content +// +// Copyright (c) 2015, Intel Corporation. All rights reserved.
+// +// This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// **/ + +#string STR_PROPERTIES_MODULE_NAME +#language en-US +"TCG2 (Trusted Computing Group) DXE" diff --git a/Core/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.c b/Core/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.c new file mode 100644 index 0000000000..69adad43aa --- /dev/null +++ b/Core/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.c @@ -0,0 +1,854 @@ +/** @file + Initialize TPM2 device and measure FVs before handing off control to DXE. + +Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PERF_ID_TCG2_PEI 0x3080 + +typedef struct { + EFI_GUID *EventGuid; + EFI_TCG2_EVENT_LOG_FORMAT LogFormat; +} TCG2_EVENT_INFO_STRUCT; + +TCG2_EVENT_INFO_STRUCT mTcg2EventInfo[] = { + {&gTcgEventEntryHobGuid, EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2}, + {&gTcgEvent2EntryHobGuid, EFI_TCG2_EVENT_LOG_FORMAT_TCG_2}, +}; + +BOOLEAN mImageInMemory = FALSE; +EFI_PEI_FILE_HANDLE mFileHandle; + +EFI_PEI_PPI_DESCRIPTOR mTpmInitializedPpiList = { + EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, + &gPeiTpmInitializedPpiGuid, + NULL +}; + +EFI_PEI_PPI_DESCRIPTOR mTpmInitializationDonePpiList = { + EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, + &gPeiTpmInitializationDonePpiGuid, + NULL +}; + +EFI_PLATFORM_FIRMWARE_BLOB *mMeasuredBaseFvInfo; +UINT32 mMeasuredBaseFvIndex = 0; + +EFI_PLATFORM_FIRMWARE_BLOB *mMeasuredChildFvInfo; +UINT32 mMeasuredChildFvIndex = 0; + +/** + Measure and record the Firmware Volum Information once FvInfoPPI install. + + @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation. + @param[in] NotifyDescriptor Address of the notification descriptor data structure. + @param[in] Ppi Address of the PPI that was installed. + + @retval EFI_SUCCESS The FV Info is measured and recorded to TPM. + @return Others Fail to measure FV. + +**/ +EFI_STATUS +EFIAPI +FirmwareVolmeInfoPpiNotifyCallback ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, + IN VOID *Ppi + ); + +/** + Record all measured Firmware Volum Information into a Guid Hob + + @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation. + @param[in] NotifyDescriptor Address of the notification descriptor data structure. + @param[in] Ppi Address of the PPI that was installed. + + @retval EFI_SUCCESS The FV Info is measured and recorded to TPM. + @return Others Fail to measure FV. + +**/ +EFI_STATUS +EFIAPI +EndofPeiSignalNotifyCallBack ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, + IN VOID *Ppi + ); + +EFI_PEI_NOTIFY_DESCRIPTOR mNotifyList[] = { + { + EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK, + &gEfiPeiFirmwareVolumeInfoPpiGuid, + FirmwareVolmeInfoPpiNotifyCallback + }, + { + EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK, + &gEfiPeiFirmwareVolumeInfo2PpiGuid, + FirmwareVolmeInfoPpiNotifyCallback + }, + { + (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gEfiEndOfPeiSignalPpiGuid, + EndofPeiSignalNotifyCallBack + } +}; + +EFI_PEI_FIRMWARE_VOLUME_INFO_MEASUREMENT_EXCLUDED_PPI *mMeasurementExcludedFvPpi; + +/** + Record all measured Firmware Volum Information into a Guid Hob + Guid Hob payload layout is + + UINT32 *************************** FIRMWARE_BLOB number + EFI_PLATFORM_FIRMWARE_BLOB******** BLOB Array + + @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation. + @param[in] NotifyDescriptor Address of the notification descriptor data structure. + @param[in] Ppi Address of the PPI that was installed. + + @retval EFI_SUCCESS The FV Info is measured and recorded to TPM. + @return Others Fail to measure FV. + +**/ +EFI_STATUS +EFIAPI +EndofPeiSignalNotifyCallBack ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, + IN VOID *Ppi + ) +{ + MEASURED_HOB_DATA *MeasuredHobData; + + MeasuredHobData = NULL; + + // + // Create a Guid hob to save all measured Fv + // + MeasuredHobData = BuildGuidHob( + &gMeasuredFvHobGuid, + sizeof(UINTN) + sizeof(EFI_PLATFORM_FIRMWARE_BLOB) * (mMeasuredBaseFvIndex + mMeasuredChildFvIndex) + ); + + if (MeasuredHobData != NULL){ + // + // Save measured FV info enty number + // + MeasuredHobData->Num = mMeasuredBaseFvIndex + mMeasuredChildFvIndex; + + // + // Save measured base Fv info + // + CopyMem (MeasuredHobData->MeasuredFvBuf, mMeasuredBaseFvInfo, sizeof(EFI_PLATFORM_FIRMWARE_BLOB) * (mMeasuredBaseFvIndex)); + + // + // Save measured child Fv info + // + CopyMem (&MeasuredHobData->MeasuredFvBuf[mMeasuredBaseFvIndex] , mMeasuredChildFvInfo, sizeof(EFI_PLATFORM_FIRMWARE_BLOB) * (mMeasuredChildFvIndex)); + } + + return EFI_SUCCESS; +} + +/** + Make sure that the current PCR allocations, the TPM supported PCRs, + and the PcdTpm2HashMask are all in agreement. +**/ +VOID +SyncPcrAllocationsAndPcrMask ( + VOID + ) +{ + EFI_STATUS Status; + EFI_TCG2_EVENT_ALGORITHM_BITMAP TpmHashAlgorithmBitmap; + UINT32 TpmActivePcrBanks; + UINT32 NewTpmActivePcrBanks; + UINT32 Tpm2PcrMask; + UINT32 NewTpm2PcrMask; + + DEBUG ((EFI_D_ERROR, "SyncPcrAllocationsAndPcrMask!\n")); + + // + // Determine the current TPM support and the Platform PCR mask. + // + Status = Tpm2GetCapabilitySupportedAndActivePcrs (&TpmHashAlgorithmBitmap, &TpmActivePcrBanks); + ASSERT_EFI_ERROR (Status); + + Tpm2PcrMask = PcdGet32 (PcdTpm2HashMask); + + // + // Find the intersection of Pcd support and TPM support. + // If banks are missing from the TPM support that are in the PCD, update the PCD. + // If banks are missing from the PCD that are active in the TPM, reallocate the banks and reboot. + // + + // + // If there are active PCR banks that are not supported by the Platform mask, + // update the TPM allocations and reboot the machine. + // + if ((TpmActivePcrBanks & Tpm2PcrMask) != TpmActivePcrBanks) { + NewTpmActivePcrBanks = TpmActivePcrBanks & Tpm2PcrMask; + + DEBUG ((EFI_D_INFO, "%a - Reallocating PCR banks from 0x%X to 0x%X.\n", __FUNCTION__, TpmActivePcrBanks, NewTpmActivePcrBanks)); + if (NewTpmActivePcrBanks == 0) { + DEBUG ((EFI_D_ERROR, "%a - No viable PCRs active! Please set a less restrictive value for PcdTpm2HashMask!\n", __FUNCTION__)); + ASSERT (FALSE); + } else { + Status = Tpm2PcrAllocateBanks (NULL, (UINT32)TpmHashAlgorithmBitmap, NewTpmActivePcrBanks); + if (EFI_ERROR (Status)) { + // + // We can't do much here, but we hope that this doesn't happen. + // + DEBUG ((EFI_D_ERROR, "%a - Failed to reallocate PCRs!\n", __FUNCTION__)); + ASSERT_EFI_ERROR (Status); + } + // + // Need reset system, since we just called Tpm2PcrAllocateBanks(). + // + ResetCold(); + } + } + + // + // If there are any PCRs that claim support in the Platform mask that are + // not supported by the TPM, update the mask. + // + if ((Tpm2PcrMask & TpmHashAlgorithmBitmap) != Tpm2PcrMask) { + NewTpm2PcrMask = Tpm2PcrMask & TpmHashAlgorithmBitmap; + + DEBUG ((EFI_D_INFO, "%a - Updating PcdTpm2HashMask from 0x%X to 0x%X.\n", __FUNCTION__, Tpm2PcrMask, NewTpm2PcrMask)); + if (NewTpm2PcrMask == 0) { + DEBUG ((EFI_D_ERROR, "%a - No viable PCRs supported! Please set a less restrictive value for PcdTpm2HashMask!\n", __FUNCTION__)); + ASSERT (FALSE); + } + + Status = PcdSet32S (PcdTpm2HashMask, NewTpm2PcrMask); + ASSERT_EFI_ERROR (Status); + } +} + +/** + Add a new entry to the Event Log. + + @param[in] DigestList A list of digest. + @param[in,out] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR data structure. + @param[in] NewEventData Pointer to the new event data. + + @retval EFI_SUCCESS The new event log entry was added. + @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event. +**/ +EFI_STATUS +LogHashEvent ( + IN TPML_DIGEST_VALUES *DigestList, + IN OUT TCG_PCR_EVENT_HDR *NewEventHdr, + IN UINT8 *NewEventData + ) +{ + VOID *HobData; + EFI_STATUS Status; + UINTN Index; + EFI_STATUS RetStatus; + UINT32 SupportedEventLogs; + TCG_PCR_EVENT2 *TcgPcrEvent2; + UINT8 *DigestBuffer; + + SupportedEventLogs = EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2 | EFI_TCG2_EVENT_LOG_FORMAT_TCG_2; + + RetStatus = EFI_SUCCESS; + for (Index = 0; Index < sizeof(mTcg2EventInfo)/sizeof(mTcg2EventInfo[0]); Index++) { + if ((SupportedEventLogs & mTcg2EventInfo[Index].LogFormat) != 0) { + DEBUG ((EFI_D_INFO, " LogFormat - 0x%08x\n", mTcg2EventInfo[Index].LogFormat)); + switch (mTcg2EventInfo[Index].LogFormat) { + case EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2: + Status = GetDigestFromDigestList (TPM_ALG_SHA1, DigestList, &NewEventHdr->Digest); + if (!EFI_ERROR (Status)) { + HobData = BuildGuidHob ( + &gTcgEventEntryHobGuid, + sizeof (*NewEventHdr) + NewEventHdr->EventSize + ); + if (HobData == NULL) { + RetStatus = EFI_OUT_OF_RESOURCES; + break; + } + + CopyMem (HobData, NewEventHdr, sizeof (*NewEventHdr)); + HobData = (VOID *) ((UINT8*)HobData + sizeof (*NewEventHdr)); + CopyMem (HobData, NewEventData, NewEventHdr->EventSize); + } + break; + case EFI_TCG2_EVENT_LOG_FORMAT_TCG_2: + // + // Use GetDigestListSize (DigestList) in the GUID HOB DataLength calculation + // to reserve enough buffer to hold TPML_DIGEST_VALUES compact binary. + // + HobData = BuildGuidHob ( + &gTcgEvent2EntryHobGuid, + sizeof(TcgPcrEvent2->PCRIndex) + sizeof(TcgPcrEvent2->EventType) + GetDigestListSize (DigestList) + sizeof(TcgPcrEvent2->EventSize) + NewEventHdr->EventSize + ); + if (HobData == NULL) { + RetStatus = EFI_OUT_OF_RESOURCES; + break; + } + + TcgPcrEvent2 = HobData; + TcgPcrEvent2->PCRIndex = NewEventHdr->PCRIndex; + TcgPcrEvent2->EventType = NewEventHdr->EventType; + DigestBuffer = (UINT8 *)&TcgPcrEvent2->Digest; + DigestBuffer = CopyDigestListToBuffer (DigestBuffer, DigestList, PcdGet32 (PcdTpm2HashMask)); + CopyMem (DigestBuffer, &NewEventHdr->EventSize, sizeof(TcgPcrEvent2->EventSize)); + DigestBuffer = DigestBuffer + sizeof(TcgPcrEvent2->EventSize); + CopyMem (DigestBuffer, NewEventData, NewEventHdr->EventSize); + break; + } + } + } + + return RetStatus; +} + +/** + Do a hash operation on a data buffer, extend a specific TPM PCR with the hash result, + and build a GUIDed HOB recording the event which will be passed to the DXE phase and + added into the Event Log. + + @param[in] Flags Bitmap providing additional information. + @param[in] HashData Physical address of the start of the data buffer + to be hashed, extended, and logged. + @param[in] HashDataLen The length, in bytes, of the buffer referenced by HashData. + @param[in] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR data structure. + @param[in] NewEventData Pointer to the new event data. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event. + @retval EFI_DEVICE_ERROR The command was unsuccessful. + +**/ +EFI_STATUS +HashLogExtendEvent ( + IN UINT64 Flags, + IN UINT8 *HashData, + IN UINTN HashDataLen, + IN TCG_PCR_EVENT_HDR *NewEventHdr, + IN UINT8 *NewEventData + ) +{ + EFI_STATUS Status; + TPML_DIGEST_VALUES DigestList; + + if (GetFirstGuidHob (&gTpmErrorHobGuid) != NULL) { + return EFI_DEVICE_ERROR; + } + + Status = HashAndExtend ( + NewEventHdr->PCRIndex, + HashData, + HashDataLen, + &DigestList + ); + if (!EFI_ERROR (Status)) { + if ((Flags & EFI_TCG2_EXTEND_ONLY) == 0) { + Status = LogHashEvent (&DigestList, NewEventHdr, NewEventData); + } + } + + if (Status == EFI_DEVICE_ERROR) { + DEBUG ((EFI_D_ERROR, "HashLogExtendEvent - %r. Disable TPM.\n", Status)); + BuildGuidHob (&gTpmErrorHobGuid,0); + REPORT_STATUS_CODE ( + EFI_ERROR_CODE | EFI_ERROR_MINOR, + (PcdGet32 (PcdStatusCodeSubClassTpmDevice) | EFI_P_EC_INTERFACE_ERROR) + ); + } + + return Status; +} + +/** + Measure CRTM version. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event. + @retval EFI_DEVICE_ERROR The command was unsuccessful. + +**/ +EFI_STATUS +MeasureCRTMVersion ( + VOID + ) +{ + TCG_PCR_EVENT_HDR TcgEventHdr; + + // + // Use FirmwareVersion string to represent CRTM version. + // OEMs should get real CRTM version string and measure it. + // + + TcgEventHdr.PCRIndex = 0; + TcgEventHdr.EventType = EV_S_CRTM_VERSION; + TcgEventHdr.EventSize = (UINT32) StrSize((CHAR16*)PcdGetPtr (PcdFirmwareVersionString)); + + return HashLogExtendEvent ( + 0, + (UINT8*)PcdGetPtr (PcdFirmwareVersionString), + TcgEventHdr.EventSize, + &TcgEventHdr, + (UINT8*)PcdGetPtr (PcdFirmwareVersionString) + ); +} + +/** + Measure FV image. + Add it into the measured FV list after the FV is measured successfully. + + @param[in] FvBase Base address of FV image. + @param[in] FvLength Length of FV image. + + @retval EFI_SUCCESS Fv image is measured successfully + or it has been already measured. + @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event. + @retval EFI_DEVICE_ERROR The command was unsuccessful. + +**/ +EFI_STATUS +MeasureFvImage ( + IN EFI_PHYSICAL_ADDRESS FvBase, + IN UINT64 FvLength + ) +{ + UINT32 Index; + EFI_STATUS Status; + EFI_PLATFORM_FIRMWARE_BLOB FvBlob; + TCG_PCR_EVENT_HDR TcgEventHdr; + + // + // Check if it is in Excluded FV list + // + if (mMeasurementExcludedFvPpi != NULL) { + for (Index = 0; Index < mMeasurementExcludedFvPpi->Count; Index ++) { + if (mMeasurementExcludedFvPpi->Fv[Index].FvBase == FvBase) { + DEBUG ((DEBUG_INFO, "The FV which is excluded by Tcg2Pei starts at: 0x%x\n", FvBase)); + DEBUG ((DEBUG_INFO, "The FV which is excluded by Tcg2Pei has the size: 0x%x\n", FvLength)); + return EFI_SUCCESS; + } + } + } + + // + // Check whether FV is in the measured FV list. + // + for (Index = 0; Index < mMeasuredBaseFvIndex; Index ++) { + if (mMeasuredBaseFvInfo[Index].BlobBase == FvBase) { + return EFI_SUCCESS; + } + } + + // + // Measure and record the FV to the TPM + // + FvBlob.BlobBase = FvBase; + FvBlob.BlobLength = FvLength; + + DEBUG ((DEBUG_INFO, "The FV which is measured by Tcg2Pei starts at: 0x%x\n", FvBlob.BlobBase)); + DEBUG ((DEBUG_INFO, "The FV which is measured by Tcg2Pei has the size: 0x%x\n", FvBlob.BlobLength)); + + TcgEventHdr.PCRIndex = 0; + TcgEventHdr.EventType = EV_EFI_PLATFORM_FIRMWARE_BLOB; + TcgEventHdr.EventSize = sizeof (FvBlob); + + Status = HashLogExtendEvent ( + 0, + (UINT8*) (UINTN) FvBlob.BlobBase, + (UINTN) FvBlob.BlobLength, + &TcgEventHdr, + (UINT8*) &FvBlob + ); + + // + // Add new FV into the measured FV list. + // + ASSERT (mMeasuredBaseFvIndex < PcdGet32 (PcdPeiCoreMaxFvSupported)); + if (mMeasuredBaseFvIndex < PcdGet32 (PcdPeiCoreMaxFvSupported)) { + mMeasuredBaseFvInfo[mMeasuredBaseFvIndex].BlobBase = FvBase; + mMeasuredBaseFvInfo[mMeasuredBaseFvIndex].BlobLength = FvLength; + mMeasuredBaseFvIndex++; + } + + return Status; +} + +/** + Measure main BIOS. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event. + @retval EFI_DEVICE_ERROR The command was unsuccessful. + +**/ +EFI_STATUS +MeasureMainBios ( + VOID + ) +{ + EFI_STATUS Status; + UINT32 FvInstances; + EFI_PEI_FV_HANDLE VolumeHandle; + EFI_FV_INFO VolumeInfo; + EFI_PEI_FIRMWARE_VOLUME_PPI *FvPpi; + + PERF_START_EX (mFileHandle, "EventRec", "Tcg2Pei", 0, PERF_ID_TCG2_PEI); + FvInstances = 0; + while (TRUE) { + // + // Traverse all firmware volume instances of Static Core Root of Trust for Measurement + // (S-CRTM), this firmware volume measure policy can be modified/enhanced by special + // platform for special CRTM TPM measuring. + // + Status = PeiServicesFfsFindNextVolume (FvInstances, &VolumeHandle); + if (EFI_ERROR (Status)) { + break; + } + + // + // Measure and record the firmware volume that is dispatched by PeiCore + // + Status = PeiServicesFfsGetVolumeInfo (VolumeHandle, &VolumeInfo); + ASSERT_EFI_ERROR (Status); + // + // Locate the corresponding FV_PPI according to founded FV's format guid + // + Status = PeiServicesLocatePpi ( + &VolumeInfo.FvFormat, + 0, + NULL, + (VOID**)&FvPpi + ); + if (!EFI_ERROR (Status)) { + MeasureFvImage ((EFI_PHYSICAL_ADDRESS) (UINTN) VolumeInfo.FvStart, VolumeInfo.FvSize); + } + + FvInstances++; + } + PERF_END_EX (mFileHandle, "EventRec", "Tcg2Pei", 0, PERF_ID_TCG2_PEI + 1); + + return EFI_SUCCESS; +} + +/** + Measure and record the Firmware Volum Information once FvInfoPPI install. + + @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation. + @param[in] NotifyDescriptor Address of the notification descriptor data structure. + @param[in] Ppi Address of the PPI that was installed. + + @retval EFI_SUCCESS The FV Info is measured and recorded to TPM. + @return Others Fail to measure FV. + +**/ +EFI_STATUS +EFIAPI +FirmwareVolmeInfoPpiNotifyCallback ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, + IN VOID *Ppi + ) +{ + EFI_PEI_FIRMWARE_VOLUME_INFO_PPI *Fv; + EFI_STATUS Status; + EFI_PEI_FIRMWARE_VOLUME_PPI *FvPpi; + UINTN Index; + + Fv = (EFI_PEI_FIRMWARE_VOLUME_INFO_PPI *) Ppi; + + // + // The PEI Core can not dispatch or load files from memory mapped FVs that do not support FvPpi. + // + Status = PeiServicesLocatePpi ( + &Fv->FvFormat, + 0, + NULL, + (VOID**)&FvPpi + ); + if (EFI_ERROR (Status)) { + return EFI_SUCCESS; + } + + // + // This is an FV from an FFS file, and the parent FV must have already been measured, + // No need to measure twice, so just record the FV and return + // + if (Fv->ParentFvName != NULL || Fv->ParentFileName != NULL ) { + + ASSERT (mMeasuredChildFvIndex < PcdGet32 (PcdPeiCoreMaxFvSupported)); + if (mMeasuredChildFvIndex < PcdGet32 (PcdPeiCoreMaxFvSupported)) { + // + // Check whether FV is in the measured child FV list. + // + for (Index = 0; Index < mMeasuredChildFvIndex; Index++) { + if (mMeasuredChildFvInfo[Index].BlobBase == (EFI_PHYSICAL_ADDRESS) (UINTN) Fv->FvInfo) { + return EFI_SUCCESS; + } + } + mMeasuredChildFvInfo[mMeasuredChildFvIndex].BlobBase = (EFI_PHYSICAL_ADDRESS) (UINTN) Fv->FvInfo; + mMeasuredChildFvInfo[mMeasuredChildFvIndex].BlobLength = Fv->FvInfoSize; + mMeasuredChildFvIndex++; + } + return EFI_SUCCESS; + } + + return MeasureFvImage ((EFI_PHYSICAL_ADDRESS) (UINTN) Fv->FvInfo, Fv->FvInfoSize); +} + +/** + Do measurement after memory is ready. + + @param[in] PeiServices Describes the list of possible PEI Services. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event. + @retval EFI_DEVICE_ERROR The command was unsuccessful. + +**/ +EFI_STATUS +PeimEntryMP ( + IN EFI_PEI_SERVICES **PeiServices + ) +{ + EFI_STATUS Status; + + Status = PeiServicesLocatePpi ( + &gEfiPeiFirmwareVolumeInfoMeasurementExcludedPpiGuid, + 0, + NULL, + (VOID**)&mMeasurementExcludedFvPpi + ); + // Do not check status, because it is optional + + mMeasuredBaseFvInfo = (EFI_PLATFORM_FIRMWARE_BLOB *) AllocateZeroPool (sizeof (EFI_PLATFORM_FIRMWARE_BLOB) * PcdGet32 (PcdPeiCoreMaxFvSupported)); + ASSERT (mMeasuredBaseFvInfo != NULL); + mMeasuredChildFvInfo = (EFI_PLATFORM_FIRMWARE_BLOB *) AllocateZeroPool (sizeof (EFI_PLATFORM_FIRMWARE_BLOB) * PcdGet32 (PcdPeiCoreMaxFvSupported)); + ASSERT (mMeasuredChildFvInfo != NULL); + + if (PcdGet8 (PcdTpm2ScrtmPolicy) == 1) { + Status = MeasureCRTMVersion (); + } + + Status = MeasureMainBios (); + + // + // Post callbacks: + // for the FvInfoPpi services to measure and record + // the additional Fvs to TPM + // + Status = PeiServicesNotifyPpi (&mNotifyList[0]); + ASSERT_EFI_ERROR (Status); + + return Status; +} + +/** + Measure and log Separator event with error, and extend the measurement result into a specific PCR. + + @param[in] PCRIndex PCR index. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR The operation was unsuccessful. + +**/ +EFI_STATUS +MeasureSeparatorEventWithError ( + IN TPM_PCRINDEX PCRIndex + ) +{ + TCG_PCR_EVENT_HDR TcgEvent; + UINT32 EventData; + + // + // Use EventData 0x1 to indicate there is error. + // + EventData = 0x1; + TcgEvent.PCRIndex = PCRIndex; + TcgEvent.EventType = EV_SEPARATOR; + TcgEvent.EventSize = (UINT32)sizeof (EventData); + return HashLogExtendEvent(0,(UINT8 *)&EventData, TcgEvent.EventSize, &TcgEvent,(UINT8 *)&EventData); +} + +/** + Entry point of this module. + + @param[in] FileHandle Handle of the file being invoked. + @param[in] PeiServices Describes the list of possible PEI Services. + + @return Status. + +**/ +EFI_STATUS +EFIAPI +PeimEntryMA ( + IN EFI_PEI_FILE_HANDLE FileHandle, + IN CONST EFI_PEI_SERVICES **PeiServices + ) +{ + EFI_STATUS Status; + EFI_STATUS Status2; + EFI_BOOT_MODE BootMode; + TPM_PCRINDEX PcrIndex; + BOOLEAN S3ErrorReport; + + if (CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceNoneGuid) || + CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceTpm12Guid)){ + DEBUG ((DEBUG_INFO, "No TPM2 instance required!\n")); + return EFI_UNSUPPORTED; + } + + if (GetFirstGuidHob (&gTpmErrorHobGuid) != NULL) { + DEBUG ((EFI_D_ERROR, "TPM2 error!\n")); + return EFI_DEVICE_ERROR; + } + + Status = PeiServicesGetBootMode (&BootMode); + ASSERT_EFI_ERROR (Status); + + // + // In S3 path, skip shadow logic. no measurement is required + // + if (BootMode != BOOT_ON_S3_RESUME) { + Status = (**PeiServices).RegisterForShadow(FileHandle); + if (Status == EFI_ALREADY_STARTED) { + mImageInMemory = TRUE; + mFileHandle = FileHandle; + } else if (Status == EFI_NOT_FOUND) { + ASSERT_EFI_ERROR (Status); + } + } + + if (!mImageInMemory) { + // + // Initialize TPM device + // + Status = Tpm2RequestUseTpm (); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "TPM2 not detected!\n")); + goto Done; + } + + S3ErrorReport = FALSE; + if (PcdGet8 (PcdTpm2InitializationPolicy) == 1) { + if (BootMode == BOOT_ON_S3_RESUME) { + Status = Tpm2Startup (TPM_SU_STATE); + if (EFI_ERROR (Status) ) { + Status = Tpm2Startup (TPM_SU_CLEAR); + if (!EFI_ERROR(Status)) { + S3ErrorReport = TRUE; + } + } + } else { + Status = Tpm2Startup (TPM_SU_CLEAR); + } + if (EFI_ERROR (Status) ) { + goto Done; + } + } + + // + // Update Tpm2HashMask according to PCR bank. + // + SyncPcrAllocationsAndPcrMask (); + + if (S3ErrorReport) { + // + // The system firmware that resumes from S3 MUST deal with a + // TPM2_Startup error appropriately. + // For example, issue a TPM2_Startup(TPM_SU_CLEAR) command and + // configuring the device securely by taking actions like extending a + // separator with an error digest (0x01) into PCRs 0 through 7. + // + for (PcrIndex = 0; PcrIndex < 8; PcrIndex++) { + Status = MeasureSeparatorEventWithError (PcrIndex); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Separator Event with Error not Measured. Error!\n")); + } + } + } + + // + // TpmSelfTest is optional on S3 path, skip it to save S3 time + // + if (BootMode != BOOT_ON_S3_RESUME) { + if (PcdGet8 (PcdTpm2SelfTestPolicy) == 1) { + Status = Tpm2SelfTest (NO); + if (EFI_ERROR (Status)) { + goto Done; + } + } + } + + // + // Only intall TpmInitializedPpi on success + // + Status = PeiServicesInstallPpi (&mTpmInitializedPpiList); + ASSERT_EFI_ERROR (Status); + } + + if (mImageInMemory) { + Status = PeimEntryMP ((EFI_PEI_SERVICES**)PeiServices); + return Status; + } + +Done: + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "TPM2 error! Build Hob\n")); + BuildGuidHob (&gTpmErrorHobGuid,0); + REPORT_STATUS_CODE ( + EFI_ERROR_CODE | EFI_ERROR_MINOR, + (PcdGet32 (PcdStatusCodeSubClassTpmDevice) | EFI_P_EC_INTERFACE_ERROR) + ); + } + // + // Always intall TpmInitializationDonePpi no matter success or fail. + // Other driver can know TPM initialization state by TpmInitializedPpi. + // + Status2 = PeiServicesInstallPpi (&mTpmInitializationDonePpiList); + ASSERT_EFI_ERROR (Status2); + + return Status; +} diff --git a/Core/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.inf b/Core/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.inf new file mode 100644 index 0000000000..3477d8206a --- /dev/null +++ b/Core/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.inf @@ -0,0 +1,92 @@ +## @file +# Initializes TPM 2.0 device and measure FVs in PEI phase +# +# This module will initialize TPM device, measure reported FVs and BIOS version. +# +# Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = Tcg2Pei + MODULE_UNI_FILE = Tcg2Pei.uni + FILE_GUID = A0C98B77-CBA5-4BB8-993B-4AF6CE33ECE4 + MODULE_TYPE = PEIM + VERSION_STRING = 1.0 + ENTRY_POINT = PeimEntryMA + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# +# [BootMode] +# S3_RESUME ## SOMETIMES_CONSUMES +# + +[Sources] + Tcg2Pei.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + HobLib + PeimEntryPoint + PeiServicesLib + BaseMemoryLib + DebugLib + Tpm2CommandLib + PeiServicesTablePointerLib + Tpm2DeviceLib + HashLib + PerformanceLib + MemoryAllocationLib + ReportStatusCodeLib + Tcg2PhysicalPresenceLib + ResetSystemLib + +[Guids] + gTcgEventEntryHobGuid ## PRODUCES ## HOB + gTpmErrorHobGuid ## SOMETIMES_PRODUCES ## HOB + gMeasuredFvHobGuid ## PRODUCES ## HOB + gTcgEvent2EntryHobGuid ## PRODUCES ## HOB + gEfiTpmDeviceInstanceNoneGuid ## SOMETIMES_PRODUCES ## GUID # TPM device identifier + gEfiTpmDeviceInstanceTpm12Guid ## SOMETIMES_PRODUCES ## GUID # TPM device identifier + +[Ppis] + gEfiPeiFirmwareVolumeInfoPpiGuid ## SOMETIMES_CONSUMES ## NOTIFY + gEfiPeiFirmwareVolumeInfo2PpiGuid ## SOMETIMES_CONSUMES ## NOTIFY + gEfiPeiFirmwareVolumeInfoMeasurementExcludedPpiGuid ## SOMETIMES_CONSUMES + gPeiTpmInitializedPpiGuid ## SOMETIMES_PRODUCES + gPeiTpmInitializationDonePpiGuid ## PRODUCES + gEfiEndOfPeiSignalPpiGuid ## SOMETIMES_CONSUMES ## NOTIFY + +[Pcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdFirmwareVersionString ## SOMETIMES_CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdTpmInstanceGuid ## CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdTpm2InitializationPolicy ## CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdTpm2SelfTestPolicy ## SOMETIMES_CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdTpm2ScrtmPolicy ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdPeiCoreMaxFvSupported ## CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdStatusCodeSubClassTpmDevice ## SOMETIMES_CONSUMES + ## SOMETIMES_CONSUMES + ## SOMETIMES_PRODUCES + gEfiSecurityPkgTokenSpaceGuid.PcdTpm2HashMask + +[Depex] + gEfiPeiMasterBootModePpiGuid AND + gEfiPeiReadOnlyVariable2PpiGuid AND + gEfiTpmDeviceSelectedGuid + +[UserExtensions.TianoCore."ExtraFiles"] + Tcg2PeiExtra.uni diff --git a/Core/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.uni b/Core/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.uni new file mode 100644 index 0000000000..4622dffaa8 --- /dev/null +++ b/Core/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.uni @@ -0,0 +1,21 @@ +// /** @file +// Initializes TPM 2.0 device and measure FVs in PEI phase +// +// This module will initialize TPM device, measure reported FVs and BIOS version. +// +// Copyright (c) 2015, Intel Corporation. All rights reserved.
+// +// This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// **/ + + +#string STR_MODULE_ABSTRACT #language en-US "Initializes TPM 2.0 device and measure FVs in PEI phase" + +#string STR_MODULE_DESCRIPTION #language en-US "This module will initialize TPM device, measure reported FVs and BIOS version." + diff --git a/Core/SecurityPkg/Tcg/Tcg2Pei/Tcg2PeiExtra.uni b/Core/SecurityPkg/Tcg/Tcg2Pei/Tcg2PeiExtra.uni new file mode 100644 index 0000000000..dea6dcc0e3 --- /dev/null +++ b/Core/SecurityPkg/Tcg/Tcg2Pei/Tcg2PeiExtra.uni @@ -0,0 +1,19 @@ +// /** @file +// Tcg2Pei Localized Strings and Content +// +// Copyright (c) 2015, Intel Corporation. All rights reserved.
+// +// This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// **/ + +#string STR_PROPERTIES_MODULE_NAME +#language en-US +"TCG2 (Trusted Computing Group) PEI" + + diff --git a/Core/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.c b/Core/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.c new file mode 100644 index 0000000000..5a1fd3e363 --- /dev/null +++ b/Core/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.c @@ -0,0 +1,649 @@ +/** @file + It updates TPM2 items in ACPI table and registers SMI2 callback + functions for Tcg2 physical presence, ClearMemory, and sample + for dTPM StartMethod. + + Caution: This module requires additional review when modified. + This driver will have external input - variable and ACPINvs data in SMM mode. + This external input must be validated carefully to avoid security issue. + + PhysicalPresenceCallback() and MemoryClearCallback() will receive untrusted input and do some check. + +Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "Tcg2Smm.h" + +typedef enum { + PtpInterfaceTis, + PtpInterfaceFifo, + PtpInterfaceCrb, + PtpInterfaceMax, +} PTP_INTERFACE_TYPE; + +/** + Return PTP interface type. + + @param[in] Register Pointer to PTP register. + + @return PTP interface type. +**/ +PTP_INTERFACE_TYPE +GetPtpInterface ( + IN VOID *Register + ) +{ + PTP_CRB_INTERFACE_IDENTIFIER InterfaceId; + PTP_FIFO_INTERFACE_CAPABILITY InterfaceCapability; + + // + // Check interface id + // + InterfaceId.Uint32 = MmioRead32 ((UINTN)&((PTP_CRB_REGISTERS *)Register)->InterfaceId); + InterfaceCapability.Uint32 = MmioRead32 ((UINTN)&((PTP_FIFO_REGISTERS *)Register)->InterfaceCapability); + + if (InterfaceId.Bits.InterfaceType == PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_TIS) { + return PtpInterfaceTis; + } + + if ((InterfaceId.Bits.InterfaceType == PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_CRB) && + (InterfaceId.Bits.InterfaceVersion == PTP_INTERFACE_IDENTIFIER_INTERFACE_VERSION_CRB) && + (InterfaceId.Bits.CapCRB != 0)) { + return PtpInterfaceCrb; + } + + if ((InterfaceId.Bits.InterfaceType == PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_FIFO) && + (InterfaceId.Bits.InterfaceVersion == PTP_INTERFACE_IDENTIFIER_INTERFACE_VERSION_FIFO) && + (InterfaceId.Bits.CapFIFO != 0) && + (InterfaceCapability.Bits.InterfaceVersion == INTERFACE_CAPABILITY_INTERFACE_VERSION_PTP)) { + return PtpInterfaceFifo; + } + + // + // No Ptp interface available + // + return PtpInterfaceMax; +} + +EFI_TPM2_ACPI_TABLE mTpm2AcpiTemplate = { + { + EFI_ACPI_5_0_TRUSTED_COMPUTING_PLATFORM_2_TABLE_SIGNATURE, + sizeof (mTpm2AcpiTemplate), + EFI_TPM2_ACPI_TABLE_REVISION, + // + // Compiler initializes the remaining bytes to 0 + // These fields should be filled in in production + // + }, + 0, // BIT0~15: PlatformClass + // BIT16~31: Reserved + 0, // Control Area + EFI_TPM2_ACPI_TABLE_START_METHOD_TIS, // StartMethod +}; + +EFI_SMM_VARIABLE_PROTOCOL *mSmmVariable; +TCG_NVS *mTcgNvs; + +/** + Software SMI callback for TPM physical presence which is called from ACPI method. + + Caution: This function may receive untrusted input. + Variable and ACPINvs are external input, so this function will validate + its data structure to be valid value. + + @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister(). + @param[in] Context Points to an optional handler context which was specified when the + handler was registered. + @param[in, out] CommBuffer A pointer to a collection of data in memory that will + be conveyed from a non-SMM environment into an SMM environment. + @param[in, out] CommBufferSize The size of the CommBuffer. + + @retval EFI_SUCCESS The interrupt was handled successfully. + +**/ +EFI_STATUS +EFIAPI +PhysicalPresenceCallback ( + IN EFI_HANDLE DispatchHandle, + IN CONST VOID *Context, + IN OUT VOID *CommBuffer, + IN OUT UINTN *CommBufferSize + ) +{ + UINT32 MostRecentRequest; + UINT32 Response; + UINT32 OperationRequest; + UINT32 RequestParameter; + + + if (mTcgNvs->PhysicalPresence.Parameter == TCG_ACPI_FUNCTION_RETURN_REQUEST_RESPONSE_TO_OS) { + mTcgNvs->PhysicalPresence.ReturnCode = Tcg2PhysicalPresenceLibReturnOperationResponseToOsFunction ( + &MostRecentRequest, + &Response + ); + mTcgNvs->PhysicalPresence.LastRequest = MostRecentRequest; + mTcgNvs->PhysicalPresence.Response = Response; + return EFI_SUCCESS; + } else if ((mTcgNvs->PhysicalPresence.Parameter == TCG_ACPI_FUNCTION_SUBMIT_REQUEST_TO_BIOS) + || (mTcgNvs->PhysicalPresence.Parameter == TCG_ACPI_FUNCTION_SUBMIT_REQUEST_TO_BIOS_2)) { + + OperationRequest = mTcgNvs->PhysicalPresence.Request; + RequestParameter = mTcgNvs->PhysicalPresence.RequestParameter; + mTcgNvs->PhysicalPresence.ReturnCode = Tcg2PhysicalPresenceLibSubmitRequestToPreOSFunctionEx ( + &OperationRequest, + &RequestParameter + ); + mTcgNvs->PhysicalPresence.Request = OperationRequest; + mTcgNvs->PhysicalPresence.RequestParameter = RequestParameter; + } else if (mTcgNvs->PhysicalPresence.Parameter == TCG_ACPI_FUNCTION_GET_USER_CONFIRMATION_STATUS_FOR_REQUEST) { + mTcgNvs->PhysicalPresence.ReturnCode = Tcg2PhysicalPresenceLibGetUserConfirmationStatusFunction (mTcgNvs->PPRequestUserConfirm); + } + + return EFI_SUCCESS; +} + + +/** + Software SMI callback for MemoryClear which is called from ACPI method. + + Caution: This function may receive untrusted input. + Variable and ACPINvs are external input, so this function will validate + its data structure to be valid value. + + @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister(). + @param[in] Context Points to an optional handler context which was specified when the + handler was registered. + @param[in, out] CommBuffer A pointer to a collection of data in memory that will + be conveyed from a non-SMM environment into an SMM environment. + @param[in, out] CommBufferSize The size of the CommBuffer. + + @retval EFI_SUCCESS The interrupt was handled successfully. + +**/ +EFI_STATUS +EFIAPI +MemoryClearCallback ( + IN EFI_HANDLE DispatchHandle, + IN CONST VOID *Context, + IN OUT VOID *CommBuffer, + IN OUT UINTN *CommBufferSize + ) +{ + EFI_STATUS Status; + UINTN DataSize; + UINT8 MorControl; + + mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_SUCCESS; + if (mTcgNvs->MemoryClear.Parameter == ACPI_FUNCTION_DSM_MEMORY_CLEAR_INTERFACE) { + MorControl = (UINT8) mTcgNvs->MemoryClear.Request; + } else if (mTcgNvs->MemoryClear.Parameter == ACPI_FUNCTION_PTS_CLEAR_MOR_BIT) { + DataSize = sizeof (UINT8); + Status = mSmmVariable->SmmGetVariable ( + MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME, + &gEfiMemoryOverwriteControlDataGuid, + NULL, + &DataSize, + &MorControl + ); + if (EFI_ERROR (Status)) { + mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_GENERAL_FAILURE; + DEBUG ((EFI_D_ERROR, "[TPM] Get MOR variable failure! Status = %r\n", Status)); + return EFI_SUCCESS; + } + + if (MOR_CLEAR_MEMORY_VALUE (MorControl) == 0x0) { + return EFI_SUCCESS; + } + MorControl &= ~MOR_CLEAR_MEMORY_BIT_MASK; + } + + DataSize = sizeof (UINT8); + Status = mSmmVariable->SmmSetVariable ( + MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME, + &gEfiMemoryOverwriteControlDataGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + DataSize, + &MorControl + ); + if (EFI_ERROR (Status)) { + mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_GENERAL_FAILURE; + DEBUG ((EFI_D_ERROR, "[TPM] Set MOR variable failure! Status = %r\n", Status)); + } + + return EFI_SUCCESS; +} + +/** + Find the operation region in TCG ACPI table by given Name and Size, + and initialize it if the region is found. + + @param[in, out] Table The TPM item in ACPI table. + @param[in] Name The name string to find in TPM table. + @param[in] Size The size of the region to find. + + @return The allocated address for the found region. + +**/ +VOID * +AssignOpRegion ( + EFI_ACPI_DESCRIPTION_HEADER *Table, + UINT32 Name, + UINT16 Size + ) +{ + EFI_STATUS Status; + AML_OP_REGION_32_8 *OpRegion; + EFI_PHYSICAL_ADDRESS MemoryAddress; + + MemoryAddress = SIZE_4GB - 1; + + // + // Patch some pointers for the ASL code before loading the SSDT. + // + for (OpRegion = (AML_OP_REGION_32_8 *) (Table + 1); + OpRegion <= (AML_OP_REGION_32_8 *) ((UINT8 *) Table + Table->Length); + OpRegion = (AML_OP_REGION_32_8 *) ((UINT8 *) OpRegion + 1)) { + if ((OpRegion->OpRegionOp == AML_EXT_REGION_OP) && + (OpRegion->NameString == Name) && + (OpRegion->DWordPrefix == AML_DWORD_PREFIX) && + (OpRegion->BytePrefix == AML_BYTE_PREFIX)) { + + Status = gBS->AllocatePages(AllocateMaxAddress, EfiACPIMemoryNVS, EFI_SIZE_TO_PAGES (Size), &MemoryAddress); + ASSERT_EFI_ERROR (Status); + ZeroMem ((VOID *)(UINTN)MemoryAddress, Size); + OpRegion->RegionOffset = (UINT32) (UINTN) MemoryAddress; + OpRegion->RegionLen = (UINT8) Size; + break; + } + } + + return (VOID *) (UINTN) MemoryAddress; +} + +/** + Patch version string of Physical Presence interface supported by platform. The initial string tag in TPM +ACPI table is "$PV". + + @param[in, out] Table The TPM item in ACPI table. + @param[in] PPVer Version string of Physical Presence interface supported by platform. + + @return The allocated address for the found region. + +**/ +EFI_STATUS +UpdatePPVersion ( + EFI_ACPI_DESCRIPTION_HEADER *Table, + CHAR8 *PPVer + ) +{ + EFI_STATUS Status; + UINT8 *DataPtr; + + // + // Patch some pointers for the ASL code before loading the SSDT. + // + for (DataPtr = (UINT8 *)(Table + 1); + DataPtr <= (UINT8 *) ((UINT8 *) Table + Table->Length - PHYSICAL_PRESENCE_VERSION_SIZE); + DataPtr += 1) { + if (AsciiStrCmp((CHAR8 *)DataPtr, PHYSICAL_PRESENCE_VERSION_TAG) == 0) { + Status = AsciiStrCpyS((CHAR8 *)DataPtr, PHYSICAL_PRESENCE_VERSION_SIZE, PPVer); + DEBUG((EFI_D_INFO, "TPM2 Physical Presence Interface Version update status 0x%x\n", Status)); + return Status; + } + } + + return EFI_NOT_FOUND; +} + +/** + Patch TPM2 device HID string. The initial string tag in TPM2 ACPI table is "NNN0000". + + @param[in, out] Table The TPM2 SSDT ACPI table. + + @return HID Update status. + +**/ +EFI_STATUS +UpdateHID ( + EFI_ACPI_DESCRIPTION_HEADER *Table + ) +{ + EFI_STATUS Status; + UINT8 *DataPtr; + CHAR8 Hid[TPM_HID_ACPI_SIZE]; + UINT32 ManufacturerID; + UINT32 FirmwareVersion1; + UINT32 FirmwareVersion2; + BOOLEAN PnpHID; + + PnpHID = TRUE; + + // + // Initialize HID with Default PNP string + // + ZeroMem(Hid, TPM_HID_ACPI_SIZE); + + // + // Get Manufacturer ID + // + Status = Tpm2GetCapabilityManufactureID(&ManufacturerID); + if (!EFI_ERROR(Status)) { + DEBUG((EFI_D_INFO, "TPM_PT_MANUFACTURER 0x%08x\n", ManufacturerID)); + // + // ManufacturerID defined in TCG Vendor ID Registry + // may tailed with 0x00 or 0x20 + // + if ((ManufacturerID >> 24) == 0x00 || ((ManufacturerID >> 24) == 0x20)) { + // + // HID containing PNP ID "NNN####" + // NNN is uppercase letter for Vendor ID specified by manufacturer + // + CopyMem(Hid, &ManufacturerID, 3); + } else { + // + // HID containing ACP ID "NNNN####" + // NNNN is uppercase letter for Vendor ID specified by manufacturer + // + CopyMem(Hid, &ManufacturerID, 4); + PnpHID = FALSE; + } + } else { + DEBUG ((EFI_D_ERROR, "Get TPM_PT_MANUFACTURER failed %x!\n", Status)); + ASSERT(FALSE); + return Status; + } + + Status = Tpm2GetCapabilityFirmwareVersion(&FirmwareVersion1, &FirmwareVersion2); + if (!EFI_ERROR(Status)) { + DEBUG((EFI_D_INFO, "TPM_PT_FIRMWARE_VERSION_1 0x%x\n", FirmwareVersion1)); + DEBUG((EFI_D_INFO, "TPM_PT_FIRMWARE_VERSION_2 0x%x\n", FirmwareVersion2)); + // + // #### is Firmware Version 1 + // + if (PnpHID) { + AsciiSPrint(Hid + 3, TPM_HID_PNP_SIZE - 3, "%02d%02d", ((FirmwareVersion1 & 0xFFFF0000) >> 16), (FirmwareVersion1 & 0x0000FFFF)); + } else { + AsciiSPrint(Hid + 4, TPM_HID_ACPI_SIZE - 4, "%02d%02d", ((FirmwareVersion1 & 0xFFFF0000) >> 16), (FirmwareVersion1 & 0x0000FFFF)); + } + + } else { + DEBUG ((EFI_D_ERROR, "Get TPM_PT_FIRMWARE_VERSION_X failed %x!\n", Status)); + ASSERT(FALSE); + return Status; + } + + // + // Patch HID in ASL code before loading the SSDT. + // + for (DataPtr = (UINT8 *)(Table + 1); + DataPtr <= (UINT8 *) ((UINT8 *) Table + Table->Length - TPM_HID_PNP_SIZE); + DataPtr += 1) { + if (AsciiStrCmp((CHAR8 *)DataPtr, TPM_HID_TAG) == 0) { + if (PnpHID) { + CopyMem(DataPtr, Hid, TPM_HID_PNP_SIZE); + // + // if HID is PNP ID, patch the last byte in HID TAG to Noop + // + *(DataPtr + TPM_HID_PNP_SIZE) = AML_NOOP_OP; + } else { + + CopyMem(DataPtr, Hid, TPM_HID_ACPI_SIZE); + } + DEBUG((DEBUG_INFO, "TPM2 ACPI _HID is patched to %a\n", DataPtr)); + + return Status; + } + } + + DEBUG((EFI_D_ERROR, "TPM2 ACPI HID TAG for patch not found!\n")); + return EFI_NOT_FOUND; +} + +/** + Initialize and publish TPM items in ACPI table. + + @retval EFI_SUCCESS The TCG ACPI table is published successfully. + @retval Others The TCG ACPI table is not published. + +**/ +EFI_STATUS +PublishAcpiTable ( + VOID + ) +{ + EFI_STATUS Status; + EFI_ACPI_TABLE_PROTOCOL *AcpiTable; + UINTN TableKey; + EFI_ACPI_DESCRIPTION_HEADER *Table; + UINTN TableSize; + + Status = GetSectionFromFv ( + &gEfiCallerIdGuid, + EFI_SECTION_RAW, + 0, + (VOID **) &Table, + &TableSize + ); + ASSERT_EFI_ERROR (Status); + + // + // Update Table version before measuring it to PCR + // + Status = UpdatePPVersion(Table, (CHAR8 *)PcdGetPtr(PcdTcgPhysicalPresenceInterfaceVer)); + ASSERT_EFI_ERROR (Status); + + DEBUG (( + DEBUG_INFO, + "Current physical presence interface version - %a\n", + (CHAR8 *) PcdGetPtr(PcdTcgPhysicalPresenceInterfaceVer) + )); + + // + // Update TPM2 HID before measuring it to PCR + // + Status = UpdateHID(Table); + if (EFI_ERROR(Status)) { + return Status; + } + + // + // Measure to PCR[0] with event EV_POST_CODE ACPI DATA + // + TpmMeasureAndLogData( + 0, + EV_POST_CODE, + EV_POSTCODE_INFO_ACPI_DATA, + ACPI_DATA_LEN, + Table, + TableSize + ); + + + ASSERT (Table->OemTableId == SIGNATURE_64 ('T', 'p', 'm', '2', 'T', 'a', 'b', 'l')); + CopyMem (Table->OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (Table->OemId) ); + mTcgNvs = AssignOpRegion (Table, SIGNATURE_32 ('T', 'N', 'V', 'S'), (UINT16) sizeof (TCG_NVS)); + ASSERT (mTcgNvs != NULL); + + // + // Publish the TPM ACPI table. Table is re-checksumed. + // + Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTable); + ASSERT_EFI_ERROR (Status); + + TableKey = 0; + Status = AcpiTable->InstallAcpiTable ( + AcpiTable, + Table, + TableSize, + &TableKey + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} + +/** + Publish TPM2 ACPI table + + @retval EFI_SUCCESS The TPM2 ACPI table is published successfully. + @retval Others The TPM2 ACPI table is not published. + +**/ +EFI_STATUS +PublishTpm2 ( + VOID + ) +{ + EFI_STATUS Status; + EFI_ACPI_TABLE_PROTOCOL *AcpiTable; + UINTN TableKey; + UINT64 OemTableId; + EFI_TPM2_ACPI_CONTROL_AREA *ControlArea; + PTP_INTERFACE_TYPE InterfaceType; + + mTpm2AcpiTemplate.Header.Revision = PcdGet8(PcdTpm2AcpiTableRev); + DEBUG((DEBUG_INFO, "Tpm2 ACPI table revision is %d\n", mTpm2AcpiTemplate.Header.Revision)); + + // + // PlatformClass is only valid for version 4 and above + // BIT0~15: PlatformClass + // BIT16~31: Reserved + // + if (mTpm2AcpiTemplate.Header.Revision >= EFI_TPM2_ACPI_TABLE_REVISION_4) { + mTpm2AcpiTemplate.Flags = (mTpm2AcpiTemplate.Flags & 0xFFFF0000) | PcdGet8(PcdTpmPlatformClass); + DEBUG((DEBUG_INFO, "Tpm2 ACPI table PlatformClass is %d\n", (mTpm2AcpiTemplate.Flags & 0x0000FFFF))); + } + + // + // Measure to PCR[0] with event EV_POST_CODE ACPI DATA + // + TpmMeasureAndLogData( + 0, + EV_POST_CODE, + EV_POSTCODE_INFO_ACPI_DATA, + ACPI_DATA_LEN, + &mTpm2AcpiTemplate, + sizeof(mTpm2AcpiTemplate) + ); + + InterfaceType = GetPtpInterface ((VOID *) (UINTN) PcdGet64 (PcdTpmBaseAddress)); + switch (InterfaceType) { + case PtpInterfaceCrb: + mTpm2AcpiTemplate.StartMethod = EFI_TPM2_ACPI_TABLE_START_METHOD_COMMAND_RESPONSE_BUFFER_INTERFACE; + mTpm2AcpiTemplate.AddressOfControlArea = PcdGet64 (PcdTpmBaseAddress) + 0x40; + ControlArea = (EFI_TPM2_ACPI_CONTROL_AREA *)(UINTN)mTpm2AcpiTemplate.AddressOfControlArea; + ControlArea->CommandSize = 0xF80; + ControlArea->ResponseSize = 0xF80; + ControlArea->Command = PcdGet64 (PcdTpmBaseAddress) + 0x80; + ControlArea->Response = PcdGet64 (PcdTpmBaseAddress) + 0x80; + break; + case PtpInterfaceFifo: + case PtpInterfaceTis: + break; + default: + DEBUG((EFI_D_ERROR, "TPM2 InterfaceType get error! %d\n", InterfaceType)); + break; + } + + CopyMem (mTpm2AcpiTemplate.Header.OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (mTpm2AcpiTemplate.Header.OemId)); + OemTableId = PcdGet64 (PcdAcpiDefaultOemTableId); + CopyMem (&mTpm2AcpiTemplate.Header.OemTableId, &OemTableId, sizeof (UINT64)); + mTpm2AcpiTemplate.Header.OemRevision = PcdGet32 (PcdAcpiDefaultOemRevision); + mTpm2AcpiTemplate.Header.CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId); + mTpm2AcpiTemplate.Header.CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision); + + // + // Construct ACPI table + // + Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTable); + ASSERT_EFI_ERROR (Status); + + Status = AcpiTable->InstallAcpiTable ( + AcpiTable, + &mTpm2AcpiTemplate, + sizeof(mTpm2AcpiTemplate), + &TableKey + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} + +/** + The driver's entry point. + + It install callbacks for TPM physical presence and MemoryClear, and locate + SMM variable to be used in the callback function. + + @param[in] ImageHandle The firmware allocated handle for the EFI image. + @param[in] SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The entry point is executed successfully. + @retval Others Some error occurs when executing this entry point. + +**/ +EFI_STATUS +EFIAPI +InitializeTcgSmm ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_SMM_SW_DISPATCH2_PROTOCOL *SwDispatch; + EFI_SMM_SW_REGISTER_CONTEXT SwContext; + EFI_HANDLE SwHandle; + + if (!CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceTpm20DtpmGuid)){ + DEBUG ((EFI_D_ERROR, "No TPM2 DTPM instance required!\n")); + return EFI_UNSUPPORTED; + } + + Status = PublishAcpiTable (); + ASSERT_EFI_ERROR (Status); + + // + // Get the Sw dispatch protocol and register SMI callback functions. + // + Status = gSmst->SmmLocateProtocol (&gEfiSmmSwDispatch2ProtocolGuid, NULL, (VOID**)&SwDispatch); + ASSERT_EFI_ERROR (Status); + SwContext.SwSmiInputValue = (UINTN) -1; + Status = SwDispatch->Register (SwDispatch, PhysicalPresenceCallback, &SwContext, &SwHandle); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + return Status; + } + mTcgNvs->PhysicalPresence.SoftwareSmi = (UINT8) SwContext.SwSmiInputValue; + + SwContext.SwSmiInputValue = (UINTN) -1; + Status = SwDispatch->Register (SwDispatch, MemoryClearCallback, &SwContext, &SwHandle); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + return Status; + } + mTcgNvs->MemoryClear.SoftwareSmi = (UINT8) SwContext.SwSmiInputValue; + + // + // Locate SmmVariableProtocol. + // + Status = gSmst->SmmLocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID**)&mSmmVariable); + ASSERT_EFI_ERROR (Status); + + // + // Set TPM2 ACPI table + // + Status = PublishTpm2 (); + ASSERT_EFI_ERROR (Status); + + + return EFI_SUCCESS; +} + diff --git a/Core/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.h b/Core/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.h new file mode 100644 index 0000000000..100804cf2a --- /dev/null +++ b/Core/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.h @@ -0,0 +1,105 @@ +/** @file + The header file for Tcg2 SMM driver. + +Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +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 +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#pragma pack(1) +typedef struct { + UINT8 SoftwareSmi; + UINT32 Parameter; + UINT32 Response; + UINT32 Request; + UINT32 RequestParameter; + UINT32 LastRequest; + UINT32 ReturnCode; +} PHYSICAL_PRESENCE_NVS; + +typedef struct { + UINT8 SoftwareSmi; + UINT32 Parameter; + UINT32 Request; + UINT32 ReturnCode; +} MEMORY_CLEAR_NVS; + +typedef struct { + PHYSICAL_PRESENCE_NVS PhysicalPresence; + MEMORY_CLEAR_NVS MemoryClear; + UINT32 PPRequestUserConfirm; +} TCG_NVS; + +typedef struct { + UINT8 OpRegionOp; + UINT32 NameString; + UINT8 RegionSpace; + UINT8 DWordPrefix; + UINT32 RegionOffset; + UINT8 BytePrefix; + UINT8 RegionLen; +} AML_OP_REGION_32_8; +#pragma pack() + +// +// The definition for TCG MOR +// +#define ACPI_FUNCTION_DSM_MEMORY_CLEAR_INTERFACE 1 +#define ACPI_FUNCTION_PTS_CLEAR_MOR_BIT 2 + +// +// The return code for Memory Clear Interface Functions +// +#define MOR_REQUEST_SUCCESS 0 +#define MOR_REQUEST_GENERAL_FAILURE 1 + +// +// Physical Presence Interface Version supported by Platform +// +#define PHYSICAL_PRESENCE_VERSION_TAG "$PV" +#define PHYSICAL_PRESENCE_VERSION_SIZE 4 + +// +// PNP _HID for TPM2 device +// +#define TPM_HID_TAG "NNNN0000" +#define TPM_HID_PNP_SIZE 8 +#define TPM_HID_ACPI_SIZE 9 + +#endif // __TCG_SMM_H__ diff --git a/Core/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.inf b/Core/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.inf new file mode 100644 index 0000000000..c4efa2a188 --- /dev/null +++ b/Core/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.inf @@ -0,0 +1,86 @@ +## @file +# Provides ACPI metholds for TPM 2.0 support +# +# This driver implements TPM 2.0 definition block in ACPI table and +# registers SMI callback functions for Tcg2 physical presence and +# MemoryClear to handle the requests from ACPI method. +# +# Caution: This module requires additional review when modified. +# This driver will have external input - variable and ACPINvs data in SMM mode. +# This external input must be validated carefully to avoid security issue. +# +# Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = Tcg2Smm + MODULE_UNI_FILE = Tcg2Smm.uni + FILE_GUID = 44A20657-10B8-4049-A148-ACD8812AF257 + MODULE_TYPE = DXE_SMM_DRIVER + PI_SPECIFICATION_VERSION = 0x0001000A + VERSION_STRING = 1.0 + ENTRY_POINT = InitializeTcgSmm + +[Sources] + Tcg2Smm.h + Tcg2Smm.c + Tpm.asl + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + UefiDriverEntryPoint + SmmServicesTableLib + UefiBootServicesTableLib + DebugLib + DxeServicesLib + TpmMeasurementLib + Tpm2CommandLib + Tcg2PhysicalPresenceLib + IoLib + +[Guids] + ## SOMETIMES_PRODUCES ## Variable:L"MemoryOverwriteRequestControl" + ## SOMETIMES_CONSUMES ## Variable:L"MemoryOverwriteRequestControl" + gEfiMemoryOverwriteControlDataGuid + + gEfiTpmDeviceInstanceTpm20DtpmGuid ## PRODUCES ## GUID # TPM device identifier + +[Protocols] + gEfiSmmSwDispatch2ProtocolGuid ## CONSUMES + gEfiSmmVariableProtocolGuid ## CONSUMES + gEfiAcpiTableProtocolGuid ## CONSUMES + +[Pcd] + gEfiSecurityPkgTokenSpaceGuid.PcdTpmInstanceGuid ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemId ## SOMETIMES_CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemTableId ## SOMETIMES_CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemRevision ## SOMETIMES_CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorId ## SOMETIMES_CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorRevision ## SOMETIMES_CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdTpmBaseAddress ## CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdTcgPhysicalPresenceInterfaceVer ## CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdTpm2AcpiTableRev ## CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdTpmPlatformClass ## SOMETIMES_CONSUMES + +[Depex] + gEfiAcpiTableProtocolGuid AND + gEfiSmmSwDispatch2ProtocolGuid AND + gEfiSmmVariableProtocolGuid AND + gEfiTcg2ProtocolGuid + +[UserExtensions.TianoCore."ExtraFiles"] + Tcg2SmmExtra.uni diff --git a/Core/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.uni b/Core/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.uni new file mode 100644 index 0000000000..297e71a06d --- /dev/null +++ b/Core/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.uni @@ -0,0 +1,28 @@ +// /** @file +// Provides ACPI metholds for TPM 2.0 support +// +// This driver implements TPM 2.0 definition block in ACPI table and +// registers SMI callback functions for TCG2 physical presence and +// MemoryClear to handle the requests from ACPI method. +// +// Caution: This module requires additional review when modified. +// This driver will have external input - variable and ACPINvs data in SMM mode. +// This external input must be validated carefully to avoid security issue. +// +// Copyright (c) 2015, Intel Corporation. All rights reserved.
+// +// This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// **/ + + +#string STR_MODULE_ABSTRACT #language en-US "Provides ACPI metholds for TPM 2.0 support" + +#string STR_MODULE_DESCRIPTION #language en-US "This driver implements TPM 2.0 definition block in ACPI table and registers SMI callback functions for TCG2 physical presence and MemoryClear to handle the requests from ACPI method.\n" + "Caution: This module requires additional review when modified. This driver will have external input - variable and ACPINvs data in SMM mode. This external input must be validated carefully to avoid security issues." + diff --git a/Core/SecurityPkg/Tcg/Tcg2Smm/Tcg2SmmExtra.uni b/Core/SecurityPkg/Tcg/Tcg2Smm/Tcg2SmmExtra.uni new file mode 100644 index 0000000000..e2a7b1d02f --- /dev/null +++ b/Core/SecurityPkg/Tcg/Tcg2Smm/Tcg2SmmExtra.uni @@ -0,0 +1,19 @@ +// /** @file +// Tcg2Smm Localized Strings and Content +// +// Copyright (c) 2015, Intel Corporation. All rights reserved.
+// +// This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// **/ + +#string STR_PROPERTIES_MODULE_NAME +#language en-US +"TCG2 (Trusted Computing Group) SMM" + + diff --git a/Core/SecurityPkg/Tcg/Tcg2Smm/Tpm.asl b/Core/SecurityPkg/Tcg/Tcg2Smm/Tpm.asl new file mode 100644 index 0000000000..cf0642e104 --- /dev/null +++ b/Core/SecurityPkg/Tcg/Tcg2Smm/Tpm.asl @@ -0,0 +1,368 @@ +/** @file + The TPM2 definition block in ACPI table for TCG2 physical presence + and MemoryClear. + +Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.
+(c)Copyright 2016 HP Development Company, L.P.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +DefinitionBlock ( + "Tpm.aml", + "SSDT", + 2, + "INTEL ", + "Tpm2Tabl", + 0x1000 + ) +{ + Scope (\_SB) + { + Device (TPM) + { + // + // TCG2 + // + + // + // TAG for patching TPM2.0 _HID + // + Name (_HID, "NNNN0000") + + Name (_CID, "MSFT0101") + + // + // Readable name of this device, don't know if this way is correct yet + // + Name (_STR, Unicode ("TPM 2.0 Device")) + + // + // Return the resource consumed by TPM device + // + Name (_CRS, ResourceTemplate () { + Memory32Fixed (ReadWrite, 0xfed40000, 0x5000) + }) + + // + // Operational region for Smi port access + // + OperationRegion (SMIP, SystemIO, 0xB2, 1) + Field (SMIP, ByteAcc, NoLock, Preserve) + { + IOB2, 8 + } + + // + // Operational region for TPM access + // + OperationRegion (TPMR, SystemMemory, 0xfed40000, 0x5000) + Field (TPMR, AnyAcc, NoLock, Preserve) + { + ACC0, 8, + } + + // + // Operational region for TPM support, TPM Physical Presence and TPM Memory Clear + // Region Offset 0xFFFF0000 and Length 0xF0 will be fixed in C code. + // + OperationRegion (TNVS, SystemMemory, 0xFFFF0000, 0xF0) + Field (TNVS, AnyAcc, NoLock, Preserve) + { + PPIN, 8, // Software SMI for Physical Presence Interface + PPIP, 32, // Used for save physical presence paramter + PPRP, 32, // Physical Presence request operation response + PPRQ, 32, // Physical Presence request operation + PPRM, 32, // Physical Presence request operation parameter + LPPR, 32, // Last Physical Presence request operation + FRET, 32, // Physical Presence function return code + MCIN, 8, // Software SMI for Memory Clear Interface + MCIP, 32, // Used for save the Mor paramter + MORD, 32, // Memory Overwrite Request Data + MRET, 32, // Memory Overwrite function return code + UCRQ, 32 // Phyical Presence request operation to Get User Confirmation Status + } + + Method (PTS, 1, Serialized) + { + // + // Detect Sx state for MOR, only S4, S5 need to handle + // + If (LAnd (LLess (Arg0, 6), LGreater (Arg0, 3))) + { + // + // Bit4 -- DisableAutoDetect. 0 -- Firmware MAY autodetect. + // + If (LNot (And (MORD, 0x10))) + { + // + // Triggle the SMI through ACPI _PTS method. + // + Store (0x02, MCIP) + + // + // Triggle the SMI interrupt + // + Store (MCIN, IOB2) + } + } + Return (0) + } + + Method (_STA, 0) + { + if (LEqual (ACC0, 0xff)) + { + Return (0) + } + Return (0x0f) + } + + // + // TCG Hardware Information + // + Method (HINF, 3, Serialized, 0, {BuffObj, PkgObj}, {UnknownObj, UnknownObj, UnknownObj}) // IntObj, IntObj, PkgObj + { + // + // Switch by function index + // + Switch (ToInteger(Arg1)) + { + Case (0) + { + // + // Standard query + // + Return (Buffer () {0x03}) + } + Case (1) + { + // + // Return failure if no TPM present + // + Name(TPMV, Package () {0x01, Package () {0x2, 0x0}}) + if (LEqual (_STA (), 0x00)) + { + Return (Package () {0x00}) + } + + // + // Return TPM version + // + Return (TPMV) + } + Default {BreakPoint} + } + Return (Buffer () {0}) + } + + Name(TPM2, Package (0x02){ + Zero, + Zero + }) + + Name(TPM3, Package (0x03){ + Zero, + Zero, + Zero + }) + + // + // TCG Physical Presence Interface + // + Method (TPPI, 3, Serialized, 0, {BuffObj, PkgObj, IntObj, StrObj}, {UnknownObj, UnknownObj, UnknownObj}) // IntObj, IntObj, PkgObj + { + // + // Switch by function index + // + Switch (ToInteger(Arg1)) + { + Case (0) + { + // + // Standard query, supports function 1-8 + // + Return (Buffer () {0xFF, 0x01}) + } + Case (1) + { + // + // a) Get Physical Presence Interface Version + // + Return ("$PV") + } + Case (2) + { + // + // b) Submit TPM Operation Request to Pre-OS Environment + // + + Store (DerefOf (Index (Arg2, 0x00)), PPRQ) + Store (0, PPRM) + Store (0x02, PPIP) + + // + // Triggle the SMI interrupt + // + Store (PPIN, IOB2) + Return (FRET) + + + } + Case (3) + { + // + // c) Get Pending TPM Operation Requested By the OS + // + + Store (PPRQ, Index (TPM2, 0x01)) + Return (TPM2) + } + Case (4) + { + // + // d) Get Platform-Specific Action to Transition to Pre-OS Environment + // + Return (2) + } + Case (5) + { + // + // e) Return TPM Operation Response to OS Environment + // + Store (0x05, PPIP) + + // + // Triggle the SMI interrupt + // + Store (PPIN, IOB2) + + Store (LPPR, Index (TPM3, 0x01)) + Store (PPRP, Index (TPM3, 0x02)) + + Return (TPM3) + } + Case (6) + { + + // + // f) Submit preferred user language (Not implemented) + // + + Return (3) + + } + Case (7) + { + // + // g) Submit TPM Operation Request to Pre-OS Environment 2 + // + Store (7, PPIP) + Store (DerefOf (Index (Arg2, 0x00)), PPRQ) + Store (0, PPRM) + If (LEqual (PPRQ, 23)) { + Store (DerefOf (Index (Arg2, 0x01)), PPRM) + } + + // + // Triggle the SMI interrupt + // + Store (PPIN, IOB2) + Return (FRET) + } + Case (8) + { + // + // e) Get User Confirmation Status for Operation + // + Store (8, PPIP) + Store (DerefOf (Index (Arg2, 0x00)), UCRQ) + + // + // Triggle the SMI interrupt + // + Store (PPIN, IOB2) + + Return (FRET) + } + + Default {BreakPoint} + } + Return (1) + } + + Method (TMCI, 3, Serialized, 0, IntObj, {UnknownObj, UnknownObj, UnknownObj}) // IntObj, IntObj, PkgObj + { + // + // Switch by function index + // + Switch (ToInteger (Arg1)) + { + Case (0) + { + // + // Standard query, supports function 1-1 + // + Return (Buffer () {0x03}) + } + Case (1) + { + // + // Save the Operation Value of the Request to MORD (reserved memory) + // + Store (DerefOf (Index (Arg2, 0x00)), MORD) + + // + // Triggle the SMI through ACPI _DSM method. + // + Store (0x01, MCIP) + + // + // Triggle the SMI interrupt + // + Store (MCIN, IOB2) + Return (MRET) + } + Default {BreakPoint} + } + Return (1) + } + + Method (_DSM, 4, Serialized, 0, UnknownObj, {BuffObj, IntObj, IntObj, PkgObj}) + { + + // + // TCG Hardware Information + // + If(LEqual(Arg0, ToUUID ("cf8e16a5-c1e8-4e25-b712-4f54a96702c8"))) + { + Return (HINF (Arg1, Arg2, Arg3)) + } + + // + // TCG Physical Presence Interface + // + If(LEqual(Arg0, ToUUID ("3dddfaa6-361b-4eb4-a424-8d10089d1653"))) + { + Return (TPPI (Arg1, Arg2, Arg3)) + } + + // + // TCG Memory Clear Interface + // + If(LEqual(Arg0, ToUUID ("376054ed-cc13-4675-901c-4756d7f2d45d"))) + { + Return (TMCI (Arg1, Arg2, Arg3)) + } + + Return (Buffer () {0}) + } + } + } +} diff --git a/Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfig.vfr b/Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfig.vfr new file mode 100644 index 0000000000..94e3229e88 --- /dev/null +++ b/Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfig.vfr @@ -0,0 +1,74 @@ +/** @file + VFR file used by the TCG configuration component. + +Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "TcgConfigNvData.h" + +formset + guid = TCG_CONFIG_FORM_SET_GUID, + title = STRING_TOKEN(STR_TPM_TITLE), + help = STRING_TOKEN(STR_TPM_HELP), + classguid = EFI_HII_PLATFORM_SETUP_FORMSET_GUID, + + varstore TCG_CONFIGURATION, + varid = TCG_CONFIGURATION_VARSTORE_ID, + name = TCG_CONFIGURATION, + guid = TCG_CONFIG_FORM_SET_GUID; + + form formid = TCG_CONFIGURATION_FORM_ID, + title = STRING_TOKEN(STR_TPM_TITLE); + + subtitle text = STRING_TOKEN(STR_NULL); + + text + help = STRING_TOKEN(STR_TPM_STATE_HELP), + text = STRING_TOKEN(STR_TPM_STATE_PROMPT), + text = STRING_TOKEN(STR_TPM_STATE_CONTENT); + + subtitle text = STRING_TOKEN(STR_NULL); + + oneof varid = TCG_CONFIGURATION.TpmOperation, + questionid = KEY_TPM_ACTION, + prompt = STRING_TOKEN(STR_TPM_OPERATION), + help = STRING_TOKEN(STR_TPM_OPERATION_HELP), + flags = INTERACTIVE | RESET_REQUIRED, + // + // Disable (TPM_ORD_PhysicalDisable) command is not available when disabled. + // Activate/deactivate (TPM_ORD_physicalSetDeactivated) command is not available when disabled. + // + suppressif ideqval TCG_CONFIGURATION.TpmEnable == 0; + option text = STRING_TOKEN(STR_DISABLE), value = PHYSICAL_PRESENCE_DISABLE, flags = 0; + option text = STRING_TOKEN(STR_TPM_ACTIVATE), value = PHYSICAL_PRESENCE_ACTIVATE, flags = 0; + option text = STRING_TOKEN(STR_TPM_DEACTIVATE), value = PHYSICAL_PRESENCE_DEACTIVATE, flags = 0; + option text = STRING_TOKEN(STR_TPM_DEACTIVATE_DISABLE), value = PHYSICAL_PRESENCE_DEACTIVATE_DISABLE, flags = 0; + endif + // + // Clear (TPM_ORD_ForceClear) command is not available when disabled or deactivated. + // + suppressif ideqval TCG_CONFIGURATION.TpmEnable == 0 OR + ideqval TCG_CONFIGURATION.TpmActivate == 0; + option text = STRING_TOKEN(STR_TPM_CLEAR), value = PHYSICAL_PRESENCE_CLEAR, flags = 0; + option text = STRING_TOKEN(STR_TPM_CLEAR_ENABLE_ACTIVATE), value = PHYSICAL_PRESENCE_CLEAR_ENABLE_ACTIVATE, flags = 0; + endif + + option text = STRING_TOKEN(STR_ENABLE), value = PHYSICAL_PRESENCE_ENABLE, flags = DEFAULT; + option text = STRING_TOKEN(STR_TPM_ENABLE_ACTIVATE), value = PHYSICAL_PRESENCE_ENABLE_ACTIVATE, flags = 0; + option text = STRING_TOKEN(STR_TPM_ENABLE_ACTIVATE_CLEAR), value = PHYSICAL_PRESENCE_ENABLE_ACTIVATE_CLEAR, flags = 0; + option text = STRING_TOKEN(STR_TPM_ENABLE_ACTIVATE_CLEAR_E_A), value = PHYSICAL_PRESENCE_ENABLE_ACTIVATE_CLEAR_ENABLE_ACTIVATE, flags = 0; + endoneof; + + subtitle text = STRING_TOKEN(STR_NULL); + + endform; + +endformset; diff --git a/Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDriver.c b/Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDriver.c new file mode 100644 index 0000000000..a9d3105456 --- /dev/null +++ b/Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDriver.c @@ -0,0 +1,156 @@ +/** @file + The module entry point for Tcg configuration module. + +Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE 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 + +/** + The entry point for Tcg configuration driver. + + @param[in] ImageHandle The image handle of the driver. + @param[in] SystemTable The system table. + + @retval EFI_ALREADY_STARTED The driver already exists in system. + @retval EFI_OUT_OF_RESOURCES Fail to execute entry point due to lack of resources. + @retval EFI_SUCCES All the related protocols are installed on the driver. + @retval Others Fail to install protocols as indicated. + +**/ +EFI_STATUS +EFIAPI +TcgConfigDriverEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + TCG_CONFIG_PRIVATE_DATA *PrivateData; + EFI_TCG_PROTOCOL *TcgProtocol; + + if (!CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceTpm12Guid)){ + DEBUG ((EFI_D_ERROR, "No TPM12 instance required!\n")); + return EFI_UNSUPPORTED; + } + + Status = Tpm12RequestUseTpm (); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "TPM not detected!\n")); + return Status; + } + + Status = gBS->LocateProtocol (&gEfiTcgProtocolGuid, NULL, (VOID **) &TcgProtocol); + if (EFI_ERROR (Status)) { + TcgProtocol = NULL; + } + + Status = gBS->OpenProtocol ( + ImageHandle, + &gEfiCallerIdGuid, + NULL, + ImageHandle, + ImageHandle, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); + if (!EFI_ERROR (Status)) { + return EFI_ALREADY_STARTED; + } + + // + // Create a private data structure. + // + PrivateData = AllocateCopyPool (sizeof (TCG_CONFIG_PRIVATE_DATA), &mTcgConfigPrivateDateTemplate); + if (PrivateData == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + PrivateData->Configuration = AllocatePool (sizeof (TCG_CONFIGURATION)); + if (PrivateData->Configuration == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ErrorExit; + } + + PrivateData->TcgProtocol = TcgProtocol; + + // + // Install TCG configuration form + // + Status = InstallTcgConfigForm (PrivateData); + if (EFI_ERROR (Status)) { + goto ErrorExit; + } + + // + // Install private GUID. + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &ImageHandle, + &gEfiCallerIdGuid, + PrivateData, + NULL + ); + + if (EFI_ERROR (Status)) { + goto ErrorExit; + } + + return EFI_SUCCESS; + +ErrorExit: + if (PrivateData != NULL) { + UninstallTcgConfigForm (PrivateData); + } + + return Status; +} + +/** + Unload the Tcg configuration form. + + @param[in] ImageHandle The driver's image handle. + + @retval EFI_SUCCESS The Tcg configuration form is unloaded. + @retval Others Failed to unload the form. + +**/ +EFI_STATUS +EFIAPI +TcgConfigDriverUnload ( + IN EFI_HANDLE ImageHandle + ) +{ + EFI_STATUS Status; + TCG_CONFIG_PRIVATE_DATA *PrivateData; + + Status = gBS->HandleProtocol ( + ImageHandle, + &gEfiCallerIdGuid, + (VOID **) &PrivateData + ); + if (EFI_ERROR (Status)) { + return Status; + } + + ASSERT (PrivateData->Signature == TCG_CONFIG_PRIVATE_DATA_SIGNATURE); + + gBS->UninstallMultipleProtocolInterfaces ( + &ImageHandle, + &gEfiCallerIdGuid, + PrivateData, + NULL + ); + + UninstallTcgConfigForm (PrivateData); + + return EFI_SUCCESS; +} diff --git a/Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDxe.inf b/Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDxe.inf new file mode 100644 index 0000000000..82fc35eea0 --- /dev/null +++ b/Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDxe.inf @@ -0,0 +1,83 @@ +## @file +# Provides the capability to update TPM state setup browser +# By this module, user may enable/disable/activate/deactivate/clear TPM, etc. +# +# Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = TcgConfigDxe + MODULE_UNI_FILE = TcgConfigDxe.uni + FILE_GUID = 1FA4DAFE-FA5D-4d75-BEA6-5863862C520A + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = TcgConfigDriverEntryPoint + UNLOAD_IMAGE = TcgConfigDriverUnload + +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + TcgConfigDriver.c + TcgConfigImpl.c + TcgConfigImpl.h + TcgConfig.vfr + TcgConfigStrings.uni + TcgConfigNvData.h + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + MemoryAllocationLib + UefiLib + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + UefiDriverEntryPoint + UefiHiiServicesLib + DebugLib + HiiLib + PcdLib + PrintLib + Tpm12DeviceLib + +[Guids] + ## SOMETIMES_PRODUCES ## Variable:L"PhysicalPresence" + ## SOMETIMES_CONSUMES ## Variable:L"PhysicalPresence" + gEfiPhysicalPresenceGuid + + gEfiIfrTianoGuid ## SOMETIMES_PRODUCES ## GUID # HII opcode + ## PRODUCES ## HII + ## CONSUMES ## HII + gTcgConfigFormSetGuid + gEfiTpmDeviceInstanceTpm12Guid ## CONSUMES ## GUID # TPM device identifier + +[Protocols] + gEfiHiiConfigAccessProtocolGuid ## PRODUCES + gEfiDevicePathProtocolGuid ## PRODUCES + gEfiTcgProtocolGuid ## CONSUMES + +[Pcd] + gEfiSecurityPkgTokenSpaceGuid.PcdTpmInstanceGuid ## CONSUMES + +[Depex] + gEfiHiiConfigRoutingProtocolGuid AND + gEfiHiiDatabaseProtocolGuid AND + gEfiVariableArchProtocolGuid AND + gEfiVariableWriteArchProtocolGuid + +[UserExtensions.TianoCore."ExtraFiles"] + TcgConfigDxeExtra.uni diff --git a/Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDxe.uni b/Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDxe.uni new file mode 100644 index 0000000000..c308271c0d --- /dev/null +++ b/Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDxe.uni @@ -0,0 +1,21 @@ +// /** @file +// Provides the capability to update TPM state setup browser +// +// By this module, user may enable/disable/activate/deactivate/clear TPM, etc. +// +// Copyright (c) 2011 - 2014, Intel Corporation. All rights reserved.
+// +// This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// **/ + + +#string STR_MODULE_ABSTRACT #language en-US "Provides the capability to update TPM state setup browser" + +#string STR_MODULE_DESCRIPTION #language en-US "By this module, user may enable/disable/activate/deactivate/clear TPM, etc." + diff --git a/Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDxeExtra.uni b/Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDxeExtra.uni new file mode 100644 index 0000000000..2856bf1d40 --- /dev/null +++ b/Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDxeExtra.uni @@ -0,0 +1,19 @@ +// /** @file +// TcgConfigDxe Localized Strings and Content +// +// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.
+// +// This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// **/ + +#string STR_PROPERTIES_MODULE_NAME +#language en-US +"TCG (Trusted Computing Group) Config DXE" + + diff --git a/Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigImpl.c b/Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigImpl.c new file mode 100644 index 0000000000..7fa5611cfd --- /dev/null +++ b/Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigImpl.c @@ -0,0 +1,509 @@ +/** @file + HII Config Access protocol implementation of TCG configuration module. + +Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE 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 + format. + @param[out] Progress On return, points to a character in the Request + string. Points to the string's null terminator if + request was successful. Points to the most recent + '&' before the first failing name/value pair (or + the beginning of the string if the failure is in + the first name/value pair) if the request was not + successful. + @param[out] Results A null-terminated Unicode string in + format which has all values filled + in for the names in the Request string. String to + be allocated by the called function. + + @retval EFI_SUCCESS The Results is filled with the requested values. + @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results. + @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name. + @retval EFI_NOT_FOUND Routing data doesn't match any storage in this + driver. + +**/ +EFI_STATUS +EFIAPI +TcgExtractConfig ( + IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, + IN CONST EFI_STRING Request, + OUT EFI_STRING *Progress, + OUT EFI_STRING *Results + ) +{ + EFI_STATUS Status; + TCG_CONFIG_PRIVATE_DATA *PrivateData; + EFI_STRING ConfigRequestHdr; + EFI_STRING ConfigRequest; + BOOLEAN AllocatedRequest; + UINTN Size; + BOOLEAN TpmEnable; + BOOLEAN TpmActivate; + + if (Progress == NULL || Results == NULL) { + return EFI_INVALID_PARAMETER; + } + + *Progress = Request; + if ((Request != NULL) && !HiiIsConfigHdrMatch (Request, &gTcgConfigFormSetGuid, mTcgStorageName)) { + return EFI_NOT_FOUND; + } + + ConfigRequestHdr = NULL; + ConfigRequest = NULL; + AllocatedRequest = FALSE; + Size = 0; + + PrivateData = TCG_CONFIG_PRIVATE_DATA_FROM_THIS (This); + + // + // Convert buffer data to by helper function BlockToConfig() + // + PrivateData->Configuration->TpmOperation = PHYSICAL_PRESENCE_ENABLE; + + // + // Get current TPM state. + // + if (PrivateData->TcgProtocol != NULL) { + Status = GetTpmState (PrivateData->TcgProtocol, &TpmEnable, &TpmActivate); + if (EFI_ERROR (Status)) { + return Status; + } + + PrivateData->Configuration->TpmEnable = TpmEnable; + PrivateData->Configuration->TpmActivate = TpmActivate; + } + + ConfigRequest = Request; + if ((Request == NULL) || (StrStr (Request, L"OFFSET") == NULL)) { + // + // Request has no request element, construct full request string. + // Allocate and fill a buffer large enough to hold the template + // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator + // + ConfigRequestHdr = HiiConstructConfigHdr (&gTcgConfigFormSetGuid, mTcgStorageName, PrivateData->DriverHandle); + Size = (StrLen (ConfigRequestHdr) + 32 + 1) * sizeof (CHAR16); + ConfigRequest = AllocateZeroPool (Size); + ASSERT (ConfigRequest != NULL); + AllocatedRequest = TRUE; + UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", ConfigRequestHdr, sizeof (TCG_CONFIGURATION)); + FreePool (ConfigRequestHdr); + } + + Status = gHiiConfigRouting->BlockToConfig ( + gHiiConfigRouting, + ConfigRequest, + (UINT8 *) PrivateData->Configuration, + sizeof (TCG_CONFIGURATION), + Results, + Progress + ); + // + // Free the allocated config request string. + // + if (AllocatedRequest) { + FreePool (ConfigRequest); + } + // + // Set Progress string to the original request string. + // + if (Request == NULL) { + *Progress = NULL; + } else if (StrStr (Request, L"OFFSET") == NULL) { + *Progress = Request + StrLen (Request); + } + + return Status; +} + +/** + This function processes the results of changes in configuration. + + @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + @param[in] Configuration A null-terminated Unicode string in + 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 to buffer data by helper function ConfigToBlock() + // + BufferSize = sizeof (TCG_CONFIGURATION); + Status = gHiiConfigRouting->ConfigToBlock ( + gHiiConfigRouting, + Configuration, + (UINT8 *) &TcgConfiguration, + &BufferSize, + Progress + ); + if (EFI_ERROR (Status)) { + return Status; + } + + return EFI_SUCCESS; +} + +/** + Save TPM request to variable space. + + @param[in] PpRequest Physical Presence request command. + + @retval EFI_SUCCESS The operation is finished successfully. + @retval Others Other errors as indicated. + +**/ +EFI_STATUS +SavePpRequest ( + IN UINT8 PpRequest + ) +{ + EFI_STATUS Status; + UINTN DataSize; + EFI_PHYSICAL_PRESENCE PpData; + + // + // Save TPM command to variable. + // + DataSize = sizeof (EFI_PHYSICAL_PRESENCE); + Status = gRT->GetVariable ( + PHYSICAL_PRESENCE_VARIABLE, + &gEfiPhysicalPresenceGuid, + NULL, + &DataSize, + &PpData + ); + if (EFI_ERROR (Status)) { + return Status; + } + + PpData.PPRequest = PpRequest; + Status = gRT->SetVariable ( + PHYSICAL_PRESENCE_VARIABLE, + &gEfiPhysicalPresenceGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + DataSize, + &PpData + ); + if (EFI_ERROR(Status)) { + return Status; + } + + return EFI_SUCCESS; +} + +/** + This function processes the results of changes in configuration. + + @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + @param[in] Action Specifies the type of action taken by the browser. + @param[in] QuestionId A unique value which is sent to the original + exporting driver so that it can identify the type + of data to expect. + @param[in] Type The type of value for the question. + @param[in] Value A pointer to the data being sent to the original + exporting driver. + @param[out] ActionRequest On return, points to the action requested by the + callback function. + + @retval EFI_SUCCESS The callback successfully handled the action. + @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the + variable and its data. + @retval EFI_DEVICE_ERROR The variable could not be saved. + @retval EFI_UNSUPPORTED The specified Action is not supported by the + callback. + +**/ +EFI_STATUS +EFIAPI +TcgCallback ( + IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, + IN EFI_BROWSER_ACTION Action, + IN EFI_QUESTION_ID QuestionId, + IN UINT8 Type, + IN EFI_IFR_TYPE_VALUE *Value, + OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest + ) +{ + TCG_CONFIG_PRIVATE_DATA *PrivateData; + CHAR16 State[32]; + + if ((This == NULL) || (Value == NULL) || (ActionRequest == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if (Action == EFI_BROWSER_ACTION_FORM_OPEN) { + if (QuestionId == KEY_TPM_ACTION) { + + PrivateData = TCG_CONFIG_PRIVATE_DATA_FROM_THIS (This); + UnicodeSPrint ( + State, + sizeof (State), + L"%s, and %s", + PrivateData->Configuration->TpmEnable ? L"Enabled" : L"Disabled", + PrivateData->Configuration->TpmActivate ? L"Activated" : L"Deactivated" + ); + HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_TPM_STATE_CONTENT), State, NULL); + } + return EFI_SUCCESS; + } + + if ((Action != EFI_BROWSER_ACTION_CHANGED) || (QuestionId != KEY_TPM_ACTION)) { + return EFI_UNSUPPORTED; + } + + SavePpRequest (Value->u8); + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT; + + return EFI_SUCCESS; +} + +/** + This function publish the TCG configuration Form for TPM device. + + @param[in, out] PrivateData Points to TCG configuration private data. + + @retval EFI_SUCCESS HII Form is installed for this network device. + @retval EFI_OUT_OF_RESOURCES Not enough resource for HII Form installation. + @retval Others Other errors as indicated. + +**/ +EFI_STATUS +InstallTcgConfigForm ( + IN OUT TCG_CONFIG_PRIVATE_DATA *PrivateData + ) +{ + EFI_STATUS Status; + EFI_HII_HANDLE HiiHandle; + EFI_HANDLE DriverHandle; + EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess; + + DriverHandle = NULL; + ConfigAccess = &PrivateData->ConfigAccess; + Status = gBS->InstallMultipleProtocolInterfaces ( + &DriverHandle, + &gEfiDevicePathProtocolGuid, + &mTcgHiiVendorDevicePath, + &gEfiHiiConfigAccessProtocolGuid, + ConfigAccess, + NULL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + PrivateData->DriverHandle = DriverHandle; + + // + // Publish the HII package list + // + HiiHandle = HiiAddPackages ( + &gTcgConfigFormSetGuid, + DriverHandle, + TcgConfigDxeStrings, + TcgConfigBin, + NULL + ); + if (HiiHandle == NULL) { + gBS->UninstallMultipleProtocolInterfaces ( + DriverHandle, + &gEfiDevicePathProtocolGuid, + &mTcgHiiVendorDevicePath, + &gEfiHiiConfigAccessProtocolGuid, + ConfigAccess, + NULL + ); + + return EFI_OUT_OF_RESOURCES; + } + + PrivateData->HiiHandle = HiiHandle; + + return EFI_SUCCESS; +} + +/** + This function removes TCG configuration Form. + + @param[in, out] PrivateData Points to TCG configuration private data. + +**/ +VOID +UninstallTcgConfigForm ( + IN OUT TCG_CONFIG_PRIVATE_DATA *PrivateData + ) +{ + // + // Uninstall HII package list + // + if (PrivateData->HiiHandle != NULL) { + HiiRemovePackages (PrivateData->HiiHandle); + PrivateData->HiiHandle = NULL; + } + + // + // Uninstall HII Config Access Protocol + // + if (PrivateData->DriverHandle != NULL) { + gBS->UninstallMultipleProtocolInterfaces ( + PrivateData->DriverHandle, + &gEfiDevicePathProtocolGuid, + &mTcgHiiVendorDevicePath, + &gEfiHiiConfigAccessProtocolGuid, + &PrivateData->ConfigAccess, + NULL + ); + PrivateData->DriverHandle = NULL; + } + + if (PrivateData->Configuration != NULL) { + FreePool(PrivateData->Configuration); + } + FreePool (PrivateData); +} diff --git a/Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigImpl.h b/Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigImpl.h new file mode 100644 index 0000000000..a03abaa1dd --- /dev/null +++ b/Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigImpl.h @@ -0,0 +1,194 @@ +/** @file + The header file of HII Config Access protocol implementation of TCG + configuration module. + +Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __TCG_CONFIG_IMPL_H__ +#define __TCG_CONFIG_IMPL_H__ + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "TcgConfigNvData.h" + +// +// Tool generated IFR binary data and String package data +// +extern UINT8 TcgConfigBin[]; +extern UINT8 TcgConfigDxeStrings[]; + +/// +/// HII specific Vendor Device Path definition. +/// +typedef struct { + VENDOR_DEVICE_PATH VendorDevicePath; + EFI_DEVICE_PATH_PROTOCOL End; +} HII_VENDOR_DEVICE_PATH; + +typedef struct { + UINTN Signature; + + EFI_HII_CONFIG_ACCESS_PROTOCOL ConfigAccess; + EFI_HII_HANDLE HiiHandle; + EFI_HANDLE DriverHandle; + + TCG_CONFIGURATION *Configuration; + EFI_TCG_PROTOCOL *TcgProtocol; +} TCG_CONFIG_PRIVATE_DATA; + +extern TCG_CONFIG_PRIVATE_DATA mTcgConfigPrivateDateTemplate; + +#define TCG_CONFIG_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('T', 'C', 'G', 'D') +#define TCG_CONFIG_PRIVATE_DATA_FROM_THIS(a) CR (a, TCG_CONFIG_PRIVATE_DATA, ConfigAccess, TCG_CONFIG_PRIVATE_DATA_SIGNATURE) + + +/** + This function publish the TCG configuration Form for TPM device. + + @param[in, out] PrivateData Points to TCG configuration private data. + + @retval EFI_SUCCESS HII Form is installed for this network device. + @retval EFI_OUT_OF_RESOURCES Not enough resource for HII Form installation. + @retval Others Other errors as indicated. + +**/ +EFI_STATUS +InstallTcgConfigForm ( + IN OUT TCG_CONFIG_PRIVATE_DATA *PrivateData + ); + +/** + This function removes TCG configuration Form. + + @param[in, out] PrivateData Points to TCG configuration private data. + +**/ +VOID +UninstallTcgConfigForm ( + IN OUT TCG_CONFIG_PRIVATE_DATA *PrivateData + ); + +/** + This function allows a caller to extract the current configuration for one + or more named elements from the target driver. + + @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + @param[in] Request A null-terminated Unicode string in + format. + @param[out] Progress On return, points to a character in the Request + string. Points to the string's null terminator if + request was successful. Points to the most recent + '&' before the first failing name/value pair (or + the beginning of the string if the failure is in + the first name/value pair) if the request was not + successful. + @param[out] Results A null-terminated Unicode string in + format which has all values filled + in for the names in the Request string. String to + be allocated by the called function. + + @retval EFI_SUCCESS The Results is filled with the requested values. + @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results. + @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name. + @retval EFI_NOT_FOUND Routing data doesn't match any storage in this + driver. + +**/ +EFI_STATUS +EFIAPI +TcgExtractConfig ( + IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, + IN CONST EFI_STRING Request, + OUT EFI_STRING *Progress, + OUT EFI_STRING *Results + ); + +/** + This function processes the results of changes in configuration. + + @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + @param[in] Configuration A null-terminated Unicode string in + format. + @param[out] Progress A pointer to a string filled in with the offset of + the most recent '&' before the first failing + name/value pair (or the beginning of the string if + the failure is in the first name/value pair) or + the terminating NULL if all was successful. + + @retval EFI_SUCCESS The Results is processed successfully. + @retval EFI_INVALID_PARAMETER Configuration is NULL. + @retval EFI_NOT_FOUND Routing data doesn't match any storage in this + driver. + +**/ +EFI_STATUS +EFIAPI +TcgRouteConfig ( + IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, + IN CONST EFI_STRING Configuration, + OUT EFI_STRING *Progress + ); + +/** + This function processes the results of changes in configuration. + + @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + @param[in] Action Specifies the type of action taken by the browser. + @param[in] QuestionId A unique value which is sent to the original + exporting driver so that it can identify the type + of data to expect. + @param[in] Type The type of value for the question. + @param[in] Value A pointer to the data being sent to the original + exporting driver. + @param[out] ActionRequest On return, points to the action requested by the + callback function. + + @retval EFI_SUCCESS The callback successfully handled the action. + @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the + variable and its data. + @retval EFI_DEVICE_ERROR The variable could not be saved. + @retval EFI_UNSUPPORTED The specified Action is not supported by the + callback. + +**/ +EFI_STATUS +EFIAPI +TcgCallback ( + IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, + IN EFI_BROWSER_ACTION Action, + IN EFI_QUESTION_ID QuestionId, + IN UINT8 Type, + IN EFI_IFR_TYPE_VALUE *Value, + OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest + ); + +#endif diff --git a/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.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __TCG_CONFIG_NV_DATA_H__ +#define __TCG_CONFIG_NV_DATA_H__ + +#include +#include +#include + +#define TCG_CONFIGURATION_VARSTORE_ID 0x0001 +#define TCG_CONFIGURATION_FORM_ID 0x0001 + +#define KEY_TPM_ACTION 0x3000 + +#define LABEL_TCG_CONFIGURATION_TPM_OPERATION 0x0001 +#define LABEL_END 0xffff + +// +// Nv Data structure referenced by IFR +// +typedef struct { + UINT8 TpmOperation; + BOOLEAN TpmEnable; + BOOLEAN TpmActivate; +} TCG_CONFIGURATION; + +#endif diff --git a/Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigStrings.uni b/Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigStrings.uni new file mode 100644 index 0000000000..fd8458dc00 --- /dev/null +++ b/Core/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigStrings.uni @@ -0,0 +1,40 @@ +/** @file + String definitions for TCG configuration form. + +Copyright (c) 2011 - 2012, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#langdef en-US "English" + +#string STR_TPM_TITLE #language en-US "TCG Configuration" +#string STR_TPM_HELP #language en-US "Press to select TCG Setup options." +#string STR_TPM_STATE_PROMPT #language en-US "Current TPM State" +#string STR_TPM_STATE_HELP #language en-US "Current TPM device state: enabled or disabled; activated or deactivated." +#string STR_TPM_STATE_CONTENT #language en-US "" + +#string STR_TPM_OPERATION #language en-US "TPM Operation" +#string STR_TPM_OPERATION_HELP #language en-US "Select one of the supported operation to change TPM state." + +#string STR_ENABLE #language en-US "Enable" +#string STR_DISABLE #language en-US "Disable" +#string STR_TPM_ACTIVATE #language en-US "Activate" +#string STR_TPM_DEACTIVATE #language en-US "Deactivate" +#string STR_TPM_CLEAR #language en-US "Force TPM Clear" +#string STR_TPM_ENABLE_ACTIVATE #language en-US "Enable and Activate" +#string STR_TPM_DEACTIVATE_DISABLE #language en-US "Deactivate and Disable" +#string STR_TPM_ENABLE_ACTIVATE_CLEAR #language en-US "Enable, Activate, and Force TPM Clear" +#string STR_TPM_CLEAR_ENABLE_ACTIVATE #language en-US "Force TPM Clear, Enable, and Activate" +#string STR_TPM_ENABLE_ACTIVATE_CLEAR_E_A #language en-US "Enable, Activate, Force TPM Clear, Enable, and Activate" + +#string STR_NULL #language en-US "" + +#string STR_HIDE_TPM_PROMPT #language en-US "Hide TPM" +#string STR_HIDE_TPM_HELP #language en-US "Check to hide TPM in OS" \ No newline at end of file diff --git a/Core/SecurityPkg/Tcg/TcgDxe/TcgDxe.c b/Core/SecurityPkg/Tcg/TcgDxe/TcgDxe.c new file mode 100644 index 0000000000..5b7c5c3e16 --- /dev/null +++ b/Core/SecurityPkg/Tcg/TcgDxe/TcgDxe.c @@ -0,0 +1,1467 @@ +/** @file + This module implements TCG EFI Protocol. + +Caution: This module requires additional review when modified. +This driver will have external input - TcgDxePassThroughToTpm +This external input must be validated carefully to avoid security issue like +buffer overflow, integer overflow. + +TcgDxePassThroughToTpm() will receive untrusted input and do basic validation. + +Copyright (c) 2005 - 2017, Intel Corporation. All rights reserved.
+(C) Copyright 2016 Hewlett Packard Enterprise Development LP
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TCG_DXE_DATA_FROM_THIS(this) \ + BASE_CR (this, TCG_DXE_DATA, TcgProtocol) + +typedef struct _TCG_DXE_DATA { + EFI_TCG_PROTOCOL TcgProtocol; + TCG_EFI_BOOT_SERVICE_CAPABILITY BsCap; + EFI_TCG_CLIENT_ACPI_TABLE *TcgClientAcpiTable; + EFI_TCG_SERVER_ACPI_TABLE *TcgServerAcpiTable; + UINTN EventLogSize; + UINT8 *LastEvent; +} TCG_DXE_DATA; + + + +EFI_TCG_CLIENT_ACPI_TABLE mTcgClientAcpiTemplate = { + { + EFI_ACPI_3_0_TRUSTED_COMPUTING_PLATFORM_ALLIANCE_CAPABILITIES_TABLE_SIGNATURE, + sizeof (mTcgClientAcpiTemplate), + 0x02 //Revision + // + // Compiler initializes the remaining bytes to 0 + // These fields should be filled in in production + // + }, + 0, // 0 for PC Client Platform Class + 0, // Log Area Max Length + (EFI_PHYSICAL_ADDRESS) (SIZE_4GB - 1) // Log Area Start Address +}; + +// +// The following EFI_TCG_SERVER_ACPI_TABLE default setting is just one example, +// the TPM device connectes to LPC, and also defined the ACPI _UID as 0xFF, +// this _UID can be changed and should match with the _UID setting of the TPM +// ACPI device object +// +EFI_TCG_SERVER_ACPI_TABLE mTcgServerAcpiTemplate = { + { + EFI_ACPI_3_0_TRUSTED_COMPUTING_PLATFORM_ALLIANCE_CAPABILITIES_TABLE_SIGNATURE, + sizeof (mTcgServerAcpiTemplate), + 0x02 //Revision + // + // Compiler initializes the remaining bytes to 0 + // These fields should be filled in in production + // + }, + 1, // 1 for Server Platform Class + 0, // Reserved + 0, // Log Area Max Length + (EFI_PHYSICAL_ADDRESS) (SIZE_4GB - 1), // Log Area Start Address + 0x0120, // TCG Specification revision 1.2 + 0, // Device Flags + 0, // Interrupt Flags + 0, // GPE + {0}, // Reserved 3 bytes + 0, // Global System Interrupt + { + EFI_ACPI_3_0_SYSTEM_MEMORY, + 0, + 0, + EFI_ACPI_3_0_BYTE, + 0 // Base Address + }, + 0, // Reserved + {0}, // Configuration Address + 0xFF, // ACPI _UID value of the device, can be changed for different platforms + 0, // ACPI _UID value of the device, can be changed for different platforms + 0, // ACPI _UID value of the device, can be changed for different platforms + 0 // ACPI _UID value of the device, can be changed for different platforms +}; + +UINTN mBootAttempts = 0; +CHAR16 mBootVarName[] = L"BootOrder"; + +/** + Get All processors EFI_CPU_LOCATION in system. LocationBuf is allocated inside the function + Caller is responsible to free LocationBuf. + + @param[out] LocationBuf Returns Processor Location Buffer. + @param[out] Num Returns processor number. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_UNSUPPORTED MpService protocol not found. + +**/ +EFI_STATUS +GetProcessorsCpuLocation ( + OUT EFI_CPU_PHYSICAL_LOCATION **LocationBuf, + OUT UINTN *Num + ) +{ + EFI_STATUS Status; + EFI_MP_SERVICES_PROTOCOL *MpProtocol; + UINTN ProcessorNum; + UINTN EnabledProcessorNum; + EFI_PROCESSOR_INFORMATION ProcessorInfo; + EFI_CPU_PHYSICAL_LOCATION *ProcessorLocBuf; + UINTN Index; + + Status = gBS->LocateProtocol (&gEfiMpServiceProtocolGuid, NULL, (VOID **) &MpProtocol); + if (EFI_ERROR (Status)) { + // + // MP protocol is not installed + // + return EFI_UNSUPPORTED; + } + + Status = MpProtocol->GetNumberOfProcessors( + MpProtocol, + &ProcessorNum, + &EnabledProcessorNum + ); + if (EFI_ERROR(Status)){ + return Status; + } + + Status = gBS->AllocatePool( + EfiBootServicesData, + sizeof(EFI_CPU_PHYSICAL_LOCATION) * ProcessorNum, + (VOID **) &ProcessorLocBuf + ); + if (EFI_ERROR(Status)){ + return Status; + } + + // + // Get each processor Location info + // + for (Index = 0; Index < ProcessorNum; Index++) { + Status = MpProtocol->GetProcessorInfo( + MpProtocol, + Index, + &ProcessorInfo + ); + if (EFI_ERROR(Status)){ + FreePool(ProcessorLocBuf); + return Status; + } + + // + // Get all Processor Location info & measure + // + CopyMem( + &ProcessorLocBuf[Index], + &ProcessorInfo.Location, + sizeof(EFI_CPU_PHYSICAL_LOCATION) + ); + } + + *LocationBuf = ProcessorLocBuf; + *Num = ProcessorNum; + + return Status; +} + +/** + This service provides EFI protocol capability information, state information + about the TPM, and Event Log state information. + + @param[in] This Indicates the calling context + @param[out] ProtocolCapability The callee allocates memory for a TCG_BOOT_SERVICE_CAPABILITY + structure and fills in the fields with the EFI protocol + capability information and the current TPM state information. + @param[out] TCGFeatureFlags This is a pointer to the feature flags. No feature + flags are currently defined so this parameter + MUST be set to 0. However, in the future, + feature flags may be defined that, for example, + enable hash algorithm agility. + @param[out] EventLogLocation This is a pointer to the address of the event log in memory. + @param[out] EventLogLastEntry If the Event Log contains more than one entry, + this is a pointer to the address of the start of + the last entry in the event log in memory. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_INVALID_PARAMETER ProtocolCapability does not match TCG capability. + +**/ +EFI_STATUS +EFIAPI +TcgDxeStatusCheck ( + IN EFI_TCG_PROTOCOL *This, + OUT TCG_EFI_BOOT_SERVICE_CAPABILITY *ProtocolCapability, + OUT UINT32 *TCGFeatureFlags, + OUT EFI_PHYSICAL_ADDRESS *EventLogLocation, + OUT EFI_PHYSICAL_ADDRESS *EventLogLastEntry + ) +{ + TCG_DXE_DATA *TcgData; + + TcgData = TCG_DXE_DATA_FROM_THIS (This); + + if (ProtocolCapability != NULL) { + *ProtocolCapability = TcgData->BsCap; + } + + if (TCGFeatureFlags != NULL) { + *TCGFeatureFlags = 0; + } + + if (EventLogLocation != NULL) { + if (PcdGet8 (PcdTpmPlatformClass) == TCG_PLATFORM_TYPE_CLIENT) { + *EventLogLocation = TcgData->TcgClientAcpiTable->Lasa; + } else { + *EventLogLocation = TcgData->TcgServerAcpiTable->Lasa; + } + } + + if (EventLogLastEntry != NULL) { + if (TcgData->BsCap.TPMDeactivatedFlag || (!TcgData->BsCap.TPMPresentFlag)) { + *EventLogLastEntry = (EFI_PHYSICAL_ADDRESS)(UINTN)0; + } else { + *EventLogLastEntry = (EFI_PHYSICAL_ADDRESS)(UINTN)TcgData->LastEvent; + } + } + + return EFI_SUCCESS; +} + +/** +Single function calculates SHA1 digest value for all raw data. It +combines Sha1Init(), Sha1Update() and Sha1Final(). + +@param[in] Data Raw data to be digested. +@param[in] DataLen Size of the raw data. +@param[out] Digest Pointer to a buffer that stores the final digest. + +@retval EFI_SUCCESS Always successfully calculate the final digest. +**/ +EFI_STATUS +EFIAPI +TpmCommHashAll ( + IN CONST UINT8 *Data, + IN UINTN DataLen, + OUT TPM_DIGEST *Digest + ) +{ + VOID *Sha1Ctx; + UINTN CtxSize; + + CtxSize = Sha1GetContextSize (); + Sha1Ctx = AllocatePool (CtxSize); + ASSERT (Sha1Ctx != NULL); + + Sha1Init (Sha1Ctx); + Sha1Update (Sha1Ctx, Data, DataLen); + Sha1Final (Sha1Ctx, (UINT8 *)Digest); + + FreePool (Sha1Ctx); + + return EFI_SUCCESS; +} + +/** + This service abstracts the capability to do a hash operation on a data buffer. + + @param[in] This Indicates the calling context + @param[in] HashData Pointer to the data buffer to be hashed + @param[in] HashDataLen Length of the data buffer to be hashed + @param[in] AlgorithmId Identification of the Algorithm to use for the hashing operation + @param[in, out] HashedDataLen Resultant length of the hashed data + @param[in, out] HashedDataResult Resultant buffer of the hashed data + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_INVALID_PARAMETER HashDataLen is NULL. + @retval EFI_INVALID_PARAMETER HashDataLenResult is NULL. + @retval EFI_OUT_OF_RESOURCES Cannot allocate buffer of size *HashedDataLen. + @retval EFI_UNSUPPORTED AlgorithmId not supported. + @retval EFI_BUFFER_TOO_SMALL *HashedDataLen < sizeof (TCG_DIGEST). + +**/ +EFI_STATUS +EFIAPI +TcgDxeHashAll ( + IN EFI_TCG_PROTOCOL *This, + IN UINT8 *HashData, + IN UINT64 HashDataLen, + IN TCG_ALGORITHM_ID AlgorithmId, + IN OUT UINT64 *HashedDataLen, + IN OUT UINT8 **HashedDataResult + ) +{ + if (HashedDataLen == NULL || HashedDataResult == NULL) { + return EFI_INVALID_PARAMETER; + } + + switch (AlgorithmId) { + case TPM_ALG_SHA: + if (*HashedDataLen == 0) { + *HashedDataLen = sizeof (TPM_DIGEST); + *HashedDataResult = AllocatePool ((UINTN) *HashedDataLen); + if (*HashedDataResult == NULL) { + return EFI_OUT_OF_RESOURCES; + } + } + + if (*HashedDataLen < sizeof (TPM_DIGEST)) { + *HashedDataLen = sizeof (TPM_DIGEST); + return EFI_BUFFER_TOO_SMALL; + } + *HashedDataLen = sizeof (TPM_DIGEST); + + if (*HashedDataResult == NULL) { + *HashedDataResult = AllocatePool ((UINTN) *HashedDataLen); + } + + return TpmCommHashAll ( + HashData, + (UINTN) HashDataLen, + (TPM_DIGEST*)*HashedDataResult + ); + default: + return EFI_UNSUPPORTED; + } +} + +/** +Add a new entry to the Event Log. + +@param[in, out] EventLogPtr Pointer to the Event Log data. +@param[in, out] LogSize Size of the Event Log. +@param[in] MaxSize Maximum size of the Event Log. +@param[in] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR data structure. +@param[in] NewEventData Pointer to the new event data. + +@retval EFI_SUCCESS The new event log entry was added. +@retval EFI_OUT_OF_RESOURCES No enough memory to log the new event. + +**/ +EFI_STATUS +TpmCommLogEvent ( + IN OUT UINT8 **EventLogPtr, + IN OUT UINTN *LogSize, + IN UINTN MaxSize, + IN TCG_PCR_EVENT_HDR *NewEventHdr, + IN UINT8 *NewEventData + ) +{ + UINTN NewLogSize; + + // + // Prevent Event Overflow + // + if ((UINTN) NewEventHdr->EventSize > MAX_UINTN - sizeof (*NewEventHdr)) { + return EFI_OUT_OF_RESOURCES; + } + + NewLogSize = sizeof (*NewEventHdr) + NewEventHdr->EventSize; + if (NewLogSize > MaxSize - *LogSize) { + return EFI_OUT_OF_RESOURCES; + } + + *EventLogPtr += *LogSize; + *LogSize += NewLogSize; + CopyMem (*EventLogPtr, NewEventHdr, sizeof (*NewEventHdr)); + CopyMem ( + *EventLogPtr + sizeof (*NewEventHdr), + NewEventData, + NewEventHdr->EventSize + ); + return EFI_SUCCESS; +} + +/** + Add a new entry to the Event Log. + + @param[in] TcgData TCG_DXE_DATA structure. + @param[in] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR data structure. + @param[in] NewEventData Pointer to the new event data. + + @retval EFI_SUCCESS The new event log entry was added. + @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event. + +**/ +EFI_STATUS +EFIAPI +TcgDxeLogEventI ( + IN TCG_DXE_DATA *TcgData, + IN TCG_PCR_EVENT_HDR *NewEventHdr, + IN UINT8 *NewEventData + ) +{ + if (PcdGet8 (PcdTpmPlatformClass) == TCG_PLATFORM_TYPE_CLIENT) { + TcgData->LastEvent = (UINT8*)(UINTN)TcgData->TcgClientAcpiTable->Lasa; + return TpmCommLogEvent ( + &TcgData->LastEvent, + &TcgData->EventLogSize, + (UINTN)TcgData->TcgClientAcpiTable->Laml, + NewEventHdr, + NewEventData + ); + } else { + TcgData->LastEvent = (UINT8*)(UINTN)TcgData->TcgServerAcpiTable->Lasa; + return TpmCommLogEvent ( + &TcgData->LastEvent, + &TcgData->EventLogSize, + (UINTN)TcgData->TcgServerAcpiTable->Laml, + NewEventHdr, + NewEventData + ); + } +} + +/** + This service abstracts the capability to add an entry to the Event Log. + + @param[in] This Indicates the calling context + @param[in] TCGLogData Pointer to the start of the data buffer containing + the TCG_PCR_EVENT data structure. All fields in + this structure are properly filled by the caller. + @param[in, out] EventNumber The event number of the event just logged + @param[in] Flags Indicate additional flags. Only one flag has been + defined at this time, which is 0x01 and means the + extend operation should not be performed. All + other bits are reserved. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_OUT_OF_RESOURCES Insufficient memory in the event log to complete this action. + +**/ +EFI_STATUS +EFIAPI +TcgDxeLogEvent ( + IN EFI_TCG_PROTOCOL *This, + IN TCG_PCR_EVENT *TCGLogData, + IN OUT UINT32 *EventNumber, + IN UINT32 Flags + ) +{ + TCG_DXE_DATA *TcgData; + + if (TCGLogData == NULL){ + return EFI_INVALID_PARAMETER; + } + + TcgData = TCG_DXE_DATA_FROM_THIS (This); + + if (TcgData->BsCap.TPMDeactivatedFlag || (!TcgData->BsCap.TPMPresentFlag)) { + return EFI_DEVICE_ERROR; + } + return TcgDxeLogEventI ( + TcgData, + (TCG_PCR_EVENT_HDR*)TCGLogData, + TCGLogData->Event + ); +} + +/** + This service is a proxy for commands to the TPM. + + @param[in] This Indicates the calling context + @param[in] TpmInputParameterBlockSize Size of the TPM input parameter block + @param[in] TpmInputParameterBlock Pointer to the TPM input parameter block + @param[in] TpmOutputParameterBlockSize Size of the TPM output parameter block + @param[in] TpmOutputParameterBlock Pointer to the TPM output parameter block + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_INVALID_PARAMETER Invalid ordinal. + @retval EFI_UNSUPPORTED Current Task Priority Level >= EFI_TPL_CALLBACK. + @retval EFI_TIMEOUT The TIS timed-out. + +**/ +EFI_STATUS +EFIAPI +TcgDxePassThroughToTpm ( + IN EFI_TCG_PROTOCOL *This, + IN UINT32 TpmInputParameterBlockSize, + IN UINT8 *TpmInputParameterBlock, + IN UINT32 TpmOutputParameterBlockSize, + IN UINT8 *TpmOutputParameterBlock + ) +{ + if (TpmInputParameterBlock == NULL || + TpmOutputParameterBlock == NULL || + TpmInputParameterBlockSize == 0 || + TpmOutputParameterBlockSize == 0) { + return EFI_INVALID_PARAMETER; + } + + return Tpm12SubmitCommand ( + TpmInputParameterBlockSize, + TpmInputParameterBlock, + &TpmOutputParameterBlockSize, + TpmOutputParameterBlock + ); +} + +/** + Do a hash operation on a data buffer, extend a specific TPM PCR with the hash result, + and add an entry to the Event Log. + + @param[in] TcgData TCG_DXE_DATA structure. + @param[in] HashData Physical address of the start of the data buffer + to be hashed, extended, and logged. + @param[in] HashDataLen The length, in bytes, of the buffer referenced by HashData + @param[in, out] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR data structure. + @param[in] NewEventData Pointer to the new event data. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event. + @retval EFI_DEVICE_ERROR The command was unsuccessful. + +**/ +EFI_STATUS +EFIAPI +TcgDxeHashLogExtendEventI ( + IN TCG_DXE_DATA *TcgData, + IN UINT8 *HashData, + IN UINT64 HashDataLen, + IN OUT TCG_PCR_EVENT_HDR *NewEventHdr, + IN UINT8 *NewEventData + ) +{ + EFI_STATUS Status; + + if (!TcgData->BsCap.TPMPresentFlag) { + return EFI_DEVICE_ERROR; + } + + if (HashDataLen > 0 || HashData != NULL) { + Status = TpmCommHashAll ( + HashData, + (UINTN) HashDataLen, + &NewEventHdr->Digest + ); + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_ERROR, "TpmCommHashAll Failed. %x\n", Status)); + goto Done; + } + } + + Status = Tpm12Extend ( + &NewEventHdr->Digest, + NewEventHdr->PCRIndex, + NULL + ); + if (!EFI_ERROR (Status)) { + Status = TcgDxeLogEventI (TcgData, NewEventHdr, NewEventData); + } + +Done: + if ((Status == EFI_DEVICE_ERROR) || (Status == EFI_TIMEOUT)) { + DEBUG ((EFI_D_ERROR, "TcgDxeHashLogExtendEventI - %r. Disable TPM.\n", Status)); + TcgData->BsCap.TPMPresentFlag = FALSE; + REPORT_STATUS_CODE ( + EFI_ERROR_CODE | EFI_ERROR_MINOR, + (PcdGet32 (PcdStatusCodeSubClassTpmDevice) | EFI_P_EC_INTERFACE_ERROR) + ); + Status = EFI_DEVICE_ERROR; + } + + return Status; +} + +/** + This service abstracts the capability to do a hash operation on a data buffer, + extend a specific TPM PCR with the hash result, and add an entry to the Event Log + + @param[in] This Indicates the calling context + @param[in] HashData Physical address of the start of the data buffer + to be hashed, extended, and logged. + @param[in] HashDataLen The length, in bytes, of the buffer referenced by HashData + @param[in] AlgorithmId Identification of the Algorithm to use for the hashing operation + @param[in, out] TCGLogData The physical address of the start of the data + buffer containing the TCG_PCR_EVENT data structure. + @param[in, out] EventNumber The event number of the event just logged. + @param[out] EventLogLastEntry Physical address of the first byte of the entry + just placed in the Event Log. If the Event Log was + empty when this function was called then this physical + address will be the same as the physical address of + the start of the Event Log. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_UNSUPPORTED AlgorithmId != TPM_ALG_SHA. + @retval EFI_UNSUPPORTED Current TPL >= EFI_TPL_CALLBACK. + @retval EFI_DEVICE_ERROR The command was unsuccessful. + +**/ +EFI_STATUS +EFIAPI +TcgDxeHashLogExtendEvent ( + IN EFI_TCG_PROTOCOL *This, + IN EFI_PHYSICAL_ADDRESS HashData, + IN UINT64 HashDataLen, + IN TPM_ALGORITHM_ID AlgorithmId, + IN OUT TCG_PCR_EVENT *TCGLogData, + IN OUT UINT32 *EventNumber, + OUT EFI_PHYSICAL_ADDRESS *EventLogLastEntry + ) +{ + TCG_DXE_DATA *TcgData; + EFI_STATUS Status; + + if (TCGLogData == NULL || EventLogLastEntry == NULL){ + return EFI_INVALID_PARAMETER; + } + + TcgData = TCG_DXE_DATA_FROM_THIS (This); + + if (TcgData->BsCap.TPMDeactivatedFlag || (!TcgData->BsCap.TPMPresentFlag)) { + return EFI_DEVICE_ERROR; + } + + if (AlgorithmId != TPM_ALG_SHA) { + return EFI_UNSUPPORTED; + } + + if (HashData == 0 && HashDataLen > 0) { + return EFI_INVALID_PARAMETER; + } + + Status = TcgDxeHashLogExtendEventI ( + TcgData, + (UINT8 *) (UINTN) HashData, + HashDataLen, + (TCG_PCR_EVENT_HDR*)TCGLogData, + TCGLogData->Event + ); + + if (!EFI_ERROR(Status)){ + *EventLogLastEntry = (EFI_PHYSICAL_ADDRESS)(UINTN) TcgData->LastEvent; + } + + return Status; +} + +TCG_DXE_DATA mTcgDxeData = { + { + TcgDxeStatusCheck, + TcgDxeHashAll, + TcgDxeLogEvent, + TcgDxePassThroughToTpm, + TcgDxeHashLogExtendEvent + }, + { + sizeof (mTcgDxeData.BsCap), + { 1, 2, 0, 0 }, + { 1, 2, 0, 0 }, + 1, + TRUE, + FALSE + }, + &mTcgClientAcpiTemplate, + &mTcgServerAcpiTemplate, + 0, + NULL +}; + +/** + Initialize the Event Log and log events passed from the PEI phase. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_OUT_OF_RESOURCES Out of memory. + +**/ +EFI_STATUS +EFIAPI +SetupEventLog ( + VOID + ) +{ + EFI_STATUS Status; + TCG_PCR_EVENT *TcgEvent; + EFI_PEI_HOB_POINTERS GuidHob; + EFI_PHYSICAL_ADDRESS Lasa; + + if (PcdGet8 (PcdTpmPlatformClass) == TCG_PLATFORM_TYPE_CLIENT) { + Lasa = mTcgClientAcpiTemplate.Lasa; + + Status = gBS->AllocatePages ( + AllocateMaxAddress, + EfiACPIMemoryNVS, + EFI_SIZE_TO_PAGES (PcdGet32 (PcdTcgLogAreaMinLen)), + &Lasa + ); + if (EFI_ERROR (Status)) { + return Status; + } + mTcgClientAcpiTemplate.Lasa = Lasa; + // + // To initialize them as 0xFF is recommended + // because the OS can know the last entry for that. + // + SetMem ((VOID *)(UINTN)mTcgClientAcpiTemplate.Lasa, PcdGet32 (PcdTcgLogAreaMinLen), 0xFF); + mTcgClientAcpiTemplate.Laml = PcdGet32 (PcdTcgLogAreaMinLen); + + } else { + Lasa = mTcgServerAcpiTemplate.Lasa; + + Status = gBS->AllocatePages ( + AllocateMaxAddress, + EfiACPIMemoryNVS, + EFI_SIZE_TO_PAGES (PcdGet32 (PcdTcgLogAreaMinLen)), + &Lasa + ); + if (EFI_ERROR (Status)) { + return Status; + } + mTcgServerAcpiTemplate.Lasa = Lasa; + // + // To initialize them as 0xFF is recommended + // because the OS can know the last entry for that. + // + SetMem ((VOID *)(UINTN)mTcgServerAcpiTemplate.Lasa, PcdGet32 (PcdTcgLogAreaMinLen), 0xFF); + mTcgServerAcpiTemplate.Laml = PcdGet32 (PcdTcgLogAreaMinLen); + } + + GuidHob.Raw = GetHobList (); + while (!EFI_ERROR (Status) && + (GuidHob.Raw = GetNextGuidHob (&gTcgEventEntryHobGuid, GuidHob.Raw)) != NULL) { + TcgEvent = GET_GUID_HOB_DATA (GuidHob.Guid); + GuidHob.Raw = GET_NEXT_HOB (GuidHob); + Status = TcgDxeLogEventI ( + &mTcgDxeData, + (TCG_PCR_EVENT_HDR*)TcgEvent, + TcgEvent->Event + ); + } + + return Status; +} + +/** + Measure and log an action string, and extend the measurement result into PCR[5]. + + @param[in] String A specific string that indicates an Action event. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR The operation was unsuccessful. + +**/ +EFI_STATUS +EFIAPI +TcgMeasureAction ( + IN CHAR8 *String + ) +{ + TCG_PCR_EVENT_HDR TcgEvent; + + TcgEvent.PCRIndex = 5; + TcgEvent.EventType = EV_EFI_ACTION; + TcgEvent.EventSize = (UINT32)AsciiStrLen (String); + return TcgDxeHashLogExtendEventI ( + &mTcgDxeData, + (UINT8*)String, + TcgEvent.EventSize, + &TcgEvent, + (UINT8 *) String + ); +} + +/** + Measure and log EFI handoff tables, and extend the measurement result into PCR[1]. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR The operation was unsuccessful. + +**/ +EFI_STATUS +EFIAPI +MeasureHandoffTables ( + VOID + ) +{ + EFI_STATUS Status; + TCG_PCR_EVENT_HDR TcgEvent; + EFI_HANDOFF_TABLE_POINTERS HandoffTables; + UINTN ProcessorNum; + EFI_CPU_PHYSICAL_LOCATION *ProcessorLocBuf; + + ProcessorLocBuf = NULL; + Status = EFI_SUCCESS; + + if (PcdGet8 (PcdTpmPlatformClass) == TCG_PLATFORM_TYPE_SERVER) { + // + // Tcg Server spec. + // Measure each processor EFI_CPU_PHYSICAL_LOCATION with EV_TABLE_OF_DEVICES to PCR[1] + // + Status = GetProcessorsCpuLocation(&ProcessorLocBuf, &ProcessorNum); + + if (!EFI_ERROR(Status)){ + TcgEvent.PCRIndex = 1; + TcgEvent.EventType = EV_TABLE_OF_DEVICES; + TcgEvent.EventSize = sizeof (HandoffTables); + + HandoffTables.NumberOfTables = 1; + HandoffTables.TableEntry[0].VendorGuid = gEfiMpServiceProtocolGuid; + HandoffTables.TableEntry[0].VendorTable = ProcessorLocBuf; + + Status = TcgDxeHashLogExtendEventI ( + &mTcgDxeData, + (UINT8*)(UINTN)ProcessorLocBuf, + sizeof(EFI_CPU_PHYSICAL_LOCATION) * ProcessorNum, + &TcgEvent, + (UINT8*)&HandoffTables + ); + + FreePool(ProcessorLocBuf); + } + } + + return Status; +} + +/** + Measure and log Separator event, and extend the measurement result into a specific PCR. + + @param[in] PCRIndex PCR index. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR The operation was unsuccessful. + +**/ +EFI_STATUS +EFIAPI +MeasureSeparatorEvent ( + IN TPM_PCRINDEX PCRIndex + ) +{ + TCG_PCR_EVENT_HDR TcgEvent; + UINT32 EventData; + + EventData = 0; + TcgEvent.PCRIndex = PCRIndex; + TcgEvent.EventType = EV_SEPARATOR; + TcgEvent.EventSize = (UINT32)sizeof (EventData); + return TcgDxeHashLogExtendEventI ( + &mTcgDxeData, + (UINT8 *)&EventData, + sizeof (EventData), + &TcgEvent, + (UINT8 *)&EventData + ); +} + +/** + Read an EFI Variable. + + This function allocates a buffer to return the contents of the variable. The caller is + responsible for freeing the buffer. + + @param[in] VarName A Null-terminated string that is the name of the vendor's variable. + @param[in] VendorGuid A unique identifier for the vendor. + @param[out] VarSize The size of the variable data. + + @return A pointer to the buffer to return the contents of the variable.Otherwise NULL. + +**/ +VOID * +EFIAPI +ReadVariable ( + IN CHAR16 *VarName, + IN EFI_GUID *VendorGuid, + OUT UINTN *VarSize + ) +{ + EFI_STATUS Status; + VOID *VarData; + + *VarSize = 0; + Status = gRT->GetVariable ( + VarName, + VendorGuid, + NULL, + VarSize, + NULL + ); + if (Status != EFI_BUFFER_TOO_SMALL) { + return NULL; + } + + VarData = AllocatePool (*VarSize); + if (VarData != NULL) { + Status = gRT->GetVariable ( + VarName, + VendorGuid, + NULL, + VarSize, + VarData + ); + if (EFI_ERROR (Status)) { + FreePool (VarData); + VarData = NULL; + *VarSize = 0; + } + } + return VarData; +} + +/** + Measure and log an EFI variable, and extend the measurement result into a specific PCR. + + @param[in] PCRIndex PCR Index. + @param[in] EventType Event type. + @param[in] VarName A Null-terminated string that is the name of the vendor's variable. + @param[in] VendorGuid A unique identifier for the vendor. + @param[in] VarData The content of the variable data. + @param[in] VarSize The size of the variable data. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_OUT_OF_RESOURCES Out of memory. + @retval EFI_DEVICE_ERROR The operation was unsuccessful. + +**/ +EFI_STATUS +EFIAPI +MeasureVariable ( + IN TPM_PCRINDEX PCRIndex, + IN TCG_EVENTTYPE EventType, + IN CHAR16 *VarName, + IN EFI_GUID *VendorGuid, + IN VOID *VarData, + IN UINTN VarSize + ) +{ + EFI_STATUS Status; + TCG_PCR_EVENT_HDR TcgEvent; + UINTN VarNameLength; + EFI_VARIABLE_DATA *VarLog; + + VarNameLength = StrLen (VarName); + TcgEvent.PCRIndex = PCRIndex; + TcgEvent.EventType = EventType; + TcgEvent.EventSize = (UINT32)(sizeof (*VarLog) + VarNameLength * sizeof (*VarName) + VarSize + - sizeof (VarLog->UnicodeName) - sizeof (VarLog->VariableData)); + + VarLog = (EFI_VARIABLE_DATA*)AllocatePool (TcgEvent.EventSize); + if (VarLog == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + VarLog->VariableName = *VendorGuid; + VarLog->UnicodeNameLength = VarNameLength; + VarLog->VariableDataLength = VarSize; + CopyMem ( + VarLog->UnicodeName, + VarName, + VarNameLength * sizeof (*VarName) + ); + CopyMem ( + (CHAR16 *)VarLog->UnicodeName + VarNameLength, + VarData, + VarSize + ); + + Status = TcgDxeHashLogExtendEventI ( + &mTcgDxeData, + (UINT8*)VarLog, + TcgEvent.EventSize, + &TcgEvent, + (UINT8*)VarLog + ); + FreePool (VarLog); + return Status; +} + +/** + Read then Measure and log an EFI boot variable, and extend the measurement result into PCR[5]. + + @param[in] VarName A Null-terminated string that is the name of the vendor's variable. + @param[in] VendorGuid A unique identifier for the vendor. + @param[out] VarSize The size of the variable data. + @param[out] VarData Pointer to the content of the variable. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_OUT_OF_RESOURCES Out of memory. + @retval EFI_DEVICE_ERROR The operation was unsuccessful. + +**/ +EFI_STATUS +EFIAPI +ReadAndMeasureBootVariable ( + IN CHAR16 *VarName, + IN EFI_GUID *VendorGuid, + OUT UINTN *VarSize, + OUT VOID **VarData + ) +{ + EFI_STATUS Status; + + *VarData = ReadVariable (VarName, VendorGuid, VarSize); + if (*VarData == NULL) { + return EFI_NOT_FOUND; + } + + Status = MeasureVariable ( + 5, + EV_EFI_VARIABLE_BOOT, + VarName, + VendorGuid, + *VarData, + *VarSize + ); + return Status; +} + +/** + Measure and log all EFI boot variables, and extend the measurement result into a specific PCR. + + The EFI boot variables are BootOrder and Boot#### variables. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_OUT_OF_RESOURCES Out of memory. + @retval EFI_DEVICE_ERROR The operation was unsuccessful. + +**/ +EFI_STATUS +EFIAPI +MeasureAllBootVariables ( + VOID + ) +{ + EFI_STATUS Status; + UINT16 *BootOrder; + UINTN BootCount; + UINTN Index; + VOID *BootVarData; + UINTN Size; + + Status = ReadAndMeasureBootVariable ( + mBootVarName, + &gEfiGlobalVariableGuid, + &BootCount, + (VOID **) &BootOrder + ); + if (Status == EFI_NOT_FOUND || BootOrder == NULL) { + return EFI_SUCCESS; + } + + if (EFI_ERROR (Status)) { + // + // BootOrder can't be NULL if status is not EFI_NOT_FOUND + // + FreePool (BootOrder); + return Status; + } + + BootCount /= sizeof (*BootOrder); + for (Index = 0; Index < BootCount; Index++) { + UnicodeSPrint (mBootVarName, sizeof (mBootVarName), L"Boot%04x", BootOrder[Index]); + Status = ReadAndMeasureBootVariable ( + mBootVarName, + &gEfiGlobalVariableGuid, + &Size, + &BootVarData + ); + if (!EFI_ERROR (Status)) { + FreePool (BootVarData); + } + } + + FreePool (BootOrder); + return EFI_SUCCESS; +} + +/** + Ready to Boot Event notification handler. + + Sequence of OS boot events is measured in this event notification handler. + + @param[in] Event Event whose notification function is being invoked + @param[in] Context Pointer to the notification function's context + +**/ +VOID +EFIAPI +OnReadyToBoot ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + TPM_PCRINDEX PcrIndex; + + if (mBootAttempts == 0) { + + // + // Measure handoff tables. + // + Status = MeasureHandoffTables (); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "HOBs not Measured. Error!\n")); + } + + // + // Measure BootOrder & Boot#### variables. + // + Status = MeasureAllBootVariables (); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Boot Variables not Measured. Error!\n")); + } + + // + // 1. This is the first boot attempt. + // + Status = TcgMeasureAction ( + EFI_CALLING_EFI_APPLICATION + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "%a not Measured. Error!\n", EFI_CALLING_EFI_APPLICATION)); + } + + // + // 2. Draw a line between pre-boot env and entering post-boot env. + // + for (PcrIndex = 0; PcrIndex < 8; PcrIndex++) { + Status = MeasureSeparatorEvent (PcrIndex); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Separator Event not Measured. Error!\n")); + } + } + + // + // 3. Measure GPT. It would be done in SAP driver. + // + + // + // 4. Measure PE/COFF OS loader. It would be done in SAP driver. + // + + // + // 5. Read & Measure variable. BootOrder already measured. + // + } else { + // + // 6. Not first attempt, meaning a return from last attempt + // + Status = TcgMeasureAction ( + EFI_RETURNING_FROM_EFI_APPLICATOIN + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "%a not Measured. Error!\n", EFI_RETURNING_FROM_EFI_APPLICATOIN)); + } + } + + DEBUG ((EFI_D_INFO, "TPM TcgDxe Measure Data when ReadyToBoot\n")); + // + // Increase boot attempt counter. + // + mBootAttempts++; +} + +/** + Install TCG ACPI Table when ACPI Table Protocol is available. + + A system's firmware uses an ACPI table to identify the system's TCG capabilities + to the Post-Boot environment. The information in this ACPI table is not guaranteed + to be valid until the Host Platform transitions from pre-boot state to post-boot state. + + @param[in] Event Event whose notification function is being invoked + @param[in] Context Pointer to the notification function's context +**/ +VOID +EFIAPI +InstallAcpiTable ( + IN EFI_EVENT Event, + IN VOID* Context + ) +{ + UINTN TableKey; + EFI_STATUS Status; + EFI_ACPI_TABLE_PROTOCOL *AcpiTable; + UINT8 Checksum; + UINT64 OemTableId; + + Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **)&AcpiTable); + if (EFI_ERROR (Status)) { + return; + } + + if (PcdGet8 (PcdTpmPlatformClass) == TCG_PLATFORM_TYPE_CLIENT) { + CopyMem (mTcgClientAcpiTemplate.Header.OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (mTcgClientAcpiTemplate.Header.OemId)); + OemTableId = PcdGet64 (PcdAcpiDefaultOemTableId); + CopyMem (&mTcgClientAcpiTemplate.Header.OemTableId, &OemTableId, sizeof (UINT64)); + mTcgClientAcpiTemplate.Header.OemRevision = PcdGet32 (PcdAcpiDefaultOemRevision); + mTcgClientAcpiTemplate.Header.CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId); + mTcgClientAcpiTemplate.Header.CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision); + // + // The ACPI table must be checksumed before calling the InstallAcpiTable() + // service of the ACPI table protocol to install it. + // + Checksum = CalculateCheckSum8 ((UINT8 *)&mTcgClientAcpiTemplate, sizeof (mTcgClientAcpiTemplate)); + mTcgClientAcpiTemplate.Header.Checksum = Checksum; + + Status = AcpiTable->InstallAcpiTable ( + AcpiTable, + &mTcgClientAcpiTemplate, + sizeof (mTcgClientAcpiTemplate), + &TableKey + ); + } else { + CopyMem (mTcgServerAcpiTemplate.Header.OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (mTcgServerAcpiTemplate.Header.OemId)); + OemTableId = PcdGet64 (PcdAcpiDefaultOemTableId); + CopyMem (&mTcgServerAcpiTemplate.Header.OemTableId, &OemTableId, sizeof (UINT64)); + mTcgServerAcpiTemplate.Header.OemRevision = PcdGet32 (PcdAcpiDefaultOemRevision); + mTcgServerAcpiTemplate.Header.CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId); + mTcgServerAcpiTemplate.Header.CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision); + // + // The ACPI table must be checksumed before calling the InstallAcpiTable() + // service of the ACPI table protocol to install it. + // + Checksum = CalculateCheckSum8 ((UINT8 *)&mTcgServerAcpiTemplate, sizeof (mTcgServerAcpiTemplate)); + mTcgServerAcpiTemplate.Header.Checksum = Checksum; + + mTcgServerAcpiTemplate.BaseAddress.Address = PcdGet64 (PcdTpmBaseAddress); + Status = AcpiTable->InstallAcpiTable ( + AcpiTable, + &mTcgServerAcpiTemplate, + sizeof (mTcgServerAcpiTemplate), + &TableKey + ); + } + + if (EFI_ERROR (Status)) { + DEBUG((EFI_D_ERROR, "Tcg Acpi Table installation failure")); + } +} + +/** + Exit Boot Services Event notification handler. + + Measure invocation and success of ExitBootServices. + + @param[in] Event Event whose notification function is being invoked + @param[in] Context Pointer to the notification function's context + +**/ +VOID +EFIAPI +OnExitBootServices ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + + // + // Measure invocation of ExitBootServices, + // + Status = TcgMeasureAction ( + EFI_EXIT_BOOT_SERVICES_INVOCATION + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "%a not Measured. Error!\n", EFI_EXIT_BOOT_SERVICES_INVOCATION)); + } + + // + // Measure success of ExitBootServices + // + Status = TcgMeasureAction ( + EFI_EXIT_BOOT_SERVICES_SUCCEEDED + ); + if (EFI_ERROR (Status)){ + DEBUG ((EFI_D_ERROR, "%a not Measured. Error!\n", EFI_EXIT_BOOT_SERVICES_SUCCEEDED)); + } +} + +/** + Exit Boot Services Failed Event notification handler. + + Measure Failure of ExitBootServices. + + @param[in] Event Event whose notification function is being invoked + @param[in] Context Pointer to the notification function's context + +**/ +VOID +EFIAPI +OnExitBootServicesFailed ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + + // + // Measure Failure of ExitBootServices, + // + Status = TcgMeasureAction ( + EFI_EXIT_BOOT_SERVICES_FAILED + ); + if (EFI_ERROR (Status)){ + DEBUG ((EFI_D_ERROR, "%a not Measured. Error!\n", EFI_EXIT_BOOT_SERVICES_FAILED)); + } +} + +/** + Get TPM Deactivated state. + + @param[out] TPMDeactivatedFlag Returns TPM Deactivated state. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR The operation was unsuccessful. + +**/ +EFI_STATUS +GetTpmStatus ( + OUT BOOLEAN *TPMDeactivatedFlag + ) +{ + EFI_STATUS Status; + TPM_STCLEAR_FLAGS VolatileFlags; + + Status = Tpm12GetCapabilityFlagVolatile (&VolatileFlags); + if (!EFI_ERROR (Status)) { + *TPMDeactivatedFlag = VolatileFlags.deactivated; + } + + return Status; +} + +/** + The driver's entry point. + + It publishes EFI TCG Protocol. + + @param[in] ImageHandle The firmware allocated handle for the EFI image. + @param[in] SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The entry point is executed successfully. + @retval other Some error occurs when executing this entry point. + +**/ +EFI_STATUS +EFIAPI +DriverEntry ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_EVENT Event; + VOID *Registration; + + if (!CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceTpm12Guid)){ + DEBUG ((EFI_D_ERROR, "No TPM12 instance required!\n")); + return EFI_UNSUPPORTED; + } + + if (GetFirstGuidHob (&gTpmErrorHobGuid) != NULL) { + DEBUG ((EFI_D_ERROR, "TPM error!\n")); + return EFI_DEVICE_ERROR; + } + + Status = Tpm12RequestUseTpm (); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "TPM not detected!\n")); + return Status; + } + + Status = GetTpmStatus (&mTcgDxeData.BsCap.TPMDeactivatedFlag); + if (EFI_ERROR (Status)) { + DEBUG (( + EFI_D_ERROR, + "Line %d in file " __FILE__ ":\n " + "DriverEntry: TPM not working properly\n", + __LINE__ + )); + return Status; + } + + Status = gBS->InstallProtocolInterface ( + &ImageHandle, + &gEfiTcgProtocolGuid, + EFI_NATIVE_INTERFACE, + &mTcgDxeData.TcgProtocol + ); + if (!EFI_ERROR (Status) && (!mTcgDxeData.BsCap.TPMDeactivatedFlag) && mTcgDxeData.BsCap.TPMPresentFlag) { + // + // Setup the log area and copy event log from hob list to it + // + Status = SetupEventLog (); + ASSERT_EFI_ERROR (Status); + + // + // Measure handoff tables, Boot#### variables etc. + // + Status = EfiCreateEventReadyToBootEx ( + TPL_CALLBACK, + OnReadyToBoot, + NULL, + &Event + ); + + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + OnExitBootServices, + NULL, + &gEfiEventExitBootServicesGuid, + &Event + ); + + // + // Measure Exit Boot Service failed + // + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + OnExitBootServicesFailed, + NULL, + &gEventExitBootServicesFailedGuid, + &Event + ); + } + + // + // Install ACPI Table + // + EfiCreateProtocolNotifyEvent (&gEfiAcpiTableProtocolGuid, TPL_CALLBACK, InstallAcpiTable, NULL, &Registration); + + return Status; +} diff --git a/Core/SecurityPkg/Tcg/TcgDxe/TcgDxe.inf b/Core/SecurityPkg/Tcg/TcgDxe/TcgDxe.inf new file mode 100644 index 0000000000..1b96ecbe2a --- /dev/null +++ b/Core/SecurityPkg/Tcg/TcgDxe/TcgDxe.inf @@ -0,0 +1,86 @@ +## @file +# Produces TCG protocol and measures boot environment +# This module will produce TCG protocol and measure boot environment. +# +# Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = TcgDxe + MODULE_UNI_FILE = TcgDxe.uni + FILE_GUID = A5683620-7998-4bb2-A377-1C1E31E1E215 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = DriverEntry + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF +# + +[Sources] + TcgDxe.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + CryptoPkg/CryptoPkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + MemoryAllocationLib + BaseLib + UefiBootServicesTableLib + HobLib + UefiDriverEntryPoint + UefiRuntimeServicesTableLib + BaseMemoryLib + DebugLib + Tpm12DeviceLib + BaseCryptLib + PrintLib + UefiLib + PcdLib + ReportStatusCodeLib + Tpm12CommandLib + +[Guids] + gEfiGlobalVariableGuid ## SOMETIMES_CONSUMES ## Variable:L"BootXXXX" + gTcgEventEntryHobGuid ## SOMETIMES_CONSUMES ## HOB + gTpmErrorHobGuid ## SOMETIMES_CONSUMES ## HOB + gEfiEventExitBootServicesGuid ## CONSUMES ## Event + gEventExitBootServicesFailedGuid ## SOMETIMES_CONSUMES ## Event + gEfiTpmDeviceInstanceTpm12Guid ## PRODUCES ## GUID # TPM device identifier + +[Protocols] + gEfiTcgProtocolGuid ## PRODUCES + gEfiAcpiTableProtocolGuid ## NOTIFY + gEfiMpServiceProtocolGuid ## SOMETIMES_CONSUMES + +[Pcd] + gEfiSecurityPkgTokenSpaceGuid.PcdTpmPlatformClass ## SOMETIMES_CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdTpmInstanceGuid ## CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdTpmBaseAddress ## SOMETIMES_CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemId ## SOMETIMES_CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemTableId ## SOMETIMES_CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemRevision ## SOMETIMES_CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorId ## SOMETIMES_CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorRevision ## SOMETIMES_CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdStatusCodeSubClassTpmDevice ## SOMETIMES_CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdTcgLogAreaMinLen ## CONSUMES + +[Depex] + TRUE + +[UserExtensions.TianoCore."ExtraFiles"] + TcgDxeExtra.uni + \ No newline at end of file diff --git a/Core/SecurityPkg/Tcg/TcgDxe/TcgDxe.uni b/Core/SecurityPkg/Tcg/TcgDxe/TcgDxe.uni new file mode 100644 index 0000000000..d8e9b91edf --- /dev/null +++ b/Core/SecurityPkg/Tcg/TcgDxe/TcgDxe.uni @@ -0,0 +1,21 @@ +// /** @file +// Produces TCG protocol and measures boot environment +// +// This module will produce TCG protocol and measure boot environment. +// +// Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.
+// +// This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// **/ + + +#string STR_MODULE_ABSTRACT #language en-US "Produces TCG protocol and measures boot environment" + +#string STR_MODULE_DESCRIPTION #language en-US "This module will produce TCG protocol and measure boot environment." + diff --git a/Core/SecurityPkg/Tcg/TcgDxe/TcgDxeExtra.uni b/Core/SecurityPkg/Tcg/TcgDxe/TcgDxeExtra.uni new file mode 100644 index 0000000000..f6f8b634e0 --- /dev/null +++ b/Core/SecurityPkg/Tcg/TcgDxe/TcgDxeExtra.uni @@ -0,0 +1,19 @@ +// /** @file +// TcgDxe Localized Strings and Content +// +// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.
+// +// This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// **/ + +#string STR_PROPERTIES_MODULE_NAME +#language en-US +"TCG (Trusted Computing Group) DXE" + + diff --git a/Core/SecurityPkg/Tcg/TcgPei/TcgPei.c b/Core/SecurityPkg/Tcg/TcgPei/TcgPei.c new file mode 100644 index 0000000000..63807f44ff --- /dev/null +++ b/Core/SecurityPkg/Tcg/TcgPei/TcgPei.c @@ -0,0 +1,841 @@ +/** @file + Initialize TPM device and measure FVs before handing off control to DXE. + +Copyright (c) 2005 - 2017, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +BOOLEAN mImageInMemory = FALSE; + +EFI_PEI_PPI_DESCRIPTOR mTpmInitializedPpiList = { + EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, + &gPeiTpmInitializedPpiGuid, + NULL +}; + +EFI_PEI_PPI_DESCRIPTOR mTpmInitializationDonePpiList = { + EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, + &gPeiTpmInitializationDonePpiGuid, + NULL +}; + +EFI_PLATFORM_FIRMWARE_BLOB *mMeasuredBaseFvInfo; +UINT32 mMeasuredBaseFvIndex = 0; + +EFI_PLATFORM_FIRMWARE_BLOB *mMeasuredChildFvInfo; +UINT32 mMeasuredChildFvIndex = 0; + +EFI_PEI_FIRMWARE_VOLUME_INFO_MEASUREMENT_EXCLUDED_PPI *mMeasurementExcludedFvPpi; + +/** + Lock physical presence if needed. + + @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation + @param[in] NotifyDescriptor Address of the notification descriptor data structure. + @param[in] Ppi Address of the PPI that was installed. + + @retval EFI_SUCCESS Operation completed successfully. + +**/ +EFI_STATUS +EFIAPI +PhysicalPresencePpiNotifyCallback ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, + IN VOID *Ppi + ); + +/** + Measure and record the Firmware Volum Information once FvInfoPPI install. + + @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation. + @param[in] NotifyDescriptor Address of the notification descriptor data structure. + @param[in] Ppi Address of the PPI that was installed. + + @retval EFI_SUCCESS The FV Info is measured and recorded to TPM. + @return Others Fail to measure FV. + +**/ +EFI_STATUS +EFIAPI +FirmwareVolmeInfoPpiNotifyCallback ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, + IN VOID *Ppi + ); + +/** + Record all measured Firmware Volum Information into a Guid Hob + + @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation. + @param[in] NotifyDescriptor Address of the notification descriptor data structure. + @param[in] Ppi Address of the PPI that was installed. + + @retval EFI_SUCCESS The FV Info is measured and recorded to TPM. + @return Others Fail to measure FV. + +**/ +EFI_STATUS +EFIAPI +EndofPeiSignalNotifyCallBack ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, + IN VOID *Ppi + ); + +EFI_PEI_NOTIFY_DESCRIPTOR mNotifyList[] = { + { + EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK, + &gPeiLockPhysicalPresencePpiGuid, + PhysicalPresencePpiNotifyCallback + }, + { + EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK, + &gEfiPeiFirmwareVolumeInfoPpiGuid, + FirmwareVolmeInfoPpiNotifyCallback + }, + { + EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK, + &gEfiPeiFirmwareVolumeInfo2PpiGuid, + FirmwareVolmeInfoPpiNotifyCallback + }, + { + (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gEfiEndOfPeiSignalPpiGuid, + EndofPeiSignalNotifyCallBack + } +}; + +/** + Record all measured Firmware Volum Information into a Guid Hob + Guid Hob payload layout is + + UINT32 *************************** FIRMWARE_BLOB number + EFI_PLATFORM_FIRMWARE_BLOB******** BLOB Array + + @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation. + @param[in] NotifyDescriptor Address of the notification descriptor data structure. + @param[in] Ppi Address of the PPI that was installed. + + @retval EFI_SUCCESS The FV Info is measured and recorded to TPM. + @return Others Fail to measure FV. + +**/ +EFI_STATUS +EFIAPI +EndofPeiSignalNotifyCallBack ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, + IN VOID *Ppi + ) +{ + MEASURED_HOB_DATA *MeasuredHobData; + + MeasuredHobData = NULL; + + // + // Create a Guid hob to save all measured Fv + // + MeasuredHobData = BuildGuidHob( + &gMeasuredFvHobGuid, + sizeof(UINTN) + sizeof(EFI_PLATFORM_FIRMWARE_BLOB) * (mMeasuredBaseFvIndex + mMeasuredChildFvIndex) + ); + + if (MeasuredHobData != NULL){ + // + // Save measured FV info enty number + // + MeasuredHobData->Num = mMeasuredBaseFvIndex + mMeasuredChildFvIndex; + + // + // Save measured base Fv info + // + CopyMem (MeasuredHobData->MeasuredFvBuf, mMeasuredBaseFvInfo, sizeof(EFI_PLATFORM_FIRMWARE_BLOB) * (mMeasuredBaseFvIndex)); + + // + // Save measured child Fv info + // + CopyMem (&MeasuredHobData->MeasuredFvBuf[mMeasuredBaseFvIndex] , mMeasuredChildFvInfo, sizeof(EFI_PLATFORM_FIRMWARE_BLOB) * (mMeasuredChildFvIndex)); + } + + return EFI_SUCCESS; +} + +/** +Single function calculates SHA1 digest value for all raw data. It +combines Sha1Init(), Sha1Update() and Sha1Final(). + +@param[in] Data Raw data to be digested. +@param[in] DataLen Size of the raw data. +@param[out] Digest Pointer to a buffer that stores the final digest. + +@retval EFI_SUCCESS Always successfully calculate the final digest. +**/ +EFI_STATUS +EFIAPI +TpmCommHashAll ( + IN CONST UINT8 *Data, + IN UINTN DataLen, + OUT TPM_DIGEST *Digest + ) +{ + VOID *Sha1Ctx; + UINTN CtxSize; + + CtxSize = Sha1GetContextSize (); + Sha1Ctx = AllocatePool (CtxSize); + ASSERT (Sha1Ctx != NULL); + + Sha1Init (Sha1Ctx); + Sha1Update (Sha1Ctx, Data, DataLen); + Sha1Final (Sha1Ctx, (UINT8 *)Digest); + + FreePool (Sha1Ctx); + + return EFI_SUCCESS; +} + +/** + Do a hash operation on a data buffer, extend a specific TPM PCR with the hash result, + and build a GUIDed HOB recording the event which will be passed to the DXE phase and + added into the Event Log. + + @param[in] PeiServices Describes the list of possible PEI Services. + @param[in] HashData Physical address of the start of the data buffer + to be hashed, extended, and logged. + @param[in] HashDataLen The length, in bytes, of the buffer referenced by HashData. + @param[in] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR data structure. + @param[in] NewEventData Pointer to the new event data. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event. + @retval EFI_DEVICE_ERROR The command was unsuccessful. + +**/ +EFI_STATUS +HashLogExtendEvent ( + IN EFI_PEI_SERVICES **PeiServices, + IN UINT8 *HashData, + IN UINTN HashDataLen, + IN TCG_PCR_EVENT_HDR *NewEventHdr, + IN UINT8 *NewEventData + ) +{ + EFI_STATUS Status; + VOID *HobData; + + if (GetFirstGuidHob (&gTpmErrorHobGuid) != NULL) { + return EFI_DEVICE_ERROR; + } + + HobData = NULL; + if (HashDataLen != 0) { + Status = TpmCommHashAll ( + HashData, + HashDataLen, + &NewEventHdr->Digest + ); + if (EFI_ERROR (Status)) { + goto Done; + } + } + + Status = Tpm12Extend ( + &NewEventHdr->Digest, + NewEventHdr->PCRIndex, + NULL + ); + if (EFI_ERROR (Status)) { + goto Done; + } + + HobData = BuildGuidHob ( + &gTcgEventEntryHobGuid, + sizeof (*NewEventHdr) + NewEventHdr->EventSize + ); + if (HobData == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + CopyMem (HobData, NewEventHdr, sizeof (*NewEventHdr)); + HobData = (VOID *) ((UINT8*)HobData + sizeof (*NewEventHdr)); + CopyMem (HobData, NewEventData, NewEventHdr->EventSize); + +Done: + if ((Status == EFI_DEVICE_ERROR) || (Status == EFI_TIMEOUT)) { + DEBUG ((EFI_D_ERROR, "HashLogExtendEvent - %r. Disable TPM.\n", Status)); + BuildGuidHob (&gTpmErrorHobGuid,0); + REPORT_STATUS_CODE ( + EFI_ERROR_CODE | EFI_ERROR_MINOR, + (PcdGet32 (PcdStatusCodeSubClassTpmDevice) | EFI_P_EC_INTERFACE_ERROR) + ); + Status = EFI_DEVICE_ERROR; + } + return Status; +} + +/** + Measure CRTM version. + + @param[in] PeiServices Describes the list of possible PEI Services. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event. + @retval EFI_DEVICE_ERROR The command was unsuccessful. + +**/ +EFI_STATUS +EFIAPI +MeasureCRTMVersion ( + IN EFI_PEI_SERVICES **PeiServices + ) +{ + TCG_PCR_EVENT_HDR TcgEventHdr; + + // + // Use FirmwareVersion string to represent CRTM version. + // OEMs should get real CRTM version string and measure it. + // + + TcgEventHdr.PCRIndex = 0; + TcgEventHdr.EventType = EV_S_CRTM_VERSION; + TcgEventHdr.EventSize = (UINT32) StrSize((CHAR16*)PcdGetPtr (PcdFirmwareVersionString)); + + return HashLogExtendEvent ( + PeiServices, + (UINT8*)PcdGetPtr (PcdFirmwareVersionString), + TcgEventHdr.EventSize, + &TcgEventHdr, + (UINT8*)PcdGetPtr (PcdFirmwareVersionString) + ); +} + +/** + Measure FV image. + Add it into the measured FV list after the FV is measured successfully. + + @param[in] FvBase Base address of FV image. + @param[in] FvLength Length of FV image. + + @retval EFI_SUCCESS Fv image is measured successfully + or it has been already measured. + @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event. + @retval EFI_DEVICE_ERROR The command was unsuccessful. + +**/ +EFI_STATUS +EFIAPI +MeasureFvImage ( + IN EFI_PHYSICAL_ADDRESS FvBase, + IN UINT64 FvLength + ) +{ + UINT32 Index; + EFI_STATUS Status; + EFI_PLATFORM_FIRMWARE_BLOB FvBlob; + TCG_PCR_EVENT_HDR TcgEventHdr; + + // + // Check if it is in Excluded FV list + // + if (mMeasurementExcludedFvPpi != NULL) { + for (Index = 0; Index < mMeasurementExcludedFvPpi->Count; Index ++) { + if (mMeasurementExcludedFvPpi->Fv[Index].FvBase == FvBase) { + DEBUG ((DEBUG_INFO, "The FV which is excluded by TcgPei starts at: 0x%x\n", FvBase)); + DEBUG ((DEBUG_INFO, "The FV which is excluded by TcgPei has the size: 0x%x\n", FvLength)); + return EFI_SUCCESS; + } + } + } + + // + // Check whether FV is in the measured FV list. + // + for (Index = 0; Index < mMeasuredBaseFvIndex; Index ++) { + if (mMeasuredBaseFvInfo[Index].BlobBase == FvBase) { + return EFI_SUCCESS; + } + } + + // + // Measure and record the FV to the TPM + // + FvBlob.BlobBase = FvBase; + FvBlob.BlobLength = FvLength; + + DEBUG ((DEBUG_INFO, "The FV which is measured by TcgPei starts at: 0x%x\n", FvBlob.BlobBase)); + DEBUG ((DEBUG_INFO, "The FV which is measured by TcgPei has the size: 0x%x\n", FvBlob.BlobLength)); + + TcgEventHdr.PCRIndex = 0; + TcgEventHdr.EventType = EV_EFI_PLATFORM_FIRMWARE_BLOB; + TcgEventHdr.EventSize = sizeof (FvBlob); + + Status = HashLogExtendEvent ( + (EFI_PEI_SERVICES **) GetPeiServicesTablePointer(), + (UINT8*) (UINTN) FvBlob.BlobBase, + (UINTN) FvBlob.BlobLength, + &TcgEventHdr, + (UINT8*) &FvBlob + ); + + // + // Add new FV into the measured FV list. + // + ASSERT (mMeasuredBaseFvIndex < PcdGet32 (PcdPeiCoreMaxFvSupported)); + if (mMeasuredBaseFvIndex < PcdGet32 (PcdPeiCoreMaxFvSupported)) { + mMeasuredBaseFvInfo[mMeasuredBaseFvIndex].BlobBase = FvBase; + mMeasuredBaseFvInfo[mMeasuredBaseFvIndex].BlobLength = FvLength; + mMeasuredBaseFvIndex++; + } + + return Status; +} + +/** + Measure main BIOS. + + @param[in] PeiServices Describes the list of possible PEI Services. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event. + @retval EFI_DEVICE_ERROR The command was unsuccessful. + +**/ +EFI_STATUS +EFIAPI +MeasureMainBios ( + IN EFI_PEI_SERVICES **PeiServices + ) +{ + EFI_STATUS Status; + UINT32 FvInstances; + EFI_PEI_FV_HANDLE VolumeHandle; + EFI_FV_INFO VolumeInfo; + EFI_PEI_FIRMWARE_VOLUME_PPI *FvPpi; + + FvInstances = 0; + while (TRUE) { + // + // Traverse all firmware volume instances of Static Core Root of Trust for Measurement + // (S-CRTM), this firmware volume measure policy can be modified/enhanced by special + // platform for special CRTM TPM measuring. + // + Status = PeiServicesFfsFindNextVolume (FvInstances, &VolumeHandle); + if (EFI_ERROR (Status)) { + break; + } + + // + // Measure and record the firmware volume that is dispatched by PeiCore + // + Status = PeiServicesFfsGetVolumeInfo (VolumeHandle, &VolumeInfo); + ASSERT_EFI_ERROR (Status); + // + // Locate the corresponding FV_PPI according to founded FV's format guid + // + Status = PeiServicesLocatePpi ( + &VolumeInfo.FvFormat, + 0, + NULL, + (VOID**)&FvPpi + ); + if (!EFI_ERROR (Status)) { + MeasureFvImage ((EFI_PHYSICAL_ADDRESS) (UINTN) VolumeInfo.FvStart, VolumeInfo.FvSize); + } + + FvInstances++; + } + + return EFI_SUCCESS; +} + +/** + Measure and record the Firmware Volum Information once FvInfoPPI install. + + @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation. + @param[in] NotifyDescriptor Address of the notification descriptor data structure. + @param[in] Ppi Address of the PPI that was installed. + + @retval EFI_SUCCESS The FV Info is measured and recorded to TPM. + @return Others Fail to measure FV. + +**/ +EFI_STATUS +EFIAPI +FirmwareVolmeInfoPpiNotifyCallback ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, + IN VOID *Ppi + ) +{ + EFI_PEI_FIRMWARE_VOLUME_INFO_PPI *Fv; + EFI_STATUS Status; + EFI_PEI_FIRMWARE_VOLUME_PPI *FvPpi; + UINTN Index; + + Fv = (EFI_PEI_FIRMWARE_VOLUME_INFO_PPI *) Ppi; + + // + // The PEI Core can not dispatch or load files from memory mapped FVs that do not support FvPpi. + // + Status = PeiServicesLocatePpi ( + &Fv->FvFormat, + 0, + NULL, + (VOID**)&FvPpi + ); + if (EFI_ERROR (Status)) { + return EFI_SUCCESS; + } + + // + // This is an FV from an FFS file, and the parent FV must have already been measured, + // No need to measure twice, so just record the FV and return + // + if (Fv->ParentFvName != NULL || Fv->ParentFileName != NULL ) { + + ASSERT (mMeasuredChildFvIndex < PcdGet32 (PcdPeiCoreMaxFvSupported)); + if (mMeasuredChildFvIndex < PcdGet32 (PcdPeiCoreMaxFvSupported)) { + // + // Check whether FV is in the measured child FV list. + // + for (Index = 0; Index < mMeasuredChildFvIndex; Index++) { + if (mMeasuredChildFvInfo[Index].BlobBase == (EFI_PHYSICAL_ADDRESS) (UINTN) Fv->FvInfo) { + return EFI_SUCCESS; + } + } + mMeasuredChildFvInfo[mMeasuredChildFvIndex].BlobBase = (EFI_PHYSICAL_ADDRESS) (UINTN) Fv->FvInfo; + mMeasuredChildFvInfo[mMeasuredChildFvIndex].BlobLength = Fv->FvInfoSize; + mMeasuredChildFvIndex++; + } + return EFI_SUCCESS; + } + + return MeasureFvImage ((EFI_PHYSICAL_ADDRESS) (UINTN) Fv->FvInfo, Fv->FvInfoSize); +} + +/** + Set physicalPresenceLifetimeLock, physicalPresenceHWEnable and physicalPresenceCMDEnable bit by corresponding PCDs. + And lock physical presence if needed. + + @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation + @param[in] NotifyDescriptor Address of the notification descriptor data structure. + @param[in] Ppi Address of the PPI that was installed. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_ABORTED physicalPresenceCMDEnable is locked. + @retval EFI_DEVICE_ERROR The command was unsuccessful. + +**/ +EFI_STATUS +EFIAPI +PhysicalPresencePpiNotifyCallback ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, + IN VOID *Ppi + ) +{ + EFI_STATUS Status; + TPM_PERMANENT_FLAGS TpmPermanentFlags; + PEI_LOCK_PHYSICAL_PRESENCE_PPI *LockPhysicalPresencePpi; + TPM_PHYSICAL_PRESENCE PhysicalPresenceValue; + + Status = Tpm12GetCapabilityFlagPermanent (&TpmPermanentFlags); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // 1. Set physicalPresenceLifetimeLock, physicalPresenceHWEnable and physicalPresenceCMDEnable bit by PCDs. + // + if (PcdGetBool (PcdPhysicalPresenceLifetimeLock) && !TpmPermanentFlags.physicalPresenceLifetimeLock) { + // + // Lock TPM LifetimeLock is required, and LifetimeLock is not locked yet. + // + PhysicalPresenceValue = TPM_PHYSICAL_PRESENCE_LIFETIME_LOCK; + TpmPermanentFlags.physicalPresenceLifetimeLock = TRUE; + + if (PcdGetBool (PcdPhysicalPresenceCmdEnable)) { + PhysicalPresenceValue |= TPM_PHYSICAL_PRESENCE_CMD_ENABLE; + TpmPermanentFlags.physicalPresenceCMDEnable = TRUE; + } else { + PhysicalPresenceValue |= TPM_PHYSICAL_PRESENCE_CMD_DISABLE; + TpmPermanentFlags.physicalPresenceCMDEnable = FALSE; + } + + if (PcdGetBool (PcdPhysicalPresenceHwEnable)) { + PhysicalPresenceValue |= TPM_PHYSICAL_PRESENCE_HW_ENABLE; + } else { + PhysicalPresenceValue |= TPM_PHYSICAL_PRESENCE_HW_DISABLE; + } + + Status = Tpm12PhysicalPresence ( + PhysicalPresenceValue + ); + if (EFI_ERROR (Status)) { + return Status; + } + } + + // + // 2. Lock physical presence if it is required. + // + LockPhysicalPresencePpi = (PEI_LOCK_PHYSICAL_PRESENCE_PPI *) Ppi; + if (!LockPhysicalPresencePpi->LockPhysicalPresence ((CONST EFI_PEI_SERVICES**) PeiServices)) { + return EFI_SUCCESS; + } + + if (!TpmPermanentFlags.physicalPresenceCMDEnable) { + if (TpmPermanentFlags.physicalPresenceLifetimeLock) { + // + // physicalPresenceCMDEnable is locked, can't change. + // + return EFI_ABORTED; + } + + // + // Enable physical presence command + // It is necessary in order to lock physical presence + // + Status = Tpm12PhysicalPresence ( + TPM_PHYSICAL_PRESENCE_CMD_ENABLE + ); + if (EFI_ERROR (Status)) { + return Status; + } + } + + // + // Lock physical presence + // + Status = Tpm12PhysicalPresence ( + TPM_PHYSICAL_PRESENCE_LOCK + ); + return Status; +} + +/** + Check if TPM chip is activeated or not. + + @param[in] PeiServices Describes the list of possible PEI Services. + + @retval TRUE TPM is activated. + @retval FALSE TPM is deactivated. + +**/ +BOOLEAN +IsTpmUsable ( + VOID + ) +{ + EFI_STATUS Status; + TPM_PERMANENT_FLAGS TpmPermanentFlags; + + Status = Tpm12GetCapabilityFlagPermanent (&TpmPermanentFlags); + if (EFI_ERROR (Status)) { + return FALSE; + } + return (BOOLEAN)(!TpmPermanentFlags.deactivated); +} + +/** + Do measurement after memory is ready. + + @param[in] PeiServices Describes the list of possible PEI Services. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event. + @retval EFI_DEVICE_ERROR The command was unsuccessful. + +**/ +EFI_STATUS +EFIAPI +PeimEntryMP ( + IN EFI_PEI_SERVICES **PeiServices + ) +{ + EFI_STATUS Status; + + Status = PeiServicesLocatePpi ( + &gEfiPeiFirmwareVolumeInfoMeasurementExcludedPpiGuid, + 0, + NULL, + (VOID**)&mMeasurementExcludedFvPpi + ); + // Do not check status, because it is optional + + mMeasuredBaseFvInfo = (EFI_PLATFORM_FIRMWARE_BLOB *) AllocateZeroPool (sizeof (EFI_PLATFORM_FIRMWARE_BLOB) * PcdGet32 (PcdPeiCoreMaxFvSupported)); + ASSERT (mMeasuredBaseFvInfo != NULL); + mMeasuredChildFvInfo = (EFI_PLATFORM_FIRMWARE_BLOB *) AllocateZeroPool (sizeof (EFI_PLATFORM_FIRMWARE_BLOB) * PcdGet32 (PcdPeiCoreMaxFvSupported)); + ASSERT (mMeasuredChildFvInfo != NULL); + + Status = Tpm12RequestUseTpm (); + if (EFI_ERROR (Status)) { + return Status; + } + + if (IsTpmUsable ()) { + if (PcdGet8 (PcdTpmScrtmPolicy) == 1) { + Status = MeasureCRTMVersion (PeiServices); + } + + Status = MeasureMainBios (PeiServices); + } + + // + // Post callbacks: + // 1). for the FvInfoPpi services to measure and record + // the additional Fvs to TPM + // 2). for the OperatorPresencePpi service to determine whether to + // lock the TPM + // + Status = PeiServicesNotifyPpi (&mNotifyList[0]); + ASSERT_EFI_ERROR (Status); + + return Status; +} + +/** + Entry point of this module. + + @param[in] FileHandle Handle of the file being invoked. + @param[in] PeiServices Describes the list of possible PEI Services. + + @return Status. + +**/ +EFI_STATUS +EFIAPI +PeimEntryMA ( + IN EFI_PEI_FILE_HANDLE FileHandle, + IN CONST EFI_PEI_SERVICES **PeiServices + ) +{ + EFI_STATUS Status; + EFI_STATUS Status2; + EFI_BOOT_MODE BootMode; + + if (!CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceTpm12Guid)){ + DEBUG ((EFI_D_ERROR, "No TPM12 instance required!\n")); + return EFI_UNSUPPORTED; + } + + if (GetFirstGuidHob (&gTpmErrorHobGuid) != NULL) { + DEBUG ((EFI_D_ERROR, "TPM error!\n")); + return EFI_DEVICE_ERROR; + } + + // + // Initialize TPM device + // + Status = PeiServicesGetBootMode (&BootMode); + ASSERT_EFI_ERROR (Status); + + // + // In S3 path, skip shadow logic. no measurement is required + // + if (BootMode != BOOT_ON_S3_RESUME) { + Status = (**PeiServices).RegisterForShadow(FileHandle); + if (Status == EFI_ALREADY_STARTED) { + mImageInMemory = TRUE; + } else if (Status == EFI_NOT_FOUND) { + ASSERT_EFI_ERROR (Status); + } + } + + if (!mImageInMemory) { + Status = Tpm12RequestUseTpm (); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "TPM not detected!\n")); + goto Done; + } + + if (PcdGet8 (PcdTpmInitializationPolicy) == 1) { + if (BootMode == BOOT_ON_S3_RESUME) { + Status = Tpm12Startup (TPM_ST_STATE); + } else { + Status = Tpm12Startup (TPM_ST_CLEAR); + } + if (EFI_ERROR (Status) ) { + goto Done; + } + } + + // + // TpmSelfTest is optional on S3 path, skip it to save S3 time + // + if (BootMode != BOOT_ON_S3_RESUME) { + Status = Tpm12ContinueSelfTest (); + if (EFI_ERROR (Status)) { + goto Done; + } + } + + // + // Only intall TpmInitializedPpi on success + // + Status = PeiServicesInstallPpi (&mTpmInitializedPpiList); + ASSERT_EFI_ERROR (Status); + } + + if (mImageInMemory) { + Status = PeimEntryMP ((EFI_PEI_SERVICES**)PeiServices); + return Status; + } + +Done: + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "TPM error! Build Hob\n")); + BuildGuidHob (&gTpmErrorHobGuid,0); + REPORT_STATUS_CODE ( + EFI_ERROR_CODE | EFI_ERROR_MINOR, + (PcdGet32 (PcdStatusCodeSubClassTpmDevice) | EFI_P_EC_INTERFACE_ERROR) + ); + } + // + // Always intall TpmInitializationDonePpi no matter success or fail. + // Other driver can know TPM initialization state by TpmInitializedPpi. + // + Status2 = PeiServicesInstallPpi (&mTpmInitializationDonePpiList); + ASSERT_EFI_ERROR (Status2); + + return Status; +} diff --git a/Core/SecurityPkg/Tcg/TcgPei/TcgPei.inf b/Core/SecurityPkg/Tcg/TcgPei/TcgPei.inf new file mode 100644 index 0000000000..9a44d8fbda --- /dev/null +++ b/Core/SecurityPkg/Tcg/TcgPei/TcgPei.inf @@ -0,0 +1,93 @@ +## @file +# Initializes TPM device and measures FVs in PEI phase +# +# This module will initialize TPM device, measure reported FVs and BIOS version. +# This module may also lock TPM physical presence and physicalPresenceLifetimeLock. +# +# Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = TcgPei + MODULE_UNI_FILE = TcgPei.uni + FILE_GUID = 2BE1E4A6-6505-43b3-9FFC-A3C8330E0432 + MODULE_TYPE = PEIM + VERSION_STRING = 1.0 + ENTRY_POINT = PeimEntryMA + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# +# [BootMode] +# S3_RESUME ## SOMETIMES_CONSUMES +# + +[Sources] + TcgPei.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + CryptoPkg/CryptoPkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + HobLib + PeimEntryPoint + PeiServicesLib + BaseMemoryLib + DebugLib + BaseCryptLib + Tpm12DeviceLib + TimerLib + PeiServicesTablePointerLib + BaseLib + PcdLib + MemoryAllocationLib + ReportStatusCodeLib + Tpm12CommandLib + +[Guids] + gTcgEventEntryHobGuid ## PRODUCES ## HOB + gTpmErrorHobGuid ## SOMETIMES_PRODUCES ## HOB + gMeasuredFvHobGuid ## PRODUCES ## HOB + gEfiTpmDeviceInstanceTpm12Guid ## PRODUCES ## GUID # TPM device identifier + +[Ppis] + gPeiLockPhysicalPresencePpiGuid ## SOMETIMES_CONSUMES ## NOTIFY + gEfiPeiFirmwareVolumeInfoPpiGuid ## SOMETIMES_CONSUMES ## NOTIFY + gEfiPeiFirmwareVolumeInfo2PpiGuid ## SOMETIMES_CONSUMES ## NOTIFY + gEfiPeiFirmwareVolumeInfoMeasurementExcludedPpiGuid ## SOMETIMES_CONSUMES + gPeiTpmInitializedPpiGuid ## SOMETIMES_PRODUCES + gPeiTpmInitializationDonePpiGuid ## PRODUCES + gEfiEndOfPeiSignalPpiGuid ## SOMETIMES_CONSUMES ## NOTIFY + +[Pcd] + gEfiSecurityPkgTokenSpaceGuid.PcdPhysicalPresenceLifetimeLock ## SOMETIMES_CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdPhysicalPresenceCmdEnable ## SOMETIMES_CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdPhysicalPresenceHwEnable ## SOMETIMES_CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdFirmwareVersionString ## SOMETIMES_CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdTpmInstanceGuid ## CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdTpmInitializationPolicy ## CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdTpmScrtmPolicy ## SOMETIMES_CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdPeiCoreMaxFvSupported ## CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdStatusCodeSubClassTpmDevice ## SOMETIMES_CONSUMES + +[Depex] + gEfiPeiMasterBootModePpiGuid AND + gEfiPeiReadOnlyVariable2PpiGuid AND + gEfiTpmDeviceSelectedGuid + +[UserExtensions.TianoCore."ExtraFiles"] + TcgPeiExtra.uni + \ No newline at end of file diff --git a/Core/SecurityPkg/Tcg/TcgPei/TcgPei.uni b/Core/SecurityPkg/Tcg/TcgPei/TcgPei.uni new file mode 100644 index 0000000000..b2d2d5c1c1 --- /dev/null +++ b/Core/SecurityPkg/Tcg/TcgPei/TcgPei.uni @@ -0,0 +1,22 @@ +// /** @file +// Initializes TPM device and measures FVs in PEI phase +// +// This module will initialize TPM device, measure reported FVs and BIOS version. +// This module may also lock TPM physical presence and physicalPresenceLifetimeLock. +// +// Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.
+// +// This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// **/ + + +#string STR_MODULE_ABSTRACT #language en-US "Initializes TPM device and measures FVs in PEI phase" + +#string STR_MODULE_DESCRIPTION #language en-US "This module will initialize TPM device, measure reported FVs and BIOS version. This module may also lock TPM physical presence and physicalPresenceLifetimeLock." + diff --git a/Core/SecurityPkg/Tcg/TcgPei/TcgPeiExtra.uni b/Core/SecurityPkg/Tcg/TcgPei/TcgPeiExtra.uni new file mode 100644 index 0000000000..e469d984c8 --- /dev/null +++ b/Core/SecurityPkg/Tcg/TcgPei/TcgPeiExtra.uni @@ -0,0 +1,19 @@ +// /** @file +// TcgPei Localized Strings and Content +// +// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.
+// +// This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// **/ + +#string STR_PROPERTIES_MODULE_NAME +#language en-US +"TCG (Trusted Computing Group) PEI" + + diff --git a/Core/SecurityPkg/Tcg/TcgSmm/TcgSmm.c b/Core/SecurityPkg/Tcg/TcgSmm/TcgSmm.c new file mode 100644 index 0000000000..589bab694b --- /dev/null +++ b/Core/SecurityPkg/Tcg/TcgSmm/TcgSmm.c @@ -0,0 +1,465 @@ +/** @file + It updates TPM items in ACPI table and registers SMI callback + functions for physical presence and ClearMemory. + + Caution: This module requires additional review when modified. + This driver will have external input - variable and ACPINvs data in SMM mode. + This external input must be validated carefully to avoid security issue. + + PhysicalPresenceCallback() and MemoryClearCallback() will receive untrusted input and do some check. + +Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "TcgSmm.h" + +EFI_SMM_VARIABLE_PROTOCOL *mSmmVariable; +TCG_NVS *mTcgNvs; + +/** + Software SMI callback for TPM physical presence which is called from ACPI method. + + Caution: This function may receive untrusted input. + Variable and ACPINvs are external input, so this function will validate + its data structure to be valid value. + + @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister(). + @param[in] Context Points to an optional handler context which was specified when the + handler was registered. + @param[in, out] CommBuffer A pointer to a collection of data in memory that will + be conveyed from a non-SMM environment into an SMM environment. + @param[in, out] CommBufferSize The size of the CommBuffer. + + @retval EFI_SUCCESS The interrupt was handled successfully. + +**/ +EFI_STATUS +EFIAPI +PhysicalPresenceCallback ( + IN EFI_HANDLE DispatchHandle, + IN CONST VOID *Context, + IN OUT VOID *CommBuffer, + IN OUT UINTN *CommBufferSize + ) +{ + EFI_STATUS Status; + UINTN DataSize; + EFI_PHYSICAL_PRESENCE PpData; + EFI_PHYSICAL_PRESENCE_FLAGS Flags; + BOOLEAN RequestConfirmed; + + // + // Get the Physical Presence variable + // + DataSize = sizeof (EFI_PHYSICAL_PRESENCE); + Status = mSmmVariable->SmmGetVariable ( + PHYSICAL_PRESENCE_VARIABLE, + &gEfiPhysicalPresenceGuid, + NULL, + &DataSize, + &PpData + ); + + DEBUG ((EFI_D_INFO, "[TPM] PP callback, Parameter = %x\n", mTcgNvs->PhysicalPresence.Parameter)); + if (mTcgNvs->PhysicalPresence.Parameter == ACPI_FUNCTION_RETURN_REQUEST_RESPONSE_TO_OS) { + if (EFI_ERROR (Status)) { + mTcgNvs->PhysicalPresence.ReturnCode = PP_RETURN_TPM_OPERATION_RESPONSE_FAILURE; + mTcgNvs->PhysicalPresence.LastRequest = 0; + mTcgNvs->PhysicalPresence.Response = 0; + DEBUG ((EFI_D_ERROR, "[TPM] Get PP variable failure! Status = %r\n", Status)); + return EFI_SUCCESS; + } + mTcgNvs->PhysicalPresence.ReturnCode = PP_RETURN_TPM_OPERATION_RESPONSE_SUCCESS; + mTcgNvs->PhysicalPresence.LastRequest = PpData.LastPPRequest; + mTcgNvs->PhysicalPresence.Response = PpData.PPResponse; + } else if ((mTcgNvs->PhysicalPresence.Parameter == ACPI_FUNCTION_SUBMIT_REQUEST_TO_BIOS) + || (mTcgNvs->PhysicalPresence.Parameter == ACPI_FUNCTION_SUBMIT_REQUEST_TO_BIOS_2)) { + if (EFI_ERROR (Status)) { + mTcgNvs->PhysicalPresence.ReturnCode = TCG_PP_SUBMIT_REQUEST_TO_PREOS_GENERAL_FAILURE; + DEBUG ((EFI_D_ERROR, "[TPM] Get PP variable failure! Status = %r\n", Status)); + return EFI_SUCCESS; + } + if (mTcgNvs->PhysicalPresence.Request == PHYSICAL_PRESENCE_SET_OPERATOR_AUTH) { + // + // This command requires UI to prompt user for Auth data. + // + mTcgNvs->PhysicalPresence.ReturnCode = TCG_PP_SUBMIT_REQUEST_TO_PREOS_NOT_IMPLEMENTED; + return EFI_SUCCESS; + } + + if (PpData.PPRequest != mTcgNvs->PhysicalPresence.Request) { + PpData.PPRequest = (UINT8) mTcgNvs->PhysicalPresence.Request; + DataSize = sizeof (EFI_PHYSICAL_PRESENCE); + Status = mSmmVariable->SmmSetVariable ( + PHYSICAL_PRESENCE_VARIABLE, + &gEfiPhysicalPresenceGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + DataSize, + &PpData + ); + } + + if (EFI_ERROR (Status)) { + mTcgNvs->PhysicalPresence.ReturnCode = TCG_PP_SUBMIT_REQUEST_TO_PREOS_GENERAL_FAILURE; + return EFI_SUCCESS; + } + mTcgNvs->PhysicalPresence.ReturnCode = TCG_PP_SUBMIT_REQUEST_TO_PREOS_SUCCESS; + + if (mTcgNvs->PhysicalPresence.Request >= TCG_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION) { + DataSize = sizeof (EFI_PHYSICAL_PRESENCE_FLAGS); + Status = mSmmVariable->SmmGetVariable ( + PHYSICAL_PRESENCE_FLAGS_VARIABLE, + &gEfiPhysicalPresenceGuid, + NULL, + &DataSize, + &Flags + ); + if (EFI_ERROR (Status)) { + Flags.PPFlags = TCG_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_PROVISION; + } + mTcgNvs->PhysicalPresence.ReturnCode = TcgPpVendorLibSubmitRequestToPreOSFunction (mTcgNvs->PhysicalPresence.Request, Flags.PPFlags); + } + } else if (mTcgNvs->PhysicalPresence.Parameter == ACPI_FUNCTION_GET_USER_CONFIRMATION_STATUS_FOR_REQUEST) { + if (EFI_ERROR (Status)) { + mTcgNvs->PhysicalPresence.ReturnCode = TCG_PP_GET_USER_CONFIRMATION_BLOCKED_BY_BIOS_CONFIGURATION; + DEBUG ((EFI_D_ERROR, "[TPM] Get PP variable failure! Status = %r\n", Status)); + return EFI_SUCCESS; + } + // + // Get the Physical Presence flags + // + DataSize = sizeof (EFI_PHYSICAL_PRESENCE_FLAGS); + Status = mSmmVariable->SmmGetVariable ( + PHYSICAL_PRESENCE_FLAGS_VARIABLE, + &gEfiPhysicalPresenceGuid, + NULL, + &DataSize, + &Flags + ); + if (EFI_ERROR (Status)) { + mTcgNvs->PhysicalPresence.ReturnCode = TCG_PP_GET_USER_CONFIRMATION_BLOCKED_BY_BIOS_CONFIGURATION; + DEBUG ((EFI_D_ERROR, "[TPM] Get PP flags failure! Status = %r\n", Status)); + return EFI_SUCCESS; + } + + RequestConfirmed = FALSE; + + switch (mTcgNvs->PPRequestUserConfirm) { + case PHYSICAL_PRESENCE_ENABLE: + case PHYSICAL_PRESENCE_DISABLE: + case PHYSICAL_PRESENCE_ACTIVATE: + case PHYSICAL_PRESENCE_DEACTIVATE: + case PHYSICAL_PRESENCE_ENABLE_ACTIVATE: + case PHYSICAL_PRESENCE_DEACTIVATE_DISABLE: + case PHYSICAL_PRESENCE_SET_OWNER_INSTALL_TRUE: + case PHYSICAL_PRESENCE_SET_OWNER_INSTALL_FALSE: + case PHYSICAL_PRESENCE_ENABLE_ACTIVATE_OWNER_TRUE: + case PHYSICAL_PRESENCE_DEACTIVATE_DISABLE_OWNER_FALSE: + if ((Flags.PPFlags & TCG_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_PROVISION) != 0) { + RequestConfirmed = TRUE; + } + break; + + case PHYSICAL_PRESENCE_CLEAR: + case PHYSICAL_PRESENCE_ENABLE_ACTIVATE_CLEAR: + if ((Flags.PPFlags & TCG_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_CLEAR) != 0) { + RequestConfirmed = TRUE; + } + break; + + case PHYSICAL_PRESENCE_DEFERRED_PP_UNOWNERED_FIELD_UPGRADE: + if ((Flags.PPFlags & TCG_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_MAINTENANCE) != 0) { + RequestConfirmed = TRUE; + } + break; + + case PHYSICAL_PRESENCE_ENABLE_ACTIVATE_CLEAR_ENABLE_ACTIVATE: + case PHYSICAL_PRESENCE_CLEAR_ENABLE_ACTIVATE: + if ((Flags.PPFlags & TCG_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_CLEAR) != 0 && (Flags.PPFlags & TCG_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_PROVISION) != 0) { + RequestConfirmed = TRUE; + } + break; + + case PHYSICAL_PRESENCE_SET_NO_PPI_PROVISION_FALSE: + case PHYSICAL_PRESENCE_SET_NO_PPI_CLEAR_FALSE: + case PHYSICAL_PRESENCE_SET_NO_PPI_MAINTENANCE_FALSE: + case PHYSICAL_PRESENCE_NO_ACTION: + RequestConfirmed = TRUE; + break; + + case PHYSICAL_PRESENCE_SET_OPERATOR_AUTH: + // + // This command requires UI to prompt user for Auth data + // + mTcgNvs->PhysicalPresence.ReturnCode = TCG_PP_GET_USER_CONFIRMATION_NOT_IMPLEMENTED; + return EFI_SUCCESS; + default: + break; + } + + if (RequestConfirmed) { + mTcgNvs->PhysicalPresence.ReturnCode = TCG_PP_GET_USER_CONFIRMATION_ALLOWED_AND_PPUSER_NOT_REQUIRED; + } else { + mTcgNvs->PhysicalPresence.ReturnCode = TCG_PP_GET_USER_CONFIRMATION_ALLOWED_AND_PPUSER_REQUIRED; + } + if (mTcgNvs->PhysicalPresence.Request >= TCG_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION) { + mTcgNvs->PhysicalPresence.ReturnCode = TcgPpVendorLibGetUserConfirmationStatusFunction (mTcgNvs->PhysicalPresence.Request, Flags.PPFlags); + } + } + + return EFI_SUCCESS; +} + + +/** + Software SMI callback for MemoryClear which is called from ACPI method. + + Caution: This function may receive untrusted input. + Variable and ACPINvs are external input, so this function will validate + its data structure to be valid value. + + @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister(). + @param[in] Context Points to an optional handler context which was specified when the + handler was registered. + @param[in, out] CommBuffer A pointer to a collection of data in memory that will + be conveyed from a non-SMM environment into an SMM environment. + @param[in, out] CommBufferSize The size of the CommBuffer. + + @retval EFI_SUCCESS The interrupt was handled successfully. + +**/ +EFI_STATUS +EFIAPI +MemoryClearCallback ( + IN EFI_HANDLE DispatchHandle, + IN CONST VOID *Context, + IN OUT VOID *CommBuffer, + IN OUT UINTN *CommBufferSize + ) +{ + EFI_STATUS Status; + UINTN DataSize; + UINT8 MorControl; + + mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_SUCCESS; + if (mTcgNvs->MemoryClear.Parameter == ACPI_FUNCTION_DSM_MEMORY_CLEAR_INTERFACE) { + MorControl = (UINT8) mTcgNvs->MemoryClear.Request; + } else if (mTcgNvs->MemoryClear.Parameter == ACPI_FUNCTION_PTS_CLEAR_MOR_BIT) { + DataSize = sizeof (UINT8); + Status = mSmmVariable->SmmGetVariable ( + MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME, + &gEfiMemoryOverwriteControlDataGuid, + NULL, + &DataSize, + &MorControl + ); + if (EFI_ERROR (Status)) { + mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_GENERAL_FAILURE; + DEBUG ((EFI_D_ERROR, "[TPM] Get MOR variable failure! Status = %r\n", Status)); + return EFI_SUCCESS; + } + + if (MOR_CLEAR_MEMORY_VALUE (MorControl) == 0x0) { + return EFI_SUCCESS; + } + MorControl &= ~MOR_CLEAR_MEMORY_BIT_MASK; + } + + DataSize = sizeof (UINT8); + Status = mSmmVariable->SmmSetVariable ( + MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME, + &gEfiMemoryOverwriteControlDataGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + DataSize, + &MorControl + ); + if (EFI_ERROR (Status)) { + mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_GENERAL_FAILURE; + DEBUG ((EFI_D_ERROR, "[TPM] Set MOR variable failure! Status = %r\n", Status)); + } + + return EFI_SUCCESS; +} + +/** + Find the operation region in TCG ACPI table by given Name and Size, + and initialize it if the region is found. + + @param[in, out] Table The TPM item in ACPI table. + @param[in] Name The name string to find in TPM table. + @param[in] Size The size of the region to find. + + @return The allocated address for the found region. + +**/ +VOID * +AssignOpRegion ( + EFI_ACPI_DESCRIPTION_HEADER *Table, + UINT32 Name, + UINT16 Size + ) +{ + EFI_STATUS Status; + AML_OP_REGION_32_8 *OpRegion; + EFI_PHYSICAL_ADDRESS MemoryAddress; + + MemoryAddress = SIZE_4GB - 1; + + // + // Patch some pointers for the ASL code before loading the SSDT. + // + for (OpRegion = (AML_OP_REGION_32_8 *) (Table + 1); + OpRegion <= (AML_OP_REGION_32_8 *) ((UINT8 *) Table + Table->Length); + OpRegion = (AML_OP_REGION_32_8 *) ((UINT8 *) OpRegion + 1)) { + if ((OpRegion->OpRegionOp == AML_EXT_REGION_OP) && + (OpRegion->NameString == Name) && + (OpRegion->DWordPrefix == AML_DWORD_PREFIX) && + (OpRegion->BytePrefix == AML_BYTE_PREFIX)) { + + Status = gBS->AllocatePages(AllocateMaxAddress, EfiACPIMemoryNVS, EFI_SIZE_TO_PAGES (Size), &MemoryAddress); + ASSERT_EFI_ERROR (Status); + ZeroMem ((VOID *)(UINTN)MemoryAddress, Size); + OpRegion->RegionOffset = (UINT32) (UINTN) MemoryAddress; + OpRegion->RegionLen = (UINT8) Size; + break; + } + } + + return (VOID *) (UINTN) MemoryAddress; +} + +/** + Initialize and publish TPM items in ACPI table. + + @retval EFI_SUCCESS The TCG ACPI table is published successfully. + @retval Others The TCG ACPI table is not published. + +**/ +EFI_STATUS +PublishAcpiTable ( + VOID + ) +{ + EFI_STATUS Status; + EFI_ACPI_TABLE_PROTOCOL *AcpiTable; + UINTN TableKey; + EFI_ACPI_DESCRIPTION_HEADER *Table; + UINTN TableSize; + + Status = GetSectionFromFv ( + &gEfiCallerIdGuid, + EFI_SECTION_RAW, + 0, + (VOID **) &Table, + &TableSize + ); + ASSERT_EFI_ERROR (Status); + + + // + // Measure to PCR[0] with event EV_POST_CODE ACPI DATA + // + TpmMeasureAndLogData( + 0, + EV_POST_CODE, + EV_POSTCODE_INFO_ACPI_DATA, + ACPI_DATA_LEN, + Table, + TableSize + ); + + + ASSERT (Table->OemTableId == SIGNATURE_64 ('T', 'c', 'g', 'T', 'a', 'b', 'l', 'e')); + CopyMem (Table->OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (Table->OemId) ); + mTcgNvs = AssignOpRegion (Table, SIGNATURE_32 ('T', 'N', 'V', 'S'), (UINT16) sizeof (TCG_NVS)); + ASSERT (mTcgNvs != NULL); + + // + // Publish the TPM ACPI table + // + Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTable); + ASSERT_EFI_ERROR (Status); + + TableKey = 0; + Status = AcpiTable->InstallAcpiTable ( + AcpiTable, + Table, + TableSize, + &TableKey + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} + +/** + The driver's entry point. + + It install callbacks for TPM physical presence and MemoryClear, and locate + SMM variable to be used in the callback function. + + @param[in] ImageHandle The firmware allocated handle for the EFI image. + @param[in] SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The entry point is executed successfully. + @retval Others Some error occurs when executing this entry point. + +**/ +EFI_STATUS +EFIAPI +InitializeTcgSmm ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_SMM_SW_DISPATCH2_PROTOCOL *SwDispatch; + EFI_SMM_SW_REGISTER_CONTEXT SwContext; + EFI_HANDLE SwHandle; + + if (!CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceTpm12Guid)){ + DEBUG ((EFI_D_ERROR, "No TPM12 instance required!\n")); + return EFI_UNSUPPORTED; + } + + Status = PublishAcpiTable (); + ASSERT_EFI_ERROR (Status); + + // + // Get the Sw dispatch protocol and register SMI callback functions. + // + Status = gSmst->SmmLocateProtocol (&gEfiSmmSwDispatch2ProtocolGuid, NULL, (VOID**)&SwDispatch); + ASSERT_EFI_ERROR (Status); + SwContext.SwSmiInputValue = (UINTN) -1; + Status = SwDispatch->Register (SwDispatch, PhysicalPresenceCallback, &SwContext, &SwHandle); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + return Status; + } + mTcgNvs->PhysicalPresence.SoftwareSmi = (UINT8) SwContext.SwSmiInputValue; + + SwContext.SwSmiInputValue = (UINTN) -1; + Status = SwDispatch->Register (SwDispatch, MemoryClearCallback, &SwContext, &SwHandle); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + return Status; + } + mTcgNvs->MemoryClear.SoftwareSmi = (UINT8) SwContext.SwSmiInputValue; + + // + // Locate SmmVariableProtocol. + // + Status = gSmst->SmmLocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID**)&mSmmVariable); + ASSERT_EFI_ERROR (Status); + + return EFI_SUCCESS; +} + diff --git a/Core/SecurityPkg/Tcg/TcgSmm/TcgSmm.h b/Core/SecurityPkg/Tcg/TcgSmm/TcgSmm.h new file mode 100644 index 0000000000..21e4ad96d2 --- /dev/null +++ b/Core/SecurityPkg/Tcg/TcgSmm/TcgSmm.h @@ -0,0 +1,105 @@ +/** @file + The header file for TCG SMM driver. + +Copyright (c) 2012 - 2016, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +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 +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#pragma pack(1) +typedef struct { + UINT8 SoftwareSmi; + UINT32 Parameter; + UINT32 Response; + UINT32 Request; + UINT32 LastRequest; + UINT32 ReturnCode; +} PHYSICAL_PRESENCE_NVS; + +typedef struct { + UINT8 SoftwareSmi; + UINT32 Parameter; + UINT32 Request; + UINT32 ReturnCode; +} MEMORY_CLEAR_NVS; + +typedef struct { + PHYSICAL_PRESENCE_NVS PhysicalPresence; + MEMORY_CLEAR_NVS MemoryClear; + UINT32 PPRequestUserConfirm; +} TCG_NVS; + +typedef struct { + UINT8 OpRegionOp; + UINT32 NameString; + UINT8 RegionSpace; + UINT8 DWordPrefix; + UINT32 RegionOffset; + UINT8 BytePrefix; + UINT8 RegionLen; +} AML_OP_REGION_32_8; +#pragma pack() + +// +// The definition for TCG physical presence ACPI function +// +#define ACPI_FUNCTION_GET_PHYSICAL_PRESENCE_INTERFACE_VERSION 1 +#define ACPI_FUNCTION_SUBMIT_REQUEST_TO_BIOS 2 +#define ACPI_FUNCTION_GET_PENDING_REQUEST_BY_OS 3 +#define ACPI_FUNCTION_GET_PLATFORM_ACTION_TO_TRANSITION_TO_BIOS 4 +#define ACPI_FUNCTION_RETURN_REQUEST_RESPONSE_TO_OS 5 +#define ACPI_FUNCTION_SUBMIT_PREFERRED_USER_LANGUAGE 6 +#define ACPI_FUNCTION_SUBMIT_REQUEST_TO_BIOS_2 7 +#define ACPI_FUNCTION_GET_USER_CONFIRMATION_STATUS_FOR_REQUEST 8 + +// +// The return code for Return TPM Operation Response to OS Environment +// +#define PP_RETURN_TPM_OPERATION_RESPONSE_SUCCESS 0 +#define PP_RETURN_TPM_OPERATION_RESPONSE_FAILURE 1 + +// +// The definition for TCG MOR +// +#define ACPI_FUNCTION_DSM_MEMORY_CLEAR_INTERFACE 1 +#define ACPI_FUNCTION_PTS_CLEAR_MOR_BIT 2 + +// +// The return code for Memory Clear Interface Functions +// +#define MOR_REQUEST_SUCCESS 0 +#define MOR_REQUEST_GENERAL_FAILURE 1 + +#endif // __TCG_SMM_H__ diff --git a/Core/SecurityPkg/Tcg/TcgSmm/TcgSmm.inf b/Core/SecurityPkg/Tcg/TcgSmm/TcgSmm.inf new file mode 100644 index 0000000000..be7a96bc62 --- /dev/null +++ b/Core/SecurityPkg/Tcg/TcgSmm/TcgSmm.inf @@ -0,0 +1,83 @@ +## @file +# Implements ACPI metholds for the TCG feature +# +# This driver implements TPM definition block in ACPI table and registers SMI +# callback functions for physical presence and MemoryClear to handle the requests +# from ACPI method. +# +# Caution: This module requires additional review when modified. +# This driver will have external input - variable and ACPINvs data in SMM mode. +# This external input must be validated carefully to avoid security issue. +# +# Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = TcgSmm + MODULE_UNI_FILE = TcgSmm.uni + FILE_GUID = 42293093-76B9-4482-8C02-3BEFDEA9B35D + MODULE_TYPE = DXE_SMM_DRIVER + PI_SPECIFICATION_VERSION = 0x0001000A + VERSION_STRING = 1.0 + ENTRY_POINT = InitializeTcgSmm + +[Sources] + TcgSmm.c + TcgSmm.h + Tpm.asl + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + UefiDriverEntryPoint + SmmServicesTableLib + UefiBootServicesTableLib + DebugLib + DxeServicesLib + TpmMeasurementLib + PcdLib + TcgPpVendorLib + +[Guids] + ## SOMETIMES_PRODUCES ## Variable:L"PhysicalPresence" + ## SOMETIMES_CONSUMES ## Variable:L"PhysicalPresence" + ## SOMETIMES_CONSUMES ## Variable:L"PhysicalPresenceFlags" + gEfiPhysicalPresenceGuid + + ## SOMETIMES_PRODUCES ## Variable:L"MemoryOverwriteRequestControl" + ## SOMETIMES_CONSUMES ## Variable:L"MemoryOverwriteRequestControl" + gEfiMemoryOverwriteControlDataGuid + + gEfiTpmDeviceInstanceTpm12Guid ## PRODUCES ## GUID # TPM device identifier + +[Protocols] + gEfiSmmSwDispatch2ProtocolGuid ## CONSUMES + gEfiSmmVariableProtocolGuid ## CONSUMES + gEfiAcpiTableProtocolGuid ## CONSUMES + +[Pcd] + gEfiSecurityPkgTokenSpaceGuid.PcdTpmInstanceGuid ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemId ## SOMETIMES_CONSUMES + +[Depex] + gEfiAcpiTableProtocolGuid AND + gEfiSmmSwDispatch2ProtocolGuid AND + gEfiSmmVariableProtocolGuid AND + gEfiTcgProtocolGuid + +[UserExtensions.TianoCore."ExtraFiles"] + TcgSmmExtra.uni + \ No newline at end of file diff --git a/Core/SecurityPkg/Tcg/TcgSmm/TcgSmm.uni b/Core/SecurityPkg/Tcg/TcgSmm/TcgSmm.uni new file mode 100644 index 0000000000..81f7f8d53a --- /dev/null +++ b/Core/SecurityPkg/Tcg/TcgSmm/TcgSmm.uni @@ -0,0 +1,27 @@ +// /** @file +// Implements ACPI metholds for the TCG feature +// +// This driver implements TPM definition block in ACPI table and registers SMI +// callback functions for physical presence and MemoryClear to handle the requests +// from ACPI method. +// +// Caution: This module requires additional review when modified. +// This driver will have external input - variable and ACPINvs data in SMM mode. +// This external input must be validated carefully to avoid security issue. +// +// Copyright (c) 2011 - 2014, Intel Corporation. All rights reserved.
+// +// This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// **/ + + +#string STR_MODULE_ABSTRACT #language en-US "Implements ACPI methods for the TCG feature" + +#string STR_MODULE_DESCRIPTION #language en-US "This driver implements TPM definition block in ACPI table and registers SMI callback functions for physical presence and MemoryClear to handle the requests from ACPI method. Caution: This module requires additional review when modified. This driver will have external input - variable and ACPINvs data in SMM mode. This external input must be validated carefully to avoid security issues." + diff --git a/Core/SecurityPkg/Tcg/TcgSmm/TcgSmmExtra.uni b/Core/SecurityPkg/Tcg/TcgSmm/TcgSmmExtra.uni new file mode 100644 index 0000000000..b9ca98bb6e --- /dev/null +++ b/Core/SecurityPkg/Tcg/TcgSmm/TcgSmmExtra.uni @@ -0,0 +1,19 @@ +// /** @file +// TcgSmm Localized Strings and Content +// +// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.
+// +// This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// **/ + +#string STR_PROPERTIES_MODULE_NAME +#language en-US +"TCG (Trusted Computing Group) SMM" + + diff --git a/Core/SecurityPkg/Tcg/TcgSmm/Tpm.asl b/Core/SecurityPkg/Tcg/TcgSmm/Tpm.asl new file mode 100644 index 0000000000..b5449d98b4 --- /dev/null +++ b/Core/SecurityPkg/Tcg/TcgSmm/Tpm.asl @@ -0,0 +1,356 @@ +/** @file + The TPM definition block in ACPI table for physical presence + and MemoryClear. + +Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +DefinitionBlock ( + "Tpm.aml", + "SSDT", + 2, + "INTEL ", + "TcgTable", + 0x1000 + ) +{ + Scope (\_SB) + { + Device (TPM) + { + // + // Define _HID, "PNP0C31" is defined in + // "Secure Startup-FVE and TPM Admin BIOS and Platform Requirements" + // + Name (_HID, EISAID ("PNP0C31")) + + // + // Readable name of this device, don't know if this way is correct yet + // + Name (_STR, Unicode ("TPM 1.2 Device")) + + // + // Return the resource consumed by TPM device + // + Name (_CRS, ResourceTemplate () { + Memory32Fixed (ReadWrite, 0xfed40000, 0x5000) + }) + + // + // Operational region for Smi port access + // + OperationRegion (SMIP, SystemIO, 0xB2, 1) + Field (SMIP, ByteAcc, NoLock, Preserve) + { + IOB2, 8 + } + + // + // Operational region for TPM access + // + OperationRegion (TPMR, SystemMemory, 0xfed40000, 0x5000) + Field (TPMR, AnyAcc, NoLock, Preserve) + { + ACC0, 8, + } + + // + // Operational region for TPM support, TPM Physical Presence and TPM Memory Clear + // Region Offset 0xFFFF0000 and Length 0xF0 will be fixed in C code. + // + OperationRegion (TNVS, SystemMemory, 0xFFFF0000, 0xF0) + Field (TNVS, AnyAcc, NoLock, Preserve) + { + PPIN, 8, // Software SMI for Physical Presence Interface + PPIP, 32, // Used for save physical presence paramter + PPRP, 32, // Physical Presence request operation response + PPRQ, 32, // Physical Presence request operation + LPPR, 32, // Last Physical Presence request operation + FRET, 32, // Physical Presence function return code + MCIN, 8, // Software SMI for Memory Clear Interface + MCIP, 32, // Used for save the Mor paramter + MORD, 32, // Memory Overwrite Request Data + MRET, 32, // Memory Overwrite function return code + UCRQ, 32 // Phyical Presence request operation to Get User Confirmation Status + } + + Method (PTS, 1, Serialized) + { + // + // Detect Sx state for MOR, only S4, S5 need to handle + // + If (LAnd (LLess (Arg0, 6), LGreater (Arg0, 3))) + { + // + // Bit4 -- DisableAutoDetect. 0 -- Firmware MAY autodetect. + // + If (LNot (And (MORD, 0x10))) + { + // + // Triggle the SMI through ACPI _PTS method. + // + Store (0x02, MCIP) + + // + // Triggle the SMI interrupt + // + Store (MCIN, IOB2) + } + } + Return (0) + } + + Method (_STA, 0) + { + if (LEqual (ACC0, 0xff)) + { + Return (0) + } + Return (0x0f) + } + + // + // TCG Hardware Information + // + Method (HINF, 3, Serialized, 0, {BuffObj, PkgObj}, {UnknownObj, UnknownObj, UnknownObj}) // IntObj, IntObj, PkgObj + { + // + // Switch by function index + // + Switch (ToInteger(Arg1)) + { + Case (0) + { + // + // Standard query + // + Return (Buffer () {0x03}) + } + Case (1) + { + // + // Return failure if no TPM present + // + Name(TPMV, Package () {0x01, Package () {0x1, 0x20}}) + if (LEqual (_STA (), 0x00)) + { + Return (Package () {0x00}) + } + + // + // Return TPM version + // + Return (TPMV) + } + Default {BreakPoint} + } + Return (Buffer () {0}) + } + + Name(TPM2, Package (0x02){ + Zero, + Zero + }) + + Name(TPM3, Package (0x03){ + Zero, + Zero, + Zero + }) + + // + // TCG Physical Presence Interface + // + Method (TPPI, 3, Serialized, 0, {BuffObj, PkgObj, IntObj, StrObj}, {UnknownObj, UnknownObj, UnknownObj}) // IntObj, IntObj, PkgObj + { + // + // Switch by function index + // + Switch (ToInteger(Arg1)) + { + Case (0) + { + // + // Standard query, supports function 1-8 + // + Return (Buffer () {0xFF, 0x01}) + } + Case (1) + { + // + // a) Get Physical Presence Interface Version + // + Return ("1.2") + } + Case (2) + { + // + // b) Submit TPM Operation Request to Pre-OS Environment + // + + Store (DerefOf (Index (Arg2, 0x00)), PPRQ) + Store (0x02, PPIP) + + // + // Triggle the SMI interrupt + // + Store (PPIN, IOB2) + Return (FRET) + + + } + Case (3) + { + // + // c) Get Pending TPM Operation Requested By the OS + // + + Store (PPRQ, Index (TPM2, 0x01)) + Return (TPM2) + } + Case (4) + { + // + // d) Get Platform-Specific Action to Transition to Pre-OS Environment + // + Return (2) + } + Case (5) + { + // + // e) Return TPM Operation Response to OS Environment + // + Store (0x05, PPIP) + + // + // Triggle the SMI interrupt + // + Store (PPIN, IOB2) + + Store (LPPR, Index (TPM3, 0x01)) + Store (PPRP, Index (TPM3, 0x02)) + + Return (TPM3) + } + Case (6) + { + + // + // f) Submit preferred user language (Not implemented) + // + + Return (3) + + } + Case (7) + { + // + // g) Submit TPM Operation Request to Pre-OS Environment 2 + // + Store (7, PPIP) + Store (DerefOf (Index (Arg2, 0x00)), PPRQ) + + // + // Triggle the SMI interrupt + // + Store (PPIN, IOB2) + Return (FRET) + } + Case (8) + { + // + // e) Get User Confirmation Status for Operation + // + Store (8, PPIP) + Store (DerefOf (Index (Arg2, 0x00)), UCRQ) + + // + // Triggle the SMI interrupt + // + Store (PPIN, IOB2) + + Return (FRET) + } + + Default {BreakPoint} + } + Return (1) + } + + Method (TMCI, 3, Serialized, 0, IntObj, {UnknownObj, UnknownObj, UnknownObj}) // IntObj, IntObj, PkgObj + { + // + // Switch by function index + // + Switch (ToInteger (Arg1)) + { + Case (0) + { + // + // Standard query, supports function 1-1 + // + Return (Buffer () {0x03}) + } + Case (1) + { + // + // Save the Operation Value of the Request to MORD (reserved memory) + // + Store (DerefOf (Index (Arg2, 0x00)), MORD) + + // + // Triggle the SMI through ACPI _DSM method. + // + Store (0x01, MCIP) + + // + // Triggle the SMI interrupt + // + Store (MCIN, IOB2) + Return (MRET) + } + Default {BreakPoint} + } + Return (1) + } + + Method (_DSM, 4, Serialized, 0, UnknownObj, {BuffObj, IntObj, IntObj, PkgObj}) + { + + // + // TCG Hardware Information + // + If(LEqual(Arg0, ToUUID ("cf8e16a5-c1e8-4e25-b712-4f54a96702c8"))) + { + Return (HINF (Arg1, Arg2, Arg3)) + } + + // + // TCG Physical Presence Interface + // + If(LEqual(Arg0, ToUUID ("3dddfaa6-361b-4eb4-a424-8d10089d1653"))) + { + Return (TPPI (Arg1, Arg2, Arg3)) + } + + // + // TCG Memory Clear Interface + // + If(LEqual(Arg0, ToUUID ("376054ed-cc13-4675-901c-4756d7f2d45d"))) + { + Return (TMCI (Arg1, Arg2, Arg3)) + } + + Return (Buffer () {0}) + } + } + } +} diff --git a/Core/SecurityPkg/Tcg/TrEEConfig/TpmDetection.c b/Core/SecurityPkg/Tcg/TrEEConfig/TpmDetection.c new file mode 100644 index 0000000000..4e675d3602 --- /dev/null +++ b/Core/SecurityPkg/Tcg/TrEEConfig/TpmDetection.c @@ -0,0 +1,105 @@ +/** @file + TPM1.2/dTPM2.0 auto detection. + +Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "TrEEConfigNvData.h" + +/** + This routine check both SetupVariable and real TPM device, and return final TpmDevice configuration. + + @param SetupTpmDevice TpmDevice configuration in setup driver + + @return TpmDevice configuration +**/ +UINT8 +DetectTpmDevice ( + IN UINT8 SetupTpmDevice + ) +{ + EFI_STATUS Status; + EFI_BOOT_MODE BootMode; + TREE_DEVICE_DETECTION TrEEDeviceDetection; + EFI_PEI_READ_ONLY_VARIABLE2_PPI *VariablePpi; + UINTN Size; + + Status = PeiServicesGetBootMode (&BootMode); + ASSERT_EFI_ERROR (Status); + + // + // In S3, we rely on normal boot Detection, because we save to ReadOnly Variable in normal boot. + // + if (BootMode == BOOT_ON_S3_RESUME) { + DEBUG ((EFI_D_INFO, "DetectTpmDevice: S3 mode\n")); + + Status = PeiServicesLocatePpi (&gEfiPeiReadOnlyVariable2PpiGuid, 0, NULL, (VOID **) &VariablePpi); + ASSERT_EFI_ERROR (Status); + + Size = sizeof(TREE_DEVICE_DETECTION); + ZeroMem (&TrEEDeviceDetection, sizeof(TrEEDeviceDetection)); + Status = VariablePpi->GetVariable ( + VariablePpi, + TREE_DEVICE_DETECTION_NAME, + &gTrEEConfigFormSetGuid, + NULL, + &Size, + &TrEEDeviceDetection + ); + if (!EFI_ERROR (Status) && + (TrEEDeviceDetection.TpmDeviceDetected >= TPM_DEVICE_MIN) && + (TrEEDeviceDetection.TpmDeviceDetected <= TPM_DEVICE_MAX)) { + DEBUG ((EFI_D_ERROR, "TpmDevice from DeviceDetection: %x\n", TrEEDeviceDetection.TpmDeviceDetected)); + return TrEEDeviceDetection.TpmDeviceDetected; + } + } + + DEBUG ((EFI_D_INFO, "DetectTpmDevice:\n")); + + // dTPM available and not disabled by setup + // We need check if it is TPM1.2 or TPM2.0 + // So try TPM1.2 command at first + + Status = Tpm12RequestUseTpm (); + if (EFI_ERROR (Status)) { + // + // dTPM not available + // + return TPM_DEVICE_NULL; + } + + if (BootMode == BOOT_ON_S3_RESUME) { + Status = Tpm12Startup (TPM_ST_STATE); + } else { + Status = Tpm12Startup (TPM_ST_CLEAR); + } + if (EFI_ERROR (Status)) { + return TPM_DEVICE_2_0_DTPM; + } + + // NO initialization needed again. + Status = PcdSet8S (PcdTpmInitializationPolicy, 0); + ASSERT_EFI_ERROR (Status); + return TPM_DEVICE_1_2; +} diff --git a/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfig.vfr b/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfig.vfr new file mode 100644 index 0000000000..84b55a9f15 --- /dev/null +++ b/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfig.vfr @@ -0,0 +1,68 @@ +/** @file + VFR file used by the TREE configuration component. + +Copyright (c) 2013, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE 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.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "TrEEConfigImpl.h" + +extern TPM_INSTANCE_ID mTpmInstanceId[TPM_DEVICE_MAX + 1]; + +/** + The entry point for TrEE configuration driver. + + @param[in] ImageHandle The image handle of the driver. + @param[in] SystemTable The system table. + + @retval EFI_ALREADY_STARTED The driver already exists in system. + @retval EFI_OUT_OF_RESOURCES Fail to execute entry point due to lack of resources. + @retval EFI_SUCCES All the related protocols are installed on the driver. + @retval Others Fail to install protocols as indicated. + +**/ +EFI_STATUS +EFIAPI +TrEEConfigDriverEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + TREE_CONFIG_PRIVATE_DATA *PrivateData; + TREE_CONFIGURATION TrEEConfiguration; + TREE_DEVICE_DETECTION TrEEDeviceDetection; + UINTN Index; + UINTN DataSize; + EDKII_VARIABLE_LOCK_PROTOCOL *VariableLockProtocol; + + Status = gBS->OpenProtocol ( + ImageHandle, + &gEfiCallerIdGuid, + NULL, + ImageHandle, + ImageHandle, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); + if (!EFI_ERROR (Status)) { + return EFI_ALREADY_STARTED; + } + + // + // Create a private data structure. + // + PrivateData = AllocateCopyPool (sizeof (TREE_CONFIG_PRIVATE_DATA), &mTrEEConfigPrivateDateTemplate); + ASSERT (PrivateData != NULL); + + // + // Install private GUID. + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &ImageHandle, + &gEfiCallerIdGuid, + PrivateData, + NULL + ); + ASSERT_EFI_ERROR (Status); + + DataSize = sizeof(TrEEConfiguration); + Status = gRT->GetVariable ( + TREE_STORAGE_NAME, + &gTrEEConfigFormSetGuid, + NULL, + &DataSize, + &TrEEConfiguration + ); + if (EFI_ERROR (Status)) { + // + // Variable not ready, set default value + // + TrEEConfiguration.TpmDevice = TPM_DEVICE_DEFAULT; + } + + // + // Validation + // + if ((TrEEConfiguration.TpmDevice > TPM_DEVICE_MAX) || (TrEEConfiguration.TpmDevice < TPM_DEVICE_MIN)) { + TrEEConfiguration.TpmDevice = TPM_DEVICE_DEFAULT; + } + + // + // Save to variable so platform driver can get it. + // + Status = gRT->SetVariable ( + TREE_STORAGE_NAME, + &gTrEEConfigFormSetGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, + sizeof(TrEEConfiguration), + &TrEEConfiguration + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "TrEEConfigDriver: Fail to set TREE_STORAGE_NAME\n")); + } + + // + // Sync data from PCD to variable, so that we do not need detect again in S3 phase. + // + TrEEDeviceDetection.TpmDeviceDetected = TPM_DEVICE_NULL; + for (Index = 0; Index < sizeof(mTpmInstanceId)/sizeof(mTpmInstanceId[0]); Index++) { + if (CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &mTpmInstanceId[Index].TpmInstanceGuid)) { + TrEEDeviceDetection.TpmDeviceDetected = mTpmInstanceId[Index].TpmDevice; + break; + } + } + + PrivateData->TpmDeviceDetected = TrEEDeviceDetection.TpmDeviceDetected; + + // + // Save to variable so platform driver can get it. + // + Status = gRT->SetVariable ( + TREE_DEVICE_DETECTION_NAME, + &gTrEEConfigFormSetGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, + sizeof(TrEEDeviceDetection), + &TrEEDeviceDetection + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "TrEEConfigDriver: Fail to set TREE_DEVICE_DETECTION_NAME\n")); + Status = gRT->SetVariable ( + TREE_DEVICE_DETECTION_NAME, + &gTrEEConfigFormSetGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, + 0, + NULL + ); + ASSERT_EFI_ERROR (Status); + } + + // + // We should lock TrEEDeviceDetection, because it contains information needed at S3. + // + Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **)&VariableLockProtocol); + if (!EFI_ERROR (Status)) { + Status = VariableLockProtocol->RequestToLock ( + VariableLockProtocol, + TREE_DEVICE_DETECTION_NAME, + &gTrEEConfigFormSetGuid + ); + ASSERT_EFI_ERROR (Status); + } + + // + // Install TrEE configuration form + // + Status = InstallTrEEConfigForm (PrivateData); + if (EFI_ERROR (Status)) { + goto ErrorExit; + } + + return EFI_SUCCESS; + +ErrorExit: + if (PrivateData != NULL) { + UninstallTrEEConfigForm (PrivateData); + } + + return Status; +} + +/** + Unload the TrEE configuration form. + + @param[in] ImageHandle The driver's image handle. + + @retval EFI_SUCCESS The TrEE configuration form is unloaded. + @retval Others Failed to unload the form. + +**/ +EFI_STATUS +EFIAPI +TrEEConfigDriverUnload ( + IN EFI_HANDLE ImageHandle + ) +{ + EFI_STATUS Status; + TREE_CONFIG_PRIVATE_DATA *PrivateData; + + Status = gBS->HandleProtocol ( + ImageHandle, + &gEfiCallerIdGuid, + (VOID **) &PrivateData + ); + if (EFI_ERROR (Status)) { + return Status; + } + + ASSERT (PrivateData->Signature == TREE_CONFIG_PRIVATE_DATA_SIGNATURE); + + gBS->UninstallMultipleProtocolInterfaces ( + &ImageHandle, + &gEfiCallerIdGuid, + PrivateData, + NULL + ); + + UninstallTrEEConfigForm (PrivateData); + + return EFI_SUCCESS; +} diff --git a/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigDxe.inf b/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigDxe.inf new file mode 100644 index 0000000000..368570aea0 --- /dev/null +++ b/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigDxe.inf @@ -0,0 +1,88 @@ +## @file +# TPM device configuration for TPM 2.0 +# +# By this module, user may select TPM device, clear TPM state, etc. +# NOTE: This module is only for reference only, each platform should have its own setup page. +# +# Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = TrEEConfigDxe + MODULE_UNI_FILE = TrEEConfigDxe.uni + FILE_GUID = 3141FD4D-EA02-4a70-9BCE-97EE837319AC + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = TrEEConfigDriverEntryPoint + UNLOAD_IMAGE = TrEEConfigDriverUnload + +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + TrEEConfigDriver.c + TrEEConfigImpl.c + TrEEConfigImpl.h + TrEEConfig.vfr + TrEEConfigStrings.uni + TrEEConfigNvData.h + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + MemoryAllocationLib + UefiLib + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + UefiDriverEntryPoint + UefiHiiServicesLib + DebugLib + HiiLib + PcdLib + PrintLib + Tpm2DeviceLib + Tpm2CommandLib + +[Guids] + ## SOMETIMES_PRODUCES ## Variable:L"TrEEPhysicalPresence" + ## SOMETIMES_CONSUMES ## Variable:L"TrEEPhysicalPresence" + gEfiTrEEPhysicalPresenceGuid + + ## PRODUCES ## HII + ## SOMETIMES_PRODUCES ## Variable:L"TREE_CONFIGURATION" + ## SOMETIMES_CONSUMES ## Variable:L"TREE_CONFIGURATION" + ## PRODUCES ## Variable:L"TREE_DEVICE_DETECTION" + ## SOMETIMES_CONSUMES ## Variable:L"TREE_DEVICE_DETECTION" + gTrEEConfigFormSetGuid + +[Protocols] + gEfiHiiConfigAccessProtocolGuid ## PRODUCES + gEfiDevicePathProtocolGuid ## PRODUCES + gEdkiiVariableLockProtocolGuid ## SOMETIMES_CONSUMES + +[Pcd] + gEfiSecurityPkgTokenSpaceGuid.PcdTpmInstanceGuid ## CONSUMES + +[Depex] + gEfiTrEEProtocolGuid AND + gEfiHiiConfigRoutingProtocolGuid AND + gEfiHiiDatabaseProtocolGuid AND + gEfiVariableArchProtocolGuid AND + gEfiVariableWriteArchProtocolGuid + +[UserExtensions.TianoCore."ExtraFiles"] + TrEEConfigDxeExtra.uni \ No newline at end of file diff --git a/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigDxe.uni b/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigDxe.uni new file mode 100644 index 0000000000..6b84586b2c --- /dev/null +++ b/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigDxe.uni @@ -0,0 +1,22 @@ +// /** @file +// TPM device configuration for TPM 2.0 +// +// By this module, user may select TPM device, clear TPM state, etc. +// NOTE: This module is only for reference only, each platform should have its own setup page. +// +// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.
+// +// This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// **/ + + +#string STR_MODULE_ABSTRACT #language en-US "TPM device configuration for TPM 2.0" + +#string STR_MODULE_DESCRIPTION #language en-US "By this module, user may select TPM device, clear TPM state, etc. NOTE: This module is only for reference only, each platform should have its own setup page." + diff --git a/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigDxeExtra.uni b/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigDxeExtra.uni new file mode 100644 index 0000000000..c1b243e563 --- /dev/null +++ b/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigDxeExtra.uni @@ -0,0 +1,19 @@ +// /** @file +// TrEEConfigDxe Localized Strings and Content +// +// Copyright (c) 2014, Intel Corporation. All rights reserved.
+// +// This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// **/ + +#string STR_PROPERTIES_MODULE_NAME +#language en-US +"TrEE (Trusted Execution Environment) Configuration DXE" + + diff --git a/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigImpl.c b/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigImpl.c new file mode 100644 index 0000000000..2f03adcc8c --- /dev/null +++ b/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigImpl.c @@ -0,0 +1,344 @@ +/** @file + HII Config Access protocol implementation of TREE configuration module. + NOTE: This module is only for reference only, each platform should have its own setup page. + +Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE 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 +#include +#include + +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 + format. + @param[out] Progress On return, points to a character in the Request + string. Points to the string's null terminator if + request was successful. Points to the most recent + '&' before the first failing name/value pair (or + the beginning of the string if the failure is in + the first name/value pair) if the request was not + successful. + @param[out] Results A null-terminated Unicode string in + format which has all values filled + in for the names in the Request string. String to + be allocated by the called function. + + @retval EFI_SUCCESS The Results is filled with the requested values. + @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results. + @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name. + @retval EFI_NOT_FOUND Routing data doesn't match any storage in this + driver. + +**/ +EFI_STATUS +EFIAPI +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 + 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.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +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 + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#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 + format. + @param[out] Progress On return, points to a character in the Request + string. Points to the string's null terminator if + request was successful. Points to the most recent + '&' before the first failing name/value pair (or + the beginning of the string if the failure is in + the first name/value pair) if the request was not + successful. + @param[out] Results A null-terminated Unicode string in + format which has all values filled + in for the names in the Request string. String to + be allocated by the called function. + + @retval EFI_SUCCESS The Results is filled with the requested values. + @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results. + @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name. + @retval EFI_NOT_FOUND Routing data doesn't match any storage in this + driver. + +**/ +EFI_STATUS +EFIAPI +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 + 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.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +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 +#include +#include + +#define TREE_CONFIGURATION_VARSTORE_ID 0x0001 +#define TREE_CONFIGURATION_FORM_ID 0x0001 + +#define KEY_TPM_DEVICE 0x2000 +#define KEY_TPM2_OPERATION 0x2001 + +#define TPM_DEVICE_NULL 0 +#define TPM_DEVICE_1_2 1 +#define TPM_DEVICE_2_0_DTPM 2 +#define TPM_DEVICE_MIN TPM_DEVICE_1_2 +#define TPM_DEVICE_MAX TPM_DEVICE_2_0_DTPM +#define TPM_DEVICE_DEFAULT TPM_DEVICE_1_2 + +// +// Nv Data structure referenced by IFR, TPM device user desired +// +typedef struct { + UINT8 TpmDevice; +} TREE_CONFIGURATION; + +// +// Variable saved for S3, TPM detected, only valid in S3 path. +// This variable is ReadOnly. +// +typedef struct { + UINT8 TpmDeviceDetected; +} TREE_DEVICE_DETECTION; + +#define TREE_STORAGE_NAME L"TREE_CONFIGURATION" +#define TREE_DEVICE_DETECTION_NAME L"TREE_DEVICE_DETECTION" + +#define TPM_INSTANCE_ID_LIST { \ + {TPM_DEVICE_INTERFACE_NONE, TPM_DEVICE_NULL}, \ + {TPM_DEVICE_INTERFACE_TPM12, TPM_DEVICE_1_2}, \ + {TPM_DEVICE_INTERFACE_TPM20_DTPM, TPM_DEVICE_2_0_DTPM}, \ +} + +// +// BUGBUG: In order to pass VfrCompiler, we have to redefine GUID here. +// +#ifndef __BASE_H__ +typedef struct { + UINT32 Data1; + UINT16 Data2; + UINT16 Data3; + UINT8 Data4[8]; +} GUID; +#endif + +typedef struct { + GUID TpmInstanceGuid; + UINT8 TpmDevice; +} TPM_INSTANCE_ID; + +#endif diff --git a/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigPei.inf b/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigPei.inf new file mode 100644 index 0000000000..a4d6b58c6a --- /dev/null +++ b/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigPei.inf @@ -0,0 +1,77 @@ +## @file +# Set TPM device type +# +# This module initializes TPM device type based on variable and detection. +# NOTE: This module is only for reference only, each platform should have its own setup page. +# +# Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = TrEEConfigPei + MODULE_UNI_FILE = TrEEConfigPei.uni + FILE_GUID = A5C1EF72-9379-4370-B4C7-0F5126CAC38E + MODULE_TYPE = PEIM + VERSION_STRING = 1.0 + ENTRY_POINT = TrEEConfigPeimEntryPoint + +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# +# [BootMode] +# S3_RESUME ## SOMETIMES_CONSUMES +# + +[Sources] + TrEEConfigPeim.c + TrEEConfigNvData.h + TpmDetection.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + MemoryAllocationLib + PeiServicesLib + PeimEntryPoint + DebugLib + PcdLib + TimerLib + Tpm12CommandLib + Tpm12DeviceLib + +[Guids] + ## SOMETIMES_CONSUMES ## Variable:L"TREE_CONFIGURATION" + ## SOMETIMES_CONSUMES ## Variable:L"TREE_DEVICE_DETECTION" + gTrEEConfigFormSetGuid + gEfiTpmDeviceSelectedGuid ## PRODUCES ## GUID # Used as a PPI GUID + gEfiTpmDeviceInstanceNoneGuid ## SOMETIMES_CONSUMES ## GUID # TPM device identifier + +[Ppis] + gEfiPeiReadOnlyVariable2PpiGuid ## CONSUMES + gPeiTpmInitializationDonePpiGuid ## SOMETIMES_PRODUCES + +[Pcd] + gEfiSecurityPkgTokenSpaceGuid.PcdTpmInstanceGuid ## PRODUCES + gEfiSecurityPkgTokenSpaceGuid.PcdTpmInitializationPolicy ## PRODUCES + gEfiSecurityPkgTokenSpaceGuid.PcdTpmAutoDetection ## CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdTpmBaseAddress ## SOMETIMES_CONSUMES + +[Depex] + gEfiPeiMasterBootModePpiGuid AND + gEfiPeiReadOnlyVariable2PpiGuid + +[UserExtensions.TianoCore."ExtraFiles"] + TrEEConfigPeiExtra.uni \ No newline at end of file diff --git a/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigPei.uni b/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigPei.uni new file mode 100644 index 0000000000..7050be29a4 --- /dev/null +++ b/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigPei.uni @@ -0,0 +1,23 @@ +// /** @file +// Set TPM device type +// +// This module initializes TPM device type based on variable and detection. +// NOTE: This module is only for reference only, each platform should have its own setup page. +// +// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.
+// +// This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// **/ + + +#string STR_MODULE_ABSTRACT #language en-US "Set TPM device type" + +#string STR_MODULE_DESCRIPTION #language en-US "This module initializes TPM device type based on variable and detection.\n" + "NOTE: This module is only for reference only, each platform should have its own setup page." + diff --git a/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigPeiExtra.uni b/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigPeiExtra.uni new file mode 100644 index 0000000000..1ebef052c3 --- /dev/null +++ b/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigPeiExtra.uni @@ -0,0 +1,19 @@ +// /** @file +// TrEEConfigDxe Localized Strings and Content +// +// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.
+// +// This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// **/ + +#string STR_PROPERTIES_MODULE_NAME +#language en-US +"TrEE (Trusted Execution Environment) Configuration DXE" + + diff --git a/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigPeim.c b/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigPeim.c new file mode 100644 index 0000000000..b4a3d52347 --- /dev/null +++ b/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigPeim.c @@ -0,0 +1,159 @@ +/** @file + The module entry point for TrEE configuration module. + +Copyright (c) 2013 - 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + + +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "TrEEConfigNvData.h" + +TPM_INSTANCE_ID mTpmInstanceId[] = TPM_INSTANCE_ID_LIST; + +CONST EFI_PEI_PPI_DESCRIPTOR gTpmSelectedPpi = { + (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gEfiTpmDeviceSelectedGuid, + NULL +}; + +EFI_PEI_PPI_DESCRIPTOR mTpmInitializationDonePpiList = { + EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, + &gPeiTpmInitializationDonePpiGuid, + NULL +}; + +/** + This routine check both SetupVariable and real TPM device, and return final TpmDevice configuration. + + @param SetupTpmDevice TpmDevice configuration in setup driver + + @return TpmDevice configuration +**/ +UINT8 +DetectTpmDevice ( + IN UINT8 SetupTpmDevice + ); + +/** + The entry point for TrEE configuration driver. + + @param FileHandle Handle of the file being invoked. + @param PeiServices Describes the list of possible PEI Services. + + @retval EFI_SUCCES Convert variable to PCD successfully. + @retval Others Fail to convert variable to PCD. +**/ +EFI_STATUS +EFIAPI +TrEEConfigPeimEntryPoint ( + IN EFI_PEI_FILE_HANDLE FileHandle, + IN CONST EFI_PEI_SERVICES **PeiServices + ) +{ + UINTN Size; + EFI_STATUS Status; + EFI_STATUS Status2; + EFI_PEI_READ_ONLY_VARIABLE2_PPI *VariablePpi; + TREE_CONFIGURATION TrEEConfiguration; + UINTN Index; + UINT8 TpmDevice; + + Status = PeiServicesLocatePpi (&gEfiPeiReadOnlyVariable2PpiGuid, 0, NULL, (VOID **) &VariablePpi); + ASSERT_EFI_ERROR (Status); + + Size = sizeof(TrEEConfiguration); + Status = VariablePpi->GetVariable ( + VariablePpi, + TREE_STORAGE_NAME, + &gTrEEConfigFormSetGuid, + NULL, + &Size, + &TrEEConfiguration + ); + if (EFI_ERROR (Status)) { + // + // Variable not ready, set default value + // + TrEEConfiguration.TpmDevice = TPM_DEVICE_DEFAULT; + } + + // + // Validation + // + if ((TrEEConfiguration.TpmDevice > TPM_DEVICE_MAX) || (TrEEConfiguration.TpmDevice < TPM_DEVICE_MIN)) { + TrEEConfiguration.TpmDevice = TPM_DEVICE_DEFAULT; + } + + // + // Although we have SetupVariable info, we still need detect TPM device manually. + // + DEBUG ((EFI_D_INFO, "TrEEConfiguration.TpmDevice from Setup: %x\n", TrEEConfiguration.TpmDevice)); + + if (PcdGetBool (PcdTpmAutoDetection)) { + TpmDevice = DetectTpmDevice (TrEEConfiguration.TpmDevice); + DEBUG ((EFI_D_INFO, "TpmDevice final: %x\n", TpmDevice)); + if (TpmDevice != TPM_DEVICE_NULL) { + TrEEConfiguration.TpmDevice = TpmDevice; + } + } else { + TpmDevice = TrEEConfiguration.TpmDevice; + } + + // + // Convert variable to PCD. + // This is work-around because there is no gurantee DynamicHiiPcd can return correct value in DXE phase. + // Using DynamicPcd instead. + // + // NOTE: TrEEConfiguration variable contains the desired TpmDevice type, + // while PcdTpmInstanceGuid PCD contains the real detected TpmDevice type + // + for (Index = 0; Index < sizeof(mTpmInstanceId)/sizeof(mTpmInstanceId[0]); Index++) { + if (TpmDevice == mTpmInstanceId[Index].TpmDevice) { + Size = sizeof(mTpmInstanceId[Index].TpmInstanceGuid); + Status = PcdSetPtrS (PcdTpmInstanceGuid, &Size, &mTpmInstanceId[Index].TpmInstanceGuid); + ASSERT_EFI_ERROR (Status); + DEBUG ((EFI_D_INFO, "TpmDevice PCD: %g\n", &mTpmInstanceId[Index].TpmInstanceGuid)); + break; + } + } + + // + // Selection done + // + Status = PeiServicesInstallPpi (&gTpmSelectedPpi); + ASSERT_EFI_ERROR (Status); + + // + // Even if no TPM is selected or detected, we still need intall TpmInitializationDonePpi. + // Because TcgPei or TrEEPei will not run, but we still need a way to notify other driver. + // Other driver can know TPM initialization state by TpmInitializedPpi. + // + if (CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceNoneGuid)) { + Status2 = PeiServicesInstallPpi (&mTpmInitializationDonePpiList); + ASSERT_EFI_ERROR (Status2); + } + + return Status; +} diff --git a/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigStrings.uni b/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigStrings.uni new file mode 100644 index 0000000000..41d6c2412f --- /dev/null +++ b/Core/SecurityPkg/Tcg/TrEEConfig/TrEEConfigStrings.uni @@ -0,0 +1,40 @@ +/** @file + String definitions for TCG configuration form. + +Copyright (c) 2013, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#langdef en-US "English" + +#string STR_TREE_TITLE #language en-US "TrEE Configuration" +#string STR_TREE_HELP #language en-US "Press to select TrEE Setup options." + +#string STR_TREE_DEVICE_STATE_PROMPT #language en-US "Current TPM Device" +#string STR_TREE_DEVICE_STATE_HELP #language en-US "Current TPM Device: Disable, TPM1.2, or TPM2.0" +#string STR_TREE_DEVICE_STATE_CONTENT #language en-US "" + +#string STR_TREE_DEVICE_PROMPT #language en-US "Attempt TPM Device" +#string STR_TREE_DEVICE_HELP #language en-US "Attempt TPM Device: Disable, TPM1.2, or TPM2.0" +#string STR_TREE_DEVICE_CONTENT #language en-US "" + +#string STR_TREE_PP_OPERATION #language en-US "TPM2 Physical Presence Operation" + +#string STR_TREE_OPERATION #language en-US "TPM2 Operation" +#string STR_TREE_OPERATION_HELP #language en-US "Select one of the supported operation to change TPM2 state." + +#string STR_TREE_NO_ACTION #language en-US "No Action" +#string STR_TREE_CLEAR #language en-US "TPM2 ClearControl(NO) + Clear" + +#string STR_TREE_TPM_DISABLE #language en-US "Disable" +#string STR_TREE_TPM_1_2 #language en-US "TPM 1.2" +#string STR_TREE_TPM_2_0_DTPM #language en-US "TPM 2.0 (DTPM)" + +#string STR_NULL #language en-US "" diff --git a/Core/SecurityPkg/Tcg/TrEEDxe/MeasureBootPeCoff.c b/Core/SecurityPkg/Tcg/TrEEDxe/MeasureBootPeCoff.c new file mode 100644 index 0000000000..a7de5883cc --- /dev/null +++ b/Core/SecurityPkg/Tcg/TrEEDxe/MeasureBootPeCoff.c @@ -0,0 +1,427 @@ +/** @file + This module implements measuring PeCoff image for TrEE Protocol. + + Caution: This file requires additional review when modified. + This driver will have external input - PE/COFF image. + This external input must be validated carefully to avoid security issue like + buffer overflow, integer overflow. + +Copyright (c) 2013 - 2017, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +UINTN mTrEEDxeImageSize = 0; + +/** + Reads contents of a PE/COFF image in memory buffer. + + Caution: This function may receive untrusted input. + PE/COFF image is external input, so this function will make sure the PE/COFF image content + read is within the image buffer. + + @param FileHandle Pointer to the file handle to read the PE/COFF image. + @param FileOffset Offset into the PE/COFF image to begin the read operation. + @param ReadSize On input, the size in bytes of the requested read operation. + On output, the number of bytes actually read. + @param Buffer Output buffer that contains the data read from the PE/COFF image. + + @retval EFI_SUCCESS The specified portion of the PE/COFF image was read and the size +**/ +EFI_STATUS +EFIAPI +TrEEDxeImageRead ( + IN VOID *FileHandle, + IN UINTN FileOffset, + IN OUT UINTN *ReadSize, + OUT VOID *Buffer + ) +{ + UINTN EndPosition; + + if (FileHandle == NULL || ReadSize == NULL || Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (MAX_ADDRESS - FileOffset < *ReadSize) { + return EFI_INVALID_PARAMETER; + } + + EndPosition = FileOffset + *ReadSize; + if (EndPosition > mTrEEDxeImageSize) { + *ReadSize = (UINT32)(mTrEEDxeImageSize - FileOffset); + } + + if (FileOffset >= mTrEEDxeImageSize) { + *ReadSize = 0; + } + + CopyMem (Buffer, (UINT8 *)((UINTN) FileHandle + FileOffset), *ReadSize); + + return EFI_SUCCESS; +} + +/** + Measure PE image into TPM log based on the authenticode image hashing in + PE/COFF Specification 8.0 Appendix A. + + Caution: This function may receive untrusted input. + PE/COFF image is external input, so this function will validate its data structure + within this image buffer before use. + + Notes: PE/COFF image is checked by BasePeCoffLib PeCoffLoaderGetImageInfo(). + + @param[in] PCRIndex TPM PCR index + @param[in] ImageAddress Start address of image buffer. + @param[in] ImageSize Image size + @param[out] DigestList Digeest list of this image. + + @retval EFI_SUCCESS Successfully measure image. + @retval EFI_OUT_OF_RESOURCES No enough resource to measure image. + @retval other error value +**/ +EFI_STATUS +MeasurePeImageAndExtend ( + IN UINT32 PCRIndex, + IN EFI_PHYSICAL_ADDRESS ImageAddress, + IN UINTN ImageSize, + OUT TPML_DIGEST_VALUES *DigestList + ) +{ + EFI_STATUS Status; + EFI_IMAGE_DOS_HEADER *DosHdr; + UINT32 PeCoffHeaderOffset; + EFI_IMAGE_SECTION_HEADER *Section; + UINT8 *HashBase; + UINTN HashSize; + UINTN SumOfBytesHashed; + EFI_IMAGE_SECTION_HEADER *SectionHeader; + UINTN Index; + UINTN Pos; + UINT16 Magic; + EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr; + UINT32 NumberOfRvaAndSizes; + UINT32 CertSize; + HASH_HANDLE HashHandle; + PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; + + HashHandle = 0xFFFFFFFF; // Know bad value + + Status = EFI_UNSUPPORTED; + SectionHeader = NULL; + + // + // Check PE/COFF image + // + ZeroMem (&ImageContext, sizeof (ImageContext)); + ImageContext.Handle = (VOID *) (UINTN) ImageAddress; + mTrEEDxeImageSize = ImageSize; + ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) TrEEDxeImageRead; + + // + // Get information about the image being loaded + // + Status = PeCoffLoaderGetImageInfo (&ImageContext); + if (EFI_ERROR (Status)) { + // + // The information can't be got from the invalid PeImage + // + DEBUG ((DEBUG_INFO, "TreeDxe: PeImage invalid. Cannot retrieve image information.\n")); + goto Finish; + } + + DosHdr = (EFI_IMAGE_DOS_HEADER *) (UINTN) ImageAddress; + PeCoffHeaderOffset = 0; + if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) { + PeCoffHeaderOffset = DosHdr->e_lfanew; + } + + Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINT8 *) (UINTN) ImageAddress + PeCoffHeaderOffset); + if (Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) { + Status = EFI_UNSUPPORTED; + goto Finish; + } + + // + // PE/COFF Image Measurement + // + // NOTE: The following codes/steps are based upon the authenticode image hashing in + // PE/COFF Specification 8.0 Appendix A. + // + // + + // 1. Load the image header into memory. + + // 2. Initialize a SHA hash context. + + Status = HashStart (&HashHandle); + if (EFI_ERROR (Status)) { + goto Finish; + } + + // + // Measuring PE/COFF Image Header; + // But CheckSum field and SECURITY data directory (certificate) are excluded + // + if (Hdr.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + // + // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value + // in the PE/COFF Header. If the MachineType is Itanium(IA64) and the + // Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC + // then override the magic value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC + // + Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC; + } else { + // + // Get the magic value from the PE/COFF Optional Header + // + Magic = Hdr.Pe32->OptionalHeader.Magic; + } + + // + // 3. Calculate the distance from the base of the image header to the image checksum address. + // 4. Hash the image header from its base to beginning of the image checksum. + // + HashBase = (UINT8 *) (UINTN) ImageAddress; + if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + // + // Use PE32 offset + // + NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes; + HashSize = (UINTN) (&Hdr.Pe32->OptionalHeader.CheckSum) - (UINTN) HashBase; + } else { + // + // Use PE32+ offset + // + NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes; + HashSize = (UINTN) (&Hdr.Pe32Plus->OptionalHeader.CheckSum) - (UINTN) HashBase; + } + + Status = HashUpdate (HashHandle, HashBase, HashSize); + if (EFI_ERROR (Status)) { + goto Finish; + } + + // + // 5. Skip over the image checksum (it occupies a single ULONG). + // + if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) { + // + // 6. Since there is no Cert Directory in optional header, hash everything + // from the end of the checksum to the end of image header. + // + if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + // + // Use PE32 offset. + // + HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.CheckSum + sizeof (UINT32); + HashSize = Hdr.Pe32->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress); + } else { + // + // Use PE32+ offset. + // + HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32); + HashSize = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress); + } + + if (HashSize != 0) { + Status = HashUpdate (HashHandle, HashBase, HashSize); + if (EFI_ERROR (Status)) { + goto Finish; + } + } + } else { + // + // 7. Hash everything from the end of the checksum to the start of the Cert Directory. + // + if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + // + // Use PE32 offset + // + HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.CheckSum + sizeof (UINT32); + HashSize = (UINTN) (&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - (UINTN) HashBase; + } else { + // + // Use PE32+ offset + // + HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32); + HashSize = (UINTN) (&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - (UINTN) HashBase; + } + + if (HashSize != 0) { + Status = HashUpdate (HashHandle, HashBase, HashSize); + if (EFI_ERROR (Status)) { + goto Finish; + } + } + + // + // 8. Skip over the Cert Directory. (It is sizeof(IMAGE_DATA_DIRECTORY) bytes.) + // 9. Hash everything from the end of the Cert Directory to the end of image header. + // + if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + // + // Use PE32 offset + // + HashBase = (UINT8 *) &Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]; + HashSize = Hdr.Pe32->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress); + } else { + // + // Use PE32+ offset + // + HashBase = (UINT8 *) &Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]; + HashSize = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN) (HashBase - ImageAddress); + } + + if (HashSize != 0) { + Status = HashUpdate (HashHandle, HashBase, HashSize); + if (EFI_ERROR (Status)) { + goto Finish; + } + } + } + + // + // 10. Set the SUM_OF_BYTES_HASHED to the size of the header + // + if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + // + // Use PE32 offset + // + SumOfBytesHashed = Hdr.Pe32->OptionalHeader.SizeOfHeaders; + } else { + // + // Use PE32+ offset + // + SumOfBytesHashed = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders; + } + + // + // 11. Build a temporary table of pointers to all the IMAGE_SECTION_HEADER + // structures in the image. The 'NumberOfSections' field of the image + // header indicates how big the table should be. Do not include any + // IMAGE_SECTION_HEADERs in the table whose 'SizeOfRawData' field is zero. + // + SectionHeader = (EFI_IMAGE_SECTION_HEADER *) AllocateZeroPool (sizeof (EFI_IMAGE_SECTION_HEADER) * Hdr.Pe32->FileHeader.NumberOfSections); + if (SectionHeader == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Finish; + } + + // + // 12. Using the 'PointerToRawData' in the referenced section headers as + // a key, arrange the elements in the table in ascending order. In other + // words, sort the section headers according to the disk-file offset of + // the section. + // + Section = (EFI_IMAGE_SECTION_HEADER *) ( + (UINT8 *) (UINTN) ImageAddress + + PeCoffHeaderOffset + + sizeof(UINT32) + + sizeof(EFI_IMAGE_FILE_HEADER) + + Hdr.Pe32->FileHeader.SizeOfOptionalHeader + ); + for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) { + Pos = Index; + while ((Pos > 0) && (Section->PointerToRawData < SectionHeader[Pos - 1].PointerToRawData)) { + CopyMem (&SectionHeader[Pos], &SectionHeader[Pos - 1], sizeof(EFI_IMAGE_SECTION_HEADER)); + Pos--; + } + CopyMem (&SectionHeader[Pos], Section, sizeof(EFI_IMAGE_SECTION_HEADER)); + Section += 1; + } + + // + // 13. Walk through the sorted table, bring the corresponding section + // into memory, and hash the entire section (using the 'SizeOfRawData' + // field in the section header to determine the amount of data to hash). + // 14. Add the section's 'SizeOfRawData' to SUM_OF_BYTES_HASHED . + // 15. Repeat steps 13 and 14 for all the sections in the sorted table. + // + for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) { + Section = (EFI_IMAGE_SECTION_HEADER *) &SectionHeader[Index]; + if (Section->SizeOfRawData == 0) { + continue; + } + HashBase = (UINT8 *) (UINTN) ImageAddress + Section->PointerToRawData; + HashSize = (UINTN) Section->SizeOfRawData; + + Status = HashUpdate (HashHandle, HashBase, HashSize); + if (EFI_ERROR (Status)) { + goto Finish; + } + + SumOfBytesHashed += HashSize; + } + + // + // 16. If the file size is greater than SUM_OF_BYTES_HASHED, there is extra + // data in the file that needs to be added to the hash. This data begins + // at file offset SUM_OF_BYTES_HASHED and its length is: + // FileSize - (CertDirectory->Size) + // + if (ImageSize > SumOfBytesHashed) { + HashBase = (UINT8 *) (UINTN) ImageAddress + SumOfBytesHashed; + + if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) { + CertSize = 0; + } else { + if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + // + // Use PE32 offset. + // + CertSize = Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size; + } else { + // + // Use PE32+ offset. + // + CertSize = Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size; + } + } + + if (ImageSize > CertSize + SumOfBytesHashed) { + HashSize = (UINTN) (ImageSize - CertSize - SumOfBytesHashed); + + Status = HashUpdate (HashHandle, HashBase, HashSize); + if (EFI_ERROR (Status)) { + goto Finish; + } + } else if (ImageSize < CertSize + SumOfBytesHashed) { + Status = EFI_UNSUPPORTED; + goto Finish; + } + } + + // + // 17. Finalize the SHA hash. + // + Status = HashCompleteAndExtend (HashHandle, PCRIndex, NULL, 0, DigestList); + if (EFI_ERROR (Status)) { + goto Finish; + } + +Finish: + if (SectionHeader != NULL) { + FreePool (SectionHeader); + } + + return Status; +} diff --git a/Core/SecurityPkg/Tcg/TrEEDxe/TrEEDxe.c b/Core/SecurityPkg/Tcg/TrEEDxe/TrEEDxe.c new file mode 100644 index 0000000000..95e9d745ad --- /dev/null +++ b/Core/SecurityPkg/Tcg/TrEEDxe/TrEEDxe.c @@ -0,0 +1,1877 @@ +/** @file + This module implements TrEE Protocol. + +Copyright (c) 2013 - 2017, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PERF_ID_TREE_DXE 0x3120 + +typedef struct { + CHAR16 *VariableName; + EFI_GUID *VendorGuid; +} VARIABLE_TYPE; + +#define TREE_DEFAULT_MAX_COMMAND_SIZE 0x1000 +#define TREE_DEFAULT_MAX_RESPONSE_SIZE 0x1000 + +typedef struct { + EFI_GUID *EventGuid; + TREE_EVENT_LOG_FORMAT LogFormat; +} TREE_EVENT_INFO_STRUCT; + +TREE_EVENT_INFO_STRUCT mTreeEventInfo[] = { + {&gTcgEventEntryHobGuid, TREE_EVENT_LOG_FORMAT_TCG_1_2}, +}; + +#define TCG_EVENT_LOG_AREA_COUNT_MAX 2 + +typedef struct { + TREE_EVENT_LOG_FORMAT EventLogFormat; + EFI_PHYSICAL_ADDRESS Lasa; + UINT64 Laml; + UINTN EventLogSize; + UINT8 *LastEvent; + BOOLEAN EventLogStarted; + BOOLEAN EventLogTruncated; +} TCG_EVENT_LOG_AREA_STRUCT; + +typedef struct _TCG_DXE_DATA { + TREE_BOOT_SERVICE_CAPABILITY BsCap; + EFI_TCG_CLIENT_ACPI_TABLE *TcgClientAcpiTable; + EFI_TCG_SERVER_ACPI_TABLE *TcgServerAcpiTable; + TCG_EVENT_LOG_AREA_STRUCT EventLogAreaStruct[TCG_EVENT_LOG_AREA_COUNT_MAX]; +} TCG_DXE_DATA; + +EFI_TCG_CLIENT_ACPI_TABLE mTcgClientAcpiTemplate = { + { + EFI_ACPI_3_0_TRUSTED_COMPUTING_PLATFORM_ALLIANCE_CAPABILITIES_TABLE_SIGNATURE, + sizeof (mTcgClientAcpiTemplate), + 0x02 //Revision + // + // Compiler initializes the remaining bytes to 0 + // These fields should be filled in in production + // + }, + 0, // 0 for PC Client Platform Class + 0, // Log Area Max Length + (EFI_PHYSICAL_ADDRESS) (SIZE_4GB - 1) // Log Area Start Address +}; + +// +// The following EFI_TCG_SERVER_ACPI_TABLE default setting is just one example, +// the TPM device connectes to LPC, and also defined the ACPI _UID as 0xFF, +// this _UID can be changed and should match with the _UID setting of the TPM +// ACPI device object +// +EFI_TCG_SERVER_ACPI_TABLE mTcgServerAcpiTemplate = { + { + EFI_ACPI_3_0_TRUSTED_COMPUTING_PLATFORM_ALLIANCE_CAPABILITIES_TABLE_SIGNATURE, + sizeof (mTcgServerAcpiTemplate), + 0x02 //Revision + // + // Compiler initializes the remaining bytes to 0 + // These fields should be filled in in production + // + }, + 1, // 1 for Server Platform Class + 0, // Reserved + 0, // Log Area Max Length + (EFI_PHYSICAL_ADDRESS) (SIZE_4GB - 1), // Log Area Start Address + 0x0100, // TCG Specification revision 1.0 + 2, // Device Flags + 0, // Interrupt Flags + 0, // GPE + {0}, // Reserved 3 bytes + 0, // Global System Interrupt + { + EFI_ACPI_3_0_SYSTEM_MEMORY, + 0, + 0, + EFI_ACPI_3_0_BYTE, + 0x0 // Base Address + }, + 0, // Reserved + {0}, // Configuration Address + 0xFF, // ACPI _UID value of the device, can be changed for different platforms + 0, // ACPI _UID value of the device, can be changed for different platforms + 0, // ACPI _UID value of the device, can be changed for different platforms + 0 // ACPI _UID value of the device, can be changed for different platforms +}; + +TCG_DXE_DATA mTcgDxeData = { + { + sizeof (TREE_BOOT_SERVICE_CAPABILITY_1_0), // Size + { 1, 0 }, // StructureVersion + { 1, 0 }, // ProtocolVersion + TREE_BOOT_HASH_ALG_SHA1, // HashAlgorithmBitmap + TREE_EVENT_LOG_FORMAT_TCG_1_2, // SupportedEventLogs + TRUE, // TrEEPresentFlag + TREE_DEFAULT_MAX_COMMAND_SIZE, // MaxCommandSize + TREE_DEFAULT_MAX_RESPONSE_SIZE, // MaxResponseSize + 0 // ManufacturerID + }, + &mTcgClientAcpiTemplate, + &mTcgServerAcpiTemplate, +}; + +UINTN mBootAttempts = 0; +CHAR16 mBootVarName[] = L"BootOrder"; + +VARIABLE_TYPE mVariableType[] = { + {EFI_SECURE_BOOT_MODE_NAME, &gEfiGlobalVariableGuid}, + {EFI_PLATFORM_KEY_NAME, &gEfiGlobalVariableGuid}, + {EFI_KEY_EXCHANGE_KEY_NAME, &gEfiGlobalVariableGuid}, + {EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid}, + {EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid}, +}; + +EFI_HANDLE mImageHandle; + +/** + Measure PE image into TPM log based on the authenticode image hashing in + PE/COFF Specification 8.0 Appendix A. + + Caution: This function may receive untrusted input. + PE/COFF image is external input, so this function will validate its data structure + within this image buffer before use. + + Notes: PE/COFF image is checked by BasePeCoffLib PeCoffLoaderGetImageInfo(). + + @param[in] PCRIndex TPM PCR index + @param[in] ImageAddress Start address of image buffer. + @param[in] ImageSize Image size + @param[out] DigestList Digeest list of this image. + + @retval EFI_SUCCESS Successfully measure image. + @retval EFI_OUT_OF_RESOURCES No enough resource to measure image. + @retval other error value +**/ +EFI_STATUS +MeasurePeImageAndExtend ( + IN UINT32 PCRIndex, + IN EFI_PHYSICAL_ADDRESS ImageAddress, + IN UINTN ImageSize, + OUT TPML_DIGEST_VALUES *DigestList + ); + +/** + + This function dump raw data. + + @param Data raw data + @param Size raw data size + +**/ +VOID +InternalDumpData ( + IN UINT8 *Data, + IN UINTN Size + ) +{ + UINTN Index; + for (Index = 0; Index < Size; Index++) { + DEBUG ((EFI_D_INFO, "%02x", (UINTN)Data[Index])); + } +} + +/** + + This function dump raw data with colume format. + + @param Data raw data + @param Size raw data size + +**/ +VOID +InternalDumpHex ( + IN UINT8 *Data, + IN UINTN Size + ) +{ + UINTN Index; + UINTN Count; + UINTN Left; + +#define COLUME_SIZE (16 * 2) + + Count = Size / COLUME_SIZE; + Left = Size % COLUME_SIZE; + for (Index = 0; Index < Count; Index++) { + DEBUG ((EFI_D_INFO, "%04x: ", Index * COLUME_SIZE)); + InternalDumpData (Data + Index * COLUME_SIZE, COLUME_SIZE); + DEBUG ((EFI_D_INFO, "\n")); + } + + if (Left != 0) { + DEBUG ((EFI_D_INFO, "%04x: ", Index * COLUME_SIZE)); + InternalDumpData (Data + Index * COLUME_SIZE, Left); + DEBUG ((EFI_D_INFO, "\n")); + } +} + +/** + Get All processors EFI_CPU_LOCATION in system. LocationBuf is allocated inside the function + Caller is responsible to free LocationBuf. + + @param[out] LocationBuf Returns Processor Location Buffer. + @param[out] Num Returns processor number. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_UNSUPPORTED MpService protocol not found. + +**/ +EFI_STATUS +GetProcessorsCpuLocation ( + OUT EFI_CPU_PHYSICAL_LOCATION **LocationBuf, + OUT UINTN *Num + ) +{ + EFI_STATUS Status; + EFI_MP_SERVICES_PROTOCOL *MpProtocol; + UINTN ProcessorNum; + UINTN EnabledProcessorNum; + EFI_PROCESSOR_INFORMATION ProcessorInfo; + EFI_CPU_PHYSICAL_LOCATION *ProcessorLocBuf; + UINTN Index; + + Status = gBS->LocateProtocol (&gEfiMpServiceProtocolGuid, NULL, (VOID **) &MpProtocol); + if (EFI_ERROR (Status)) { + // + // MP protocol is not installed + // + return EFI_UNSUPPORTED; + } + + Status = MpProtocol->GetNumberOfProcessors( + MpProtocol, + &ProcessorNum, + &EnabledProcessorNum + ); + if (EFI_ERROR(Status)){ + return Status; + } + + Status = gBS->AllocatePool( + EfiBootServicesData, + sizeof(EFI_CPU_PHYSICAL_LOCATION) * ProcessorNum, + (VOID **) &ProcessorLocBuf + ); + if (EFI_ERROR(Status)){ + return Status; + } + + // + // Get each processor Location info + // + for (Index = 0; Index < ProcessorNum; Index++) { + Status = MpProtocol->GetProcessorInfo( + MpProtocol, + Index, + &ProcessorInfo + ); + if (EFI_ERROR(Status)){ + FreePool(ProcessorLocBuf); + return Status; + } + + // + // Get all Processor Location info & measure + // + CopyMem( + &ProcessorLocBuf[Index], + &ProcessorInfo.Location, + sizeof(EFI_CPU_PHYSICAL_LOCATION) + ); + } + + *LocationBuf = ProcessorLocBuf; + *Num = ProcessorNum; + + return Status; +} + +/** + The EFI_TREE_PROTOCOL GetCapability function call provides protocol + capability information and state information about the TrEE. + + @param[in] This Indicates the calling context + @param[in, out] ProtocolCapability The caller allocates memory for a TREE_BOOT_SERVICE_CAPABILITY + structure and sets the size field to the size of the structure allocated. + The callee fills in the fields with the EFI protocol capability information + and the current TrEE state information up to the number of fields which + fit within the size of the structure passed in. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR The command was unsuccessful. + The ProtocolCapability variable will not be populated. + @retval EFI_INVALID_PARAMETER One or more of the parameters are incorrect. + The ProtocolCapability variable will not be populated. + @retval EFI_BUFFER_TOO_SMALL The ProtocolCapability variable is too small to hold the full response. + It will be partially populated (required Size field will be set). +**/ +EFI_STATUS +EFIAPI +TreeGetCapability ( + IN EFI_TREE_PROTOCOL *This, + IN OUT TREE_BOOT_SERVICE_CAPABILITY *ProtocolCapability + ) +{ + DEBUG ((EFI_D_INFO, "TreeGetCapability ...\n")); + + if ((This == NULL) || (ProtocolCapability == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if (ProtocolCapability->Size < mTcgDxeData.BsCap.Size) { + ProtocolCapability->Size = mTcgDxeData.BsCap.Size; + return EFI_BUFFER_TOO_SMALL; + } + + CopyMem (ProtocolCapability, &mTcgDxeData.BsCap, mTcgDxeData.BsCap.Size); + DEBUG ((EFI_D_INFO, "TreeGetCapability - %r\n", EFI_SUCCESS)); + return EFI_SUCCESS; +} + +/** + This function dump event log. + + @param[in] EventLogFormat The type of the event log for which the information is requested. + @param[in] EventLogLocation A pointer to the memory address of the event log. + @param[in] EventLogLastEntry If the Event Log contains more than one entry, this is a pointer to the + address of the start of the last entry in the event log in memory. +**/ +VOID +DumpEventLog ( + IN TREE_EVENT_LOG_FORMAT EventLogFormat, + IN EFI_PHYSICAL_ADDRESS EventLogLocation, + IN EFI_PHYSICAL_ADDRESS EventLogLastEntry + ) +{ + TCG_PCR_EVENT_HDR *EventHdr; + UINTN Index; + + DEBUG ((EFI_D_INFO, "EventLogFormat: (0x%x)\n", EventLogFormat)); + + switch (EventLogFormat) { + case TREE_EVENT_LOG_FORMAT_TCG_1_2: + EventHdr = (TCG_PCR_EVENT_HDR *)(UINTN)EventLogLocation; + while ((UINTN)EventHdr <= EventLogLastEntry) { + DEBUG ((EFI_D_INFO, " Event:\n")); + DEBUG ((EFI_D_INFO, " PCRIndex - %d\n", EventHdr->PCRIndex)); + DEBUG ((EFI_D_INFO, " EventType - 0x%08x\n", EventHdr->EventType)); + DEBUG ((EFI_D_INFO, " Digest - ")); + for (Index = 0; Index < sizeof(TCG_DIGEST); Index++) { + DEBUG ((EFI_D_INFO, "%02x ", EventHdr->Digest.digest[Index])); + } + DEBUG ((EFI_D_INFO, "\n")); + DEBUG ((EFI_D_INFO, " EventSize - 0x%08x\n", EventHdr->EventSize)); + InternalDumpHex ((UINT8 *)(EventHdr + 1), EventHdr->EventSize); + EventHdr = (TCG_PCR_EVENT_HDR *)((UINTN)EventHdr + sizeof(TCG_PCR_EVENT_HDR) + EventHdr->EventSize); + } + break; + } + + return ; +} + +/** + The EFI_TREE_PROTOCOL Get Event Log function call allows a caller to + retrieve the address of a given event log and its last entry. + + @param[in] This Indicates the calling context + @param[in] EventLogFormat The type of the event log for which the information is requested. + @param[out] EventLogLocation A pointer to the memory address of the event log. + @param[out] EventLogLastEntry If the Event Log contains more than one entry, this is a pointer to the + address of the start of the last entry in the event log in memory. + @param[out] EventLogTruncated If the Event Log is missing at least one entry because an event would + have exceeded the area allocated for events, this value is set to TRUE. + Otherwise, the value will be FALSE and the Event Log will be complete. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_INVALID_PARAMETER One or more of the parameters are incorrect + (e.g. asking for an event log whose format is not supported). +**/ +EFI_STATUS +EFIAPI +TreeGetEventLog ( + IN EFI_TREE_PROTOCOL *This, + IN TREE_EVENT_LOG_FORMAT EventLogFormat, + OUT EFI_PHYSICAL_ADDRESS *EventLogLocation, + OUT EFI_PHYSICAL_ADDRESS *EventLogLastEntry, + OUT BOOLEAN *EventLogTruncated + ) +{ + UINTN Index; + + DEBUG ((EFI_D_INFO, "TreeGetEventLog ...\n")); + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + for (Index = 0; Index < sizeof(mTreeEventInfo)/sizeof(mTreeEventInfo[0]); Index++) { + if (EventLogFormat == mTreeEventInfo[Index].LogFormat) { + break; + } + } + + if (Index == sizeof(mTreeEventInfo)/sizeof(mTreeEventInfo[0])) { + return EFI_INVALID_PARAMETER; + } + + if (!mTcgDxeData.BsCap.TrEEPresentFlag) { + if (EventLogLocation != NULL) { + *EventLogLocation = 0; + } + if (EventLogLastEntry != NULL) { + *EventLogLastEntry = 0; + } + if (EventLogTruncated != NULL) { + *EventLogTruncated = FALSE; + } + return EFI_SUCCESS; + } + + if (EventLogLocation != NULL) { + *EventLogLocation = mTcgDxeData.EventLogAreaStruct[Index].Lasa; + DEBUG ((EFI_D_INFO, "TreeGetEventLog (EventLogLocation - %x)\n", *EventLogLocation)); + } + + if (EventLogLastEntry != NULL) { + if (!mTcgDxeData.EventLogAreaStruct[Index].EventLogStarted) { + *EventLogLastEntry = (EFI_PHYSICAL_ADDRESS)(UINTN)0; + } else { + *EventLogLastEntry = (EFI_PHYSICAL_ADDRESS)(UINTN)mTcgDxeData.EventLogAreaStruct[Index].LastEvent; + } + DEBUG ((EFI_D_INFO, "TreeGetEventLog (EventLogLastEntry - %x)\n", *EventLogLastEntry)); + } + + if (EventLogTruncated != NULL) { + *EventLogTruncated = mTcgDxeData.EventLogAreaStruct[Index].EventLogTruncated; + DEBUG ((EFI_D_INFO, "TreeGetEventLog (EventLogTruncated - %x)\n", *EventLogTruncated)); + } + + DEBUG ((EFI_D_INFO, "TreeGetEventLog - %r\n", EFI_SUCCESS)); + + // Dump Event Log for debug purpose + if ((EventLogLocation != NULL) && (EventLogLastEntry != NULL)) { + DumpEventLog (EventLogFormat, *EventLogLocation, *EventLogLastEntry); + } + + return EFI_SUCCESS; +} + +/** + Add a new entry to the Event Log. + + @param[in, out] EventLogPtr Pointer to the Event Log data. + @param[in, out] LogSize Size of the Event Log. + @param[in] MaxSize Maximum size of the Event Log. + @param[in] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR/TCG_PCR_EVENT_EX data structure. + @param[in] NewEventHdrSize New event header size. + @param[in] NewEventData Pointer to the new event data. + @param[in] NewEventSize New event data size. + + @retval EFI_SUCCESS The new event log entry was added. + @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event. + +**/ +EFI_STATUS +TcgCommLogEvent ( + IN OUT UINT8 **EventLogPtr, + IN OUT UINTN *LogSize, + IN UINTN MaxSize, + IN VOID *NewEventHdr, + IN UINT32 NewEventHdrSize, + IN UINT8 *NewEventData, + IN UINT32 NewEventSize + ) +{ + UINTN NewLogSize; + + if (NewEventSize > MAX_ADDRESS - NewEventHdrSize) { + return EFI_OUT_OF_RESOURCES; + } + + NewLogSize = NewEventHdrSize + NewEventSize; + + if (NewLogSize > MAX_ADDRESS - *LogSize) { + return EFI_OUT_OF_RESOURCES; + } + + if (NewLogSize + *LogSize > MaxSize) { + DEBUG ((EFI_D_INFO, " MaxSize - 0x%x\n", MaxSize)); + DEBUG ((EFI_D_INFO, " NewLogSize - 0x%x\n", NewLogSize)); + DEBUG ((EFI_D_INFO, " LogSize - 0x%x\n", *LogSize)); + DEBUG ((EFI_D_INFO, "TcgCommLogEvent - %r\n", EFI_OUT_OF_RESOURCES)); + return EFI_OUT_OF_RESOURCES; + } + + *EventLogPtr += *LogSize; + *LogSize += NewLogSize; + CopyMem (*EventLogPtr, NewEventHdr, NewEventHdrSize); + CopyMem ( + *EventLogPtr + NewEventHdrSize, + NewEventData, + NewEventSize + ); + return EFI_SUCCESS; +} + +/** + Add a new entry to the Event Log. + + @param[in] EventLogFormat The type of the event log for which the information is requested. + @param[in] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR/TCG_PCR_EVENT_EX data structure. + @param[in] NewEventHdrSize New event header size. + @param[in] NewEventData Pointer to the new event data. + @param[in] NewEventSize New event data size. + + @retval EFI_SUCCESS The new event log entry was added. + @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event. + +**/ +EFI_STATUS +TcgDxeLogEvent ( + IN TREE_EVENT_LOG_FORMAT EventLogFormat, + IN VOID *NewEventHdr, + IN UINT32 NewEventHdrSize, + IN UINT8 *NewEventData, + IN UINT32 NewEventSize + ) +{ + EFI_STATUS Status; + UINTN Index; + + for (Index = 0; Index < sizeof(mTreeEventInfo)/sizeof(mTreeEventInfo[0]); Index++) { + if (EventLogFormat == mTreeEventInfo[Index].LogFormat) { + break; + } + } + + if (Index == sizeof(mTreeEventInfo)/sizeof(mTreeEventInfo[0])) { + return EFI_INVALID_PARAMETER; + } + + if (mTcgDxeData.EventLogAreaStruct[Index].EventLogTruncated) { + return EFI_VOLUME_FULL; + } + + mTcgDxeData.EventLogAreaStruct[Index].LastEvent = (UINT8*)(UINTN)mTcgDxeData.EventLogAreaStruct[Index].Lasa; + Status = TcgCommLogEvent ( + &mTcgDxeData.EventLogAreaStruct[Index].LastEvent, + &mTcgDxeData.EventLogAreaStruct[Index].EventLogSize, + (UINTN)mTcgDxeData.EventLogAreaStruct[Index].Laml, + NewEventHdr, + NewEventHdrSize, + NewEventData, + NewEventSize + ); + + if (Status == EFI_DEVICE_ERROR) { + return EFI_DEVICE_ERROR; + } else if (Status == EFI_OUT_OF_RESOURCES) { + mTcgDxeData.EventLogAreaStruct[Index].EventLogTruncated = TRUE; + return EFI_VOLUME_FULL; + } else if (Status == EFI_SUCCESS) { + mTcgDxeData.EventLogAreaStruct[Index].EventLogStarted = TRUE; + } + + return Status; +} + +/** + Add a new entry to the Event Log. + + @param[in] DigestList A list of digest. + @param[in,out] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR data structure. + @param[in] NewEventData Pointer to the new event data. + + @retval EFI_SUCCESS The new event log entry was added. + @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event. +**/ +EFI_STATUS +TcgDxeLogHashEvent ( + IN TPML_DIGEST_VALUES *DigestList, + IN OUT TCG_PCR_EVENT_HDR *NewEventHdr, + IN UINT8 *NewEventData + ) +{ + EFI_STATUS Status; + EFI_TPL OldTpl; + UINTN Index; + EFI_STATUS RetStatus; + + RetStatus = EFI_SUCCESS; + for (Index = 0; Index < sizeof(mTreeEventInfo)/sizeof(mTreeEventInfo[0]); Index++) { + DEBUG ((EFI_D_INFO, " LogFormat - 0x%08x\n", mTreeEventInfo[Index].LogFormat)); + switch (mTreeEventInfo[Index].LogFormat) { + case TREE_EVENT_LOG_FORMAT_TCG_1_2: + Status = GetDigestFromDigestList (TPM_ALG_SHA1, DigestList, &NewEventHdr->Digest); + if (!EFI_ERROR (Status)) { + // + // Enter critical region + // + OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL); + Status = TcgDxeLogEvent ( + mTreeEventInfo[Index].LogFormat, + NewEventHdr, + sizeof(TCG_PCR_EVENT_HDR), + NewEventData, + NewEventHdr->EventSize + ); + if (Status != EFI_SUCCESS) { + RetStatus = Status; + } + gBS->RestoreTPL (OldTpl); + // + // Exit critical region + // + } + break; + } + } + + return RetStatus; +} + +/** + Do a hash operation on a data buffer, extend a specific TPM PCR with the hash result, + and add an entry to the Event Log. + + @param[in] Flags Bitmap providing additional information. + @param[in] HashData Physical address of the start of the data buffer + to be hashed, extended, and logged. + @param[in] HashDataLen The length, in bytes, of the buffer referenced by HashData + @param[in, out] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR data structure. + @param[in] NewEventData Pointer to the new event data. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event. + @retval EFI_DEVICE_ERROR The command was unsuccessful. + +**/ +EFI_STATUS +TcgDxeHashLogExtendEvent ( + IN UINT64 Flags, + IN UINT8 *HashData, + IN UINT64 HashDataLen, + IN OUT TCG_PCR_EVENT_HDR *NewEventHdr, + IN UINT8 *NewEventData + ) +{ + EFI_STATUS Status; + TPML_DIGEST_VALUES DigestList; + + if (!mTcgDxeData.BsCap.TrEEPresentFlag) { + return EFI_DEVICE_ERROR; + } + + Status = HashAndExtend ( + NewEventHdr->PCRIndex, + HashData, + (UINTN)HashDataLen, + &DigestList + ); + if (!EFI_ERROR (Status)) { + if ((Flags & TREE_EXTEND_ONLY) == 0) { + Status = TcgDxeLogHashEvent (&DigestList, NewEventHdr, NewEventData); + } + } + + if (Status == EFI_DEVICE_ERROR) { + DEBUG ((EFI_D_ERROR, "TcgDxeHashLogExtendEvent - %r. Disable TPM.\n", Status)); + mTcgDxeData.BsCap.TrEEPresentFlag = FALSE; + REPORT_STATUS_CODE ( + EFI_ERROR_CODE | EFI_ERROR_MINOR, + (PcdGet32 (PcdStatusCodeSubClassTpmDevice) | EFI_P_EC_INTERFACE_ERROR) + ); + } + + return Status; +} + +/** + The EFI_TREE_PROTOCOL HashLogExtendEvent function call provides callers with + an opportunity to extend and optionally log events without requiring + knowledge of actual TPM commands. + The extend operation will occur even if this function cannot create an event + log entry (e.g. due to the event log being full). + + @param[in] This Indicates the calling context + @param[in] Flags Bitmap providing additional information. + @param[in] DataToHash Physical address of the start of the data buffer to be hashed. + @param[in] DataToHashLen The length in bytes of the buffer referenced by DataToHash. + @param[in] Event Pointer to data buffer containing information about the event. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR The command was unsuccessful. + @retval EFI_VOLUME_FULL The extend operation occurred, but the event could not be written to one or more event logs. + @retval EFI_INVALID_PARAMETER One or more of the parameters are incorrect. + @retval EFI_UNSUPPORTED The PE/COFF image type is not supported. +**/ +EFI_STATUS +EFIAPI +TreeHashLogExtendEvent ( + IN EFI_TREE_PROTOCOL *This, + IN UINT64 Flags, + IN EFI_PHYSICAL_ADDRESS DataToHash, + IN UINT64 DataToHashLen, + IN TrEE_EVENT *Event + ) +{ + EFI_STATUS Status; + TCG_PCR_EVENT_HDR NewEventHdr; + TPML_DIGEST_VALUES DigestList; + + DEBUG ((EFI_D_INFO, "TreeHashLogExtendEvent ...\n")); + + if ((This == NULL) || (DataToHash == 0) || (Event == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if (!mTcgDxeData.BsCap.TrEEPresentFlag) { + return EFI_UNSUPPORTED; + } + + if (Event->Size < Event->Header.HeaderSize + sizeof(UINT32)) { + return EFI_INVALID_PARAMETER; + } + + if (Event->Header.PCRIndex > MAX_PCR_INDEX) { + return EFI_INVALID_PARAMETER; + } + + NewEventHdr.PCRIndex = Event->Header.PCRIndex; + NewEventHdr.EventType = Event->Header.EventType; + NewEventHdr.EventSize = Event->Size - sizeof(UINT32) - Event->Header.HeaderSize; + if ((Flags & PE_COFF_IMAGE) != 0) { + Status = MeasurePeImageAndExtend ( + NewEventHdr.PCRIndex, + DataToHash, + (UINTN)DataToHashLen, + &DigestList + ); + if (!EFI_ERROR (Status)) { + if ((Flags & TREE_EXTEND_ONLY) == 0) { + Status = TcgDxeLogHashEvent (&DigestList, &NewEventHdr, Event->Event); + } + } + if (Status == EFI_DEVICE_ERROR) { + DEBUG ((EFI_D_ERROR, "MeasurePeImageAndExtend - %r. Disable TPM.\n", Status)); + mTcgDxeData.BsCap.TrEEPresentFlag = FALSE; + REPORT_STATUS_CODE ( + EFI_ERROR_CODE | EFI_ERROR_MINOR, + (PcdGet32 (PcdStatusCodeSubClassTpmDevice) | EFI_P_EC_INTERFACE_ERROR) + ); + } + } else { + Status = TcgDxeHashLogExtendEvent ( + Flags, + (UINT8 *) (UINTN) DataToHash, + DataToHashLen, + &NewEventHdr, + Event->Event + ); + } + DEBUG ((EFI_D_INFO, "TreeHashLogExtendEvent - %r\n", Status)); + return Status; +} + +/** + This service enables the sending of commands to the TrEE. + + @param[in] This Indicates the calling context + @param[in] InputParameterBlockSize Size of the TrEE input parameter block. + @param[in] InputParameterBlock Pointer to the TrEE input parameter block. + @param[in] OutputParameterBlockSize Size of the TrEE output parameter block. + @param[in] OutputParameterBlock Pointer to the TrEE output parameter block. + + @retval EFI_SUCCESS The command byte stream was successfully sent to the device and a response was successfully received. + @retval EFI_DEVICE_ERROR The command was not successfully sent to the device or a response was not successfully received from the device. + @retval EFI_INVALID_PARAMETER One or more of the parameters are incorrect. + @retval EFI_BUFFER_TOO_SMALL The output parameter block is too small. +**/ +EFI_STATUS +EFIAPI +TreeSubmitCommand ( + IN EFI_TREE_PROTOCOL *This, + IN UINT32 InputParameterBlockSize, + IN UINT8 *InputParameterBlock, + IN UINT32 OutputParameterBlockSize, + IN UINT8 *OutputParameterBlock + ) +{ + EFI_STATUS Status; + + DEBUG ((EFI_D_INFO, "TreeSubmitCommand ...\n")); + + if ((This == NULL) || + (InputParameterBlockSize == 0) || (InputParameterBlock == NULL) || + (OutputParameterBlockSize == 0) || (OutputParameterBlock == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if (!mTcgDxeData.BsCap.TrEEPresentFlag) { + return EFI_UNSUPPORTED; + } + + if (InputParameterBlockSize > mTcgDxeData.BsCap.MaxCommandSize) { + return EFI_INVALID_PARAMETER; + } + if (OutputParameterBlockSize > mTcgDxeData.BsCap.MaxResponseSize) { + return EFI_INVALID_PARAMETER; + } + + Status = Tpm2SubmitCommand ( + InputParameterBlockSize, + InputParameterBlock, + &OutputParameterBlockSize, + OutputParameterBlock + ); + DEBUG ((EFI_D_INFO, "TreeSubmitCommand - %r\n", Status)); + return Status; +} + + +EFI_TREE_PROTOCOL mTreeProtocol = { + TreeGetCapability, + TreeGetEventLog, + TreeHashLogExtendEvent, + TreeSubmitCommand +}; + +/** + Initialize the Event Log and log events passed from the PEI phase. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_OUT_OF_RESOURCES Out of memory. + +**/ +EFI_STATUS +SetupEventLog ( + VOID + ) +{ + EFI_STATUS Status; + VOID *TcgEvent; + EFI_PEI_HOB_POINTERS GuidHob; + EFI_PHYSICAL_ADDRESS Lasa; + UINTN Index; + + DEBUG ((EFI_D_INFO, "SetupEventLog\n")); + + // + // 1. Create Log Area + // + for (Index = 0; Index < sizeof(mTreeEventInfo)/sizeof(mTreeEventInfo[0]); Index++) { + mTcgDxeData.EventLogAreaStruct[Index].EventLogFormat = mTreeEventInfo[Index].LogFormat; + Lasa = (EFI_PHYSICAL_ADDRESS) (SIZE_4GB - 1); + Status = gBS->AllocatePages ( + AllocateMaxAddress, + EfiACPIMemoryNVS, + EFI_SIZE_TO_PAGES (PcdGet32 (PcdTcgLogAreaMinLen)), + &Lasa + ); + if (EFI_ERROR (Status)) { + return Status; + } + mTcgDxeData.EventLogAreaStruct[Index].Lasa = Lasa; + mTcgDxeData.EventLogAreaStruct[Index].Laml = PcdGet32 (PcdTcgLogAreaMinLen); + // + // To initialize them as 0xFF is recommended + // because the OS can know the last entry for that. + // + SetMem ((VOID *)(UINTN)Lasa, PcdGet32 (PcdTcgLogAreaMinLen), 0xFF); + } + + // + // 2. Create ACPI table for TCG1.2 only + // + if (PcdGet8 (PcdTpmPlatformClass) == TCG_PLATFORM_TYPE_CLIENT) { + mTcgClientAcpiTemplate.Lasa = mTcgDxeData.EventLogAreaStruct[0].Lasa; + mTcgClientAcpiTemplate.Laml = PcdGet32 (PcdTcgLogAreaMinLen); + } else { + mTcgServerAcpiTemplate.Lasa = mTcgDxeData.EventLogAreaStruct[0].Lasa; + mTcgServerAcpiTemplate.Laml = PcdGet32 (PcdTcgLogAreaMinLen); + } + + // + // 3. Sync data from PEI to DXE + // + Status = EFI_SUCCESS; + for (Index = 0; Index < sizeof(mTreeEventInfo)/sizeof(mTreeEventInfo[0]); Index++) { + GuidHob.Raw = GetHobList (); + Status = EFI_SUCCESS; + while (!EFI_ERROR (Status) && + (GuidHob.Raw = GetNextGuidHob (mTreeEventInfo[Index].EventGuid, GuidHob.Raw)) != NULL) { + TcgEvent = GET_GUID_HOB_DATA (GuidHob.Guid); + GuidHob.Raw = GET_NEXT_HOB (GuidHob); + switch (mTreeEventInfo[Index].LogFormat) { + case TREE_EVENT_LOG_FORMAT_TCG_1_2: + Status = TcgDxeLogEvent ( + mTreeEventInfo[Index].LogFormat, + TcgEvent, + sizeof(TCG_PCR_EVENT_HDR), + ((TCG_PCR_EVENT*)TcgEvent)->Event, + ((TCG_PCR_EVENT_HDR*)TcgEvent)->EventSize + ); + break; + } + } + } + + return Status; +} + +/** + Measure and log an action string, and extend the measurement result into PCR[5]. + + @param[in] String A specific string that indicates an Action event. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR The operation was unsuccessful. + +**/ +EFI_STATUS +TcgMeasureAction ( + IN CHAR8 *String + ) +{ + TCG_PCR_EVENT_HDR TcgEvent; + + TcgEvent.PCRIndex = 5; + TcgEvent.EventType = EV_EFI_ACTION; + TcgEvent.EventSize = (UINT32)AsciiStrLen (String); + return TcgDxeHashLogExtendEvent ( + 0, + (UINT8*)String, + TcgEvent.EventSize, + &TcgEvent, + (UINT8 *) String + ); +} + +/** + Measure and log EFI handoff tables, and extend the measurement result into PCR[1]. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR The operation was unsuccessful. + +**/ +EFI_STATUS +MeasureHandoffTables ( + VOID + ) +{ + EFI_STATUS Status; + TCG_PCR_EVENT_HDR TcgEvent; + EFI_HANDOFF_TABLE_POINTERS HandoffTables; + UINTN ProcessorNum; + EFI_CPU_PHYSICAL_LOCATION *ProcessorLocBuf; + + ProcessorLocBuf = NULL; + Status = EFI_SUCCESS; + + if (PcdGet8 (PcdTpmPlatformClass) == TCG_PLATFORM_TYPE_SERVER) { + // + // Tcg Server spec. + // Measure each processor EFI_CPU_PHYSICAL_LOCATION with EV_TABLE_OF_DEVICES to PCR[1] + // + Status = GetProcessorsCpuLocation(&ProcessorLocBuf, &ProcessorNum); + + if (!EFI_ERROR(Status)){ + TcgEvent.PCRIndex = 1; + TcgEvent.EventType = EV_TABLE_OF_DEVICES; + TcgEvent.EventSize = sizeof (HandoffTables); + + HandoffTables.NumberOfTables = 1; + HandoffTables.TableEntry[0].VendorGuid = gEfiMpServiceProtocolGuid; + HandoffTables.TableEntry[0].VendorTable = ProcessorLocBuf; + + Status = TcgDxeHashLogExtendEvent ( + 0, + (UINT8*)(UINTN)ProcessorLocBuf, + sizeof(EFI_CPU_PHYSICAL_LOCATION) * ProcessorNum, + &TcgEvent, + (UINT8*)&HandoffTables + ); + + FreePool(ProcessorLocBuf); + } + } + + return Status; +} + +/** + Measure and log Separator event, and extend the measurement result into a specific PCR. + + @param[in] PCRIndex PCR index. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_DEVICE_ERROR The operation was unsuccessful. + +**/ +EFI_STATUS +MeasureSeparatorEvent ( + IN TPM_PCRINDEX PCRIndex + ) +{ + TCG_PCR_EVENT_HDR TcgEvent; + UINT32 EventData; + + DEBUG ((EFI_D_INFO, "MeasureSeparatorEvent Pcr - %x\n", PCRIndex)); + + EventData = 0; + TcgEvent.PCRIndex = PCRIndex; + TcgEvent.EventType = EV_SEPARATOR; + TcgEvent.EventSize = (UINT32)sizeof (EventData); + return TcgDxeHashLogExtendEvent ( + 0, + (UINT8 *)&EventData, + sizeof (EventData), + &TcgEvent, + (UINT8 *)&EventData + ); +} + +/** + Measure and log an EFI variable, and extend the measurement result into a specific PCR. + + @param[in] PCRIndex PCR Index. + @param[in] EventType Event type. + @param[in] VarName A Null-terminated string that is the name of the vendor's variable. + @param[in] VendorGuid A unique identifier for the vendor. + @param[in] VarData The content of the variable data. + @param[in] VarSize The size of the variable data. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_OUT_OF_RESOURCES Out of memory. + @retval EFI_DEVICE_ERROR The operation was unsuccessful. + +**/ +EFI_STATUS +MeasureVariable ( + IN TPM_PCRINDEX PCRIndex, + IN TCG_EVENTTYPE EventType, + IN CHAR16 *VarName, + IN EFI_GUID *VendorGuid, + IN VOID *VarData, + IN UINTN VarSize + ) +{ + EFI_STATUS Status; + TCG_PCR_EVENT_HDR TcgEvent; + UINTN VarNameLength; + EFI_VARIABLE_DATA_TREE *VarLog; + + DEBUG ((EFI_D_INFO, "TrEEDxe: MeasureVariable (Pcr - %x, EventType - %x, ", (UINTN)PCRIndex, (UINTN)EventType)); + DEBUG ((EFI_D_INFO, "VariableName - %s, VendorGuid - %g)\n", VarName, VendorGuid)); + + VarNameLength = StrLen (VarName); + TcgEvent.PCRIndex = PCRIndex; + TcgEvent.EventType = EventType; + TcgEvent.EventSize = (UINT32)(sizeof (*VarLog) + VarNameLength * sizeof (*VarName) + VarSize + - sizeof (VarLog->UnicodeName) - sizeof (VarLog->VariableData)); + + VarLog = (EFI_VARIABLE_DATA_TREE*)AllocatePool (TcgEvent.EventSize); + if (VarLog == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + VarLog->VariableName = *VendorGuid; + VarLog->UnicodeNameLength = VarNameLength; + VarLog->VariableDataLength = VarSize; + CopyMem ( + VarLog->UnicodeName, + VarName, + VarNameLength * sizeof (*VarName) + ); + if (VarSize != 0 && VarData != NULL) { + CopyMem ( + (CHAR16 *)VarLog->UnicodeName + VarNameLength, + VarData, + VarSize + ); + } + + Status = TcgDxeHashLogExtendEvent ( + 0, + (UINT8*)VarLog, + TcgEvent.EventSize, + &TcgEvent, + (UINT8*)VarLog + ); + + FreePool (VarLog); + return Status; +} + +/** + Read then Measure and log an EFI variable, and extend the measurement result into a specific PCR. + + @param[in] PCRIndex PCR Index. + @param[in] EventType Event type. + @param[in] VarName A Null-terminated string that is the name of the vendor's variable. + @param[in] VendorGuid A unique identifier for the vendor. + @param[out] VarSize The size of the variable data. + @param[out] VarData Pointer to the content of the variable. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_OUT_OF_RESOURCES Out of memory. + @retval EFI_DEVICE_ERROR The operation was unsuccessful. + +**/ +EFI_STATUS +ReadAndMeasureVariable ( + IN TPM_PCRINDEX PCRIndex, + IN TCG_EVENTTYPE EventType, + IN CHAR16 *VarName, + IN EFI_GUID *VendorGuid, + OUT UINTN *VarSize, + OUT VOID **VarData + ) +{ + EFI_STATUS Status; + + Status = GetVariable2 (VarName, VendorGuid, VarData, VarSize); + if (EventType == EV_EFI_VARIABLE_DRIVER_CONFIG) { + if (EFI_ERROR (Status)) { + // + // It is valid case, so we need handle it. + // + *VarData = NULL; + *VarSize = 0; + } + } else { + // + // if status error, VarData is freed and set NULL by GetVariable2 + // + if (EFI_ERROR (Status)) { + return EFI_NOT_FOUND; + } + } + + Status = MeasureVariable ( + PCRIndex, + EventType, + VarName, + VendorGuid, + *VarData, + *VarSize + ); + return Status; +} + +/** + Read then Measure and log an EFI boot variable, and extend the measurement result into PCR[5]. + + @param[in] VarName A Null-terminated string that is the name of the vendor's variable. + @param[in] VendorGuid A unique identifier for the vendor. + @param[out] VarSize The size of the variable data. + @param[out] VarData Pointer to the content of the variable. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_OUT_OF_RESOURCES Out of memory. + @retval EFI_DEVICE_ERROR The operation was unsuccessful. + +**/ +EFI_STATUS +ReadAndMeasureBootVariable ( + IN CHAR16 *VarName, + IN EFI_GUID *VendorGuid, + OUT UINTN *VarSize, + OUT VOID **VarData + ) +{ + return ReadAndMeasureVariable ( + 5, + EV_EFI_VARIABLE_BOOT, + VarName, + VendorGuid, + VarSize, + VarData + ); +} + +/** + Read then Measure and log an EFI Secure variable, and extend the measurement result into PCR[7]. + + @param[in] VarName A Null-terminated string that is the name of the vendor's variable. + @param[in] VendorGuid A unique identifier for the vendor. + @param[out] VarSize The size of the variable data. + @param[out] VarData Pointer to the content of the variable. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_OUT_OF_RESOURCES Out of memory. + @retval EFI_DEVICE_ERROR The operation was unsuccessful. + +**/ +EFI_STATUS +ReadAndMeasureSecureVariable ( + IN CHAR16 *VarName, + IN EFI_GUID *VendorGuid, + OUT UINTN *VarSize, + OUT VOID **VarData + ) +{ + return ReadAndMeasureVariable ( + 7, + EV_EFI_VARIABLE_DRIVER_CONFIG, + VarName, + VendorGuid, + VarSize, + VarData + ); +} + +/** + Measure and log all EFI boot variables, and extend the measurement result into a specific PCR. + + The EFI boot variables are BootOrder and Boot#### variables. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_OUT_OF_RESOURCES Out of memory. + @retval EFI_DEVICE_ERROR The operation was unsuccessful. + +**/ +EFI_STATUS +MeasureAllBootVariables ( + VOID + ) +{ + EFI_STATUS Status; + UINT16 *BootOrder; + UINTN BootCount; + UINTN Index; + VOID *BootVarData; + UINTN Size; + + Status = ReadAndMeasureBootVariable ( + mBootVarName, + &gEfiGlobalVariableGuid, + &BootCount, + (VOID **) &BootOrder + ); + if (Status == EFI_NOT_FOUND || BootOrder == NULL) { + return EFI_SUCCESS; + } + + if (EFI_ERROR (Status)) { + // + // BootOrder can't be NULL if status is not EFI_NOT_FOUND + // + FreePool (BootOrder); + return Status; + } + + BootCount /= sizeof (*BootOrder); + for (Index = 0; Index < BootCount; Index++) { + UnicodeSPrint (mBootVarName, sizeof (mBootVarName), L"Boot%04x", BootOrder[Index]); + Status = ReadAndMeasureBootVariable ( + mBootVarName, + &gEfiGlobalVariableGuid, + &Size, + &BootVarData + ); + if (!EFI_ERROR (Status)) { + FreePool (BootVarData); + } + } + + FreePool (BootOrder); + return EFI_SUCCESS; +} + +/** + Measure and log all EFI Secure variables, and extend the measurement result into a specific PCR. + + The EFI boot variables are BootOrder and Boot#### variables. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_OUT_OF_RESOURCES Out of memory. + @retval EFI_DEVICE_ERROR The operation was unsuccessful. + +**/ +EFI_STATUS +MeasureAllSecureVariables ( + VOID + ) +{ + EFI_STATUS Status; + VOID *Data; + UINTN DataSize; + UINTN Index; + + Status = EFI_NOT_FOUND; + for (Index = 0; Index < sizeof(mVariableType)/sizeof(mVariableType[0]); Index++) { + Status = ReadAndMeasureSecureVariable ( + mVariableType[Index].VariableName, + mVariableType[Index].VendorGuid, + &DataSize, + &Data + ); + if (!EFI_ERROR (Status)) { + if (Data != NULL) { + FreePool (Data); + } + } + } + + return EFI_SUCCESS; +} + +/** + Measure and log launch of FirmwareDebugger, and extend the measurement result into a specific PCR. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_OUT_OF_RESOURCES Out of memory. + @retval EFI_DEVICE_ERROR The operation was unsuccessful. + +**/ +EFI_STATUS +MeasureLaunchOfFirmwareDebugger ( + VOID + ) +{ + TCG_PCR_EVENT_HDR TcgEvent; + + TcgEvent.PCRIndex = 7; + TcgEvent.EventType = EV_EFI_ACTION; + TcgEvent.EventSize = sizeof(FIRMWARE_DEBUGGER_EVENT_STRING) - 1; + return TcgDxeHashLogExtendEvent ( + 0, + (UINT8 *)FIRMWARE_DEBUGGER_EVENT_STRING, + sizeof(FIRMWARE_DEBUGGER_EVENT_STRING) - 1, + &TcgEvent, + (UINT8 *)FIRMWARE_DEBUGGER_EVENT_STRING + ); +} + +/** + Measure and log all Secure Boot Policy, and extend the measurement result into a specific PCR. + + Platform firmware adhering to the policy must therefore measure the following values into PCR[7]: (in order listed) + - The contents of the SecureBoot variable + - The contents of the PK variable + - The contents of the KEK variable + - The contents of the EFI_IMAGE_SECURITY_DATABASE variable + - The contents of the EFI_IMAGE_SECURITY_DATABASE1 variable + - Separator + - Entries in the EFI_IMAGE_SECURITY_DATABASE that are used to validate EFI Drivers or EFI Boot Applications in the boot path + + NOTE: Because of the above, UEFI variables PK, KEK, EFI_IMAGE_SECURITY_DATABASE, + EFI_IMAGE_SECURITY_DATABASE1 and SecureBoot SHALL NOT be measured into PCR[3]. + + @param[in] Event Event whose notification function is being invoked + @param[in] Context Pointer to the notification function's context +**/ +VOID +EFIAPI +MeasureSecureBootPolicy ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + VOID *Protocol; + + Status = gBS->LocateProtocol (&gEfiVariableWriteArchProtocolGuid, NULL, (VOID **)&Protocol); + if (EFI_ERROR (Status)) { + return; + } + + if (PcdGetBool (PcdFirmwareDebuggerInitialized)) { + Status = MeasureLaunchOfFirmwareDebugger (); + DEBUG ((EFI_D_INFO, "MeasureLaunchOfFirmwareDebugger - %r\n", Status)); + } + + Status = MeasureAllSecureVariables (); + DEBUG ((EFI_D_INFO, "MeasureAllSecureVariables - %r\n", Status)); + + // + // We need measure Separator(7) here, because this event must be between SecureBootPolicy (Configure) + // and ImageVerification (Authority) + // There might be a case that we need measure UEFI image from DriverOrder, besides BootOrder. So + // the Authority measurement happen before ReadToBoot event. + // + Status = MeasureSeparatorEvent (7); + DEBUG ((EFI_D_INFO, "MeasureSeparatorEvent - %r\n", Status)); + return ; +} + +/** + Ready to Boot Event notification handler. + + Sequence of OS boot events is measured in this event notification handler. + + @param[in] Event Event whose notification function is being invoked + @param[in] Context Pointer to the notification function's context + +**/ +VOID +EFIAPI +OnReadyToBoot ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + TPM_PCRINDEX PcrIndex; + + PERF_START_EX (mImageHandle, "EventRec", "TrEEDxe", 0, PERF_ID_TREE_DXE); + if (mBootAttempts == 0) { + + // + // Measure handoff tables. + // + Status = MeasureHandoffTables (); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "HOBs not Measured. Error!\n")); + } + + // + // Measure BootOrder & Boot#### variables. + // + Status = MeasureAllBootVariables (); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Boot Variables not Measured. Error!\n")); + } + + // + // 1. This is the first boot attempt. + // + Status = TcgMeasureAction ( + EFI_CALLING_EFI_APPLICATION + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "%a not Measured. Error!\n", EFI_CALLING_EFI_APPLICATION)); + } + + // + // 2. Draw a line between pre-boot env and entering post-boot env. + // PCR[7] is already done. + // + for (PcrIndex = 0; PcrIndex < 7; PcrIndex++) { + Status = MeasureSeparatorEvent (PcrIndex); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Seperator Event not Measured. Error!\n")); + } + } + + // + // 3. Measure GPT. It would be done in SAP driver. + // + + // + // 4. Measure PE/COFF OS loader. It would be done in SAP driver. + // + + // + // 5. Read & Measure variable. BootOrder already measured. + // + } else { + // + // 6. Not first attempt, meaning a return from last attempt + // + Status = TcgMeasureAction ( + EFI_RETURNING_FROM_EFI_APPLICATOIN + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "%a not Measured. Error!\n", EFI_RETURNING_FROM_EFI_APPLICATOIN)); + } + } + + DEBUG ((EFI_D_INFO, "TPM2 TrEEDxe Measure Data when ReadyToBoot\n")); + // + // Increase boot attempt counter. + // + mBootAttempts++; + PERF_END_EX (mImageHandle, "EventRec", "TrEEDxe", 0, PERF_ID_TREE_DXE + 1); +} + +/** + Install TCG ACPI Table when ACPI Table Protocol is available. + + A system's firmware uses an ACPI table to identify the system's TCG capabilities + to the Post-Boot environment. The information in this ACPI table is not guaranteed + to be valid until the Host Platform transitions from pre-boot state to post-boot state. + + @param[in] Event Event whose notification function is being invoked + @param[in] Context Pointer to the notification function's context +**/ +VOID +EFIAPI +InstallAcpiTable ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + UINTN TableKey; + EFI_STATUS Status; + EFI_ACPI_TABLE_PROTOCOL *AcpiTable; + UINT8 Checksum; + UINT64 OemTableId; + + Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **)&AcpiTable); + if (EFI_ERROR (Status)) { + return; + } + + if (PcdGet8 (PcdTpmPlatformClass) == TCG_PLATFORM_TYPE_CLIENT) { + CopyMem (mTcgClientAcpiTemplate.Header.OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (mTcgClientAcpiTemplate.Header.OemId)); + OemTableId = PcdGet64 (PcdAcpiDefaultOemTableId); + CopyMem (&mTcgClientAcpiTemplate.Header.OemTableId, &OemTableId, sizeof (UINT64)); + mTcgClientAcpiTemplate.Header.OemRevision = PcdGet32 (PcdAcpiDefaultOemRevision); + mTcgClientAcpiTemplate.Header.CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId); + mTcgClientAcpiTemplate.Header.CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision); + // + // The ACPI table must be checksumed before calling the InstallAcpiTable() + // service of the ACPI table protocol to install it. + // + Checksum = CalculateCheckSum8 ((UINT8 *)&mTcgClientAcpiTemplate, sizeof (mTcgClientAcpiTemplate)); + mTcgClientAcpiTemplate.Header.Checksum = Checksum; + + Status = AcpiTable->InstallAcpiTable ( + AcpiTable, + &mTcgClientAcpiTemplate, + sizeof (mTcgClientAcpiTemplate), + &TableKey + ); + } else { + CopyMem (mTcgServerAcpiTemplate.Header.OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (mTcgServerAcpiTemplate.Header.OemId)); + OemTableId = PcdGet64 (PcdAcpiDefaultOemTableId); + CopyMem (&mTcgServerAcpiTemplate.Header.OemTableId, &OemTableId, sizeof (UINT64)); + mTcgServerAcpiTemplate.Header.OemRevision = PcdGet32 (PcdAcpiDefaultOemRevision); + mTcgServerAcpiTemplate.Header.CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId); + mTcgServerAcpiTemplate.Header.CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision); + // + // The ACPI table must be checksumed before calling the InstallAcpiTable() + // service of the ACPI table protocol to install it. + // + Checksum = CalculateCheckSum8 ((UINT8 *)&mTcgServerAcpiTemplate, sizeof (mTcgServerAcpiTemplate)); + mTcgServerAcpiTemplate.Header.Checksum = Checksum; + + mTcgServerAcpiTemplate.BaseAddress.Address = PcdGet64 (PcdTpmBaseAddress); + Status = AcpiTable->InstallAcpiTable ( + AcpiTable, + &mTcgServerAcpiTemplate, + sizeof (mTcgServerAcpiTemplate), + &TableKey + ); + } + + if (EFI_ERROR (Status)) { + DEBUG((EFI_D_ERROR, "Tcg Acpi Table installation failure")); + } +} + +/** + Exit Boot Services Event notification handler. + + Measure invocation and success of ExitBootServices. + + @param[in] Event Event whose notification function is being invoked + @param[in] Context Pointer to the notification function's context + +**/ +VOID +EFIAPI +OnExitBootServices ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + + // + // Measure invocation of ExitBootServices, + // + Status = TcgMeasureAction ( + EFI_EXIT_BOOT_SERVICES_INVOCATION + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "%a not Measured. Error!\n", EFI_EXIT_BOOT_SERVICES_INVOCATION)); + } + + // + // Measure success of ExitBootServices + // + Status = TcgMeasureAction ( + EFI_EXIT_BOOT_SERVICES_SUCCEEDED + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "%a not Measured. Error!\n", EFI_EXIT_BOOT_SERVICES_SUCCEEDED)); + } +} + +/** + Exit Boot Services Failed Event notification handler. + + Measure Failure of ExitBootServices. + + @param[in] Event Event whose notification function is being invoked + @param[in] Context Pointer to the notification function's context + +**/ +VOID +EFIAPI +OnExitBootServicesFailed ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + + // + // Measure Failure of ExitBootServices, + // + Status = TcgMeasureAction ( + EFI_EXIT_BOOT_SERVICES_FAILED + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "%a not Measured. Error!\n", EFI_EXIT_BOOT_SERVICES_FAILED)); + } + +} + +/** + The function install TrEE protocol. + + @retval EFI_SUCCESS TrEE protocol is installed. + @retval other Some error occurs. +**/ +EFI_STATUS +InstallTrEE ( + VOID + ) +{ + EFI_STATUS Status; + EFI_HANDLE Handle; + + Handle = NULL; + Status = gBS->InstallMultipleProtocolInterfaces ( + &Handle, + &gEfiTrEEProtocolGuid, + &mTreeProtocol, + NULL + ); + return Status; +} + +/** + The driver's entry point. It publishes EFI TrEE Protocol. + + @param[in] ImageHandle The firmware allocated handle for the EFI image. + @param[in] SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The entry point is executed successfully. + @retval other Some error occurs when executing this entry point. +**/ +EFI_STATUS +EFIAPI +DriverEntry ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_EVENT Event; + VOID *Registration; + UINT32 MaxCommandSize; + UINT32 MaxResponseSize; + TPML_PCR_SELECTION Pcrs; + UINTN Index; + UINT32 TpmHashAlgorithmBitmap; + + mImageHandle = ImageHandle; + + if (CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceNoneGuid) || + CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceTpm12Guid)){ + DEBUG ((DEBUG_INFO, "No TPM2 instance required!\n")); + return EFI_UNSUPPORTED; + } + + if (GetFirstGuidHob (&gTpmErrorHobGuid) != NULL) { + DEBUG ((EFI_D_ERROR, "TPM2 error!\n")); + return EFI_DEVICE_ERROR; + } + + Status = Tpm2RequestUseTpm (); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "TPM2 not detected!\n")); + return Status; + } + + // + // Fill information + // + DEBUG ((EFI_D_INFO, "TrEE.ProtocolVersion - %02x.%02x\n", mTcgDxeData.BsCap.ProtocolVersion.Major, mTcgDxeData.BsCap.ProtocolVersion.Minor)); + DEBUG ((EFI_D_INFO, "TrEE.StructureVersion - %02x.%02x\n", mTcgDxeData.BsCap.StructureVersion.Major, mTcgDxeData.BsCap.StructureVersion.Minor)); + + Status = Tpm2GetCapabilityManufactureID (&mTcgDxeData.BsCap.ManufacturerID); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Tpm2GetCapabilityManufactureID fail!\n")); + } else { + DEBUG ((EFI_D_INFO, "Tpm2GetCapabilityManufactureID - %08x\n", mTcgDxeData.BsCap.ManufacturerID)); + } + + DEBUG_CODE ( + UINT32 FirmwareVersion1; + UINT32 FirmwareVersion2; + + Status = Tpm2GetCapabilityFirmwareVersion (&FirmwareVersion1, &FirmwareVersion2); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Tpm2GetCapabilityFirmwareVersion fail!\n")); + } else { + DEBUG ((EFI_D_INFO, "Tpm2GetCapabilityFirmwareVersion - %08x %08x\n", FirmwareVersion1, FirmwareVersion2)); + } + ); + + Status = Tpm2GetCapabilityMaxCommandResponseSize (&MaxCommandSize, &MaxResponseSize); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Tpm2GetCapabilityMaxCommandResponseSize fail!\n")); + } else { + mTcgDxeData.BsCap.MaxCommandSize = (UINT16)MaxCommandSize; + mTcgDxeData.BsCap.MaxResponseSize = (UINT16)MaxResponseSize; + DEBUG ((EFI_D_INFO, "Tpm2GetCapabilityMaxCommandResponseSize - %08x, %08x\n", MaxCommandSize, MaxResponseSize)); + } + + Status = Tpm2GetCapabilityPcrs (&Pcrs); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Tpm2GetCapabilityPcrs fail!\n")); + TpmHashAlgorithmBitmap = TREE_BOOT_HASH_ALG_SHA1; + } else { + DEBUG ((EFI_D_INFO, "Tpm2GetCapabilityPcrs Count - %08x\n", Pcrs.count)); + TpmHashAlgorithmBitmap = 0; + for (Index = 0; Index < Pcrs.count; Index++) { + DEBUG ((EFI_D_INFO, "hash - %x\n", Pcrs.pcrSelections[Index].hash)); + switch (Pcrs.pcrSelections[Index].hash) { + case TPM_ALG_SHA1: + TpmHashAlgorithmBitmap |= TREE_BOOT_HASH_ALG_SHA1; + break; + case TPM_ALG_SHA256: + TpmHashAlgorithmBitmap |= TREE_BOOT_HASH_ALG_SHA256; + break; + case TPM_ALG_SHA384: + TpmHashAlgorithmBitmap |= TREE_BOOT_HASH_ALG_SHA384; + break; + case TPM_ALG_SHA512: + TpmHashAlgorithmBitmap |= TREE_BOOT_HASH_ALG_SHA512; + break; + case TPM_ALG_SM3_256: + // TBD: Spec not define TREE_BOOT_HASH_ALG_SM3_256 yet + break; + } + } + } + DEBUG ((EFI_D_INFO, "TPM.HashAlgorithmBitmap - 0x%08x\n", TpmHashAlgorithmBitmap)); + + DEBUG ((EFI_D_INFO, "TrEE.SupportedEventLogs - 0x%08x\n", mTcgDxeData.BsCap.SupportedEventLogs)); + mTcgDxeData.BsCap.HashAlgorithmBitmap = TpmHashAlgorithmBitmap; + DEBUG ((EFI_D_INFO, "TrEE.HashAlgorithmBitmap - 0x%08x\n", mTcgDxeData.BsCap.HashAlgorithmBitmap)); + + if (mTcgDxeData.BsCap.TrEEPresentFlag) { + // + // Setup the log area and copy event log from hob list to it + // + Status = SetupEventLog (); + ASSERT_EFI_ERROR (Status); + + // + // Measure handoff tables, Boot#### variables etc. + // + Status = EfiCreateEventReadyToBootEx ( + TPL_CALLBACK, + OnReadyToBoot, + NULL, + &Event + ); + + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + OnExitBootServices, + NULL, + &gEfiEventExitBootServicesGuid, + &Event + ); + + // + // Measure Exit Boot Service failed + // + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + OnExitBootServicesFailed, + NULL, + &gEventExitBootServicesFailedGuid, + &Event + ); + + // + // Create event callback, because we need access variable on SecureBootPolicyVariable + // We should use VariableWriteArch instead of VariableArch, because Variable driver + // may update SecureBoot value based on last setting. + // + EfiCreateProtocolNotifyEvent (&gEfiVariableWriteArchProtocolGuid, TPL_CALLBACK, MeasureSecureBootPolicy, NULL, &Registration); + } + + // + // Install ACPI Table + // + EfiCreateProtocolNotifyEvent (&gEfiAcpiTableProtocolGuid, TPL_CALLBACK, InstallAcpiTable, NULL, &Registration); + + // + // Install TrEEProtocol + // + Status = InstallTrEE (); + DEBUG ((EFI_D_INFO, "InstallTrEE - %r\n", Status)); + + return Status; +} diff --git a/Core/SecurityPkg/Tcg/TrEEDxe/TrEEDxe.inf b/Core/SecurityPkg/Tcg/TrEEDxe/TrEEDxe.inf new file mode 100644 index 0000000000..2dd038aba3 --- /dev/null +++ b/Core/SecurityPkg/Tcg/TrEEDxe/TrEEDxe.inf @@ -0,0 +1,104 @@ +## @file +# Produces TrEE protocol and measure boot environment +# This module will produce TrEE protocol and measure boot environment. +# +# Caution: This module requires additional review when modified. +# This driver will have external input - PE/COFF image. +# This external input must be validated carefully to avoid security issue like +# buffer overflow, integer overflow. +# +# Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = TrEEDxe + MODULE_UNI_FILE = TrEEDxe.uni + FILE_GUID = 2A7946E3-1AB2-49a9-ACCB-C6275139C1A5 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = DriverEntry + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF +# + +[Sources] + TrEEDxe.c + MeasureBootPeCoff.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + SecurityPkg/SecurityPkg.dec + CryptoPkg/CryptoPkg.dec + +[LibraryClasses] + MemoryAllocationLib + BaseLib + UefiBootServicesTableLib + HobLib + UefiDriverEntryPoint + UefiRuntimeServicesTableLib + BaseMemoryLib + DebugLib + Tpm2CommandLib + PrintLib + UefiLib + Tpm2DeviceLib + HashLib + PerformanceLib + ReportStatusCodeLib + PeCoffLib + +[Guids] + ## SOMETIMES_CONSUMES ## Variable:L"SecureBoot" + ## SOMETIMES_CONSUMES ## Variable:L"PK" + ## SOMETIMES_CONSUMES ## Variable:L"KEK" + ## SOMETIMES_CONSUMES ## Variable:L"BootXXXX" + gEfiGlobalVariableGuid + + ## SOMETIMES_CONSUMES ## Variable:L"db" + ## SOMETIMES_CONSUMES ## Variable:L"dbx" + gEfiImageSecurityDatabaseGuid + + gTcgEventEntryHobGuid ## SOMETIMES_CONSUMES ## HOB + gTpmErrorHobGuid ## SOMETIMES_CONSUMES ## HOB + gEfiEventExitBootServicesGuid ## CONSUMES ## Event + gEventExitBootServicesFailedGuid ## SOMETIMES_CONSUMES ## Event + gEfiTpmDeviceInstanceNoneGuid ## SOMETIMES_CONSUMES ## GUID # TPM device identifier + gEfiTpmDeviceInstanceTpm12Guid ## SOMETIMES_CONSUMES ## GUID # TPM device identifier + +[Protocols] + gEfiTrEEProtocolGuid ## PRODUCES + gEfiAcpiTableProtocolGuid ## NOTIFY + gEfiMpServiceProtocolGuid ## SOMETIMES_CONSUMES + gEfiVariableWriteArchProtocolGuid ## NOTIFY + +[Pcd] + gEfiSecurityPkgTokenSpaceGuid.PcdTpmPlatformClass ## SOMETIMES_CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdFirmwareDebuggerInitialized ## SOMETIMES_CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdTpmInstanceGuid ## CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdTpmBaseAddress ## SOMETIMES_CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemId ## SOMETIMES_CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemTableId ## SOMETIMES_CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemRevision ## SOMETIMES_CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorId ## SOMETIMES_CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorRevision ## SOMETIMES_CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdStatusCodeSubClassTpmDevice ## SOMETIMES_CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdTcgLogAreaMinLen ## CONSUMES + +[Depex] + TRUE + +[UserExtensions.TianoCore."ExtraFiles"] + TrEEDxeExtra.uni diff --git a/Core/SecurityPkg/Tcg/TrEEDxe/TrEEDxe.uni b/Core/SecurityPkg/Tcg/TrEEDxe/TrEEDxe.uni new file mode 100644 index 0000000000..fd7292d3a8 --- /dev/null +++ b/Core/SecurityPkg/Tcg/TrEEDxe/TrEEDxe.uni @@ -0,0 +1,26 @@ +// /** @file +// Produces TrEE protocol and measure boot environment +// +// This module will produce TrEE protocol and measure boot environment. +// +// Caution: This module requires additional review when modified. +// This driver will have external input - PE/COFF image. +// This external input must be validated carefully to avoid security issue like +// buffer overflow, integer overflow. +// +// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.
+// +// This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// **/ + + +#string STR_MODULE_ABSTRACT #language en-US "Produces TrEE protocol and measure boot environment" + +#string STR_MODULE_DESCRIPTION #language en-US "This module will produce TrEE protocol and measure boot environment." + diff --git a/Core/SecurityPkg/Tcg/TrEEDxe/TrEEDxeExtra.uni b/Core/SecurityPkg/Tcg/TrEEDxe/TrEEDxeExtra.uni new file mode 100644 index 0000000000..2ca23ebab7 --- /dev/null +++ b/Core/SecurityPkg/Tcg/TrEEDxe/TrEEDxeExtra.uni @@ -0,0 +1,17 @@ +// /** @file +// TrEEDxe Localized Strings and Content +// +// Copyright (c) 2014, Intel Corporation. All rights reserved.
+// +// This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// **/ + +#string STR_PROPERTIES_MODULE_NAME +#language en-US +"TrEE (Trusted Execution Environment) DXE" \ No newline at end of file diff --git a/Core/SecurityPkg/Tcg/TrEEPei/TrEEPei.c b/Core/SecurityPkg/Tcg/TrEEPei/TrEEPei.c new file mode 100644 index 0000000000..b561245790 --- /dev/null +++ b/Core/SecurityPkg/Tcg/TrEEPei/TrEEPei.c @@ -0,0 +1,690 @@ +/** @file + Initialize TPM2 device and measure FVs before handing off control to DXE. + +Copyright (c) 2013 - 2017, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PERF_ID_TREE_PEI 0x3080 + +typedef struct { + EFI_GUID *EventGuid; + TREE_EVENT_LOG_FORMAT LogFormat; +} TREE_EVENT_INFO_STRUCT; + +TREE_EVENT_INFO_STRUCT mTreeEventInfo[] = { + {&gTcgEventEntryHobGuid, TREE_EVENT_LOG_FORMAT_TCG_1_2}, +}; + +BOOLEAN mImageInMemory = FALSE; +EFI_PEI_FILE_HANDLE mFileHandle; + +EFI_PEI_PPI_DESCRIPTOR mTpmInitializedPpiList = { + EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, + &gPeiTpmInitializedPpiGuid, + NULL +}; + +EFI_PEI_PPI_DESCRIPTOR mTpmInitializationDonePpiList = { + EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, + &gPeiTpmInitializationDonePpiGuid, + NULL +}; + +EFI_PLATFORM_FIRMWARE_BLOB *mMeasuredBaseFvInfo; +UINT32 mMeasuredBaseFvIndex = 0; + +EFI_PLATFORM_FIRMWARE_BLOB *mMeasuredChildFvInfo; +UINT32 mMeasuredChildFvIndex = 0; + +/** + Measure and record the Firmware Volum Information once FvInfoPPI install. + + @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation. + @param[in] NotifyDescriptor Address of the notification descriptor data structure. + @param[in] Ppi Address of the PPI that was installed. + + @retval EFI_SUCCESS The FV Info is measured and recorded to TPM. + @return Others Fail to measure FV. + +**/ +EFI_STATUS +EFIAPI +FirmwareVolmeInfoPpiNotifyCallback ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, + IN VOID *Ppi + ); + +/** + Record all measured Firmware Volum Information into a Guid Hob + + @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation. + @param[in] NotifyDescriptor Address of the notification descriptor data structure. + @param[in] Ppi Address of the PPI that was installed. + + @retval EFI_SUCCESS The FV Info is measured and recorded to TPM. + @return Others Fail to measure FV. + +**/ +EFI_STATUS +EFIAPI +EndofPeiSignalNotifyCallBack ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, + IN VOID *Ppi + ); + +EFI_PEI_NOTIFY_DESCRIPTOR mNotifyList[] = { + { + EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK, + &gEfiPeiFirmwareVolumeInfoPpiGuid, + FirmwareVolmeInfoPpiNotifyCallback + }, + { + EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK, + &gEfiPeiFirmwareVolumeInfo2PpiGuid, + FirmwareVolmeInfoPpiNotifyCallback + }, + { + (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gEfiEndOfPeiSignalPpiGuid, + EndofPeiSignalNotifyCallBack + } +}; + +EFI_PEI_FIRMWARE_VOLUME_INFO_MEASUREMENT_EXCLUDED_PPI *mMeasurementExcludedFvPpi; + +/** + Record all measured Firmware Volum Information into a Guid Hob + Guid Hob payload layout is + + UINT32 *************************** FIRMWARE_BLOB number + EFI_PLATFORM_FIRMWARE_BLOB******** BLOB Array + + @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation. + @param[in] NotifyDescriptor Address of the notification descriptor data structure. + @param[in] Ppi Address of the PPI that was installed. + + @retval EFI_SUCCESS The FV Info is measured and recorded to TPM. + @return Others Fail to measure FV. + +**/ +EFI_STATUS +EFIAPI +EndofPeiSignalNotifyCallBack ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, + IN VOID *Ppi + ) +{ + MEASURED_HOB_DATA *MeasuredHobData; + + MeasuredHobData = NULL; + + // + // Create a Guid hob to save all measured Fv + // + MeasuredHobData = BuildGuidHob( + &gMeasuredFvHobGuid, + sizeof(UINTN) + sizeof(EFI_PLATFORM_FIRMWARE_BLOB) * (mMeasuredBaseFvIndex + mMeasuredChildFvIndex) + ); + + if (MeasuredHobData != NULL){ + // + // Save measured FV info enty number + // + MeasuredHobData->Num = mMeasuredBaseFvIndex + mMeasuredChildFvIndex; + + // + // Save measured base Fv info + // + CopyMem (MeasuredHobData->MeasuredFvBuf, mMeasuredBaseFvInfo, sizeof(EFI_PLATFORM_FIRMWARE_BLOB) * (mMeasuredBaseFvIndex)); + + // + // Save measured child Fv info + // + CopyMem (&MeasuredHobData->MeasuredFvBuf[mMeasuredBaseFvIndex] , mMeasuredChildFvInfo, sizeof(EFI_PLATFORM_FIRMWARE_BLOB) * (mMeasuredChildFvIndex)); + } + + return EFI_SUCCESS; +} + +/** + Add a new entry to the Event Log. + + @param[in] DigestList A list of digest. + @param[in,out] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR data structure. + @param[in] NewEventData Pointer to the new event data. + + @retval EFI_SUCCESS The new event log entry was added. + @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event. +**/ +EFI_STATUS +LogHashEvent ( + IN TPML_DIGEST_VALUES *DigestList, + IN OUT TCG_PCR_EVENT_HDR *NewEventHdr, + IN UINT8 *NewEventData + ) +{ + VOID *HobData; + EFI_STATUS Status; + UINTN Index; + EFI_STATUS RetStatus; + + RetStatus = EFI_SUCCESS; + for (Index = 0; Index < sizeof(mTreeEventInfo)/sizeof(mTreeEventInfo[0]); Index++) { + DEBUG ((EFI_D_INFO, " LogFormat - 0x%08x\n", mTreeEventInfo[Index].LogFormat)); + switch (mTreeEventInfo[Index].LogFormat) { + case TREE_EVENT_LOG_FORMAT_TCG_1_2: + Status = GetDigestFromDigestList (TPM_ALG_SHA1, DigestList, &NewEventHdr->Digest); + if (!EFI_ERROR (Status)) { + HobData = BuildGuidHob ( + &gTcgEventEntryHobGuid, + sizeof (*NewEventHdr) + NewEventHdr->EventSize + ); + if (HobData == NULL) { + RetStatus = EFI_OUT_OF_RESOURCES; + break; + } + + CopyMem (HobData, NewEventHdr, sizeof (*NewEventHdr)); + HobData = (VOID *) ((UINT8*)HobData + sizeof (*NewEventHdr)); + CopyMem (HobData, NewEventData, NewEventHdr->EventSize); + } + break; + } + } + + return RetStatus; +} + +/** + Do a hash operation on a data buffer, extend a specific TPM PCR with the hash result, + and build a GUIDed HOB recording the event which will be passed to the DXE phase and + added into the Event Log. + + @param[in] Flags Bitmap providing additional information. + @param[in] HashData Physical address of the start of the data buffer + to be hashed, extended, and logged. + @param[in] HashDataLen The length, in bytes, of the buffer referenced by HashData. + @param[in] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR data structure. + @param[in] NewEventData Pointer to the new event data. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event. + @retval EFI_DEVICE_ERROR The command was unsuccessful. + +**/ +EFI_STATUS +HashLogExtendEvent ( + IN UINT64 Flags, + IN UINT8 *HashData, + IN UINTN HashDataLen, + IN TCG_PCR_EVENT_HDR *NewEventHdr, + IN UINT8 *NewEventData + ) +{ + EFI_STATUS Status; + TPML_DIGEST_VALUES DigestList; + + if (GetFirstGuidHob (&gTpmErrorHobGuid) != NULL) { + return EFI_DEVICE_ERROR; + } + + Status = HashAndExtend ( + NewEventHdr->PCRIndex, + HashData, + HashDataLen, + &DigestList + ); + if (!EFI_ERROR (Status)) { + if ((Flags & TREE_EXTEND_ONLY) == 0) { + Status = LogHashEvent (&DigestList, NewEventHdr, NewEventData); + } + } + + if (Status == EFI_DEVICE_ERROR) { + DEBUG ((EFI_D_ERROR, "HashLogExtendEvent - %r. Disable TPM.\n", Status)); + BuildGuidHob (&gTpmErrorHobGuid,0); + REPORT_STATUS_CODE ( + EFI_ERROR_CODE | EFI_ERROR_MINOR, + (PcdGet32 (PcdStatusCodeSubClassTpmDevice) | EFI_P_EC_INTERFACE_ERROR) + ); + } + + return Status; +} + +/** + Measure CRTM version. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event. + @retval EFI_DEVICE_ERROR The command was unsuccessful. + +**/ +EFI_STATUS +MeasureCRTMVersion ( + VOID + ) +{ + TCG_PCR_EVENT_HDR TcgEventHdr; + + // + // Use FirmwareVersion string to represent CRTM version. + // OEMs should get real CRTM version string and measure it. + // + + TcgEventHdr.PCRIndex = 0; + TcgEventHdr.EventType = EV_S_CRTM_VERSION; + TcgEventHdr.EventSize = (UINT32) StrSize((CHAR16*)PcdGetPtr (PcdFirmwareVersionString)); + + return HashLogExtendEvent ( + 0, + (UINT8*)PcdGetPtr (PcdFirmwareVersionString), + TcgEventHdr.EventSize, + &TcgEventHdr, + (UINT8*)PcdGetPtr (PcdFirmwareVersionString) + ); +} + +/** + Measure FV image. + Add it into the measured FV list after the FV is measured successfully. + + @param[in] FvBase Base address of FV image. + @param[in] FvLength Length of FV image. + + @retval EFI_SUCCESS Fv image is measured successfully + or it has been already measured. + @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event. + @retval EFI_DEVICE_ERROR The command was unsuccessful. + +**/ +EFI_STATUS +MeasureFvImage ( + IN EFI_PHYSICAL_ADDRESS FvBase, + IN UINT64 FvLength + ) +{ + UINT32 Index; + EFI_STATUS Status; + EFI_PLATFORM_FIRMWARE_BLOB FvBlob; + TCG_PCR_EVENT_HDR TcgEventHdr; + + // + // Check if it is in Excluded FV list + // + if (mMeasurementExcludedFvPpi != NULL) { + for (Index = 0; Index < mMeasurementExcludedFvPpi->Count; Index ++) { + if (mMeasurementExcludedFvPpi->Fv[Index].FvBase == FvBase) { + DEBUG ((DEBUG_INFO, "The FV which is excluded by TrEEPei starts at: 0x%x\n", FvBase)); + DEBUG ((DEBUG_INFO, "The FV which is excluded by TrEEPei has the size: 0x%x\n", FvLength)); + return EFI_SUCCESS; + } + } + } + + // + // Check whether FV is in the measured FV list. + // + for (Index = 0; Index < mMeasuredBaseFvIndex; Index ++) { + if (mMeasuredBaseFvInfo[Index].BlobBase == FvBase) { + return EFI_SUCCESS; + } + } + + // + // Measure and record the FV to the TPM + // + FvBlob.BlobBase = FvBase; + FvBlob.BlobLength = FvLength; + + DEBUG ((DEBUG_INFO, "The FV which is measured by TrEEPei starts at: 0x%x\n", FvBlob.BlobBase)); + DEBUG ((DEBUG_INFO, "The FV which is measured by TrEEPei has the size: 0x%x\n", FvBlob.BlobLength)); + + TcgEventHdr.PCRIndex = 0; + TcgEventHdr.EventType = EV_EFI_PLATFORM_FIRMWARE_BLOB; + TcgEventHdr.EventSize = sizeof (FvBlob); + + Status = HashLogExtendEvent ( + 0, + (UINT8*) (UINTN) FvBlob.BlobBase, + (UINTN) FvBlob.BlobLength, + &TcgEventHdr, + (UINT8*) &FvBlob + ); + + // + // Add new FV into the measured FV list. + // + ASSERT (mMeasuredBaseFvIndex < PcdGet32 (PcdPeiCoreMaxFvSupported)); + if (mMeasuredBaseFvIndex < PcdGet32 (PcdPeiCoreMaxFvSupported)) { + mMeasuredBaseFvInfo[mMeasuredBaseFvIndex].BlobBase = FvBase; + mMeasuredBaseFvInfo[mMeasuredBaseFvIndex].BlobLength = FvLength; + mMeasuredBaseFvIndex++; + } + + return Status; +} + +/** + Measure main BIOS. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event. + @retval EFI_DEVICE_ERROR The command was unsuccessful. + +**/ +EFI_STATUS +MeasureMainBios ( + VOID + ) +{ + EFI_STATUS Status; + UINT32 FvInstances; + EFI_PEI_FV_HANDLE VolumeHandle; + EFI_FV_INFO VolumeInfo; + EFI_PEI_FIRMWARE_VOLUME_PPI *FvPpi; + + PERF_START_EX (mFileHandle, "EventRec", "TrEEPei", 0, PERF_ID_TREE_PEI); + FvInstances = 0; + while (TRUE) { + // + // Traverse all firmware volume instances of Static Core Root of Trust for Measurement + // (S-CRTM), this firmware volume measure policy can be modified/enhanced by special + // platform for special CRTM TPM measuring. + // + Status = PeiServicesFfsFindNextVolume (FvInstances, &VolumeHandle); + if (EFI_ERROR (Status)) { + break; + } + + // + // Measure and record the firmware volume that is dispatched by PeiCore + // + Status = PeiServicesFfsGetVolumeInfo (VolumeHandle, &VolumeInfo); + ASSERT_EFI_ERROR (Status); + // + // Locate the corresponding FV_PPI according to founded FV's format guid + // + Status = PeiServicesLocatePpi ( + &VolumeInfo.FvFormat, + 0, + NULL, + (VOID**)&FvPpi + ); + if (!EFI_ERROR (Status)) { + MeasureFvImage ((EFI_PHYSICAL_ADDRESS) (UINTN) VolumeInfo.FvStart, VolumeInfo.FvSize); + } + + FvInstances++; + } + PERF_END_EX (mFileHandle, "EventRec", "TrEEPei", 0, PERF_ID_TREE_PEI + 1); + + return EFI_SUCCESS; +} + +/** + Measure and record the Firmware Volum Information once FvInfoPPI install. + + @param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation. + @param[in] NotifyDescriptor Address of the notification descriptor data structure. + @param[in] Ppi Address of the PPI that was installed. + + @retval EFI_SUCCESS The FV Info is measured and recorded to TPM. + @return Others Fail to measure FV. + +**/ +EFI_STATUS +EFIAPI +FirmwareVolmeInfoPpiNotifyCallback ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, + IN VOID *Ppi + ) +{ + EFI_PEI_FIRMWARE_VOLUME_INFO_PPI *Fv; + EFI_STATUS Status; + EFI_PEI_FIRMWARE_VOLUME_PPI *FvPpi; + UINTN Index; + + Fv = (EFI_PEI_FIRMWARE_VOLUME_INFO_PPI *) Ppi; + + // + // The PEI Core can not dispatch or load files from memory mapped FVs that do not support FvPpi. + // + Status = PeiServicesLocatePpi ( + &Fv->FvFormat, + 0, + NULL, + (VOID**)&FvPpi + ); + if (EFI_ERROR (Status)) { + return EFI_SUCCESS; + } + + // + // This is an FV from an FFS file, and the parent FV must have already been measured, + // No need to measure twice, so just record the FV and return + // + if (Fv->ParentFvName != NULL || Fv->ParentFileName != NULL ) { + + ASSERT (mMeasuredChildFvIndex < PcdGet32 (PcdPeiCoreMaxFvSupported)); + if (mMeasuredChildFvIndex < PcdGet32 (PcdPeiCoreMaxFvSupported)) { + // + // Check whether FV is in the measured child FV list. + // + for (Index = 0; Index < mMeasuredChildFvIndex; Index++) { + if (mMeasuredChildFvInfo[Index].BlobBase == (EFI_PHYSICAL_ADDRESS) (UINTN) Fv->FvInfo) { + return EFI_SUCCESS; + } + } + mMeasuredChildFvInfo[mMeasuredChildFvIndex].BlobBase = (EFI_PHYSICAL_ADDRESS) (UINTN) Fv->FvInfo; + mMeasuredChildFvInfo[mMeasuredChildFvIndex].BlobLength = Fv->FvInfoSize; + mMeasuredChildFvIndex++; + } + return EFI_SUCCESS; + } + + return MeasureFvImage ((EFI_PHYSICAL_ADDRESS) (UINTN) Fv->FvInfo, Fv->FvInfoSize); +} + +/** + Do measurement after memory is ready. + + @param[in] PeiServices Describes the list of possible PEI Services. + + @retval EFI_SUCCESS Operation completed successfully. + @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event. + @retval EFI_DEVICE_ERROR The command was unsuccessful. + +**/ +EFI_STATUS +PeimEntryMP ( + IN EFI_PEI_SERVICES **PeiServices + ) +{ + EFI_STATUS Status; + + Status = PeiServicesLocatePpi ( + &gEfiPeiFirmwareVolumeInfoMeasurementExcludedPpiGuid, + 0, + NULL, + (VOID**)&mMeasurementExcludedFvPpi + ); + // Do not check status, because it is optional + + mMeasuredBaseFvInfo = (EFI_PLATFORM_FIRMWARE_BLOB *) AllocateZeroPool (sizeof (EFI_PLATFORM_FIRMWARE_BLOB) * PcdGet32 (PcdPeiCoreMaxFvSupported)); + ASSERT (mMeasuredBaseFvInfo != NULL); + mMeasuredChildFvInfo = (EFI_PLATFORM_FIRMWARE_BLOB *) AllocateZeroPool (sizeof (EFI_PLATFORM_FIRMWARE_BLOB) * PcdGet32 (PcdPeiCoreMaxFvSupported)); + ASSERT (mMeasuredChildFvInfo != NULL); + + if (PcdGet8 (PcdTpm2ScrtmPolicy) == 1) { + Status = MeasureCRTMVersion (); + } + + Status = MeasureMainBios (); + + // + // Post callbacks: + // for the FvInfoPpi services to measure and record + // the additional Fvs to TPM + // + Status = PeiServicesNotifyPpi (&mNotifyList[0]); + ASSERT_EFI_ERROR (Status); + + return Status; +} + +/** + Entry point of this module. + + @param[in] FileHandle Handle of the file being invoked. + @param[in] PeiServices Describes the list of possible PEI Services. + + @return Status. + +**/ +EFI_STATUS +EFIAPI +PeimEntryMA ( + IN EFI_PEI_FILE_HANDLE FileHandle, + IN CONST EFI_PEI_SERVICES **PeiServices + ) +{ + EFI_STATUS Status; + EFI_STATUS Status2; + EFI_BOOT_MODE BootMode; + + if (CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceNoneGuid) || + CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceTpm12Guid)){ + DEBUG ((DEBUG_INFO, "No TPM2 instance required!\n")); + return EFI_UNSUPPORTED; + } + + if (GetFirstGuidHob (&gTpmErrorHobGuid) != NULL) { + DEBUG ((EFI_D_ERROR, "TPM2 error!\n")); + return EFI_DEVICE_ERROR; + } + + Status = PeiServicesGetBootMode (&BootMode); + ASSERT_EFI_ERROR (Status); + + // + // In S3 path, skip shadow logic. no measurement is required + // + if (BootMode != BOOT_ON_S3_RESUME) { + Status = (**PeiServices).RegisterForShadow(FileHandle); + if (Status == EFI_ALREADY_STARTED) { + mImageInMemory = TRUE; + mFileHandle = FileHandle; + } else if (Status == EFI_NOT_FOUND) { + ASSERT_EFI_ERROR (Status); + } + } + + if (!mImageInMemory) { + // + // Initialize TPM device + // + Status = Tpm2RequestUseTpm (); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "TPM2 not detected!\n")); + goto Done; + } + + if (PcdGet8 (PcdTpm2InitializationPolicy) == 1) { + if (BootMode == BOOT_ON_S3_RESUME) { + Status = Tpm2Startup (TPM_SU_STATE); + if (EFI_ERROR (Status) ) { + Status = Tpm2Startup (TPM_SU_CLEAR); + } + } else { + Status = Tpm2Startup (TPM_SU_CLEAR); + } + if (EFI_ERROR (Status) ) { + goto Done; + } + } + + // + // TpmSelfTest is optional on S3 path, skip it to save S3 time + // + if (BootMode != BOOT_ON_S3_RESUME) { + if (PcdGet8 (PcdTpm2SelfTestPolicy) == 1) { + Status = Tpm2SelfTest (NO); + if (EFI_ERROR (Status)) { + goto Done; + } + } + } + + // + // Only intall TpmInitializedPpi on success + // + Status = PeiServicesInstallPpi (&mTpmInitializedPpiList); + ASSERT_EFI_ERROR (Status); + } + + if (mImageInMemory) { + Status = PeimEntryMP ((EFI_PEI_SERVICES**)PeiServices); + return Status; + } + +Done: + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "TPM2 error! Build Hob\n")); + BuildGuidHob (&gTpmErrorHobGuid,0); + REPORT_STATUS_CODE ( + EFI_ERROR_CODE | EFI_ERROR_MINOR, + (PcdGet32 (PcdStatusCodeSubClassTpmDevice) | EFI_P_EC_INTERFACE_ERROR) + ); + } + // + // Always intall TpmInitializationDonePpi no matter success or fail. + // Other driver can know TPM initialization state by TpmInitializedPpi. + // + Status2 = PeiServicesInstallPpi (&mTpmInitializationDonePpiList); + ASSERT_EFI_ERROR (Status2); + + return Status; +} diff --git a/Core/SecurityPkg/Tcg/TrEEPei/TrEEPei.inf b/Core/SecurityPkg/Tcg/TrEEPei/TrEEPei.inf new file mode 100644 index 0000000000..61a8cd0824 --- /dev/null +++ b/Core/SecurityPkg/Tcg/TrEEPei/TrEEPei.inf @@ -0,0 +1,86 @@ +## @file +# Initializes TPM 2.0 device and measure FVs in PEI phase +# +# This module will initialize TPM device, measure reported FVs and BIOS version. +# +# Copyright (c) 2013 - 2015, Intel Corporation. All rights reserved.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = TrEEPei + MODULE_UNI_FILE = TrEEPei.uni + FILE_GUID = CA5A1928-6523-409d-A9FE-5DCC87387222 + MODULE_TYPE = PEIM + VERSION_STRING = 1.0 + ENTRY_POINT = PeimEntryMA + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# +# [BootMode] +# S3_RESUME ## SOMETIMES_CONSUMES +# + +[Sources] + TrEEPei.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + HobLib + PeimEntryPoint + PeiServicesLib + BaseMemoryLib + DebugLib + Tpm2CommandLib + PeiServicesTablePointerLib + Tpm2DeviceLib + HashLib + PerformanceLib + MemoryAllocationLib + ReportStatusCodeLib + +[Guids] + gTcgEventEntryHobGuid ## PRODUCES ## HOB + gTpmErrorHobGuid ## SOMETIMES_PRODUCES ## HOB + gMeasuredFvHobGuid ## PRODUCES ## HOB + gEfiTpmDeviceInstanceNoneGuid ## SOMETIMES_PRODUCES ## GUID # TPM device identifier + gEfiTpmDeviceInstanceTpm12Guid ## SOMETIMES_PRODUCES ## GUID # TPM device identifier + +[Ppis] + gEfiPeiFirmwareVolumeInfoPpiGuid ## SOMETIMES_CONSUMES ## NOTIFY + gEfiPeiFirmwareVolumeInfo2PpiGuid ## SOMETIMES_CONSUMES ## NOTIFY + gEfiPeiFirmwareVolumeInfoMeasurementExcludedPpiGuid ## SOMETIMES_CONSUMES + gPeiTpmInitializedPpiGuid ## SOMETIMES_PRODUCES + gPeiTpmInitializationDonePpiGuid ## PRODUCES + gEfiEndOfPeiSignalPpiGuid ## SOMETIMES_CONSUMES ## NOTIFY + +[Pcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdFirmwareVersionString ## SOMETIMES_CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdTpmInstanceGuid ## CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdTpm2InitializationPolicy ## CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdTpm2SelfTestPolicy ## SOMETIMES_CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdTpm2ScrtmPolicy ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdPeiCoreMaxFvSupported ## CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdStatusCodeSubClassTpmDevice ## SOMETIMES_CONSUMES + +[Depex] + gEfiPeiMasterBootModePpiGuid AND + gEfiPeiReadOnlyVariable2PpiGuid AND + gEfiTpmDeviceSelectedGuid + +[UserExtensions.TianoCore."ExtraFiles"] + TrEEPeiExtra.uni \ No newline at end of file diff --git a/Core/SecurityPkg/Tcg/TrEEPei/TrEEPei.uni b/Core/SecurityPkg/Tcg/TrEEPei/TrEEPei.uni new file mode 100644 index 0000000000..619484abfc --- /dev/null +++ b/Core/SecurityPkg/Tcg/TrEEPei/TrEEPei.uni @@ -0,0 +1,21 @@ +// /** @file +// Initializes TPM 2.0 device and measure FVs in PEI phase +// +// This module will initialize TPM device, measure reported FVs and BIOS version. +// +// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.
+// +// This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// **/ + + +#string STR_MODULE_ABSTRACT #language en-US "Initializes TPM 2.0 device and measure FVs in PEI phase" + +#string STR_MODULE_DESCRIPTION #language en-US "This module will initialize TPM device, measure reported FVs and BIOS version." + diff --git a/Core/SecurityPkg/Tcg/TrEEPei/TrEEPeiExtra.uni b/Core/SecurityPkg/Tcg/TrEEPei/TrEEPeiExtra.uni new file mode 100644 index 0000000000..b6743ab953 --- /dev/null +++ b/Core/SecurityPkg/Tcg/TrEEPei/TrEEPeiExtra.uni @@ -0,0 +1,19 @@ +// /** @file +// TrEEPei Localized Strings and Content +// +// Copyright (c) 2014, Intel Corporation. All rights reserved.
+// +// This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// **/ + +#string STR_PROPERTIES_MODULE_NAME +#language en-US +"TrEE (Trusted Execution Environment) PEI" + + diff --git a/Core/SecurityPkg/Tcg/TrEESmm/Tpm.asl b/Core/SecurityPkg/Tcg/TrEESmm/Tpm.asl new file mode 100644 index 0000000000..0f6b94a23d --- /dev/null +++ b/Core/SecurityPkg/Tcg/TrEESmm/Tpm.asl @@ -0,0 +1,354 @@ +/** @file + The TPM2 definition block in ACPI table for TrEE physical presence + and MemoryClear. + +Copyright (c) 2013 - 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +DefinitionBlock ( + "Tpm.aml", + "SSDT", + 2, + "INTEL ", + "Tpm2Tabl", + 0x1000 + ) +{ + Scope (\_SB) + { + Device (TPM) + { + // + // TREE + // + Name (_HID, "MSFT0101") + + // + // Readable name of this device, don't know if this way is correct yet + // + Name (_STR, Unicode ("TPM 2.0 Device")) + + // + // Return the resource consumed by TPM device + // + Name (_CRS, ResourceTemplate () { + Memory32Fixed (ReadWrite, 0xfed40000, 0x5000) + }) + + // + // Operational region for Smi port access + // + OperationRegion (SMIP, SystemIO, 0xB2, 1) + Field (SMIP, ByteAcc, NoLock, Preserve) + { + IOB2, 8 + } + + // + // Operational region for TPM access + // + OperationRegion (TPMR, SystemMemory, 0xfed40000, 0x5000) + Field (TPMR, AnyAcc, NoLock, Preserve) + { + ACC0, 8, + } + + // + // Operational region for TPM support, TPM Physical Presence and TPM Memory Clear + // Region Offset 0xFFFF0000 and Length 0xF0 will be fixed in C code. + // + OperationRegion (TNVS, SystemMemory, 0xFFFF0000, 0xF0) + Field (TNVS, AnyAcc, NoLock, Preserve) + { + PPIN, 8, // Software SMI for Physical Presence Interface + PPIP, 32, // Used for save physical presence paramter + PPRP, 32, // Physical Presence request operation response + PPRQ, 32, // Physical Presence request operation + LPPR, 32, // Last Physical Presence request operation + FRET, 32, // Physical Presence function return code + MCIN, 8, // Software SMI for Memory Clear Interface + MCIP, 32, // Used for save the Mor paramter + MORD, 32, // Memory Overwrite Request Data + MRET, 32 // Memory Overwrite function return code + } + + Method (PTS, 1, Serialized) + { + // + // Detect Sx state for MOR, only S4, S5 need to handle + // + If (LAnd (LLess (Arg0, 6), LGreater (Arg0, 3))) + { + // + // Bit4 -- DisableAutoDetect. 0 -- Firmware MAY autodetect. + // + If (LNot (And (MORD, 0x10))) + { + // + // Triggle the SMI through ACPI _PTS method. + // + Store (0x02, MCIP) + + // + // Triggle the SMI interrupt + // + Store (MCIN, IOB2) + } + } + Return (0) + } + + Method (_STA, 0) + { + if (LEqual (ACC0, 0xff)) + { + Return (0) + } + Return (0x0f) + } + + // + // TCG Hardware Information + // + Method (HINF, 3, Serialized, 0, {BuffObj, PkgObj}, {UnknownObj, UnknownObj, UnknownObj}) // IntObj, IntObj, PkgObj + { + // + // Switch by function index + // + Switch (ToInteger(Arg1)) + { + Case (0) + { + // + // Standard query + // + Return (Buffer () {0x03}) + } + Case (1) + { + // + // Return failure if no TPM present + // + Name(TPMV, Package () {0x01, Package () {0x2, 0x0}}) + if (LEqual (_STA (), 0x00)) + { + Return (Package () {0x00}) + } + + // + // Return TPM version + // + Return (TPMV) + } + Default {BreakPoint} + } + Return (Buffer () {0}) + } + + Name(TPM2, Package (0x02){ + Zero, + Zero + }) + + Name(TPM3, Package (0x03){ + Zero, + Zero, + Zero + }) + + // + // TCG Physical Presence Interface + // + Method (TPPI, 3, Serialized, 0, {BuffObj, PkgObj, IntObj, StrObj}, {UnknownObj, UnknownObj, UnknownObj}) // IntObj, IntObj, PkgObj + { + // + // Switch by function index + // + Switch (ToInteger(Arg1)) + { + Case (0) + { + // + // Standard query, supports function 1-8 + // + Return (Buffer () {0xFF, 0x01}) + } + Case (1) + { + // + // a) Get Physical Presence Interface Version + // + Return ("1.2") + } + Case (2) + { + // + // b) Submit TPM Operation Request to Pre-OS Environment + // + + Store (DerefOf (Index (Arg2, 0x00)), PPRQ) + Store (0x02, PPIP) + + // + // Triggle the SMI interrupt + // + Store (PPIN, IOB2) + Return (FRET) + + + } + Case (3) + { + // + // c) Get Pending TPM Operation Requested By the OS + // + + Store (PPRQ, Index (TPM2, 0x01)) + Return (TPM2) + } + Case (4) + { + // + // d) Get Platform-Specific Action to Transition to Pre-OS Environment + // + Return (2) + } + Case (5) + { + // + // e) Return TPM Operation Response to OS Environment + // + Store (0x05, PPIP) + + // + // Triggle the SMI interrupt + // + Store (PPIN, IOB2) + + Store (LPPR, Index (TPM3, 0x01)) + Store (PPRP, Index (TPM3, 0x02)) + + Return (TPM3) + } + Case (6) + { + + // + // f) Submit preferred user language (Not implemented) + // + + Return (3) + + } + Case (7) + { + // + // g) Submit TPM Operation Request to Pre-OS Environment 2 + // + Store (7, PPIP) + Store (DerefOf (Index (Arg2, 0x00)), PPRQ) + + // + // Triggle the SMI interrupt + // + Store (PPIN, IOB2) + Return (FRET) + } + Case (8) + { + // + // e) Get User Confirmation Status for Operation + // + Store (8, PPIP) + Store (DerefOf (Index (Arg2, 0x00)), PPRQ) + + // + // Triggle the SMI interrupt + // + Store (PPIN, IOB2) + + Return (FRET) + } + + Default {BreakPoint} + } + Return (1) + } + + Method (TMCI, 3, Serialized, 0, IntObj, {UnknownObj, UnknownObj, UnknownObj}) // IntObj, IntObj, PkgObj + { + // + // Switch by function index + // + Switch (ToInteger (Arg1)) + { + Case (0) + { + // + // Standard query, supports function 1-1 + // + Return (Buffer () {0x03}) + } + Case (1) + { + // + // Save the Operation Value of the Request to MORD (reserved memory) + // + Store (DerefOf (Index (Arg2, 0x00)), MORD) + + // + // Triggle the SMI through ACPI _DSM method. + // + Store (0x01, MCIP) + + // + // Triggle the SMI interrupt + // + Store (MCIN, IOB2) + Return (MRET) + } + Default {BreakPoint} + } + Return (1) + } + + Method (_DSM, 4, Serialized, 0, UnknownObj, {BuffObj, IntObj, IntObj, PkgObj}) + { + + // + // TCG Hardware Information + // + If(LEqual(Arg0, ToUUID ("cf8e16a5-c1e8-4e25-b712-4f54a96702c8"))) + { + Return (HINF (Arg1, Arg2, Arg3)) + } + + // + // TCG Physical Presence Interface + // + If(LEqual(Arg0, ToUUID ("3dddfaa6-361b-4eb4-a424-8d10089d1653"))) + { + Return (TPPI (Arg1, Arg2, Arg3)) + } + + // + // TCG Memory Clear Interface + // + If(LEqual(Arg0, ToUUID ("376054ed-cc13-4675-901c-4756d7f2d45d"))) + { + Return (TMCI (Arg1, Arg2, Arg3)) + } + + Return (Buffer () {0}) + } + } + } +} diff --git a/Core/SecurityPkg/Tcg/TrEESmm/TrEESmm.c b/Core/SecurityPkg/Tcg/TrEESmm/TrEESmm.c new file mode 100644 index 0000000000..1683dedc8a --- /dev/null +++ b/Core/SecurityPkg/Tcg/TrEESmm/TrEESmm.c @@ -0,0 +1,521 @@ +/** @file + It updates TPM2 items in ACPI table and registers SMI2 callback + functions for TrEE physical presence, ClearMemory, and sample + for dTPM StartMethod. + + Caution: This module requires additional review when modified. + This driver will have external input - variable and ACPINvs data in SMM mode. + This external input must be validated carefully to avoid security issue. + + PhysicalPresenceCallback() and MemoryClearCallback() will receive untrusted input and do some check. + +Copyright (c) 2013 - 2017, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include "TrEESmm.h" + +EFI_TPM2_ACPI_TABLE mTpm2AcpiTemplate = { + { + EFI_ACPI_5_0_TRUSTED_COMPUTING_PLATFORM_2_TABLE_SIGNATURE, + sizeof (mTpm2AcpiTemplate), + EFI_TPM2_ACPI_TABLE_REVISION_3, + // + // Compiler initializes the remaining bytes to 0 + // These fields should be filled in in production + // + }, + 0, // Flags + 0, // Control Area + EFI_TPM2_ACPI_TABLE_START_METHOD_TIS, // StartMethod +}; + +EFI_SMM_VARIABLE_PROTOCOL *mSmmVariable; +TCG_NVS *mTcgNvs; + +/** + Software SMI callback for TPM physical presence which is called from ACPI method. + + Caution: This function may receive untrusted input. + Variable and ACPINvs are external input, so this function will validate + its data structure to be valid value. + + @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister(). + @param[in] Context Points to an optional handler context which was specified when the + handler was registered. + @param[in, out] CommBuffer A pointer to a collection of data in memory that will + be conveyed from a non-SMM environment into an SMM environment. + @param[in, out] CommBufferSize The size of the CommBuffer. + + @retval EFI_SUCCESS The interrupt was handled successfully. + +**/ +EFI_STATUS +EFIAPI +PhysicalPresenceCallback ( + IN EFI_HANDLE DispatchHandle, + IN CONST VOID *Context, + IN OUT VOID *CommBuffer, + IN OUT UINTN *CommBufferSize + ) +{ + EFI_STATUS Status; + UINTN DataSize; + EFI_TREE_PHYSICAL_PRESENCE PpData; + EFI_TREE_PHYSICAL_PRESENCE_FLAGS Flags; + BOOLEAN RequestConfirmed; + + // + // Get the Physical Presence variable + // + DataSize = sizeof (EFI_TREE_PHYSICAL_PRESENCE); + Status = mSmmVariable->SmmGetVariable ( + TREE_PHYSICAL_PRESENCE_VARIABLE, + &gEfiTrEEPhysicalPresenceGuid, + NULL, + &DataSize, + &PpData + ); + + DEBUG ((EFI_D_INFO, "[TPM2] PP callback, Parameter = %x, Request = %x\n", mTcgNvs->PhysicalPresence.Parameter, mTcgNvs->PhysicalPresence.Request)); + + if (mTcgNvs->PhysicalPresence.Parameter == ACPI_FUNCTION_RETURN_REQUEST_RESPONSE_TO_OS) { + if (EFI_ERROR (Status)) { + mTcgNvs->PhysicalPresence.ReturnCode = PP_RETURN_TPM_OPERATION_RESPONSE_FAILURE; + mTcgNvs->PhysicalPresence.LastRequest = 0; + mTcgNvs->PhysicalPresence.Response = 0; + DEBUG ((EFI_D_ERROR, "[TPM2] Get PP variable failure! Status = %r\n", Status)); + return EFI_SUCCESS; + } + mTcgNvs->PhysicalPresence.ReturnCode = PP_RETURN_TPM_OPERATION_RESPONSE_SUCCESS; + mTcgNvs->PhysicalPresence.LastRequest = PpData.LastPPRequest; + mTcgNvs->PhysicalPresence.Response = PpData.PPResponse; + } else if ((mTcgNvs->PhysicalPresence.Parameter == ACPI_FUNCTION_SUBMIT_REQUEST_TO_BIOS) + || (mTcgNvs->PhysicalPresence.Parameter == ACPI_FUNCTION_SUBMIT_REQUEST_TO_BIOS_2)) { + if (EFI_ERROR (Status)) { + mTcgNvs->PhysicalPresence.ReturnCode = TREE_PP_SUBMIT_REQUEST_TO_PREOS_GENERAL_FAILURE; + DEBUG ((EFI_D_ERROR, "[TPM2] Get PP variable failure! Status = %r\n", Status)); + return EFI_SUCCESS; + } + if ((mTcgNvs->PhysicalPresence.Request > TREE_PHYSICAL_PRESENCE_NO_ACTION_MAX) && + (mTcgNvs->PhysicalPresence.Request < TREE_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION) ) { + // + // This command requires UI to prompt user for Auth data. + // + mTcgNvs->PhysicalPresence.ReturnCode = TREE_PP_SUBMIT_REQUEST_TO_PREOS_NOT_IMPLEMENTED; + return EFI_SUCCESS; + } + + if (PpData.PPRequest != mTcgNvs->PhysicalPresence.Request) { + PpData.PPRequest = (UINT8) mTcgNvs->PhysicalPresence.Request; + DataSize = sizeof (EFI_TREE_PHYSICAL_PRESENCE); + Status = mSmmVariable->SmmSetVariable ( + TREE_PHYSICAL_PRESENCE_VARIABLE, + &gEfiTrEEPhysicalPresenceGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + DataSize, + &PpData + ); + } + + if (EFI_ERROR (Status)) { + mTcgNvs->PhysicalPresence.ReturnCode = TREE_PP_SUBMIT_REQUEST_TO_PREOS_GENERAL_FAILURE; + DEBUG ((EFI_D_ERROR, "[TPM2] Set PP variable failure! Status = %r\n", Status)); + return EFI_SUCCESS; + } + mTcgNvs->PhysicalPresence.ReturnCode = TREE_PP_SUBMIT_REQUEST_TO_PREOS_SUCCESS; + + if (mTcgNvs->PhysicalPresence.Request >= TREE_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION) { + DataSize = sizeof (EFI_TREE_PHYSICAL_PRESENCE_FLAGS); + Status = mSmmVariable->SmmGetVariable ( + TREE_PHYSICAL_PRESENCE_FLAGS_VARIABLE, + &gEfiTrEEPhysicalPresenceGuid, + NULL, + &DataSize, + &Flags + ); + if (EFI_ERROR (Status)) { + Flags.PPFlags = 0; + } + mTcgNvs->PhysicalPresence.ReturnCode = TrEEPpVendorLibSubmitRequestToPreOSFunction (mTcgNvs->PhysicalPresence.Request, Flags.PPFlags); + } + } else if (mTcgNvs->PhysicalPresence.Parameter == ACPI_FUNCTION_GET_USER_CONFIRMATION_STATUS_FOR_REQUEST) { + if (EFI_ERROR (Status)) { + mTcgNvs->PhysicalPresence.ReturnCode = TREE_PP_GET_USER_CONFIRMATION_BLOCKED_BY_BIOS_CONFIGURATION; + DEBUG ((EFI_D_ERROR, "[TPM2] Get PP variable failure! Status = %r\n", Status)); + return EFI_SUCCESS; + } + // + // Get the Physical Presence flags + // + DataSize = sizeof (EFI_TREE_PHYSICAL_PRESENCE_FLAGS); + Status = mSmmVariable->SmmGetVariable ( + TREE_PHYSICAL_PRESENCE_FLAGS_VARIABLE, + &gEfiTrEEPhysicalPresenceGuid, + NULL, + &DataSize, + &Flags + ); + if (EFI_ERROR (Status)) { + mTcgNvs->PhysicalPresence.ReturnCode = TREE_PP_GET_USER_CONFIRMATION_BLOCKED_BY_BIOS_CONFIGURATION; + DEBUG ((EFI_D_ERROR, "[TPM2] Get PP flags failure! Status = %r\n", Status)); + return EFI_SUCCESS; + } + + RequestConfirmed = FALSE; + + switch (mTcgNvs->PhysicalPresence.Request) { + + case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR: + case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_2: + case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_3: + case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_4: + if ((Flags.PPFlags & TREE_BIOS_TPM_MANAGEMENT_FLAG_NO_PPI_CLEAR) != 0) { + RequestConfirmed = TRUE; + } + break; + + case TREE_PHYSICAL_PRESENCE_SET_NO_PPI_CLEAR_FALSE: + RequestConfirmed = TRUE; + break; + + case TREE_PHYSICAL_PRESENCE_SET_NO_PPI_CLEAR_TRUE: + break; + + default: + if (mTcgNvs->PhysicalPresence.Request <= TREE_PHYSICAL_PRESENCE_NO_ACTION_MAX) { + RequestConfirmed = TRUE; + } else { + if (mTcgNvs->PhysicalPresence.Request < TREE_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION) { + mTcgNvs->PhysicalPresence.ReturnCode = TREE_PP_GET_USER_CONFIRMATION_NOT_IMPLEMENTED; + return EFI_SUCCESS; + } + } + break; + } + + if (RequestConfirmed) { + mTcgNvs->PhysicalPresence.ReturnCode = TREE_PP_GET_USER_CONFIRMATION_ALLOWED_AND_PPUSER_NOT_REQUIRED; + } else { + mTcgNvs->PhysicalPresence.ReturnCode = TREE_PP_GET_USER_CONFIRMATION_ALLOWED_AND_PPUSER_REQUIRED; + } + if (mTcgNvs->PhysicalPresence.Request >= TREE_PHYSICAL_PRESENCE_VENDOR_SPECIFIC_OPERATION) { + mTcgNvs->PhysicalPresence.ReturnCode = TrEEPpVendorLibGetUserConfirmationStatusFunction (mTcgNvs->PhysicalPresence.Request, Flags.PPFlags); + } + } + + return EFI_SUCCESS; +} + + +/** + Software SMI callback for MemoryClear which is called from ACPI method. + + Caution: This function may receive untrusted input. + Variable and ACPINvs are external input, so this function will validate + its data structure to be valid value. + + @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister(). + @param[in] Context Points to an optional handler context which was specified when the + handler was registered. + @param[in, out] CommBuffer A pointer to a collection of data in memory that will + be conveyed from a non-SMM environment into an SMM environment. + @param[in, out] CommBufferSize The size of the CommBuffer. + + @retval EFI_SUCCESS The interrupt was handled successfully. + +**/ +EFI_STATUS +EFIAPI +MemoryClearCallback ( + IN EFI_HANDLE DispatchHandle, + IN CONST VOID *Context, + IN OUT VOID *CommBuffer, + IN OUT UINTN *CommBufferSize + ) +{ + EFI_STATUS Status; + UINTN DataSize; + UINT8 MorControl; + + mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_SUCCESS; + if (mTcgNvs->MemoryClear.Parameter == ACPI_FUNCTION_DSM_MEMORY_CLEAR_INTERFACE) { + MorControl = (UINT8) mTcgNvs->MemoryClear.Request; + } else if (mTcgNvs->MemoryClear.Parameter == ACPI_FUNCTION_PTS_CLEAR_MOR_BIT) { + DataSize = sizeof (UINT8); + Status = mSmmVariable->SmmGetVariable ( + MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME, + &gEfiMemoryOverwriteControlDataGuid, + NULL, + &DataSize, + &MorControl + ); + if (EFI_ERROR (Status)) { + mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_GENERAL_FAILURE; + DEBUG ((EFI_D_ERROR, "[TPM] Get MOR variable failure! Status = %r\n", Status)); + return EFI_SUCCESS; + } + + if (MOR_CLEAR_MEMORY_VALUE (MorControl) == 0x0) { + return EFI_SUCCESS; + } + MorControl &= ~MOR_CLEAR_MEMORY_BIT_MASK; + } + + DataSize = sizeof (UINT8); + Status = mSmmVariable->SmmSetVariable ( + MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME, + &gEfiMemoryOverwriteControlDataGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + DataSize, + &MorControl + ); + if (EFI_ERROR (Status)) { + mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_GENERAL_FAILURE; + DEBUG ((EFI_D_ERROR, "[TPM] Set MOR variable failure! Status = %r\n", Status)); + } + + return EFI_SUCCESS; +} + +/** + Find the operation region in TCG ACPI table by given Name and Size, + and initialize it if the region is found. + + @param[in, out] Table The TPM item in ACPI table. + @param[in] Name The name string to find in TPM table. + @param[in] Size The size of the region to find. + + @return The allocated address for the found region. + +**/ +VOID * +AssignOpRegion ( + EFI_ACPI_DESCRIPTION_HEADER *Table, + UINT32 Name, + UINT16 Size + ) +{ + EFI_STATUS Status; + AML_OP_REGION_32_8 *OpRegion; + EFI_PHYSICAL_ADDRESS MemoryAddress; + + MemoryAddress = SIZE_4GB - 1; + + // + // Patch some pointers for the ASL code before loading the SSDT. + // + for (OpRegion = (AML_OP_REGION_32_8 *) (Table + 1); + OpRegion <= (AML_OP_REGION_32_8 *) ((UINT8 *) Table + Table->Length); + OpRegion = (AML_OP_REGION_32_8 *) ((UINT8 *) OpRegion + 1)) { + if ((OpRegion->OpRegionOp == AML_EXT_REGION_OP) && + (OpRegion->NameString == Name) && + (OpRegion->DWordPrefix == AML_DWORD_PREFIX) && + (OpRegion->BytePrefix == AML_BYTE_PREFIX)) { + + Status = gBS->AllocatePages(AllocateMaxAddress, EfiACPIMemoryNVS, EFI_SIZE_TO_PAGES (Size), &MemoryAddress); + ASSERT_EFI_ERROR (Status); + ZeroMem ((VOID *)(UINTN)MemoryAddress, Size); + OpRegion->RegionOffset = (UINT32) (UINTN) MemoryAddress; + OpRegion->RegionLen = (UINT8) Size; + break; + } + } + + return (VOID *) (UINTN) MemoryAddress; +} + +/** + Initialize and publish TPM items in ACPI table. + + @retval EFI_SUCCESS The TCG ACPI table is published successfully. + @retval Others The TCG ACPI table is not published. + +**/ +EFI_STATUS +PublishAcpiTable ( + VOID + ) +{ + EFI_STATUS Status; + EFI_ACPI_TABLE_PROTOCOL *AcpiTable; + UINTN TableKey; + EFI_ACPI_DESCRIPTION_HEADER *Table; + UINTN TableSize; + + Status = GetSectionFromFv ( + &gEfiCallerIdGuid, + EFI_SECTION_RAW, + 0, + (VOID **) &Table, + &TableSize + ); + ASSERT_EFI_ERROR (Status); + + + // + // Measure to PCR[0] with event EV_POST_CODE ACPI DATA + // + TpmMeasureAndLogData( + 0, + EV_POST_CODE, + EV_POSTCODE_INFO_ACPI_DATA, + ACPI_DATA_LEN, + Table, + TableSize + ); + + + ASSERT (Table->OemTableId == SIGNATURE_64 ('T', 'p', 'm', '2', 'T', 'a', 'b', 'l')); + CopyMem (Table->OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (Table->OemId) ); + mTcgNvs = AssignOpRegion (Table, SIGNATURE_32 ('T', 'N', 'V', 'S'), (UINT16) sizeof (TCG_NVS)); + ASSERT (mTcgNvs != NULL); + + // + // Publish the TPM ACPI table + // + Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTable); + ASSERT_EFI_ERROR (Status); + + TableKey = 0; + Status = AcpiTable->InstallAcpiTable ( + AcpiTable, + Table, + TableSize, + &TableKey + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} + +/** + Publish TPM2 ACPI table + + @retval EFI_SUCCESS The TPM2 ACPI table is published successfully. + @retval Others The TPM2 ACPI table is not published. + +**/ +EFI_STATUS +PublishTpm2 ( + VOID + ) +{ + EFI_STATUS Status; + EFI_ACPI_TABLE_PROTOCOL *AcpiTable; + UINTN TableKey; + UINT64 OemTableId; + + // + // Measure to PCR[0] with event EV_POST_CODE ACPI DATA + // + TpmMeasureAndLogData( + 0, + EV_POST_CODE, + EV_POSTCODE_INFO_ACPI_DATA, + ACPI_DATA_LEN, + &mTpm2AcpiTemplate, + sizeof(mTpm2AcpiTemplate) + ); + + CopyMem (mTpm2AcpiTemplate.Header.OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (mTpm2AcpiTemplate.Header.OemId)); + OemTableId = PcdGet64 (PcdAcpiDefaultOemTableId); + CopyMem (&mTpm2AcpiTemplate.Header.OemTableId, &OemTableId, sizeof (UINT64)); + mTpm2AcpiTemplate.Header.OemRevision = PcdGet32 (PcdAcpiDefaultOemRevision); + mTpm2AcpiTemplate.Header.CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId); + mTpm2AcpiTemplate.Header.CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision); + + // + // Construct ACPI table + // + Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTable); + ASSERT_EFI_ERROR (Status); + + Status = AcpiTable->InstallAcpiTable ( + AcpiTable, + &mTpm2AcpiTemplate, + sizeof(mTpm2AcpiTemplate), + &TableKey + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} + +/** + The driver's entry point. + + It install callbacks for TPM physical presence and MemoryClear, and locate + SMM variable to be used in the callback function. + + @param[in] ImageHandle The firmware allocated handle for the EFI image. + @param[in] SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The entry point is executed successfully. + @retval Others Some error occurs when executing this entry point. + +**/ +EFI_STATUS +EFIAPI +InitializeTcgSmm ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_SMM_SW_DISPATCH2_PROTOCOL *SwDispatch; + EFI_SMM_SW_REGISTER_CONTEXT SwContext; + EFI_HANDLE SwHandle; + + if (!CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceTpm20DtpmGuid)){ + DEBUG ((EFI_D_ERROR, "No TPM2 DTPM instance required!\n")); + return EFI_UNSUPPORTED; + } + + Status = PublishAcpiTable (); + ASSERT_EFI_ERROR (Status); + + // + // Get the Sw dispatch protocol and register SMI callback functions. + // + Status = gSmst->SmmLocateProtocol (&gEfiSmmSwDispatch2ProtocolGuid, NULL, (VOID**)&SwDispatch); + ASSERT_EFI_ERROR (Status); + SwContext.SwSmiInputValue = (UINTN) -1; + Status = SwDispatch->Register (SwDispatch, PhysicalPresenceCallback, &SwContext, &SwHandle); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + return Status; + } + mTcgNvs->PhysicalPresence.SoftwareSmi = (UINT8) SwContext.SwSmiInputValue; + + SwContext.SwSmiInputValue = (UINTN) -1; + Status = SwDispatch->Register (SwDispatch, MemoryClearCallback, &SwContext, &SwHandle); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + return Status; + } + mTcgNvs->MemoryClear.SoftwareSmi = (UINT8) SwContext.SwSmiInputValue; + + // + // Locate SmmVariableProtocol. + // + Status = gSmst->SmmLocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID**)&mSmmVariable); + ASSERT_EFI_ERROR (Status); + + // + // Set TPM2 ACPI table + // + Status = PublishTpm2 (); + ASSERT_EFI_ERROR (Status); + + + return EFI_SUCCESS; +} + diff --git a/Core/SecurityPkg/Tcg/TrEESmm/TrEESmm.h b/Core/SecurityPkg/Tcg/TrEESmm/TrEESmm.h new file mode 100644 index 0000000000..a0e1182248 --- /dev/null +++ b/Core/SecurityPkg/Tcg/TrEESmm/TrEESmm.h @@ -0,0 +1,105 @@ +/** @file + The header file for TrEE SMM driver. + +Copyright (c) 2013 - 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +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 +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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.
+# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = TrEESmm + MODULE_UNI_FILE = TrEESmm.uni + FILE_GUID = 114B7105-6CC9-453c-BADC-16DF227BB4EF + MODULE_TYPE = DXE_SMM_DRIVER + PI_SPECIFICATION_VERSION = 0x0001000A + VERSION_STRING = 1.0 + ENTRY_POINT = InitializeTcgSmm + +[Sources] + TrEESmm.h + TrEESmm.c + Tpm.asl + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + UefiDriverEntryPoint + SmmServicesTableLib + UefiBootServicesTableLib + DebugLib + DxeServicesLib + TpmMeasurementLib + Tpm2DeviceLib + TrEEPpVendorLib + +[Guids] + ## SOMETIMES_PRODUCES ## Variable:L"PhysicalPresence" + ## SOMETIMES_CONSUMES ## Variable:L"PhysicalPresence" + ## SOMETIMES_CONSUMES ## Variable:L"PhysicalPresenceFlags" + gEfiTrEEPhysicalPresenceGuid + + ## SOMETIMES_PRODUCES ## Variable:L"MemoryOverwriteRequestControl" + ## SOMETIMES_CONSUMES ## Variable:L"MemoryOverwriteRequestControl" + gEfiMemoryOverwriteControlDataGuid + + gEfiTpmDeviceInstanceTpm20DtpmGuid ## PRODUCES ## GUID # TPM device identifier + +[Protocols] + gEfiSmmSwDispatch2ProtocolGuid ## CONSUMES + gEfiSmmVariableProtocolGuid ## CONSUMES + gEfiAcpiTableProtocolGuid ## CONSUMES + +[Pcd] + gEfiSecurityPkgTokenSpaceGuid.PcdTpmInstanceGuid ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemId ## SOMETIMES_CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemTableId ## SOMETIMES_CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemRevision ## SOMETIMES_CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorId ## SOMETIMES_CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorRevision ## SOMETIMES_CONSUMES + +[Depex] + gEfiAcpiTableProtocolGuid AND + gEfiSmmSwDispatch2ProtocolGuid AND + gEfiSmmVariableProtocolGuid + +[UserExtensions.TianoCore."ExtraFiles"] + TrEESmmExtra.uni \ No newline at end of file diff --git a/Core/SecurityPkg/Tcg/TrEESmm/TrEESmm.uni b/Core/SecurityPkg/Tcg/TrEESmm/TrEESmm.uni new file mode 100644 index 0000000000..3123918c3e --- /dev/null +++ b/Core/SecurityPkg/Tcg/TrEESmm/TrEESmm.uni @@ -0,0 +1,28 @@ +// /** @file +// Provides ACPI metholds for TPM 2.0 support +// +// This driver implements TPM 2.0 definition block in ACPI table and +// registers SMI callback functions for TrEE physical presence and +// MemoryClear to handle the requests from ACPI method. +// +// Caution: This module requires additional review when modified. +// This driver will have external input - variable and ACPINvs data in SMM mode. +// This external input must be validated carefully to avoid security issue. +// +// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.
+// +// This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// **/ + + +#string STR_MODULE_ABSTRACT #language en-US "Provides ACPI metholds for TPM 2.0 support" + +#string STR_MODULE_DESCRIPTION #language en-US "This driver implements TPM 2.0 definition block in ACPI table and registers SMI callback functions for TrEE physical presence and MemoryClear to handle the requests from ACPI method.\n" + "Caution: This module requires additional review when modified. This driver will have external input - variable and ACPINvs data in SMM mode. This external input must be validated carefully to avoid security issues." + diff --git a/Core/SecurityPkg/Tcg/TrEESmm/TrEESmmExtra.uni b/Core/SecurityPkg/Tcg/TrEESmm/TrEESmmExtra.uni new file mode 100644 index 0000000000..c7e4da28c8 --- /dev/null +++ b/Core/SecurityPkg/Tcg/TrEESmm/TrEESmmExtra.uni @@ -0,0 +1,19 @@ +// /** @file +// TrEESmm Localized Strings and Content +// +// Copyright (c) 2014, Intel Corporation. All rights reserved.
+// +// This program and the accompanying materials +// are licensed and made available under the terms and conditions of the BSD License +// which accompanies this distribution. The full text of the license may be found at +// http://opensource.org/licenses/bsd-license.php +// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +// +// **/ + +#string STR_PROPERTIES_MODULE_NAME +#language en-US +"TrEE (Trusted Execution Environment) SMM" + + -- cgit v1.2.3