From f215e02bf85f68d3a6106c2a1f4f7f063f819064 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Thu, 11 Apr 2024 10:17:27 +0200 Subject: Adding upstream version 7.0.14-dfsg. Signed-off-by: Daniel Baumann --- .../Tcg/MemoryOverwriteControl/TcgMor.c | 375 +++ .../Tcg/MemoryOverwriteControl/TcgMor.h | 42 + .../Tcg/MemoryOverwriteControl/TcgMor.inf | 61 + .../Tcg/MemoryOverwriteControl/TcgMor.uni | 16 + .../Tcg/MemoryOverwriteControl/TcgMorExtra.uni | 14 + .../MemoryOverwriteRequestControlLock/TcgMorLock.c | 191 ++ .../MemoryOverwriteRequestControlLock/TcgMorLock.h | 131 + .../TcgMorLock.uni | 16 + .../TcgMorLockExtra.uni | 14 + .../TcgMorLockSmm.c | 152 + .../TcgMorLockSmm.inf | 65 + .../Tcg/Opal/OpalPassword/ComponentName.c | 392 +++ .../SecurityPkg/Tcg/Opal/OpalPassword/OpalDriver.c | 2966 ++++++++++++++++++++ .../SecurityPkg/Tcg/Opal/OpalPassword/OpalDriver.h | 616 ++++ .../SecurityPkg/Tcg/Opal/OpalPassword/OpalHii.c | 1283 +++++++++ .../SecurityPkg/Tcg/Opal/OpalPassword/OpalHii.h | 375 +++ .../Tcg/Opal/OpalPassword/OpalHiiCallbacks.c | 112 + .../Tcg/Opal/OpalPassword/OpalHiiFormStrings.uni | 80 + .../Tcg/Opal/OpalPassword/OpalHiiFormValues.h | 109 + .../Tcg/Opal/OpalPassword/OpalPasswordCommon.h | 38 + .../Tcg/Opal/OpalPassword/OpalPasswordDxe.inf | 77 + .../Tcg/Opal/OpalPassword/OpalPasswordForm.vfr | 303 ++ .../Tcg/Opal/OpalPassword/OpalPasswordPei.c | 472 ++++ .../Tcg/Opal/OpalPassword/OpalPasswordPei.h | 60 + .../Tcg/Opal/OpalPassword/OpalPasswordPei.inf | 51 + .../Tcg/PhysicalPresencePei/PhysicalPresencePei.c | 128 + .../PhysicalPresencePei/PhysicalPresencePei.inf | 59 + .../PhysicalPresencePei/PhysicalPresencePei.uni | 18 + .../PhysicalPresencePeiExtra.uni | 14 + .../Firmware/SecurityPkg/Tcg/Tcg2Acpi/Tcg2Acpi.c | 902 ++++++ .../Firmware/SecurityPkg/Tcg/Tcg2Acpi/Tcg2Acpi.inf | 94 + .../EFI/Firmware/SecurityPkg/Tcg/Tcg2Acpi/Tpm.asl | 517 ++++ .../SecurityPkg/Tcg/Tcg2Config/Tcg2Config.vfr | 246 ++ .../SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDriver.c | 455 +++ .../SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDxe.inf | 88 + .../SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDxe.uni | 17 + .../Tcg/Tcg2Config/Tcg2ConfigDxeExtra.uni | 14 + .../SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigImpl.c | 1004 +++++++ .../SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigImpl.h | 198 ++ .../SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigNvData.h | 89 + .../SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPei.inf | 71 + .../SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPei.uni | 18 + .../Tcg/Tcg2Config/Tcg2ConfigPeiExtra.uni | 14 + .../SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPeim.c | 154 + .../Tcg/Tcg2Config/Tcg2ConfigStrings.uni | 132 + .../SecurityPkg/Tcg/Tcg2Config/Tcg2Internal.h | 26 + .../SecurityPkg/Tcg/Tcg2Config/TpmDetection.c | 100 + .../SecurityPkg/Tcg/Tcg2Dxe/MeasureBootPeCoff.c | 406 +++ .../EFI/Firmware/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c | 2801 ++++++++++++++++++ .../Firmware/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.inf | 119 + .../Firmware/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.uni | 21 + .../SecurityPkg/Tcg/Tcg2Dxe/Tcg2DxeExtra.uni | 12 + .../EFI/Firmware/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.c | 1124 ++++++++ .../Firmware/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.inf | 95 + .../Firmware/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.uni | 16 + .../SecurityPkg/Tcg/Tcg2Pei/Tcg2PeiExtra.uni | 14 + .../SecurityPkg/Tcg/Tcg2Smm/Tcg2MmDependencyDxe.c | 48 + .../Tcg/Tcg2Smm/Tcg2MmDependencyDxe.inf | 43 + .../EFI/Firmware/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.c | 375 +++ .../EFI/Firmware/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.h | 87 + .../Firmware/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.inf | 86 + .../Firmware/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.uni | 23 + .../SecurityPkg/Tcg/Tcg2Smm/Tcg2SmmExtra.uni | 14 + .../SecurityPkg/Tcg/Tcg2Smm/Tcg2StandaloneMm.c | 71 + .../SecurityPkg/Tcg/Tcg2Smm/Tcg2StandaloneMm.inf | 77 + .../SecurityPkg/Tcg/Tcg2Smm/Tcg2TraditionalMm.c | 82 + .../SecurityPkg/Tcg/TcgConfigDxe/TcgConfig.vfr | 72 + .../SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDriver.c | 150 + .../SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDxe.inf | 77 + .../SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDxe.uni | 16 + .../Tcg/TcgConfigDxe/TcgConfigDxeExtra.uni | 14 + .../SecurityPkg/Tcg/TcgConfigDxe/TcgConfigImpl.c | 503 ++++ .../SecurityPkg/Tcg/TcgConfigDxe/TcgConfigImpl.h | 188 ++ .../SecurityPkg/Tcg/TcgConfigDxe/TcgConfigNvData.h | 33 + .../Tcg/TcgConfigDxe/TcgConfigStrings.uni | 35 + .../EFI/Firmware/SecurityPkg/Tcg/TcgDxe/TcgDxe.c | 1459 ++++++++++ .../EFI/Firmware/SecurityPkg/Tcg/TcgDxe/TcgDxe.inf | 81 + .../EFI/Firmware/SecurityPkg/Tcg/TcgDxe/TcgDxe.uni | 16 + .../SecurityPkg/Tcg/TcgDxe/TcgDxeExtra.uni | 14 + .../EFI/Firmware/SecurityPkg/Tcg/TcgPei/TcgPei.c | 931 ++++++ .../EFI/Firmware/SecurityPkg/Tcg/TcgPei/TcgPei.inf | 89 + .../EFI/Firmware/SecurityPkg/Tcg/TcgPei/TcgPei.uni | 17 + .../SecurityPkg/Tcg/TcgPei/TcgPeiExtra.uni | 14 + .../EFI/Firmware/SecurityPkg/Tcg/TcgSmm/TcgSmm.c | 463 +++ .../EFI/Firmware/SecurityPkg/Tcg/TcgSmm/TcgSmm.h | 99 + .../EFI/Firmware/SecurityPkg/Tcg/TcgSmm/TcgSmm.inf | 82 + .../EFI/Firmware/SecurityPkg/Tcg/TcgSmm/TcgSmm.uni | 22 + .../SecurityPkg/Tcg/TcgSmm/TcgSmmExtra.uni | 14 + .../EFI/Firmware/SecurityPkg/Tcg/TcgSmm/Tpm.asl | 351 +++ 89 files changed, 22623 insertions(+) create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.c create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.h create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.inf create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.uni create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMorExtra.uni create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLock.c create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLock.h create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLock.uni create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLockExtra.uni create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLockSmm.c create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLockSmm.inf create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/ComponentName.c create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalDriver.c create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalDriver.h create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalHii.c create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalHii.h create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalHiiCallbacks.c create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalHiiFormStrings.uni create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalHiiFormValues.h create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordCommon.h create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordDxe.inf create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordForm.vfr create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordPei.c create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordPei.h create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordPei.inf create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePei.c create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePei.inf create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePei.uni create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePeiExtra.uni create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Acpi/Tcg2Acpi.c create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Acpi/Tcg2Acpi.inf create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Acpi/Tpm.asl create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2Config.vfr create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDriver.c create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDxe.inf create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDxe.uni create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDxeExtra.uni create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigImpl.c create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigImpl.h create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigNvData.h create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPei.inf create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPei.uni create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPeiExtra.uni create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPeim.c create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigStrings.uni create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2Internal.h create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/TpmDetection.c create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Dxe/MeasureBootPeCoff.c create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.inf create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.uni create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Dxe/Tcg2DxeExtra.uni create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.c create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.inf create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.uni create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Pei/Tcg2PeiExtra.uni create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Smm/Tcg2MmDependencyDxe.c create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Smm/Tcg2MmDependencyDxe.inf create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.c create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.h create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.inf create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.uni create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Smm/Tcg2SmmExtra.uni create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Smm/Tcg2StandaloneMm.c create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Smm/Tcg2StandaloneMm.inf create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Smm/Tcg2TraditionalMm.c create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgConfigDxe/TcgConfig.vfr create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDriver.c create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDxe.inf create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDxe.uni create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDxeExtra.uni create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigImpl.c create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigImpl.h create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigNvData.h create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigStrings.uni create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgDxe/TcgDxe.c create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgDxe/TcgDxe.inf create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgDxe/TcgDxe.uni create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgDxe/TcgDxeExtra.uni create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgPei/TcgPei.c create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgPei/TcgPei.inf create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgPei/TcgPei.uni create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgPei/TcgPeiExtra.uni create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgSmm/TcgSmm.c create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgSmm/TcgSmm.h create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgSmm/TcgSmm.inf create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgSmm/TcgSmm.uni create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgSmm/TcgSmmExtra.uni create mode 100644 src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgSmm/Tpm.asl (limited to 'src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg') diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.c new file mode 100644 index 00000000..602790b8 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.c @@ -0,0 +1,375 @@ +/** @file + TCG MOR (Memory Overwrite Request) Control Driver. + + This driver initialize 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 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "TcgMor.h" + +UINT8 mMorControl; + +/** + Ready to Boot 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 conform 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, // SecurityProtocolSpecificData + 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, // SecurityProtocolSpecificData + 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, // SecurityProtocolSpecificData + 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. + + @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); + } + + FreePool (HandleBuffer); +} + +/** + 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_SUCCESS + @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 ((DEBUG_INFO, "TcgMor: Create ReadyToBoot Event for MorControl Bit cleaning!\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/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.h b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.h new file mode 100644 index 00000000..63ff7784 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.h @@ -0,0 +1,42 @@ +/** @file + The header file for TcgMor. + +Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#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/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.inf b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.inf new file mode 100644 index 00000000..6aa727af --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.inf @@ -0,0 +1,61 @@ +## @file +# initializes 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 - 2018, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[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 EBC +# + +[Sources] + TcgMor.c + TcgMor.h + +[Packages] + MdePkg/MdePkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + UefiDriverEntryPoint + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + 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/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.uni new file mode 100644 index 00000000..6a1df103 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.uni @@ -0,0 +1,16 @@ +// /** @file +// initializes MemoryOverwriteRequestControl variable +// +// This module will clear MOR_CLEAR_MEMORY_BIT bit if it is set. +// +// Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.
+// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + + +#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/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMorExtra.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMorExtra.uni new file mode 100644 index 00000000..49170c76 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMorExtra.uni @@ -0,0 +1,14 @@ +// /** @file +// TcgMor Localized Strings and Content +// +// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.
+// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_PROPERTIES_MODULE_NAME +#language en-US +"TCG (Trusted Computing Group) MOR" + + diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLock.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLock.c new file mode 100644 index 00000000..d3be20e7 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLock.c @@ -0,0 +1,191 @@ +/** @file + TCG MOR (Memory Overwrite Request) Lock Control Driver. + + This driver initializes MemoryOverwriteRequestControlLock variable. + This module will add Variable Hook and allow MemoryOverwriteRequestControlLock variable set only once. + +Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#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_TIME_BASED_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_SUCCESS + @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/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLock.h b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLock.h new file mode 100644 index 00000000..bb477695 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLock.h @@ -0,0 +1,131 @@ +/** @file + TCG MOR (Memory Overwrite Request) Lock Control Driver header file. + +Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#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_TIME_BASED_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_TIME_BASED_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_SUCCESS + @return Others Some error occurs. +**/ +EFI_STATUS +EFIAPI +MorLockDriverInit ( + VOID + ); + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLock.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLock.uni new file mode 100644 index 00000000..711b37d8 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLock.uni @@ -0,0 +1,16 @@ +// /** @file +// Initializes MemoryOverwriteRequestControlLock variable +// +// This module will add Variable Hook and allow MemoryOverwriteRequestControlLock variable set only once. +// +// Copyright (c) 2015, Intel Corporation. All rights reserved.
+// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + + +#string STR_MODULE_ABSTRACT #language en-US "Initializes 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/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLockExtra.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLockExtra.uni new file mode 100644 index 00000000..2679c08c --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLockExtra.uni @@ -0,0 +1,14 @@ +// /** @file +// TcgMorLock Localized Strings and Content +// +// Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.
+// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_PROPERTIES_MODULE_NAME +#language en-US +"TCG (Trusted Computing Group) MOR Lock" + + diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLockSmm.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLockSmm.c new file mode 100644 index 00000000..69ef5ad6 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLockSmm.c @@ -0,0 +1,152 @@ +/** @file + TCG MOR (Memory Overwrite Request) Lock Control Driver SMM wrapper. + +Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#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_TIME_BASED_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/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLockSmm.inf b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLockSmm.inf new file mode 100644 index 00000000..4efbd6a6 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLockSmm.inf @@ -0,0 +1,65 @@ +## @file +# Initializes 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 - 2018, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[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 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/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/ComponentName.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/ComponentName.c new file mode 100644 index 00000000..8d78650a --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/ComponentName.c @@ -0,0 +1,392 @@ +/** @file + UEFI Component Name(2) protocol implementation for Opal driver. + +Copyright (c) 2016, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#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/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalDriver.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalDriver.c new file mode 100644 index 00000000..e4987ba2 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalDriver.c @@ -0,0 +1,2966 @@ +/** @file + Entrypoint of Opal UEFI Driver and contains all the logic to + register for new Opal device instances. + +Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +// 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 "OpalHii.h" + +EFI_GUID mOpalDeviceLockBoxGuid = OPAL_DEVICE_LOCKBOX_GUID; + +BOOLEAN mOpalEndOfDxe = FALSE; +OPAL_REQUEST_VARIABLE *mOpalRequestVariable = NULL; +UINTN mOpalRequestVariableSize = 0; +CHAR16 mPopUpString[100]; + +OPAL_DRIVER mOpalDriver; + +// +// Globals +// +EFI_DRIVER_BINDING_PROTOCOL gOpalDriverBinding = { + OpalEfiDriverBindingSupported, + OpalEfiDriverBindingStart, + OpalEfiDriverBindingStop, + 0x1b, + NULL, + NULL +}; + +/** + + The function determines the available actions for the OPAL_DISK provided. + + @param[in] SupportedAttributes The supported attributes for the device. + @param[in] LockingFeature The locking status for the device. + @param[in] OwnerShip The ownership for the device. + @param[out] AvalDiskActions Pointer to fill-out with appropriate disk actions. + +**/ +TCG_RESULT +EFIAPI +OpalSupportGetAvailableActions( + IN OPAL_DISK_SUPPORT_ATTRIBUTE *SupportedAttributes, + IN TCG_LOCKING_FEATURE_DESCRIPTOR *LockingFeature, + IN UINT16 OwnerShip, + OUT OPAL_DISK_ACTIONS *AvalDiskActions + ) +{ + BOOLEAN ExistingPassword; + + NULL_CHECK(AvalDiskActions); + + AvalDiskActions->AdminPass = 1; + AvalDiskActions->UserPass = 0; + AvalDiskActions->DisableUser = 0; + AvalDiskActions->Unlock = 0; + + // + // Revert is performed on locking sp, so only allow if locking sp is enabled + // + if (LockingFeature->LockingEnabled) { + AvalDiskActions->Revert = 1; + } + + // + // Psid revert is available for any device with media encryption support or pyrite 2.0 type support. + // + if (SupportedAttributes->PyriteSscV2 || SupportedAttributes->MediaEncryption) { + + // + // Only allow psid revert if media encryption is enabled or pyrite 2.0 type support.. + // Otherwise, someone who steals a disk can psid revert the disk and the user Data is still + // intact and accessible + // + AvalDiskActions->PsidRevert = 1; + AvalDiskActions->RevertKeepDataForced = 0; + + // + // Secure erase is performed by generating a new encryption key + // this is only available if encryption is supported + // + AvalDiskActions->SecureErase = 1; + } else { + AvalDiskActions->PsidRevert = 0; + AvalDiskActions->SecureErase = 0; + + // + // If no media encryption is supported, then a revert (using password) will not + // erase the Data (since you can't generate a new encryption key) + // + AvalDiskActions->RevertKeepDataForced = 1; + } + + if (LockingFeature->Locked) { + AvalDiskActions->Unlock = 1; + } else { + AvalDiskActions->Unlock = 0; + } + + // + // Only allow user to set password if an admin password exists + // + ExistingPassword = OpalUtilAdminPasswordExists(OwnerShip, LockingFeature); + AvalDiskActions->UserPass = ExistingPassword; + + // + // This will still show up even if there isn't a user, which is fine + // + AvalDiskActions->DisableUser = ExistingPassword; + + return TcgResultSuccess; +} + +/** + Enable Opal Feature for the input device. + + @param[in] Session The opal session for the opal device. + @param[in] Msid Msid + @param[in] MsidLength Msid Length + @param[in] Password Admin password + @param[in] PassLength Length of password in bytes + +**/ +TCG_RESULT +EFIAPI +OpalSupportEnableOpalFeature ( + IN OPAL_SESSION *Session, + IN VOID *Msid, + IN UINT32 MsidLength, + IN VOID *Password, + IN UINT32 PassLength + ) +{ + TCG_RESULT Ret; + + NULL_CHECK(Session); + NULL_CHECK(Msid); + NULL_CHECK(Password); + + Ret = OpalUtilSetAdminPasswordAsSid( + Session, + Msid, + MsidLength, + Password, + PassLength + ); + if (Ret == TcgResultSuccess) { + // + // Enable global locking range + // + Ret = OpalUtilSetOpalLockingRange( + Session, + Password, + PassLength, + OPAL_LOCKING_SP_LOCKING_GLOBALRANGE, + 0, + 0, + TRUE, + TRUE, + FALSE, + FALSE + ); + } + + return Ret; +} + +/** + Update password for the Opal disk. + + @param[in, out] OpalDisk The disk to update password. + @param[in] Password The input password. + @param[in] PasswordLength The input password length. + +**/ +VOID +OpalSupportUpdatePassword ( + IN OUT OPAL_DISK *OpalDisk, + IN VOID *Password, + IN UINT32 PasswordLength + ) +{ + CopyMem (OpalDisk->Password, Password, PasswordLength); + OpalDisk->PasswordLength = (UINT8) PasswordLength; +} + +/** + Extract device info from the device path. + + @param[in] DevicePath Device path info for the device. + @param[out] DevInfoLength Device information length needed. + @param[out] DevInfo Device information extracted. + +**/ +VOID +ExtractDeviceInfoFromDevicePath ( + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, + OUT UINT32 *DevInfoLength, + OUT OPAL_DEVICE_LOCKBOX_DATA *DevInfo OPTIONAL + ) +{ + EFI_DEVICE_PATH_PROTOCOL *TmpDevPath; + EFI_DEVICE_PATH_PROTOCOL *TmpDevPath2; + PCI_DEVICE_PATH *PciDevPath; + UINT8 DeviceType; + UINT8 BusNum; + OPAL_PCI_DEVICE *PciDevice; + + ASSERT (DevicePath != NULL); + ASSERT (DevInfoLength != NULL); + + DeviceType = OPAL_DEVICE_TYPE_UNKNOWN; + *DevInfoLength = 0; + + TmpDevPath = DevicePath; + + // + // Get device type. + // + while (!IsDevicePathEnd (TmpDevPath)) { + if ((TmpDevPath->Type == MESSAGING_DEVICE_PATH) && + (TmpDevPath->SubType == MSG_SATA_DP || TmpDevPath->SubType == MSG_NVME_NAMESPACE_DP)) { + if (DevInfo != NULL) { + DevInfo->DevicePathLength = (UINT32) GetDevicePathSize (DevicePath); + CopyMem (DevInfo->DevicePath, DevicePath, DevInfo->DevicePathLength); + } + + DeviceType = (TmpDevPath->SubType == MSG_SATA_DP) ? OPAL_DEVICE_TYPE_ATA : OPAL_DEVICE_TYPE_NVME; + *DevInfoLength = sizeof (OPAL_DEVICE_LOCKBOX_DATA) + (UINT32) GetDevicePathSize (DevicePath); + break; + } + TmpDevPath = NextDevicePathNode (TmpDevPath); + } + + // + // Get device info. + // + 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_SATA_DP || TmpDevPath2->SubType == MSG_NVME_NAMESPACE_DP)) { + if (DevInfo != NULL) { + PciDevice = &DevInfo->Device; + PciDevice->Segment = 0; + PciDevice->Bus = BusNum; + PciDevice->Device = PciDevPath->Device; + PciDevice->Function = PciDevPath->Function; + } + } else { + if (TmpDevPath2->Type == HARDWARE_DEVICE_PATH && TmpDevPath2->SubType == HW_PCI_DP) { + BusNum = PciRead8 (PCI_LIB_ADDRESS (BusNum, PciDevPath->Device, PciDevPath->Function, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET)); + } + } + } + + TmpDevPath = NextDevicePathNode (TmpDevPath); + TmpDevPath2 = NextDevicePathNode (TmpDevPath2); + } + + ASSERT (DeviceType != OPAL_DEVICE_TYPE_UNKNOWN); + return; +} + +/** + Build OPAL device info and save them to LockBox. + + **/ +VOID +BuildOpalDeviceInfo ( + VOID + ) +{ + EFI_STATUS Status; + OPAL_DEVICE_LOCKBOX_DATA *DevInfo; + OPAL_DEVICE_LOCKBOX_DATA *TempDevInfo; + UINTN TotalDevInfoLength; + UINT32 DevInfoLength; + OPAL_DRIVER_DEVICE *TmpDev; + UINT8 DummyData; + BOOLEAN S3InitDevicesExist; + UINTN S3InitDevicesLength; + EFI_DEVICE_PATH_PROTOCOL *S3InitDevices; + EFI_DEVICE_PATH_PROTOCOL *S3InitDevicesBak; + + // + // Build OPAL device info and save them to LockBox. + // + TotalDevInfoLength = 0; + TmpDev = mOpalDriver.DeviceList; + while (TmpDev != NULL) { + ExtractDeviceInfoFromDevicePath ( + TmpDev->OpalDisk.OpalDevicePath, + &DevInfoLength, + NULL + ); + TotalDevInfoLength += DevInfoLength; + TmpDev = TmpDev->Next; + } + + if (TotalDevInfoLength == 0) { + return; + } + + S3InitDevicesLength = sizeof (DummyData); + Status = RestoreLockBox ( + &gS3StorageDeviceInitListGuid, + &DummyData, + &S3InitDevicesLength + ); + ASSERT ((Status == EFI_NOT_FOUND) || (Status == EFI_BUFFER_TOO_SMALL)); + if (Status == EFI_NOT_FOUND) { + S3InitDevices = NULL; + S3InitDevicesExist = FALSE; + } else if (Status == EFI_BUFFER_TOO_SMALL) { + S3InitDevices = AllocatePool (S3InitDevicesLength); + ASSERT (S3InitDevices != NULL); + if (S3InitDevices == NULL) { + return; + } + + Status = RestoreLockBox ( + &gS3StorageDeviceInitListGuid, + S3InitDevices, + &S3InitDevicesLength + ); + ASSERT_EFI_ERROR (Status); + S3InitDevicesExist = TRUE; + } else { + return; + } + + DevInfo = AllocateZeroPool (TotalDevInfoLength); + ASSERT (DevInfo != NULL); + if (DevInfo == NULL) { + return; + } + + TempDevInfo = DevInfo; + TmpDev = mOpalDriver.DeviceList; + while (TmpDev != NULL) { + ExtractDeviceInfoFromDevicePath ( + TmpDev->OpalDisk.OpalDevicePath, + &DevInfoLength, + TempDevInfo + ); + TempDevInfo->Length = DevInfoLength; + TempDevInfo->OpalBaseComId = TmpDev->OpalDisk.OpalBaseComId; + CopyMem ( + TempDevInfo->Password, + TmpDev->OpalDisk.Password, + TmpDev->OpalDisk.PasswordLength + ); + TempDevInfo->PasswordLength = TmpDev->OpalDisk.PasswordLength; + + S3InitDevicesBak = S3InitDevices; + S3InitDevices = AppendDevicePathInstance ( + S3InitDevicesBak, + TmpDev->OpalDisk.OpalDevicePath + ); + if (S3InitDevicesBak != NULL) { + FreePool (S3InitDevicesBak); + } + ASSERT (S3InitDevices != NULL); + if (S3InitDevices == NULL) { + return; + } + + TempDevInfo = (OPAL_DEVICE_LOCKBOX_DATA *) ((UINTN) TempDevInfo + DevInfoLength); + TmpDev = TmpDev->Next; + } + + Status = SaveLockBox ( + &mOpalDeviceLockBoxGuid, + DevInfo, + TotalDevInfoLength + ); + ASSERT_EFI_ERROR (Status); + + Status = SetLockBoxAttributes ( + &mOpalDeviceLockBoxGuid, + LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY + ); + ASSERT_EFI_ERROR (Status); + + S3InitDevicesLength = GetDevicePathSize (S3InitDevices); + if (S3InitDevicesExist) { + Status = UpdateLockBox ( + &gS3StorageDeviceInitListGuid, + 0, + S3InitDevices, + S3InitDevicesLength + ); + ASSERT_EFI_ERROR (Status); + } else { + Status = SaveLockBox ( + &gS3StorageDeviceInitListGuid, + S3InitDevices, + S3InitDevicesLength + ); + ASSERT_EFI_ERROR (Status); + + Status = SetLockBoxAttributes ( + &gS3StorageDeviceInitListGuid, + LOCK_BOX_ATTRIBUTE_RESTORE_IN_S3_ONLY + ); + ASSERT_EFI_ERROR (Status); + } + + ZeroMem (DevInfo, TotalDevInfoLength); + FreePool (DevInfo); + FreePool (S3InitDevices); +} + +/** + + Send BlockSid command if needed. + +**/ +VOID +SendBlockSidCommand ( + VOID + ) +{ + OPAL_DRIVER_DEVICE *Itr; + TCG_RESULT Result; + OPAL_SESSION Session; + UINT32 PpStorageFlag; + + 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; + + DEBUG ((DEBUG_INFO, "OpalPassword: EndOfDxe point, send BlockSid command to device!\n")); + Result = OpalBlockSid (&Session, TRUE); // HardwareReset must always be TRUE + if (Result != TcgResultSuccess) { + DEBUG ((DEBUG_ERROR, "OpalBlockSid fail\n")); + break; + } + + // + // Record BlockSID command has been sent. + // + Itr->OpalDisk.SentBlockSID = TRUE; + } + + Itr = Itr->Next; + } + } +} + +/** + Notification function of EFI_END_OF_DXE_EVENT_GROUP_GUID event group. + + This is a notification function registered on EFI_END_OF_DXE_EVENT_GROUP_GUID event group. + + @param Event Event whose notification function is being invoked. + @param Context Pointer to the notification function's context. + +**/ +VOID +EFIAPI +OpalEndOfDxeEventNotify ( + EFI_EVENT Event, + VOID *Context + ) +{ + OPAL_DRIVER_DEVICE *TmpDev; + + DEBUG ((DEBUG_INFO, "%a() - enter\n", __FUNCTION__)); + + mOpalEndOfDxe = TRUE; + + if (mOpalRequestVariable != NULL) { + // + // Free the OPAL request variable buffer here + // as the OPAL requests should have been processed. + // + FreePool (mOpalRequestVariable); + mOpalRequestVariable = NULL; + mOpalRequestVariableSize = 0; + } + + // + // If no any device, return directly. + // + if (mOpalDriver.DeviceList == NULL) { + gBS->CloseEvent (Event); + return; + } + + BuildOpalDeviceInfo (); + + // + // Zero passsword. + // + TmpDev = mOpalDriver.DeviceList; + while (TmpDev != NULL) { + ZeroMem (TmpDev->OpalDisk.Password, TmpDev->OpalDisk.PasswordLength); + TmpDev = TmpDev->Next; + } + + // + // Send BlockSid command if needed. + // + SendBlockSidCommand (); + + DEBUG ((DEBUG_INFO, "%a() - exit\n", __FUNCTION__)); + + gBS->CloseEvent (Event); +} + +/** + Get Psid input from the popup window. + + @param[in] Dev The device which need Psid to process Psid Revert + OPAL request. + @param[in] PopUpString Pop up string. + @param[in] PopUpString2 Pop up string in line 2. + @param[in] PopUpString3 Pop up string in line 3. + + @param[out] PressEsc Whether user escape function through Press ESC. + + @retval Psid string if success. NULL if failed. + +**/ +CHAR8 * +OpalDriverPopUpPsidInput ( + IN OPAL_DRIVER_DEVICE *Dev, + IN CHAR16 *PopUpString, + IN CHAR16 *PopUpString2, + IN CHAR16 *PopUpString3, + OUT BOOLEAN *PressEsc + ) +{ + EFI_INPUT_KEY InputKey; + UINTN InputLength; + CHAR16 Mask[PSID_CHARACTER_LENGTH + 1]; + CHAR16 Unicode[PSID_CHARACTER_LENGTH + 1]; + CHAR8 *Ascii; + + ZeroMem(Unicode, sizeof(Unicode)); + ZeroMem(Mask, sizeof(Mask)); + + *PressEsc = FALSE; + + gST->ConOut->ClearScreen(gST->ConOut); + + InputLength = 0; + while (TRUE) { + Mask[InputLength] = L'_'; + if (PopUpString2 == NULL) { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &InputKey, + PopUpString, + L"---------------------", + Mask, + NULL + ); + } else { + if (PopUpString3 == NULL) { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &InputKey, + PopUpString, + PopUpString2, + L"---------------------", + Mask, + NULL + ); + } else { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &InputKey, + PopUpString, + PopUpString2, + PopUpString3, + 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; + Mask[InputLength] = 0; + 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] = InputKey.UnicodeChar; + InputLength++; + if (InputLength == PSID_CHARACTER_LENGTH) { + // + // 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) { + ZeroMem (Unicode, sizeof (Unicode)); + ZeroMem (Mask, sizeof (Mask)); + return NULL; + } + + Ascii = AllocateZeroPool (PSID_CHARACTER_LENGTH + 1); + if (Ascii == NULL) { + ZeroMem (Unicode, sizeof (Unicode)); + ZeroMem (Mask, sizeof (Mask)); + return NULL; + } + + UnicodeStrToAsciiStrS (Unicode, Ascii, PSID_CHARACTER_LENGTH + 1); + ZeroMem (Unicode, sizeof (Unicode)); + ZeroMem (Mask, sizeof (Mask)); + + return Ascii; +} + + +/** + Get password input from the popup window. + + @param[in] Dev The device which need password to unlock or + process OPAL request. + @param[in] PopUpString1 Pop up string 1. + @param[in] PopUpString2 Pop up string 2. + @param[in] PopUpString3 Pop up string 3. + @param[out] PressEsc Whether user escape function through Press ESC. + + @retval Password string if success. NULL if failed. + +**/ +CHAR8 * +OpalDriverPopUpPasswordInput ( + IN OPAL_DRIVER_DEVICE *Dev, + IN CHAR16 *PopUpString1, + IN CHAR16 *PopUpString2, + IN CHAR16 *PopUpString3, + OUT BOOLEAN *PressEsc + ) +{ + EFI_INPUT_KEY InputKey; + UINTN InputLength; + CHAR16 Mask[OPAL_MAX_PASSWORD_SIZE + 1]; + CHAR16 Unicode[OPAL_MAX_PASSWORD_SIZE + 1]; + CHAR8 *Ascii; + + ZeroMem(Unicode, sizeof(Unicode)); + ZeroMem(Mask, sizeof(Mask)); + + *PressEsc = FALSE; + + gST->ConOut->ClearScreen(gST->ConOut); + + InputLength = 0; + while (TRUE) { + Mask[InputLength] = L'_'; + if (PopUpString2 == NULL) { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &InputKey, + PopUpString1, + L"---------------------", + Mask, + NULL + ); + } else { + if (PopUpString3 == NULL) { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &InputKey, + PopUpString1, + PopUpString2, + L"---------------------", + Mask, + NULL + ); + } else { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &InputKey, + PopUpString1, + PopUpString2, + PopUpString3, + 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; + Mask[InputLength] = 0; + 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 == OPAL_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) { + ZeroMem (Unicode, sizeof (Unicode)); + return NULL; + } + + Ascii = AllocateZeroPool (OPAL_MAX_PASSWORD_SIZE + 1); + if (Ascii == NULL) { + ZeroMem (Unicode, sizeof (Unicode)); + return NULL; + } + + UnicodeStrToAsciiStrS (Unicode, Ascii, OPAL_MAX_PASSWORD_SIZE + 1); + ZeroMem (Unicode, sizeof (Unicode)); + + return Ascii; +} + +/** + Get pop up string. + + @param[in] Dev The OPAL device. + @param[in] RequestString Request string. + + @return Pop up string. + +**/ +CHAR16 * +OpalGetPopUpString ( + IN OPAL_DRIVER_DEVICE *Dev, + IN CHAR16 *RequestString + ) +{ + if (Dev->Name16 == NULL) { + UnicodeSPrint (mPopUpString, sizeof (mPopUpString), L"%s Disk", RequestString); + } else { + UnicodeSPrint (mPopUpString, sizeof (mPopUpString), L"%s %s", RequestString, Dev->Name16); + } + + return mPopUpString; +} + +/** + Check if disk is locked, show popup window and ask for password if it is. + + @param[in] Dev The device which need to be unlocked. + @param[in] RequestString Request string. + +**/ +VOID +OpalDriverRequestPassword ( + IN OPAL_DRIVER_DEVICE *Dev, + IN CHAR16 *RequestString + ) +{ + UINT8 Count; + BOOLEAN IsEnabled; + BOOLEAN IsLocked; + CHAR8 *Password; + UINT32 PasswordLen; + OPAL_SESSION Session; + BOOLEAN PressEsc; + EFI_INPUT_KEY Key; + TCG_RESULT Ret; + CHAR16 *PopUpString; + + if (Dev == NULL) { + return; + } + + DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__)); + + PopUpString = OpalGetPopUpString (Dev, RequestString); + + 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; + + IsLocked = OpalDeviceLocked (&Dev->OpalDisk.SupportedAttributes, &Dev->OpalDisk.LockingFeature); + + // + // Add PcdSkipOpalPasswordPrompt to determin whether to skip password prompt. + // Due to board design, device may not power off during system warm boot, which result in + // security status remain unlocked status, hence we add device security status check here. + // + // If device is in the locked status, device keeps locked and system continues booting. + // If device is in the unlocked status, system is forced shutdown to support security requirement. + // + if (PcdGetBool (PcdSkipOpalPasswordPrompt)) { + if (IsLocked) { + return; + } else { + gRT->ResetSystem (EfiResetShutdown, EFI_SUCCESS, 0, NULL); + } + } + + while (Count < MAX_PASSWORD_TRY_COUNT) { + Password = OpalDriverPopUpPasswordInput (Dev, PopUpString, NULL, NULL, &PressEsc); + if (PressEsc) { + if (IsLocked) { + // + // 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 the request and continue boot,", + L"Press ESC to input password again", + 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 again", + 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 (IsLocked) { + Ret = OpalUtilUpdateGlobalLockingRange(&Session, Password, PasswordLen, FALSE, FALSE); + } else { + Ret = OpalUtilUpdateGlobalLockingRange(&Session, Password, PasswordLen, TRUE, TRUE); + if (Ret == TcgResultSuccess) { + Ret = OpalUtilUpdateGlobalLockingRange(&Session, Password, PasswordLen, FALSE, FALSE); + } + } + + if (Ret == TcgResultSuccess) { + OpalSupportUpdatePassword (&Dev->OpalDisk, Password, PasswordLen); + DEBUG ((DEBUG_INFO, "%s Success\n", RequestString)); + } else { + DEBUG ((DEBUG_INFO, "%s Failure\n", RequestString)); + } + + if (Password != NULL) { + ZeroMem (Password, PasswordLen); + FreePool (Password); + } + + if (Ret == TcgResultSuccess) { + break; + } + + // + // Check whether opal device's Tries value has reach the TryLimit value, if yes, force a shutdown + // before accept new password. + // + if (Ret == TcgResultFailureInvalidType) { + Count = MAX_PASSWORD_TRY_COUNT; + 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); + } + } +} + +/** + Process Enable Feature OPAL request. + + @param[in] Dev The device which has Enable Feature OPAL request. + @param[in] RequestString Request string. + +**/ +VOID +ProcessOpalRequestEnableFeature ( + IN OPAL_DRIVER_DEVICE *Dev, + IN CHAR16 *RequestString + ) +{ + UINT8 Count; + CHAR8 *Password; + UINT32 PasswordLen; + CHAR8 *PasswordConfirm; + UINT32 PasswordLenConfirm; + OPAL_SESSION Session; + BOOLEAN PressEsc; + EFI_INPUT_KEY Key; + TCG_RESULT Ret; + CHAR16 *PopUpString; + + if (Dev == NULL) { + return; + } + + DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__)); + + PopUpString = OpalGetPopUpString (Dev, RequestString); + + Count = 0; + + ZeroMem(&Session, sizeof(Session)); + Session.Sscp = Dev->OpalDisk.Sscp; + Session.MediaId = Dev->OpalDisk.MediaId; + Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId; + + while (Count < MAX_PASSWORD_TRY_COUNT) { + Password = OpalDriverPopUpPasswordInput (Dev, PopUpString, L"Please type in your new password", NULL, &PressEsc); + if (PressEsc) { + do { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Press ENTER to skip the request and continue boot,", + L"Press ESC to input password again", + NULL + ); + } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN)); + + if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) { + gST->ConOut->ClearScreen(gST->ConOut); + return; + } else { + // + // Let user input password again. + // + continue; + } + } + + if (Password == NULL) { + Count ++; + continue; + } + PasswordLen = (UINT32) AsciiStrLen(Password); + + PasswordConfirm = OpalDriverPopUpPasswordInput (Dev, PopUpString, L"Please confirm your new password", NULL, &PressEsc); + if (PasswordConfirm == NULL) { + ZeroMem (Password, PasswordLen); + FreePool (Password); + Count ++; + continue; + } + PasswordLenConfirm = (UINT32) AsciiStrLen(PasswordConfirm); + if ((PasswordLen != PasswordLenConfirm) || + (CompareMem (Password, PasswordConfirm, PasswordLen) != 0)) { + ZeroMem (Password, PasswordLen); + FreePool (Password); + ZeroMem (PasswordConfirm, PasswordLenConfirm); + FreePool (PasswordConfirm); + do { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Passwords are not the same.", + L"Press ENTER to retry", + NULL + ); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + Count ++; + continue; + } + + if (PasswordConfirm != NULL) { + ZeroMem (PasswordConfirm, PasswordLenConfirm); + FreePool (PasswordConfirm); + } + + Ret = OpalSupportEnableOpalFeature (&Session, Dev->OpalDisk.Msid, Dev->OpalDisk.MsidLength, Password, PasswordLen); + if (Ret == TcgResultSuccess) { + OpalSupportUpdatePassword (&Dev->OpalDisk, Password, PasswordLen); + DEBUG ((DEBUG_INFO, "%s Success\n", RequestString)); + } else { + DEBUG ((DEBUG_INFO, "%s Failure\n", RequestString)); + } + + if (Password != NULL) { + ZeroMem (Password, PasswordLen); + FreePool (Password); + } + + if (Ret == TcgResultSuccess) { + break; + } + + Count++; + + do { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Request failed.", + 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.", + L"Press ENTER to skip the request and continue boot", + NULL + ); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + gST->ConOut->ClearScreen(gST->ConOut); + } +} + +/** + Process Disable User OPAL request. + + @param[in] Dev The device which has Disable User OPAL request. + @param[in] RequestString Request string. + +**/ +VOID +ProcessOpalRequestDisableUser ( + IN OPAL_DRIVER_DEVICE *Dev, + IN CHAR16 *RequestString + ) +{ + UINT8 Count; + CHAR8 *Password; + UINT32 PasswordLen; + OPAL_SESSION Session; + BOOLEAN PressEsc; + EFI_INPUT_KEY Key; + TCG_RESULT Ret; + BOOLEAN PasswordFailed; + CHAR16 *PopUpString; + + if (Dev == NULL) { + return; + } + + DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__)); + + PopUpString = OpalGetPopUpString (Dev, RequestString); + + Count = 0; + + ZeroMem(&Session, sizeof(Session)); + Session.Sscp = Dev->OpalDisk.Sscp; + Session.MediaId = Dev->OpalDisk.MediaId; + Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId; + + while (Count < MAX_PASSWORD_TRY_COUNT) { + Password = OpalDriverPopUpPasswordInput (Dev, PopUpString, NULL, NULL, &PressEsc); + if (PressEsc) { + do { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Press ENTER to skip the request and continue boot,", + L"Press ESC to input password again", + NULL + ); + } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN)); + + if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) { + gST->ConOut->ClearScreen(gST->ConOut); + return; + } else { + // + // Let user input password again. + // + continue; + } + } + + if (Password == NULL) { + Count ++; + continue; + } + PasswordLen = (UINT32) AsciiStrLen(Password); + + Ret = OpalUtilDisableUser(&Session, Password, PasswordLen, &PasswordFailed); + if (Ret == TcgResultSuccess) { + OpalSupportUpdatePassword (&Dev->OpalDisk, Password, PasswordLen); + DEBUG ((DEBUG_INFO, "%s Success\n", RequestString)); + } else { + DEBUG ((DEBUG_INFO, "%s Failure\n", RequestString)); + } + + if (Password != NULL) { + ZeroMem (Password, PasswordLen); + FreePool (Password); + } + + if (Ret == TcgResultSuccess) { + break; + } + + Count++; + + do { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Invalid password, request failed.", + 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.", + L"Press ENTER to skip the request and continue boot", + NULL + ); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + gST->ConOut->ClearScreen(gST->ConOut); + } +} + +/** + Process Psid Revert OPAL request. + + @param[in] Dev The device which has Psid Revert OPAL request. + @param[in] RequestString Request string. + +**/ +VOID +ProcessOpalRequestPsidRevert ( + IN OPAL_DRIVER_DEVICE *Dev, + IN CHAR16 *RequestString + ) +{ + UINT8 Count; + CHAR8 *Psid; + UINT32 PsidLen; + OPAL_SESSION Session; + BOOLEAN PressEsc; + EFI_INPUT_KEY Key; + TCG_RESULT Ret; + CHAR16 *PopUpString; + CHAR16 *PopUpString2; + CHAR16 *PopUpString3; + UINTN BufferSize; + + if (Dev == NULL) { + return; + } + + DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__)); + + PopUpString = OpalGetPopUpString (Dev, RequestString); + + if (Dev->OpalDisk.EstimateTimeCost > MAX_ACCEPTABLE_REVERTING_TIME) { + BufferSize = StrSize (L"Warning: Revert action will take about ####### seconds"); + PopUpString2 = AllocateZeroPool (BufferSize); + ASSERT (PopUpString2 != NULL); + UnicodeSPrint ( + PopUpString2, + BufferSize, + L"WARNING: Revert action will take about %d seconds", + Dev->OpalDisk.EstimateTimeCost + ); + PopUpString3 = L"DO NOT power off system during the revert action!"; + } else { + PopUpString2 = NULL; + PopUpString3 = NULL; + } + + Count = 0; + + ZeroMem(&Session, sizeof(Session)); + Session.Sscp = Dev->OpalDisk.Sscp; + Session.MediaId = Dev->OpalDisk.MediaId; + Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId; + + while (Count < MAX_PSID_TRY_COUNT) { + Psid = OpalDriverPopUpPsidInput (Dev, PopUpString, PopUpString2, PopUpString3, &PressEsc); + if (PressEsc) { + do { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Press ENTER to skip the request and continue boot,", + L"Press ESC to input Psid again", + NULL + ); + } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN)); + + if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) { + gST->ConOut->ClearScreen(gST->ConOut); + goto Done; + } else { + // + // Let user input Psid again. + // + continue; + } + } + + if (Psid == NULL) { + Count ++; + continue; + } + PsidLen = (UINT32) AsciiStrLen(Psid); + + Ret = OpalUtilPsidRevert(&Session, Psid, PsidLen); + if (Ret == TcgResultSuccess) { + DEBUG ((DEBUG_INFO, "%s Success\n", RequestString)); + } else { + DEBUG ((DEBUG_INFO, "%s Failure\n", RequestString)); + } + + if (Psid != NULL) { + ZeroMem (Psid, PsidLen); + FreePool (Psid); + } + + if (Ret == TcgResultSuccess) { + break; + } + + Count++; + + do { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Invalid Psid, request failed.", + L"Press ENTER to retry", + NULL + ); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + } + + if (Count >= MAX_PSID_TRY_COUNT) { + do { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Opal Psid retry count exceeds the limit.", + L"Press ENTER to skip the request and continue boot", + NULL + ); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + gST->ConOut->ClearScreen(gST->ConOut); + } + +Done: + if (PopUpString2 != NULL) { + FreePool (PopUpString2); + } +} + +/** + Process Admin Revert OPAL request. + + @param[in] Dev The device which has Revert OPAL request. + @param[in] KeepUserData Whether to keep user data or not. + @param[in] RequestString Request string. + +**/ +VOID +ProcessOpalRequestRevert ( + IN OPAL_DRIVER_DEVICE *Dev, + IN BOOLEAN KeepUserData, + IN CHAR16 *RequestString + ) +{ + UINT8 Count; + CHAR8 *Password; + UINT32 PasswordLen; + OPAL_SESSION Session; + BOOLEAN PressEsc; + EFI_INPUT_KEY Key; + TCG_RESULT Ret; + BOOLEAN PasswordFailed; + CHAR16 *PopUpString; + CHAR16 *PopUpString2; + CHAR16 *PopUpString3; + UINTN BufferSize; + + if (Dev == NULL) { + return; + } + + DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__)); + + PopUpString = OpalGetPopUpString (Dev, RequestString); + + if ((!KeepUserData) && + (Dev->OpalDisk.EstimateTimeCost > MAX_ACCEPTABLE_REVERTING_TIME)) { + BufferSize = StrSize (L"Warning: Revert action will take about ####### seconds"); + PopUpString2 = AllocateZeroPool (BufferSize); + ASSERT (PopUpString2 != NULL); + UnicodeSPrint ( + PopUpString2, + BufferSize, + L"WARNING: Revert action will take about %d seconds", + Dev->OpalDisk.EstimateTimeCost + ); + PopUpString3 = L"DO NOT power off system during the revert action!"; + } else { + PopUpString2 = NULL; + PopUpString3 = NULL; + } + + Count = 0; + + ZeroMem(&Session, sizeof(Session)); + Session.Sscp = Dev->OpalDisk.Sscp; + Session.MediaId = Dev->OpalDisk.MediaId; + Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId; + + while (Count < MAX_PASSWORD_TRY_COUNT) { + Password = OpalDriverPopUpPasswordInput (Dev, PopUpString, PopUpString2, PopUpString3, &PressEsc); + if (PressEsc) { + do { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Press ENTER to skip the request and continue boot,", + L"Press ESC to input password again", + NULL + ); + } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN)); + + if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) { + gST->ConOut->ClearScreen(gST->ConOut); + goto Done; + } else { + // + // Let user input password again. + // + continue; + } + } + + if (Password == NULL) { + Count ++; + continue; + } + PasswordLen = (UINT32) AsciiStrLen(Password); + + if ((Dev->OpalDisk.SupportedAttributes.PyriteSsc == 1) && + (Dev->OpalDisk.LockingFeature.MediaEncryption == 0)) { + // + // For pyrite type device which does not support media encryption, + // it does not accept "Keep User Data" parameter. + // So here hardcode a FALSE for this case. + // + Ret = OpalUtilRevert( + &Session, + FALSE, + Password, + PasswordLen, + &PasswordFailed, + Dev->OpalDisk.Msid, + Dev->OpalDisk.MsidLength + ); + } else { + Ret = OpalUtilRevert( + &Session, + KeepUserData, + Password, + PasswordLen, + &PasswordFailed, + Dev->OpalDisk.Msid, + Dev->OpalDisk.MsidLength + ); + } + if (Ret == TcgResultSuccess) { + OpalSupportUpdatePassword (&Dev->OpalDisk, Password, PasswordLen); + DEBUG ((DEBUG_INFO, "%s Success\n", RequestString)); + } else { + DEBUG ((DEBUG_INFO, "%s Failure\n", RequestString)); + } + + if (Password != NULL) { + ZeroMem (Password, PasswordLen); + FreePool (Password); + } + + if (Ret == TcgResultSuccess) { + break; + } + + Count++; + + do { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Invalid password, request failed.", + 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.", + L"Press ENTER to skip the request and continue boot", + NULL + ); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + gST->ConOut->ClearScreen(gST->ConOut); + } + +Done: + if (PopUpString2 != NULL) { + FreePool (PopUpString2); + } +} + +/** + Process Secure Erase OPAL request. + + @param[in] Dev The device which has Secure Erase OPAL request. + @param[in] RequestString Request string. + +**/ +VOID +ProcessOpalRequestSecureErase ( + IN OPAL_DRIVER_DEVICE *Dev, + IN CHAR16 *RequestString + ) +{ + UINT8 Count; + CHAR8 *Password; + UINT32 PasswordLen; + OPAL_SESSION Session; + BOOLEAN PressEsc; + EFI_INPUT_KEY Key; + TCG_RESULT Ret; + BOOLEAN PasswordFailed; + CHAR16 *PopUpString; + CHAR16 *PopUpString2; + CHAR16 *PopUpString3; + UINTN BufferSize; + + if (Dev == NULL) { + return; + } + + DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__)); + + PopUpString = OpalGetPopUpString (Dev, RequestString); + + if (Dev->OpalDisk.EstimateTimeCost > MAX_ACCEPTABLE_REVERTING_TIME) { + BufferSize = StrSize (L"Warning: Secure erase action will take about ####### seconds"); + PopUpString2 = AllocateZeroPool (BufferSize); + ASSERT (PopUpString2 != NULL); + UnicodeSPrint ( + PopUpString2, + BufferSize, + L"WARNING: Secure erase action will take about %d seconds", + Dev->OpalDisk.EstimateTimeCost + ); + PopUpString3 = L"DO NOT power off system during the action!"; + } else { + PopUpString2 = NULL; + PopUpString3 = NULL; + } + Count = 0; + + ZeroMem(&Session, sizeof(Session)); + Session.Sscp = Dev->OpalDisk.Sscp; + Session.MediaId = Dev->OpalDisk.MediaId; + Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId; + + while (Count < MAX_PASSWORD_TRY_COUNT) { + Password = OpalDriverPopUpPasswordInput (Dev, PopUpString, PopUpString2, PopUpString3, &PressEsc); + if (PressEsc) { + do { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Press ENTER to skip the request and continue boot,", + L"Press ESC to input password again", + NULL + ); + } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN)); + + if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) { + gST->ConOut->ClearScreen(gST->ConOut); + goto Done; + } else { + // + // Let user input password again. + // + continue; + } + } + + if (Password == NULL) { + Count ++; + continue; + } + PasswordLen = (UINT32) AsciiStrLen(Password); + + Ret = OpalUtilSecureErase(&Session, Password, PasswordLen, &PasswordFailed); + if (Ret == TcgResultSuccess) { + OpalSupportUpdatePassword (&Dev->OpalDisk, Password, PasswordLen); + DEBUG ((DEBUG_INFO, "%s Success\n", RequestString)); + } else { + DEBUG ((DEBUG_INFO, "%s Failure\n", RequestString)); + } + + if (Password != NULL) { + ZeroMem (Password, PasswordLen); + FreePool (Password); + } + + if (Ret == TcgResultSuccess) { + break; + } + + Count++; + + do { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Invalid password, request failed.", + 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.", + L"Press ENTER to skip the request and continue boot", + NULL + ); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + gST->ConOut->ClearScreen(gST->ConOut); + } + +Done: + if (PopUpString2 != NULL) { + FreePool (PopUpString2); + } +} + +/** + Process Set Admin Pwd OPAL request. + + @param[in] Dev The device which has Set Admin Pwd Feature OPAL request. + @param[in] RequestString Request string. + +**/ +VOID +ProcessOpalRequestSetUserPwd ( + IN OPAL_DRIVER_DEVICE *Dev, + IN CHAR16 *RequestString + ) +{ + UINT8 Count; + CHAR8 *OldPassword; + UINT32 OldPasswordLen; + CHAR8 *Password; + UINT32 PasswordLen; + CHAR8 *PasswordConfirm; + UINT32 PasswordLenConfirm; + OPAL_SESSION Session; + BOOLEAN PressEsc; + EFI_INPUT_KEY Key; + TCG_RESULT Ret; + CHAR16 *PopUpString; + + if (Dev == NULL) { + return; + } + + DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__)); + + PopUpString = OpalGetPopUpString (Dev, RequestString); + + Count = 0; + + while (Count < MAX_PASSWORD_TRY_COUNT) { + OldPassword = OpalDriverPopUpPasswordInput (Dev, PopUpString, L"Please type in your password", NULL, &PressEsc); + if (PressEsc) { + do { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Press ENTER to skip the request and continue boot,", + L"Press ESC to input password again", + NULL + ); + } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN)); + + if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) { + gST->ConOut->ClearScreen(gST->ConOut); + return; + } else { + // + // Let user input password again. + // + continue; + } + } + + if (OldPassword == NULL) { + Count ++; + continue; + } + OldPasswordLen = (UINT32) AsciiStrLen(OldPassword); + + ZeroMem(&Session, sizeof(Session)); + Session.Sscp = Dev->OpalDisk.Sscp; + Session.MediaId = Dev->OpalDisk.MediaId; + Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId; + Ret = OpalUtilVerifyPassword (&Session, OldPassword, OldPasswordLen, OPAL_LOCKING_SP_USER1_AUTHORITY); + if (Ret == TcgResultSuccess) { + DEBUG ((DEBUG_INFO, "Verify with USER1 authority : Success\n")); + } else { + Ret = OpalUtilVerifyPassword (&Session, OldPassword, OldPasswordLen, OPAL_LOCKING_SP_ADMIN1_AUTHORITY); + if (Ret == TcgResultSuccess) { + DEBUG ((DEBUG_INFO, "Verify with ADMIN1 authority: Success\n")); + } else { + ZeroMem (OldPassword, OldPasswordLen); + FreePool (OldPassword); + DEBUG ((DEBUG_INFO, "Verify: Failure\n")); + do { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Incorrect password.", + L"Press ENTER to retry", + NULL + ); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + Count ++; + continue; + } + } + + Password = OpalDriverPopUpPasswordInput (Dev, PopUpString, L"Please type in your new password", NULL, &PressEsc); + if (Password == NULL) { + ZeroMem (OldPassword, OldPasswordLen); + FreePool (OldPassword); + Count ++; + continue; + } + PasswordLen = (UINT32) AsciiStrLen(Password); + + PasswordConfirm = OpalDriverPopUpPasswordInput (Dev, PopUpString, L"Please confirm your new password", NULL, &PressEsc); + if (PasswordConfirm == NULL) { + ZeroMem (OldPassword, OldPasswordLen); + FreePool (OldPassword); + ZeroMem (Password, PasswordLen); + FreePool (Password); + Count ++; + continue; + } + PasswordLenConfirm = (UINT32) AsciiStrLen(PasswordConfirm); + if ((PasswordLen != PasswordLenConfirm) || + (CompareMem (Password, PasswordConfirm, PasswordLen) != 0)) { + ZeroMem (OldPassword, OldPasswordLen); + FreePool (OldPassword); + ZeroMem (Password, PasswordLen); + FreePool (Password); + ZeroMem (PasswordConfirm, PasswordLenConfirm); + FreePool (PasswordConfirm); + do { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Passwords are not the same.", + L"Press ENTER to retry", + NULL + ); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + Count ++; + continue; + } + + if (PasswordConfirm != NULL) { + ZeroMem (PasswordConfirm, PasswordLenConfirm); + FreePool (PasswordConfirm); + } + + ZeroMem(&Session, sizeof(Session)); + Session.Sscp = Dev->OpalDisk.Sscp; + Session.MediaId = Dev->OpalDisk.MediaId; + Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId; + Ret = OpalUtilSetUserPassword( + &Session, + OldPassword, + OldPasswordLen, + Password, + PasswordLen + ); + if (Ret == TcgResultSuccess) { + OpalSupportUpdatePassword (&Dev->OpalDisk, Password, PasswordLen); + DEBUG ((DEBUG_INFO, "%s Success\n", RequestString)); + } else { + DEBUG ((DEBUG_INFO, "%s Failure\n", RequestString)); + } + + if (OldPassword != NULL) { + ZeroMem (OldPassword, OldPasswordLen); + FreePool (OldPassword); + } + + if (Password != NULL) { + ZeroMem (Password, PasswordLen); + FreePool (Password); + } + + if (Ret == TcgResultSuccess) { + break; + } + + Count++; + + do { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Request failed.", + 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.", + L"Press ENTER to skip the request and continue boot", + NULL + ); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + gST->ConOut->ClearScreen(gST->ConOut); + } +} + +/** + Process Set Admin Pwd OPAL request. + + @param[in] Dev The device which has Set Admin Pwd Feature OPAL request. + @param[in] RequestString Request string. + +**/ +VOID +ProcessOpalRequestSetAdminPwd ( + IN OPAL_DRIVER_DEVICE *Dev, + IN CHAR16 *RequestString + ) +{ + UINT8 Count; + CHAR8 *OldPassword; + UINT32 OldPasswordLen; + CHAR8 *Password; + UINT32 PasswordLen; + CHAR8 *PasswordConfirm; + UINT32 PasswordLenConfirm; + OPAL_SESSION Session; + BOOLEAN PressEsc; + EFI_INPUT_KEY Key; + TCG_RESULT Ret; + CHAR16 *PopUpString; + + if (Dev == NULL) { + return; + } + + DEBUG ((DEBUG_INFO, "%a()\n", __FUNCTION__)); + + PopUpString = OpalGetPopUpString (Dev, RequestString); + + Count = 0; + + while (Count < MAX_PASSWORD_TRY_COUNT) { + OldPassword = OpalDriverPopUpPasswordInput (Dev, PopUpString, L"Please type in your password", NULL, &PressEsc); + if (PressEsc) { + do { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Press ENTER to skip the request and continue boot,", + L"Press ESC to input password again", + NULL + ); + } while ((Key.ScanCode != SCAN_ESC) && (Key.UnicodeChar != CHAR_CARRIAGE_RETURN)); + + if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) { + gST->ConOut->ClearScreen(gST->ConOut); + return; + } else { + // + // Let user input password again. + // + continue; + } + } + + if (OldPassword == NULL) { + Count ++; + continue; + } + OldPasswordLen = (UINT32) AsciiStrLen(OldPassword); + + ZeroMem(&Session, sizeof(Session)); + Session.Sscp = Dev->OpalDisk.Sscp; + Session.MediaId = Dev->OpalDisk.MediaId; + Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId; + Ret = OpalUtilVerifyPassword (&Session, OldPassword, OldPasswordLen, OPAL_LOCKING_SP_ADMIN1_AUTHORITY); + if (Ret == TcgResultSuccess) { + DEBUG ((DEBUG_INFO, "Verify: Success\n")); + } else { + ZeroMem (OldPassword, OldPasswordLen); + FreePool (OldPassword); + DEBUG ((DEBUG_INFO, "Verify: Failure\n")); + do { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Incorrect password.", + L"Press ENTER to retry", + NULL + ); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + Count ++; + continue; + } + + Password = OpalDriverPopUpPasswordInput (Dev, PopUpString, L"Please type in your new password", NULL, &PressEsc); + if (Password == NULL) { + ZeroMem (OldPassword, OldPasswordLen); + FreePool (OldPassword); + Count ++; + continue; + } + PasswordLen = (UINT32) AsciiStrLen(Password); + + PasswordConfirm = OpalDriverPopUpPasswordInput (Dev, PopUpString, L"Please confirm your new password", NULL, &PressEsc); + if (PasswordConfirm == NULL) { + ZeroMem (OldPassword, OldPasswordLen); + FreePool (OldPassword); + ZeroMem (Password, PasswordLen); + FreePool (Password); + Count ++; + continue; + } + PasswordLenConfirm = (UINT32) AsciiStrLen(PasswordConfirm); + if ((PasswordLen != PasswordLenConfirm) || + (CompareMem (Password, PasswordConfirm, PasswordLen) != 0)) { + ZeroMem (OldPassword, OldPasswordLen); + FreePool (OldPassword); + ZeroMem (Password, PasswordLen); + FreePool (Password); + ZeroMem (PasswordConfirm, PasswordLenConfirm); + FreePool (PasswordConfirm); + do { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Passwords are not the same.", + L"Press ENTER to retry", + NULL + ); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + Count ++; + continue; + } + + if (PasswordConfirm != NULL) { + ZeroMem (PasswordConfirm, PasswordLenConfirm); + FreePool (PasswordConfirm); + } + + + ZeroMem(&Session, sizeof(Session)); + Session.Sscp = Dev->OpalDisk.Sscp; + Session.MediaId = Dev->OpalDisk.MediaId; + Session.OpalBaseComId = Dev->OpalDisk.OpalBaseComId; + Ret = OpalUtilSetAdminPassword( + &Session, + OldPassword, + OldPasswordLen, + Password, + PasswordLen + ); + if (Ret == TcgResultSuccess) { + OpalSupportUpdatePassword (&Dev->OpalDisk, Password, PasswordLen); + DEBUG ((DEBUG_INFO, "%s Success\n", RequestString)); + } else { + DEBUG ((DEBUG_INFO, "%s Failure\n", RequestString)); + } + + if (OldPassword != NULL) { + ZeroMem (OldPassword, OldPasswordLen); + FreePool (OldPassword); + } + + if (Password != NULL) { + ZeroMem (Password, PasswordLen); + FreePool (Password); + } + + if (Ret == TcgResultSuccess) { + break; + } + + Count++; + + do { + CreatePopUp ( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + L"Request failed.", + 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.", + L"Press ENTER to skip the request and continue boot", + NULL + ); + } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN); + gST->ConOut->ClearScreen(gST->ConOut); + } +} + +/** + Process OPAL request. + + @param[in] Dev The device which has OPAL request. + +**/ +VOID +ProcessOpalRequest ( + IN OPAL_DRIVER_DEVICE *Dev + ) +{ + EFI_STATUS Status; + OPAL_REQUEST_VARIABLE *TempVariable; + OPAL_REQUEST_VARIABLE *Variable; + UINTN VariableSize; + EFI_DEVICE_PATH_PROTOCOL *DevicePathInVariable; + UINTN DevicePathSizeInVariable; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + UINTN DevicePathSize; + BOOLEAN KeepUserData; + + DEBUG ((DEBUG_INFO, "%a() - enter\n", __FUNCTION__)); + + if (mOpalRequestVariable == NULL) { + Status = GetVariable2 ( + OPAL_REQUEST_VARIABLE_NAME, + &gHiiSetupVariableGuid, + (VOID **) &Variable, + &VariableSize + ); + if (EFI_ERROR (Status) || (Variable == NULL)) { + return; + } + mOpalRequestVariable = Variable; + mOpalRequestVariableSize = VariableSize; + + // + // Delete the OPAL request variable. + // + Status = gRT->SetVariable ( + OPAL_REQUEST_VARIABLE_NAME, + (EFI_GUID *) &gHiiSetupVariableGuid, + 0, + 0, + NULL + ); + ASSERT_EFI_ERROR (Status); + } else { + Variable = mOpalRequestVariable; + VariableSize = mOpalRequestVariableSize; + } + + // + // Process the OPAL requests. + // + TempVariable = Variable; + while ((VariableSize > sizeof (OPAL_REQUEST_VARIABLE)) && + (VariableSize >= TempVariable->Length) && + (TempVariable->Length > sizeof (OPAL_REQUEST_VARIABLE))) { + DevicePathInVariable = (EFI_DEVICE_PATH_PROTOCOL *) ((UINTN) TempVariable + sizeof (OPAL_REQUEST_VARIABLE)); + DevicePathSizeInVariable = GetDevicePathSize (DevicePathInVariable); + DevicePath = Dev->OpalDisk.OpalDevicePath; + DevicePathSize = GetDevicePathSize (DevicePath); + if ((DevicePathSize == DevicePathSizeInVariable) && + (CompareMem (DevicePath, DevicePathInVariable, DevicePathSize) == 0)) { + // + // Found the node for the OPAL device. + // + if (TempVariable->OpalRequest.SetAdminPwd != 0) { + ProcessOpalRequestSetAdminPwd (Dev, L"Update Admin Pwd:"); + } + if (TempVariable->OpalRequest.SetUserPwd != 0) { + ProcessOpalRequestSetUserPwd (Dev, L"Set User Pwd:"); + } + if (TempVariable->OpalRequest.SecureErase!= 0) { + ProcessOpalRequestSecureErase (Dev, L"Secure Erase:"); + } + if (TempVariable->OpalRequest.Revert != 0) { + KeepUserData = (BOOLEAN) TempVariable->OpalRequest.KeepUserData; + ProcessOpalRequestRevert ( + Dev, + KeepUserData, + KeepUserData ? L"Admin Revert(keep):" : L"Admin Revert:" + ); + } + if (TempVariable->OpalRequest.PsidRevert != 0) { + ProcessOpalRequestPsidRevert (Dev, L"Psid Revert:"); + } + if (TempVariable->OpalRequest.DisableUser != 0) { + ProcessOpalRequestDisableUser (Dev, L"Disable User:"); + } + if (TempVariable->OpalRequest.EnableFeature != 0) { + ProcessOpalRequestEnableFeature (Dev, L"Enable Feature:"); + } + + // + // Update Device ownership. + // Later BlockSID command may block the update. + // + OpalDiskUpdateOwnerShip (&Dev->OpalDisk); + + break; + } + + VariableSize -= TempVariable->Length; + TempVariable = (OPAL_REQUEST_VARIABLE *) ((UINTN) TempVariable + TempVariable->Length); + } + + DEBUG ((DEBUG_INFO, "%a() - exit\n", __FUNCTION__)); +} + +/** + 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 devcie list info. + + @retval return the device list pointer. +**/ +OPAL_DRIVER_DEVICE* +OpalDriverGetDeviceList( + VOID + ) +{ + return mOpalDriver.DeviceList; +} + +/** + 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_SUCCESS This function always complete successfully. +**/ +EFI_STATUS +EFIAPI +EfiDriverEntryPoint( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE* SystemTable + ) +{ + EFI_STATUS Status; + EFI_EVENT EndOfDxeEvent; + + 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; + + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + OpalEndOfDxeEventNotify, + NULL, + &gEfiEndOfDxeEventGroupGuid, + &EndOfDxeEvent + ); + ASSERT_EFI_ERROR (Status); + + // + // 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_PROTOCOL + 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; + + if (mOpalEndOfDxe) { + return EFI_UNSUPPORTED; + } + + // + // 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 + ); + + + 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 management 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)) { + // + // Block_IO not supported on handle + // + if(Status == EFI_UNSUPPORTED) { + BlkIo = NULL; + } else { + // + // Close storage security that was opened + // + gBS->CloseProtocol( + Controller, + &gEfiStorageSecurityCommandProtocolGuid, + This->DriverBindingHandle, + Controller + ); + + FreePool(Dev); + return Status; + } + } + + // + // Save mediaId + // + if(BlkIo == NULL) { + // If no Block IO present, use defined MediaId value. + Dev->MediaId = 0x0; + } else { + 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, L"Unlock:"); + + // + // Process OPAL request from last boot. + // + ProcessOpalRequest (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/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalDriver.h b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalDriver.h new file mode 100644 index 00000000..a44d720d --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalDriver.h @@ -0,0 +1,616 @@ +/** @file + Values defined and used by the Opal UEFI Driver. + +Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#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 +#include +#include +#include +#include +#include + +#include "OpalPasswordCommon.h" +#include "OpalHiiFormValues.h" + +#define EFI_DRIVER_NAME_UNICODE L"1.0 UEFI Opal Driver" + +// UEFI 2.1 +#define LANGUAGE_RFC_3066_ENGLISH ((CHAR8*)"en") + +// UEFI/EFI < 2.1 +#define LANGUAGE_ISO_639_2_ENGLISH ((CHAR8*)"eng") + +#define 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; + +#define OPAL_MSID_LENGTH 128 + +#define MAX_PASSWORD_TRY_COUNT 5 + +// PSID Length +#define PSID_CHARACTER_LENGTH 0x20 +#define MAX_PSID_TRY_COUNT 5 + +// +// The max timeout value assume the user can wait for the revert action. The unit of this macro is second. +// If the revert time value bigger than this one, driver needs to popup a dialog to let user confirm the +// revert action. +// +#define MAX_ACCEPTABLE_REVERTING_TIME 10 + +#pragma pack(1) + +// +// Structure that is used to represent the available actions for an OpalDisk. +// The data can then be utilized to expose/hide certain actions available to an end user +// by the consumer of this library. +// +typedef struct { + // + // Indicates if the disk can support PSID Revert action. should verify disk supports PSID authority + // + UINT16 PsidRevert : 1; + + // + // Indicates if the disk can support Revert action + // + UINT16 Revert : 1; + + // + // Indicates if the user must keep data for revert action. It is true if no media encryption is supported. + // + UINT16 RevertKeepDataForced : 1; + + // + // Indicates if the disk can support set Admin password + // + UINT16 AdminPass : 1; + + // + // Indicates if the disk can support set User password. This action requires that a user + // password is first enabled. + // + UINT16 UserPass : 1; + + // + // Indicates if unlock action is available. Requires disk to be currently locked. + // + UINT16 Unlock : 1; + + // + // Indicates if Secure Erase action is available. Action requires admin credentials and media encryption support. + // + UINT16 SecureErase : 1; + + // + // Indicates if Disable User action is available. Action requires admin credentials. + // + UINT16 DisableUser : 1; +} OPAL_DISK_ACTIONS; + +// +// Structure that is used to represent an OPAL_DISK. +// +typedef struct { + UINT32 MsidLength; // Byte length of MSID Pin for device + UINT8 Msid[OPAL_MSID_LENGTH]; // 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 + UINT8 PasswordLength; + UINT8 Password[OPAL_MAX_PASSWORD_SIZE]; + + UINT32 EstimateTimeCost; + BOOLEAN SentBlockSID; // Check whether BlockSid command has been sent. +} 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 + ); + +/** + Update password for the Opal disk. + + @param[in, out] OpalDisk The disk to update password. + @param[in] Password The input password. + @param[in] PasswordLength The input password length. + +**/ +VOID +OpalSupportUpdatePassword ( + IN OUT OPAL_DISK *OpalDisk, + IN VOID *Password, + IN UINT32 PasswordLength + ); + +/** + + The function performs determines the available actions for the OPAL_DISK provided. + + @param[in] SupportedAttributes The support attribute for the device. + @param[in] LockingFeature The locking status for the device. + @param[in] OwnerShip The ownership for the device. + @param[out] AvalDiskActions Pointer to fill-out with appropriate disk actions. + +**/ +TCG_RESULT +EFIAPI +OpalSupportGetAvailableActions( + IN OPAL_DISK_SUPPORT_ATTRIBUTE *SupportedAttributes, + IN TCG_LOCKING_FEATURE_DESCRIPTOR *LockingFeature, + IN UINT16 OwnerShip, + OUT OPAL_DISK_ACTIONS *AvalDiskActions + ); + +/** + Enable Opal Feature for the input device. + + @param[in] Session The opal session for the opal device. + @param[in] Msid Msid + @param[in] MsidLength Msid Length + @param[in] Password Admin password + @param[in] PassLength Length of password in bytes + +**/ +TCG_RESULT +EFIAPI +OpalSupportEnableOpalFeature ( + IN OPAL_SESSION *Session, + IN VOID *Msid, + IN UINT32 MsidLength, + IN VOID *Password, + IN UINT32 PassLength + ); + +/** + 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 management 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/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalHii.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalHii.c new file mode 100644 index 00000000..50406a25 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalHii.c @@ -0,0 +1,1283 @@ +/** @file + Implementation of the HII for the Opal UEFI Driver. + +Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "OpalHii.h" +// +// Character definitions +// +#define UPPER_LOWER_CASE_OFFSET 0x20 + +// +// 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; + +// +// 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) + } + } +}; + +/** + Get saved OPAL request. + + @param[in] OpalDisk The disk needs to get the saved OPAL request. + @param[out] OpalRequest OPAL request got. + +**/ +VOID +GetSavedOpalRequest ( + IN OPAL_DISK *OpalDisk, + OUT OPAL_REQUEST *OpalRequest + ) +{ + EFI_STATUS Status; + OPAL_REQUEST_VARIABLE *TempVariable; + OPAL_REQUEST_VARIABLE *Variable; + UINTN VariableSize; + EFI_DEVICE_PATH_PROTOCOL *DevicePathInVariable; + UINTN DevicePathSizeInVariable; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + UINTN DevicePathSize; + + DEBUG ((DEBUG_INFO, "%a() - enter\n", __FUNCTION__)); + + Variable = NULL; + VariableSize = 0; + + Status = GetVariable2 ( + OPAL_REQUEST_VARIABLE_NAME, + &gHiiSetupVariableGuid, + (VOID **) &Variable, + &VariableSize + ); + if (EFI_ERROR (Status) || (Variable == NULL)) { + return; + } + + TempVariable = Variable; + while ((VariableSize > sizeof (OPAL_REQUEST_VARIABLE)) && + (VariableSize >= TempVariable->Length) && + (TempVariable->Length > sizeof (OPAL_REQUEST_VARIABLE))) { + DevicePathInVariable = (EFI_DEVICE_PATH_PROTOCOL *) ((UINTN) TempVariable + sizeof (OPAL_REQUEST_VARIABLE)); + DevicePathSizeInVariable = GetDevicePathSize (DevicePathInVariable); + DevicePath = OpalDisk->OpalDevicePath; + DevicePathSize = GetDevicePathSize (DevicePath); + if ((DevicePathSize == DevicePathSizeInVariable) && + (CompareMem (DevicePath, DevicePathInVariable, DevicePathSize) == 0)) { + // + // Found the node for the OPAL device. + // Get the OPAL request. + // + CopyMem (OpalRequest, &TempVariable->OpalRequest, sizeof (OPAL_REQUEST)); + DEBUG (( + DEBUG_INFO, + "OpalRequest got: 0x%x\n", + *OpalRequest + )); + break; + } + VariableSize -= TempVariable->Length; + TempVariable = (OPAL_REQUEST_VARIABLE *) ((UINTN) TempVariable + TempVariable->Length); + } + + FreePool (Variable); + + DEBUG ((DEBUG_INFO, "%a() - exit\n", __FUNCTION__)); +} + +/** + Save OPAL request. + + @param[in] OpalDisk The disk has OPAL request to save. + @param[in] OpalRequest OPAL request to save. + +**/ +VOID +SaveOpalRequest ( + IN OPAL_DISK *OpalDisk, + IN OPAL_REQUEST OpalRequest + ) +{ + EFI_STATUS Status; + OPAL_REQUEST_VARIABLE *TempVariable; + UINTN TempVariableSize; + OPAL_REQUEST_VARIABLE *Variable; + UINTN VariableSize; + OPAL_REQUEST_VARIABLE *NewVariable; + UINTN NewVariableSize; + EFI_DEVICE_PATH_PROTOCOL *DevicePathInVariable; + UINTN DevicePathSizeInVariable; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + UINTN DevicePathSize; + + DEBUG ((DEBUG_INFO, "%a() - enter\n", __FUNCTION__)); + + DEBUG (( + DEBUG_INFO, + "OpalRequest to save: 0x%x\n", + OpalRequest + )); + + Variable = NULL; + VariableSize = 0; + NewVariable = NULL; + NewVariableSize = 0; + + Status = GetVariable2 ( + OPAL_REQUEST_VARIABLE_NAME, + &gHiiSetupVariableGuid, + (VOID **) &Variable, + &VariableSize + ); + if (!EFI_ERROR (Status) && (Variable != NULL)) { + TempVariable = Variable; + TempVariableSize = VariableSize; + while ((TempVariableSize > sizeof (OPAL_REQUEST_VARIABLE)) && + (TempVariableSize >= TempVariable->Length) && + (TempVariable->Length > sizeof (OPAL_REQUEST_VARIABLE))) { + DevicePathInVariable = (EFI_DEVICE_PATH_PROTOCOL *) ((UINTN) TempVariable + sizeof (OPAL_REQUEST_VARIABLE)); + DevicePathSizeInVariable = GetDevicePathSize (DevicePathInVariable); + DevicePath = OpalDisk->OpalDevicePath; + DevicePathSize = GetDevicePathSize (DevicePath); + if ((DevicePathSize == DevicePathSizeInVariable) && + (CompareMem (DevicePath, DevicePathInVariable, DevicePathSize) == 0)) { + // + // Found the node for the OPAL device. + // Update the OPAL request. + // + CopyMem (&TempVariable->OpalRequest, &OpalRequest, sizeof (OPAL_REQUEST)); + NewVariable = Variable; + NewVariableSize = VariableSize; + break; + } + TempVariableSize -= TempVariable->Length; + TempVariable = (OPAL_REQUEST_VARIABLE *) ((UINTN) TempVariable + TempVariable->Length); + } + if (NewVariable == NULL) { + // + // The node for the OPAL device is not found. + // Create node for the OPAL device. + // + DevicePath = OpalDisk->OpalDevicePath; + DevicePathSize = GetDevicePathSize (DevicePath); + NewVariableSize = VariableSize + sizeof (OPAL_REQUEST_VARIABLE) + DevicePathSize; + NewVariable = AllocatePool (NewVariableSize); + ASSERT (NewVariable != NULL); + CopyMem (NewVariable, Variable, VariableSize); + TempVariable = (OPAL_REQUEST_VARIABLE *) ((UINTN) NewVariable + VariableSize); + TempVariable->Length = (UINT32) (sizeof (OPAL_REQUEST_VARIABLE) + DevicePathSize); + CopyMem (&TempVariable->OpalRequest, &OpalRequest, sizeof (OPAL_REQUEST)); + DevicePathInVariable = (EFI_DEVICE_PATH_PROTOCOL *) ((UINTN) TempVariable + sizeof (OPAL_REQUEST_VARIABLE)); + CopyMem (DevicePathInVariable, DevicePath, DevicePathSize); + } + } else { + DevicePath = OpalDisk->OpalDevicePath; + DevicePathSize = GetDevicePathSize (DevicePath); + NewVariableSize = sizeof (OPAL_REQUEST_VARIABLE) + DevicePathSize; + NewVariable = AllocatePool (NewVariableSize); + ASSERT (NewVariable != NULL); + NewVariable->Length = (UINT32) (sizeof (OPAL_REQUEST_VARIABLE) + DevicePathSize); + CopyMem (&NewVariable->OpalRequest, &OpalRequest, sizeof (OPAL_REQUEST)); + DevicePathInVariable = (EFI_DEVICE_PATH_PROTOCOL *) ((UINTN) NewVariable + sizeof (OPAL_REQUEST_VARIABLE)); + CopyMem (DevicePathInVariable, DevicePath, DevicePathSize); + } + Status = gRT->SetVariable ( + OPAL_REQUEST_VARIABLE_NAME, + (EFI_GUID *) &gHiiSetupVariableGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, + NewVariableSize, + NewVariable + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "OpalRequest variable set failed (%r)\n", Status)); + } + if (NewVariable != Variable) { + FreePool (NewVariable); + } + if (Variable != NULL) { + FreePool (Variable); + } + + DEBUG ((DEBUG_INFO, "%a() - exit\n", __FUNCTION__)); +} + +/** + 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; + + 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; + } + + 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; +} + +/** + 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; +} + +/** + Confirm whether user truly want to do the revert action. + + @param OpalDisk The device which need to perform data removal action. + @param ActionString Specifies the action name shown on pop up menu. + + @retval EFI_SUCCESS Confirmed user want to do the revert action. +**/ +EFI_STATUS +HiiConfirmDataRemovalAction ( + IN OPAL_DISK *OpalDisk, + IN CHAR16 *ActionString + + ) +{ + CHAR16 Unicode[512]; + EFI_INPUT_KEY Key; + CHAR16 ApproveResponse; + CHAR16 RejectResponse; + + // + // When the estimate cost time bigger than MAX_ACCEPTABLE_REVERTING_TIME, pop up dialog to let user confirm + // the revert action. + // + if (OpalDisk->EstimateTimeCost < MAX_ACCEPTABLE_REVERTING_TIME) { + return EFI_SUCCESS; + } + + ApproveResponse = L'Y'; + RejectResponse = L'N'; + + UnicodeSPrint(Unicode, StrSize(L"WARNING: ############# action needs about ####### seconds"), L"WARNING: %s action needs about %d seconds", ActionString, OpalDisk->EstimateTimeCost); + + do { + CreatePopUp( + EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, + &Key, + Unicode, + L" System should not be powered off until action completion ", + L" ", + L" Press 'Y/y' to continue, press 'N/n' to cancel ", + NULL + ); + } while ( + ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (ApproveResponse | UPPER_LOWER_CASE_OFFSET)) && + ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) != (RejectResponse | UPPER_LOWER_CASE_OFFSET)) + ); + + if ((Key.UnicodeChar | UPPER_LOWER_CASE_OFFSET) == (RejectResponse | UPPER_LOWER_CASE_OFFSET)) { + return EFI_ABORTED; + } + + return EFI_SUCCESS; +} + +/** + This function processes the results of changes in configuration. + + @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + @param Action Specifies the type of action taken by the browser. + @param QuestionId A unique value which is sent to the original + exporting driver so that it can identify the type + of data to expect. + @param Type The type of value for the question. + @param Value A pointer to the data being sent to the original + exporting driver. + @param ActionRequest On return, points to the action requested by the + callback function. + + @retval EFI_SUCCESS The callback successfully handled the action. + @retval 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; + OPAL_DISK *OpalDisk; + + 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: + DEBUG ((DEBUG_INFO, "HII_KEY_ID_VAR_SELECTED_DISK_AVAILABLE_ACTIONS\n")); + 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_REVERT: + case HII_KEY_ID_PSID_REVERT: + OpalDisk = HiiGetOpalDiskCB(gHiiConfiguration.SelectedDiskIndex); + if (OpalDisk != NULL) { + return HiiConfirmDataRemovalAction (OpalDisk, L"Revert"); + } else { + ASSERT (FALSE); + return EFI_SUCCESS; + } + + case HII_KEY_ID_SECURE_ERASE: + OpalDisk = HiiGetOpalDiskCB(gHiiConfiguration.SelectedDiskIndex); + if (OpalDisk != NULL) { + return HiiConfirmDataRemovalAction (OpalDisk, L"Secure erase"); + } else { + ASSERT (FALSE); + return EFI_SUCCESS; + } + + } + } 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; + + case HII_KEY_ID_SET_ADMIN_PWD: + DEBUG ((DEBUG_INFO, "HII_KEY_ID_SET_ADMIN_PWD\n")); + gHiiConfiguration.OpalRequest.SetAdminPwd = Value->b; + OpalDisk = HiiGetOpalDiskCB(gHiiConfiguration.SelectedDiskIndex); + if (OpalDisk != NULL) { + SaveOpalRequest (OpalDisk, gHiiConfiguration.OpalRequest); + } + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY; + return EFI_SUCCESS; + + case HII_KEY_ID_SET_USER_PWD: + DEBUG ((DEBUG_INFO, "HII_KEY_ID_SET_USER_PWD\n")); + gHiiConfiguration.OpalRequest.SetUserPwd = Value->b; + OpalDisk = HiiGetOpalDiskCB(gHiiConfiguration.SelectedDiskIndex); + if (OpalDisk != NULL) { + SaveOpalRequest (OpalDisk, gHiiConfiguration.OpalRequest); + } + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY; + return EFI_SUCCESS; + + case HII_KEY_ID_SECURE_ERASE: + DEBUG ((DEBUG_INFO, "HII_KEY_ID_SECURE_ERASE\n")); + gHiiConfiguration.OpalRequest.SecureErase = Value->b; + OpalDisk = HiiGetOpalDiskCB(gHiiConfiguration.SelectedDiskIndex); + if (OpalDisk != NULL) { + SaveOpalRequest (OpalDisk, gHiiConfiguration.OpalRequest); + } + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY; + return EFI_SUCCESS; + + case HII_KEY_ID_REVERT: + DEBUG ((DEBUG_INFO, "HII_KEY_ID_REVERT\n")); + gHiiConfiguration.OpalRequest.Revert = Value->b; + OpalDisk = HiiGetOpalDiskCB(gHiiConfiguration.SelectedDiskIndex); + if (OpalDisk != NULL) { + SaveOpalRequest (OpalDisk, gHiiConfiguration.OpalRequest); + } + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY; + return EFI_SUCCESS; + case HII_KEY_ID_KEEP_USER_DATA: + DEBUG ((DEBUG_INFO, "HII_KEY_ID_KEEP_USER_DATA\n")); + gHiiConfiguration.OpalRequest.KeepUserData = Value->b; + OpalDisk = HiiGetOpalDiskCB(gHiiConfiguration.SelectedDiskIndex); + if (OpalDisk != NULL) { + SaveOpalRequest (OpalDisk, gHiiConfiguration.OpalRequest); + } + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY; + return EFI_SUCCESS; + + case HII_KEY_ID_PSID_REVERT: + DEBUG ((DEBUG_INFO, "HII_KEY_ID_PSID_REVERT\n")); + gHiiConfiguration.OpalRequest.PsidRevert = Value->b; + OpalDisk = HiiGetOpalDiskCB(gHiiConfiguration.SelectedDiskIndex); + if (OpalDisk != NULL) { + SaveOpalRequest (OpalDisk, gHiiConfiguration.OpalRequest); + } + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY; + return EFI_SUCCESS; + + case HII_KEY_ID_DISABLE_USER: + DEBUG ((DEBUG_INFO, "HII_KEY_ID_DISABLE_USER\n")); + gHiiConfiguration.OpalRequest.DisableUser = Value->b; + OpalDisk = HiiGetOpalDiskCB(gHiiConfiguration.SelectedDiskIndex); + if (OpalDisk != NULL) { + SaveOpalRequest (OpalDisk, gHiiConfiguration.OpalRequest); + } + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY; + return EFI_SUCCESS; + + case HII_KEY_ID_ENABLE_FEATURE: + DEBUG ((DEBUG_INFO, "HII_KEY_ID_ENABLE_FEATURE\n")); + gHiiConfiguration.OpalRequest.EnableFeature = Value->b; + OpalDisk = HiiGetOpalDiskCB(gHiiConfiguration.SelectedDiskIndex); + if (OpalDisk != NULL) { + SaveOpalRequest (OpalDisk, gHiiConfiguration.OpalRequest); + } + *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); + + gHiiConfiguration.SelectedDiskAvailableActions = HII_ACTION_NONE; + ZeroMem (&gHiiConfiguration.OpalRequest, sizeof (OPAL_REQUEST)); + gHiiConfiguration.KeepUserDataForced = FALSE; + + 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.OpalRequest.KeepUserData = 1; + if (AvailActions.RevertKeepDataForced) { + gHiiConfiguration.KeepUserDataForced = TRUE; + } + } + } + + GetSavedOpalRequest (OpalDisk, &gHiiConfiguration.OpalRequest); + } + + // + // Pass the current configuration to the BIOS + // + OpalHiiSetBrowserData (); + + return EFI_SUCCESS; +} + +/** + 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; + EFI_STRING ConfigRequest; + EFI_STRING ConfigRequestHdr; + UINTN BufferSize; + UINTN Size; + BOOLEAN AllocatedRequest; + EFI_HANDLE DriverHandle; + + // + // 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; + } + + AllocatedRequest = FALSE; + BufferSize = sizeof (OPAL_HII_CONFIGURATION); + ConfigRequest = Request; + if ((Request == NULL) || (StrStr (Request, L"OFFSET") == NULL)) { + // + // Request has no request element, construct full request string. + // Allocate and fill a buffer large enough to hold the template + // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator + // + DriverHandle = HiiGetDriverImageHandleCB(); + ConfigRequestHdr = HiiConstructConfigHdr (&gHiiSetupVariableGuid, OpalPasswordStorageName, DriverHandle); + Size = (StrLen (ConfigRequestHdr) + 32 + 1) * sizeof (CHAR16); + ConfigRequest = AllocateZeroPool (Size); + if (ConfigRequest == NULL) { + return EFI_OUT_OF_RESOURCES; + } + AllocatedRequest = TRUE; + UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", ConfigRequestHdr, (UINT64)BufferSize); + FreePool (ConfigRequestHdr); + } + + // + // Convert Buffer Data to by helper function BlockToConfig( ) + // + Status = gHiiConfigRouting->BlockToConfig( + gHiiConfigRouting, + ConfigRequest, + (UINT8*)&gHiiConfiguration, + sizeof(OPAL_HII_CONFIGURATION), + Results, + Progress + ); + + // + // Free the allocated config request string. + // + if (AllocatedRequest) { + FreePool (ConfigRequest); + ConfigRequest = NULL; + } + + // + // 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); +} + + +/** + + 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_Configuration 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 need 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_SUCCESS 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; + UINT8 ActiveDataRemovalMechanism; + UINT32 RemovalMechanishLists[ResearvedMechanism]; + + 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_LENGTH, &Dev->OpalDisk.MsidLength); + if (TcgResult != TcgResultSuccess) { + return EFI_DEVICE_ERROR; + } + + if (Dev->OpalDisk.SupportedAttributes.DataRemoval) { + TcgResult = OpalUtilGetDataRemovalMechanismLists (&Session, RemovalMechanishLists); + if (TcgResult != TcgResultSuccess) { + return EFI_DEVICE_ERROR; + } + + TcgResult = OpalUtilGetActiveDataRemovalMechanism (&Session, Dev->OpalDisk.Msid, Dev->OpalDisk.MsidLength, &ActiveDataRemovalMechanism); + if (TcgResult != TcgResultSuccess) { + return EFI_DEVICE_ERROR; + } + + Dev->OpalDisk.EstimateTimeCost = RemovalMechanishLists[ActiveDataRemovalMechanism]; + } + + return OpalDiskUpdateStatus (&Dev->OpalDisk); +} + +/** + Update the device ownship + + @param OpalDisk The Opal device. + + @retval EFI_SUCCESS Get ownership success. + @retval EFI_ACCESS_DENIED Has send BlockSID command, can't change ownership. + @retval EFI_INVALID_PARAMETER Not get Msid info before get ownership info. + +**/ +EFI_STATUS +OpalDiskUpdateOwnerShip ( + OPAL_DISK *OpalDisk + ) +{ + OPAL_SESSION Session; + + if (OpalDisk->MsidLength == 0) { + return EFI_INVALID_PARAMETER; + } + + if (OpalDisk->SentBlockSID) { + return EFI_ACCESS_DENIED; + } + + ZeroMem(&Session, sizeof(Session)); + Session.Sscp = OpalDisk->Sscp; + Session.MediaId = OpalDisk->MediaId; + Session.OpalBaseComId = OpalDisk->OpalBaseComId; + + OpalDisk->Owner = OpalUtilDetermineOwnership(&Session, OpalDisk->Msid, OpalDisk->MsidLength); + return EFI_SUCCESS; +} + +/** + Update the device info. + + @param OpalDisk The Opal device. + + @retval EFI_SUCCESS 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. + @retval EFI_ACCESS_DENIED Has send BlockSID command, can't change ownership. + +**/ +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; + } + + return OpalDiskUpdateOwnerShip (OpalDisk); +} + diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalHii.h b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalHii.h new file mode 100644 index 00000000..3d84cafc --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalHii.h @@ -0,0 +1,375 @@ +/** @file + Public Header file of HII library used by Opal UEFI Driver. + Defines required callbacks of Opal HII library. + +Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _OPAL_HII_H_ +#define _OPAL_HII_H_ + +#include + +#include "OpalDriver.h" +#include "OpalHiiFormValues.h" + +#define OPAL_PASSWORD_CONFIG_GUID \ + { \ + 0x0d510a4f, 0xa81b, 0x473f, { 0x87, 0x07, 0xb7, 0xfd, 0xfb, 0xc0, 0x45, 0xba } \ + } + +#define OPAL_REQUEST_VARIABLE_NAME L"OpalRequest" + +#pragma pack(1) + +typedef struct { + UINT32 Length; + OPAL_REQUEST OpalRequest; + //EFI_DEVICE_PATH_PROTOCOL OpalDevicePath; +} OPAL_REQUEST_VARIABLE; + +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; + +#pragma pack() + +extern const EFI_GUID gHiiSetupVariableGuid; + +/** + 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_Configuration 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_SUCCESS 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 + ); + +/** + 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 + ); + +/** + 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_SUCCESS Initialize the device success. + @retval EFI_DEVICE_ERROR Get info from device failed. + +**/ +EFI_STATUS +OpalDiskInitialize ( + IN OPAL_DRIVER_DEVICE *Dev + ); + +/** + Update the device ownership + + @param OpalDisk The Opal device. + + @retval EFI_SUCCESS Get ownership success. + @retval EFI_ACCESS_DENIED Has send BlockSID command, can't change ownership. + @retval EFI_INVALID_PARAMETER Not get Msid info before get ownership info. + +**/ +EFI_STATUS +OpalDiskUpdateOwnerShip ( + OPAL_DISK *OpalDisk + ); + +#endif // _HII_H_ diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalHiiCallbacks.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalHiiCallbacks.c new file mode 100644 index 00000000..a9b08669 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalHiiCallbacks.c @@ -0,0 +1,112 @@ +/** @file + Callbacks required by the HII of the Opal UEFI Driver to help display + Opal device information. + +Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "OpalHii.h" + +/** + Get the driver image handle. + + @retval the driver image handle. + +**/ +EFI_HANDLE +HiiGetDriverImageHandleCB( + VOID + ) +{ + return gImageHandle; +} + +/** + 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; +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalHiiFormStrings.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalHiiFormStrings.uni new file mode 100644 index 00000000..6db6b9c6 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalHiiFormStrings.uni @@ -0,0 +1,80 @@ +// /** @file +// +// String definitions for Setup formset. +// +// Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.
+// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +/=# +///////////////////////////////// GENERIC DEFINITIONS ///////////////////////////////// +#langdef en-US "English" +#string STR_NULL #language en-US " " + +///////////////////////////////// FORM SET ///////////////////////////////// +#string STR_FORM_SET_HELP #language en-US "Select to manage" + +///////////////////////////////// MULTIPLE FORMS ///////////////////////////////// +#string STR_OPAL #language en-US "TCG Drive Management" + +///////////////////////////////// MAIN MENU FORM ///////////////////////////////// +#string STR_MAIN_PHY_DISKS_LBL #language en-US "Physical Disks:" +#string STR_MAIN_OPAL_TITLE_LBL #language en-US "Allows user to choose drive to configure drive security. User can also set storage action policy for use of the TCG Block SID authentication feature." + +#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 disk to see actions" + +#string STR_MAIN_NO_DISKS_PRESENT_LBL #language en-US "No disks connected to system" +#string STR_MAIN_NO_DISKS_PRESENT_LBL_HELP #language en-US "The storage needs to be connected before EndOfDxe" + +///////////////////////////////// DISK INFO MENU FORM ///////////////////////////////// +#string STR_DISK_INFO_SELECTED_DISK_NAME #language en-US " " +#string STR_DISK_INFO_TITLE_LBL #language en-US "Allows user to set and modify password; perform secure erase; and perform revert functions on drive." + +#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_OPAL_REQUESTS_LBL #language en-US "Options:" +#string STR_DISK_INFO_LOCK_HELP #language en-US "Lock the disk" +#string STR_DISK_INFO_UNLOCK_HELP #language en-US "Unlock the disk" +#string STR_DISK_INFO_SET_ADMIN_PSWD_HELP #language en-US "Set password for the administrator, reset is required for the request to be processed in next boot" +#string STR_DISK_INFO_SET_USER_PSWD_HELP #language en-US "Set password for User 1, reset is required for the request to be processed in next boot" +#string STR_DISK_INFO_SECURE_ERASE_HELP #language en-US "Securely erase the disk, reset is required for the request to be processed in next boot" +#string STR_DISK_INFO_REVERT_HELP #language en-US "Revert the disk to factory defaults, reset is required for the request to be processed in next boot" +#string STR_DISK_INFO_PSID_REVERT_HELP #language en-US "Revert the disk to factory defaults, PSID is a 32 character case sensitive value, reset is required for the request to be processed in next boot" +#string STR_DISK_INFO_DISABLE_USER_HELP #language en-US "Disable User, reset is required for the request to be processed in next boot" +#string STR_DISK_INFO_ENABLE_FEATURE_HELP #language en-US "Enable Feature, reset is required for the request to be processed in next boot" +#string STR_KEEP_USER_DATA_PROMPT #language en-US " Keep User Data" +#string STR_KEEP_USER_DATA_HELP #language en-US "Check to keep user data, otherwise data will be lost" + +#string STR_DISK_INFO_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" diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalHiiFormValues.h b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalHiiFormValues.h new file mode 100644 index 00000000..fa0a679e --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalHiiFormValues.h @@ -0,0 +1,109 @@ +/** @file + Defines Opal HII form ids, structures and values. + +Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#ifndef _OPAL_HII_FORM_VALUES_H_ +#define _OPAL_HII_FORM_VALUES_H_ + +// 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 + +#pragma pack(1) +typedef struct { + UINT16 Lock:1; + UINT16 Unlock:1; + UINT16 SetAdminPwd:1; + UINT16 SetUserPwd:1; + UINT16 SecureErase:1; + UINT16 Revert:1; + UINT16 PsidRevert:1; + UINT16 DisableUser:1; + UINT16 DisableFeature:1; + UINT16 EnableFeature:1; + UINT16 Reserved:5; + UINT16 KeepUserData:1; +} OPAL_REQUEST; + +typedef struct { + UINT8 NumDisks; + UINT8 SelectedDiskIndex; + UINT16 SelectedDiskAvailableActions; + UINT16 SupportedDisks; + BOOLEAN KeepUserDataForced; + OPAL_REQUEST OpalRequest; + 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_REVERT 0x0020 +#define HII_ACTION_PSID_REVERT 0x0040 +#define HII_ACTION_DISABLE_USER 0x0080 +#define HII_ACTION_DISABLE_FEATURE 0x0100 +#define HII_ACTION_ENABLE_FEATURE 0x0200 + +/* 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_DISK_INFO 1 + +#define HII_KEY_ID_VAR_SUPPORTED_DISKS 2 +#define HII_KEY_ID_VAR_SELECTED_DISK_AVAILABLE_ACTIONS 3 + +#define HII_KEY_ID_BLOCKSID 4 +#define HII_KEY_ID_SET_ADMIN_PWD 5 +#define HII_KEY_ID_SET_USER_PWD 6 +#define HII_KEY_ID_SECURE_ERASE 7 +#define HII_KEY_ID_REVERT 8 +#define HII_KEY_ID_KEEP_USER_DATA 9 +#define HII_KEY_ID_PSID_REVERT 0xA +#define HII_KEY_ID_DISABLE_USER 0xB +#define HII_KEY_ID_ENABLE_FEATURE 0xC + +#define HII_KEY_ID_MAX 0xC // !!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/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordCommon.h b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordCommon.h new file mode 100644 index 00000000..8563e32f --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordCommon.h @@ -0,0 +1,38 @@ +/** @file + Opal Password common header file. + +Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _OPAL_PASSWORD_COMMON_H_ +#define _OPAL_PASSWORD_COMMON_H_ + +#define OPAL_MAX_PASSWORD_SIZE 32 + +#define OPAL_DEVICE_TYPE_UNKNOWN 0x0 +#define OPAL_DEVICE_TYPE_ATA 0x1 +#define OPAL_DEVICE_TYPE_NVME 0x2 + +typedef struct { + UINT16 Segment; + UINT8 Bus; + UINT8 Device; + UINT8 Function; + UINT8 Reserved; +} OPAL_PCI_DEVICE; + +typedef struct { + UINT32 Length; + OPAL_PCI_DEVICE Device; + UINT8 PasswordLength; + UINT8 Password[OPAL_MAX_PASSWORD_SIZE]; + UINT16 OpalBaseComId; + UINT32 DevicePathLength; + EFI_DEVICE_PATH_PROTOCOL DevicePath[]; +} OPAL_DEVICE_LOCKBOX_DATA; + +#define OPAL_DEVICE_LOCKBOX_GUID { 0x56a77f0d, 0x6f05, 0x4d47, { 0xb9, 0x11, 0x4f, 0xd, 0xec, 0x5c, 0x58, 0x61 } } + +#endif // _OPAL_PASSWORD_COMMON_H_ diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordDxe.inf b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordDxe.inf new file mode 100644 index 00000000..40472595 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordDxe.inf @@ -0,0 +1,77 @@ +## @file +# This is a OpalPasswordDxe driver. +# +# This module is used to Management the Opal feature +# for Opal supported devices. +# +# Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## +[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 EBC +# + +[Sources] + OpalDriver.c + OpalDriver.h + OpalPasswordCommon.h + OpalHii.c + OpalHii.h + OpalHiiCallbacks.c + OpalHiiFormValues.h + OpalHiiFormStrings.uni + OpalPasswordForm.vfr + ComponentName.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + BaseLib + MemoryAllocationLib + UefiBootServicesTableLib + UefiDriverEntryPoint + UefiRuntimeServicesTableLib + DxeServicesTableLib + UefiHiiServicesLib + BaseMemoryLib + DebugLib + HiiLib + PrintLib + DevicePathLib + UefiLib + TcgStorageOpalLib + Tcg2PhysicalPresenceLib + PciLib + LockBoxLib + +[Protocols] + gEfiHiiConfigAccessProtocolGuid ## PRODUCES + gEfiStorageSecurityCommandProtocolGuid ## CONSUMES + gEfiComponentNameProtocolGuid ## PRODUCES + gEfiComponentName2ProtocolGuid ## PRODUCES + gEfiBlockIoProtocolGuid ## CONSUMES + +[Guids] + gEfiEndOfDxeEventGroupGuid ## CONSUMES ## Event + gS3StorageDeviceInitListGuid ## SOMETIMES_PRODUCES ## UNDEFINED + +[Pcd] + gEfiSecurityPkgTokenSpaceGuid.PcdSkipOpalPasswordPrompt ## CONSUMES + +[Depex] + gEfiHiiStringProtocolGuid AND gEfiHiiDatabaseProtocolGuid diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordForm.vfr b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordForm.vfr new file mode 100644 index 00000000..6f3290b1 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordForm.vfr @@ -0,0 +1,303 @@ +/** @file + +Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ +#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 = 0x8002, + minimum = 0x0, + maximum = 0xFFFF, + endnumeric; + endif; + + subtitle text = STRING_TOKEN(STR_MAIN_OPAL_TITLE_LBL); + + subtitle text = STRING_TOKEN(STR_NULL); + + subtitle text = STRING_TOKEN(STR_MAIN_PHY_DISKS_LBL); + + //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; + 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; + 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; + 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; + 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; + 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; + endif; + + //No disks on system + suppressif ideqval OpalHiiConfig.NumDisks > 0; + text + help = STRING_TOKEN(STR_MAIN_NO_DISKS_PRESENT_LBL_HELP), + 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 = 0x8004, + prompt = STRING_TOKEN(STR_DISK_INFO_ENABLE_BLOCKSID), + help = STRING_TOKEN(STR_DISK_INFO_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 = 0x8003, + minimum = 0x0, + maximum = 0xFFFF, + endnumeric; + endif; + + suppressif TRUE; + checkbox varid = OpalHiiConfig.KeepUserDataForced, + prompt = STRING_TOKEN(STR_NULL), + help = STRING_TOKEN(STR_NULL), + endcheckbox; + endif; + + subtitle text = STRING_TOKEN(STR_DISK_INFO_TITLE_LBL); + + 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); + + subtitle text = STRING_TOKEN(STR_OPAL_REQUESTS_LBL); + + suppressif ( questionref(SelectedDiskAvailableActions) & HII_ACTION_SET_ADMIN_PWD ) == 0; + grayoutif ideqval OpalHiiConfig.OpalRequest.Revert == 1; + grayoutif ideqval OpalHiiConfig.OpalRequest.PsidRevert == 1; + checkbox varid = OpalHiiConfig.OpalRequest.SetAdminPwd, + prompt = STRING_TOKEN(STR_DISK_INFO_SET_ADMIN_PSWD), + help = STRING_TOKEN(STR_DISK_INFO_SET_ADMIN_PSWD_HELP), + flags = INTERACTIVE | RESET_REQUIRED, + key = 0x8005, + endcheckbox; + endif; + endif; + endif; + + suppressif ( questionref(SelectedDiskAvailableActions) & HII_ACTION_SET_USER_PWD ) == 0; + grayoutif ideqval OpalHiiConfig.OpalRequest.DisableUser == 1; + grayoutif ideqval OpalHiiConfig.OpalRequest.Revert == 1; + grayoutif ideqval OpalHiiConfig.OpalRequest.PsidRevert == 1; + checkbox varid = OpalHiiConfig.OpalRequest.SetUserPwd, + prompt = STRING_TOKEN(STR_DISK_INFO_SET_USER_PSWD), + help = STRING_TOKEN(STR_DISK_INFO_SET_USER_PSWD_HELP), + flags = INTERACTIVE | RESET_REQUIRED, + key = 0x8006, + endcheckbox; + endif; + endif; + endif; + endif; + + suppressif ( questionref(SelectedDiskAvailableActions) & HII_ACTION_SECURE_ERASE ) == 0; + grayoutif ideqval OpalHiiConfig.OpalRequest.Revert == 1; + grayoutif ideqval OpalHiiConfig.OpalRequest.PsidRevert == 1; + checkbox varid = OpalHiiConfig.OpalRequest.SecureErase, + prompt = STRING_TOKEN(STR_DISK_INFO_SECURE_ERASE), + help = STRING_TOKEN(STR_DISK_INFO_SECURE_ERASE_HELP), + flags = INTERACTIVE | RESET_REQUIRED, + key = 0x8007, + endcheckbox; + endif; + endif; + endif; + + suppressif ( questionref(SelectedDiskAvailableActions) & HII_ACTION_REVERT ) == 0; + grayoutif ideqval OpalHiiConfig.OpalRequest.SetAdminPwd == 1; + grayoutif ideqval OpalHiiConfig.OpalRequest.SetUserPwd == 1; + grayoutif ideqval OpalHiiConfig.OpalRequest.SecureErase == 1; + grayoutif ideqval OpalHiiConfig.OpalRequest.DisableUser == 1; + grayoutif ideqval OpalHiiConfig.OpalRequest.PsidRevert == 1; + checkbox varid = OpalHiiConfig.OpalRequest.Revert, + prompt = STRING_TOKEN(STR_DISK_INFO_REVERT), + help = STRING_TOKEN(STR_DISK_INFO_REVERT_HELP), + flags = INTERACTIVE | RESET_REQUIRED, + key = 0x8008, + endcheckbox; + endif; + endif; + endif; + endif; + endif; + endif; + + suppressif ideqval OpalHiiConfig.OpalRequest.Revert == 0; + grayoutif ideqval OpalHiiConfig.KeepUserDataForced == 1; + checkbox varid = OpalHiiConfig.OpalRequest.KeepUserData, + prompt = STRING_TOKEN(STR_KEEP_USER_DATA_PROMPT), + help = STRING_TOKEN(STR_KEEP_USER_DATA_HELP), + flags = INTERACTIVE | RESET_REQUIRED, + key = 0x8009, + endcheckbox; + endif; + endif; + + suppressif ( questionref(SelectedDiskAvailableActions) & HII_ACTION_PSID_REVERT ) == 0; + grayoutif ideqval OpalHiiConfig.OpalRequest.SetAdminPwd == 1; + grayoutif ideqval OpalHiiConfig.OpalRequest.SetUserPwd == 1; + grayoutif ideqval OpalHiiConfig.OpalRequest.SecureErase == 1; + grayoutif ideqval OpalHiiConfig.OpalRequest.DisableUser == 1; + grayoutif ideqval OpalHiiConfig.OpalRequest.EnableFeature == 1; + grayoutif ideqval OpalHiiConfig.OpalRequest.Revert == 1; + checkbox varid = OpalHiiConfig.OpalRequest.PsidRevert, + prompt = STRING_TOKEN(STR_DISK_INFO_PSID_REVERT), + help = STRING_TOKEN(STR_DISK_INFO_PSID_REVERT_HELP), + flags = INTERACTIVE | RESET_REQUIRED, + key = 0x800A, + endcheckbox; + endif; + endif; + endif; + endif; + endif; + endif; + endif; + + suppressif ( questionref(SelectedDiskAvailableActions) & HII_ACTION_DISABLE_USER ) == 0; + grayoutif ideqval OpalHiiConfig.OpalRequest.SetUserPwd == 1; + grayoutif ideqval OpalHiiConfig.OpalRequest.Revert == 1; + grayoutif ideqval OpalHiiConfig.OpalRequest.PsidRevert == 1; + checkbox varid = OpalHiiConfig.OpalRequest.DisableUser, + prompt = STRING_TOKEN(STR_DISK_INFO_DISABLE_USER), + help = STRING_TOKEN(STR_DISK_INFO_DISABLE_USER_HELP), + flags = INTERACTIVE | RESET_REQUIRED, + key = 0x800B, + endcheckbox; + endif; + endif; + endif; + endif; + + suppressif ( questionref(SelectedDiskAvailableActions) & HII_ACTION_ENABLE_FEATURE ) == 0; + grayoutif ideqval OpalHiiConfig.OpalRequest.PsidRevert == 1; + checkbox varid = OpalHiiConfig.OpalRequest.EnableFeature, + prompt = STRING_TOKEN(STR_DISK_INFO_ENABLE_FEATURE), + help = STRING_TOKEN(STR_DISK_INFO_ENABLE_FEATURE_HELP), + flags = INTERACTIVE | RESET_REQUIRED, + key = 0x800C, + endcheckbox; + endif; + endif; + +endform; // DISK INFO FORM + +endformset; diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordPei.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordPei.c new file mode 100644 index 00000000..73540306 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordPei.c @@ -0,0 +1,472 @@ +/** @file + Opal Password PEI driver which is used to unlock Opal Password for S3. + +Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "OpalPasswordPei.h" + +EFI_GUID mOpalDeviceLockBoxGuid = OPAL_DEVICE_LOCKBOX_GUID; + + +/** + 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_PEI_DEVICE *PeiDev; + + PeiDev = OPAL_PEI_DEVICE_FROM_THIS (This); + if (PeiDev == NULL) { + return EFI_DEVICE_ERROR; + } + + return PeiDev->SscPpi->ReceiveData ( + PeiDev->SscPpi, + PeiDev->DeviceIndex, + SSC_PPI_GENERIC_TIMEOUT, + SecurityProtocolId, + SecurityProtocolSpecificData, + PayloadBufferSize, + PayloadBuffer, + 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 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_PEI_DEVICE *PeiDev; + + PeiDev = OPAL_PEI_DEVICE_FROM_THIS (This); + if (PeiDev == NULL) { + return EFI_DEVICE_ERROR; + } + + return PeiDev->SscPpi->SendData ( + PeiDev->SscPpi, + PeiDev->DeviceIndex, + SSC_PPI_GENERIC_TIMEOUT, + SecurityProtocolId, + SecurityProtocolSpecificData, + PayloadBufferSize, + PayloadBuffer + ); +} + +/** + + 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_PEI_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; + } + + Session.OpalBaseComId = OpalBaseComId; + *BlockSidSupported = SupportedAttributes.BlockSid == 1 ? TRUE : FALSE; + + Ret = OpalGetLockingInfo(&Session, &LockingFeature); + if (Ret != TcgResultSuccess) { + return FALSE; + } + + return OpalDeviceLocked (&SupportedAttributes, &LockingFeature); +} + +/** + Unlock OPAL password for S3. + + @param[in] OpalDev Opal object to unlock. + +**/ +VOID +UnlockOpalPassword ( + IN OPAL_PEI_DEVICE *OpalDev + ) +{ + TCG_RESULT Result; + OPAL_SESSION Session; + BOOLEAN BlockSidSupport; + UINT32 PpStorageFlags; + BOOLEAN BlockSIDEnabled; + + BlockSidSupport = FALSE; + if (IsOpalDeviceLocked (OpalDev, &BlockSidSupport)) { + ZeroMem(&Session, sizeof (Session)); + Session.Sscp = &OpalDev->Sscp; + Session.MediaId = 0; + Session.OpalBaseComId = OpalDev->Device->OpalBaseComId; + + Result = OpalUtilUpdateGlobalLockingRange ( + &Session, + OpalDev->Device->Password, + OpalDev->Device->PasswordLength, + FALSE, + FALSE + ); + DEBUG (( + DEBUG_INFO, + "%a() OpalUtilUpdateGlobalLockingRange() Result = 0x%x\n", + __FUNCTION__, + Result + )); + } + + PpStorageFlags = Tcg2PhysicalPresenceLibGetManagementFlags (); + if ((PpStorageFlags & TCG2_BIOS_STORAGE_MANAGEMENT_FLAG_ENABLE_BLOCK_SID) != 0) { + BlockSIDEnabled = TRUE; + } else { + BlockSIDEnabled = FALSE; + } + if (BlockSIDEnabled && BlockSidSupport) { + DEBUG ((DEBUG_INFO, "OpalPassword: S3 phase send BlockSid command to device!\n")); + ZeroMem(&Session, sizeof (Session)); + Session.Sscp = &OpalDev->Sscp; + Session.MediaId = 0; + Session.OpalBaseComId = OpalDev->Device->OpalBaseComId; + Result = OpalBlockSid (&Session, TRUE); + DEBUG (( + DEBUG_INFO, + "%a() OpalBlockSid() Result = 0x%x\n", + __FUNCTION__, + Result + )); + } +} + +/** + Unlock the OPAL NVM Express and ATA devices for S3. + + @param[in] SscPpi Pointer to the EDKII_PEI_STORAGE_SECURITY_CMD_PPI instance. + +**/ +VOID +UnlockOpalPasswordDevices ( + IN EDKII_PEI_STORAGE_SECURITY_CMD_PPI *SscPpi + ) +{ + EFI_STATUS Status; + UINT8 *DevInfoBuffer; + UINT8 DummyData; + OPAL_DEVICE_LOCKBOX_DATA *DevInfo; + UINTN DevInfoLength; + EFI_DEVICE_PATH_PROTOCOL *SscDevicePath; + UINTN SscDevicePathLength; + UINTN SscDeviceNum; + UINTN SscDeviceIndex; + OPAL_PEI_DEVICE OpalDev; + + // + // Get OPAL devices info from LockBox. + // + DevInfoBuffer = &DummyData; + DevInfoLength = sizeof (DummyData); + Status = RestoreLockBox (&mOpalDeviceLockBoxGuid, DevInfoBuffer, &DevInfoLength); + if (Status == EFI_BUFFER_TOO_SMALL) { + DevInfoBuffer = AllocatePages (EFI_SIZE_TO_PAGES (DevInfoLength)); + if (DevInfoBuffer != NULL) { + Status = RestoreLockBox (&mOpalDeviceLockBoxGuid, DevInfoBuffer, &DevInfoLength); + } + } + if (DevInfoBuffer == NULL || DevInfoBuffer == &DummyData) { + return; + } else if (EFI_ERROR (Status)) { + FreePages (DevInfoBuffer, EFI_SIZE_TO_PAGES (DevInfoLength)); + return; + } + + // + // Go through all the devices managed by the SSC PPI instance. + // + Status = SscPpi->GetNumberofDevices (SscPpi, &SscDeviceNum); + if (EFI_ERROR (Status)) { + goto Exit; + } + for (SscDeviceIndex = 1; SscDeviceIndex <= SscDeviceNum; SscDeviceIndex++) { + Status = SscPpi->GetDevicePath ( + SscPpi, + SscDeviceIndex, + &SscDevicePathLength, + &SscDevicePath + ); + if (SscDevicePathLength <= sizeof (EFI_DEVICE_PATH_PROTOCOL)) { + // + // Device path validity check. + // + continue; + } + + // + // Search the device in the restored LockBox. + // + for (DevInfo = (OPAL_DEVICE_LOCKBOX_DATA *) DevInfoBuffer; + (UINTN) DevInfo < ((UINTN) DevInfoBuffer + DevInfoLength); + DevInfo = (OPAL_DEVICE_LOCKBOX_DATA *) ((UINTN) DevInfo + DevInfo->Length)) { + // + // Find the matching device. + // + if ((DevInfo->DevicePathLength >= SscDevicePathLength) && + (CompareMem ( + DevInfo->DevicePath, + SscDevicePath, + SscDevicePathLength - sizeof (EFI_DEVICE_PATH_PROTOCOL)) == 0)) { + OpalDev.Signature = OPAL_PEI_DEVICE_SIGNATURE; + OpalDev.Sscp.ReceiveData = SecurityReceiveData; + OpalDev.Sscp.SendData = SecuritySendData; + OpalDev.Device = DevInfo; + OpalDev.Context = NULL; + OpalDev.SscPpi = SscPpi; + OpalDev.DeviceIndex = SscDeviceIndex; + UnlockOpalPassword (&OpalDev); + break; + } + } + } + +Exit: + ZeroMem (DevInfoBuffer, DevInfoLength); + FreePages (DevInfoBuffer, EFI_SIZE_TO_PAGES (DevInfoLength)); + +} + +/** + One notified function at the installation of EDKII_PEI_STORAGE_SECURITY_CMD_PPI. + It is to unlock OPAL password for S3. + + @param[in] PeiServices Indirect reference to the PEI Services Table. + @param[in] NotifyDescriptor Address of the notification descriptor data structure. + @param[in] Ppi Address of the PPI that was installed. + + @return Status of the notification. + The status code returned from this function is ignored. + +**/ +EFI_STATUS +EFIAPI +OpalPasswordStorageSecurityPpiNotify ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc, + IN VOID *Ppi + ) +{ + DEBUG ((DEBUG_INFO, "%a entered at S3 resume!\n", __FUNCTION__)); + + UnlockOpalPasswordDevices ((EDKII_PEI_STORAGE_SECURITY_CMD_PPI *) Ppi); + + DEBUG ((DEBUG_INFO, "%a exit at S3 resume!\n", __FUNCTION__)); + + return EFI_SUCCESS; +} + + +EFI_PEI_NOTIFY_DESCRIPTOR mOpalPasswordStorageSecurityPpiNotifyDesc = { + (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gEdkiiPeiStorageSecurityCommandPpiGuid, + OpalPasswordStorageSecurityPpiNotify +}; + + +/** + Main entry for this module. + + @param FileHandle Handle of the file being invoked. + @param PeiServices Pointer to PEI Services table. + + @return Status from PeiServicesNotifyPpi. + +**/ +EFI_STATUS +EFIAPI +OpalPasswordPeiInit ( + IN EFI_PEI_FILE_HANDLE FileHandle, + IN CONST EFI_PEI_SERVICES **PeiServices + ) +{ + EFI_STATUS Status; + EFI_BOOT_MODE BootMode; + + Status = PeiServicesGetBootMode (&BootMode); + if ((EFI_ERROR (Status)) || (BootMode != BOOT_ON_S3_RESUME)) { + return EFI_UNSUPPORTED; + } + + DEBUG ((DEBUG_INFO, "%a: Enters in S3 path.\n", __FUNCTION__)); + + Status = PeiServicesNotifyPpi (&mOpalPasswordStorageSecurityPpiNotifyDesc); + ASSERT_EFI_ERROR (Status); + return Status; +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordPei.h b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordPei.h new file mode 100644 index 00000000..7d8a5e1e --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordPei.h @@ -0,0 +1,60 @@ +/** @file + Opal Password PEI driver which is used to unlock Opal Password for S3. + +Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _OPAL_PASSWORD_PEI_H_ +#define _OPAL_PASSWORD_PEI_H_ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include "OpalPasswordCommon.h" + + +// +// The generic command timeout value (unit in us) for Storage Security Command +// PPI ReceiveData/SendData services +// +#define SSC_PPI_GENERIC_TIMEOUT 30000000 + +#pragma pack(1) + +#define OPAL_PEI_DEVICE_SIGNATURE SIGNATURE_32 ('o', 'p', 'd', 's') + +typedef struct { + UINTN Signature; + EFI_STORAGE_SECURITY_COMMAND_PROTOCOL Sscp; + OPAL_DEVICE_LOCKBOX_DATA *Device; + VOID *Context; + EDKII_PEI_STORAGE_SECURITY_CMD_PPI *SscPpi; + UINTN DeviceIndex; +} OPAL_PEI_DEVICE; + +#define OPAL_PEI_DEVICE_FROM_THIS(a) \ + CR (a, OPAL_PEI_DEVICE, Sscp, OPAL_PEI_DEVICE_SIGNATURE) + +#pragma pack() + +#endif // _OPAL_PASSWORD_PEI_H_ + diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordPei.inf b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordPei.inf new file mode 100644 index 00000000..c9599740 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordPei.inf @@ -0,0 +1,51 @@ +## @file +# This is a Opal Password PEI driver. +# +# Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = OpalPasswordPei + FILE_GUID = DED60489-979C-4B5A-8EE4-4068B0CC38DC + MODULE_TYPE = PEIM + VERSION_STRING = 1.0 + ENTRY_POINT = OpalPasswordPeiInit + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + OpalPasswordPei.c + OpalPasswordPei.h + OpalPasswordCommon.h + +[Packages] + MdePkg/MdePkg.dec + SecurityPkg/SecurityPkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + PeimEntryPoint + PeiServicesLib + DebugLib + IoLib + PciLib + BaseLib + BaseMemoryLib + MemoryAllocationLib + LockBoxLib + TcgStorageOpalLib + Tcg2PhysicalPresenceLib + PeiServicesTablePointerLib + +[Ppis] + gEdkiiPeiStorageSecurityCommandPpiGuid ## NOTIFY + +[Depex] + gEfiPeiMasterBootModePpiGuid diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePei.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePei.c new file mode 100644 index 00000000..4b226c75 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePei.c @@ -0,0 +1,128 @@ +/** @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 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#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 + ); + +// +// Global definitions 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/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePei.inf b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePei.inf new file mode 100644 index 00000000..5d8f3635 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePei.inf @@ -0,0 +1,59 @@ +## @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 - 2018, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + + +[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 +# + +[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 + diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePei.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePei.uni new file mode 100644 index 00000000..1e7e864c --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePei.uni @@ -0,0 +1,18 @@ +// /** @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.
+// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + + +#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/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePeiExtra.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePeiExtra.uni new file mode 100644 index 00000000..eed7519b --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePeiExtra.uni @@ -0,0 +1,14 @@ +// /** @file +// PhysicalPresencePei Localized Strings and Content +// +// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.
+// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_PROPERTIES_MODULE_NAME +#language en-US +"Physical Presence PEI" + + diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Acpi/Tcg2Acpi.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Acpi/Tcg2Acpi.c new file mode 100644 index 00000000..a0964aef --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Acpi/Tcg2Acpi.c @@ -0,0 +1,902 @@ +/** @file + This driver implements TPM 2.0 definition block in ACPI table and + populates registered SMI callback functions for Tcg2 physical presence + and MemoryClear to handle the requests for ACPI method. It needs to be + used together with Tcg2 MM drivers to exchange information on registered + SwSmiValue and allocated NVS region address. + + 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 - 2018, Intel Corporation. All rights reserved.
+Copyright (c) Microsoft Corporation. +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include + +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// +// 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 + +#define TPM_PRS_RESL "RESL" +#define TPM_PRS_RESS "RESS" +#define TPM_PRS_RES_NAME_SIZE 4 +// +// Minimum PRS resource template size +// 1 byte for BufferOp +// 1 byte for PkgLength +// 2 bytes for BufferSize +// 12 bytes for Memory32Fixed descriptor +// 5 bytes for Interrupt descriptor +// 2 bytes for END Tag +// +#define TPM_POS_RES_TEMPLATE_MIN_SIZE (1 + 1 + 2 + 12 + 5 + 2) + +// +// Max Interrupt buffer size for PRS interrupt resource +// Now support 15 interrupts in maxmum +// +#define MAX_PRS_INT_BUF_SIZE (15*4) + +#pragma pack(1) + +typedef struct { + EFI_ACPI_DESCRIPTION_HEADER Header; + // Flags field is replaced in version 4 and above + // BIT0~15: PlatformClass This field is only valid for version 4 and above + // BIT16~31: Reserved + UINT32 Flags; + UINT64 AddressOfControlArea; + UINT32 StartMethod; + UINT8 PlatformSpecificParameters[12]; // size up to 12 + UINT32 Laml; // Optional + UINT64 Lasa; // Optional +} EFI_TPM2_ACPI_TABLE_V4; + +#pragma pack() + +EFI_TPM2_ACPI_TABLE_V4 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 +}; + +TCG_NVS *mTcgNvs; + +/** + 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; + // Request to unblock this region from MM core + Status = MmUnblockMemoryRequest (MemoryAddress, EFI_SIZE_TO_PAGES (Size)); + if (Status != EFI_UNSUPPORTED && EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + } + break; + } + } + + return (VOID *) (UINTN) MemoryAddress; +} + +/** + Locate the MM communication buffer and protocol, then use it to exchange information with + Tcg2StandaloneMmm on NVS address and SMI value. + + @param[in, out] TcgNvs The NVS subject to send to MM environment. + + @return The status for locating MM common buffer, communicate to MM, etc. + +**/ +EFI_STATUS +EFIAPI +ExchangeCommonBuffer ( + IN OUT TCG_NVS *TcgNvs +) +{ + EFI_STATUS Status; + EFI_MM_COMMUNICATION_PROTOCOL *MmCommunication; + EDKII_PI_SMM_COMMUNICATION_REGION_TABLE *PiSmmCommunicationRegionTable; + EFI_MEMORY_DESCRIPTOR *MmCommMemRegion; + EFI_MM_COMMUNICATE_HEADER *CommHeader; + TPM_NVS_MM_COMM_BUFFER *CommBuffer; + UINTN CommBufferSize; + UINTN Index; + + // Step 0: Sanity check for input argument + if (TcgNvs == NULL) { + DEBUG ((DEBUG_ERROR, "%a - Input argument is NULL!\n", __FUNCTION__)); + return EFI_INVALID_PARAMETER; + } + + // Step 1: Grab the common buffer header + Status = EfiGetSystemConfigurationTable (&gEdkiiPiSmmCommunicationRegionTableGuid, (VOID**) &PiSmmCommunicationRegionTable); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a - Failed to locate SMM communciation common buffer - %r!\n", __FUNCTION__, Status)); + return Status; + } + + // Step 2: Grab one that is large enough to hold TPM_NVS_MM_COMM_BUFFER, the IPL one should be sufficient + CommBufferSize = 0; + MmCommMemRegion = (EFI_MEMORY_DESCRIPTOR*) (PiSmmCommunicationRegionTable + 1); + for (Index = 0; Index < PiSmmCommunicationRegionTable->NumberOfEntries; Index++) { + if (MmCommMemRegion->Type == EfiConventionalMemory) { + CommBufferSize = EFI_PAGES_TO_SIZE ((UINTN)MmCommMemRegion->NumberOfPages); + if (CommBufferSize >= (sizeof (TPM_NVS_MM_COMM_BUFFER) + OFFSET_OF (EFI_MM_COMMUNICATE_HEADER, Data))) { + break; + } + } + MmCommMemRegion = (EFI_MEMORY_DESCRIPTOR*)((UINT8*)MmCommMemRegion + PiSmmCommunicationRegionTable->DescriptorSize); + } + + if (Index >= PiSmmCommunicationRegionTable->NumberOfEntries) { + // Could not find one that meets our goal... + DEBUG ((DEBUG_ERROR, "%a - Could not find a common buffer that is big enough for NVS!\n", __FUNCTION__)); + return EFI_OUT_OF_RESOURCES; + } + + // Step 3: Start to populate contents + // Step 3.1: MM Communication common header + CommHeader = (EFI_MM_COMMUNICATE_HEADER *) (UINTN) MmCommMemRegion->PhysicalStart; + CommBufferSize = sizeof (TPM_NVS_MM_COMM_BUFFER) + OFFSET_OF (EFI_MM_COMMUNICATE_HEADER, Data); + ZeroMem (CommHeader, CommBufferSize); + CopyGuid (&CommHeader->HeaderGuid, &gTpmNvsMmGuid); + CommHeader->MessageLength = sizeof (TPM_NVS_MM_COMM_BUFFER); + + // Step 3.2: TPM_NVS_MM_COMM_BUFFER content per our needs + CommBuffer = (TPM_NVS_MM_COMM_BUFFER *) (CommHeader->Data); + CommBuffer->Function = TpmNvsMmExchangeInfo; + CommBuffer->TargetAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) TcgNvs; + + // Step 4: Locate the protocol and signal Mmi. + Status = gBS->LocateProtocol (&gEfiMmCommunicationProtocolGuid, NULL, (VOID**) &MmCommunication); + if (!EFI_ERROR (Status)) { + Status = MmCommunication->Communicate (MmCommunication, CommHeader, &CommBufferSize); + DEBUG ((DEBUG_INFO, "%a - Communicate() = %r\n", __FUNCTION__, Status)); + } + else { + DEBUG ((DEBUG_ERROR, "%a - Failed to locate MmCommunication protocol - %r\n", __FUNCTION__, Status)); + return Status; + } + + // Step 5: If everything goes well, populate the channel number + if (!EFI_ERROR (CommBuffer->ReturnStatus)) { + // Need to demote to UINT8 according to SMI value definition + TcgNvs->PhysicalPresence.SoftwareSmi = (UINT8) CommBuffer->RegisteredPpSwiValue; + TcgNvs->MemoryClear.SoftwareSmi = (UINT8) CommBuffer->RegisteredMcSwiValue; + DEBUG (( + DEBUG_INFO, + "%a Communication returned software SMI value. PP: 0x%x; MC: 0x%x.\n", + __FUNCTION__, + TcgNvs->PhysicalPresence.SoftwareSmi, + TcgNvs->MemoryClear.SoftwareSmi + )); + } + + return (EFI_STATUS) CommBuffer->ReturnStatus; +} + +/** + 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((DEBUG_INFO, "TPM2 Physical Presence Interface Version update status 0x%x\n", Status)); + return Status; + } + } + + return EFI_NOT_FOUND; +} + +/** + Patch interrupt resources returned by TPM _PRS. ResourceTemplate to patch is determined by input + interrupt buffer size. BufferSize, PkgLength and interrupt descriptor in ByteList need to be patched + + @param[in, out] Table The TPM item in ACPI table. + @param[in] IrqBuffer Input new IRQ buffer. + @param[in] IrqBuffserSize Input new IRQ buffer size. + @param[out] IsShortFormPkgLength If _PRS returns Short length Package(ACPI spec 20.2.4). + + @return patch status. + +**/ +EFI_STATUS +UpdatePossibleResource ( + IN OUT EFI_ACPI_DESCRIPTION_HEADER *Table, + IN UINT32 *IrqBuffer, + IN UINT32 IrqBuffserSize, + OUT BOOLEAN *IsShortFormPkgLength + ) +{ + UINT8 *DataPtr; + UINT8 *DataEndPtr; + UINT32 NewPkgLength; + UINT32 OrignalPkgLength; + + NewPkgLength = 0; + OrignalPkgLength = 0; + DataEndPtr = NULL; + + // + // Follow ACPI spec + // 6.4.3 Extend Interrupt Descriptor. + // 19.3.3 ASL Resource Template + // 20 AML specification + // to patch TPM ACPI object _PRS returned ResourceTemplate() containing 2 resource descriptors and an auto appended End Tag + // + // AML data is organized by following rule. + // Code need to patch BufferSize and PkgLength and interrupt descriptor in ByteList + // + // ============= Buffer ==================== + // DefBuffer := BufferOp PkgLength BufferSize ByteList + // BufferOp := 0x11 + // + // ==============PkgLength================== + // PkgLength := PkgLeadByte | + // | + // | + // + // + // PkgLeadByte := + // + // + // + //==============BufferSize================== + // BufferSize := Integer + // Integer := ByteConst|WordConst|DwordConst.... + // + // ByteConst := BytePrefix ByteData + // + //==============ByteList=================== + // ByteList := ByteData ByteList + // + //========================================= + + // + // 1. Check TPM_PRS_RESS with PkgLength <=63 can hold the input interrupt number buffer for patching + // + for (DataPtr = (UINT8 *)(Table + 1); + DataPtr < (UINT8 *) ((UINT8 *) Table + Table->Length - (TPM_PRS_RES_NAME_SIZE + TPM_POS_RES_TEMPLATE_MIN_SIZE)); + DataPtr += 1) { + if (CompareMem(DataPtr, TPM_PRS_RESS, TPM_PRS_RES_NAME_SIZE) == 0) { + // + // Jump over object name & BufferOp + // + DataPtr += TPM_PRS_RES_NAME_SIZE + 1; + + if ((*DataPtr & (BIT7|BIT6)) == 0) { + OrignalPkgLength = (UINT32)*DataPtr; + DataEndPtr = DataPtr + OrignalPkgLength; + + // + // Jump over PkgLength = PkgLeadByte only + // + NewPkgLength++; + + // + // Jump over BufferSize + // + if (*(DataPtr + 1) == AML_BYTE_PREFIX) { + NewPkgLength += 2; + } else if (*(DataPtr + 1) == AML_WORD_PREFIX) { + NewPkgLength += 3; + } else if (*(DataPtr + 1) == AML_DWORD_PREFIX) { + NewPkgLength += 5; + } else { + ASSERT(FALSE); + return EFI_UNSUPPORTED; + } + } else { + ASSERT(FALSE); + return EFI_UNSUPPORTED; + } + + // + // Include Memory32Fixed Descriptor (12 Bytes) + Interrupt Descriptor header(5 Bytes) + End Tag(2 Bytes) + // + NewPkgLength += 19 + IrqBuffserSize; + if (NewPkgLength > 63) { + break; + } + + if (NewPkgLength > OrignalPkgLength) { + ASSERT(FALSE); + return EFI_INVALID_PARAMETER; + } + + // + // 1.1 Patch PkgLength + // + *DataPtr = (UINT8)NewPkgLength; + + // + // 1.2 Patch BufferSize = sizeof(Memory32Fixed Descriptor + Interrupt Descriptor + End Tag). + // It is Little endian. So only patch lowest byte of BufferSize due to current interrupt number limit. + // + *(DataPtr + 2) = (UINT8)(IrqBuffserSize + 19); + + // + // Notify _PRS to report short formed ResourceTemplate + // + *IsShortFormPkgLength = TRUE; + + break; + } + } + + // + // 2. Use TPM_PRS_RESL with PkgLength > 63 to hold longer input interrupt number buffer for patching + // + if (NewPkgLength > 63) { + NewPkgLength = 0; + OrignalPkgLength = 0; + for (DataPtr = (UINT8 *)(Table + 1); + DataPtr < (UINT8 *) ((UINT8 *) Table + Table->Length - (TPM_PRS_RES_NAME_SIZE + TPM_POS_RES_TEMPLATE_MIN_SIZE)); + DataPtr += 1) { + if (CompareMem(DataPtr, TPM_PRS_RESL, TPM_PRS_RES_NAME_SIZE) == 0) { + // + // Jump over object name & BufferOp + // + DataPtr += TPM_PRS_RES_NAME_SIZE + 1; + + if ((*DataPtr & (BIT7|BIT6)) != 0) { + OrignalPkgLength = (UINT32)(*(DataPtr + 1) << 4) + (*DataPtr & 0x0F); + DataEndPtr = DataPtr + OrignalPkgLength; + // + // Jump over PkgLength = PkgLeadByte + ByteData length + // + NewPkgLength += 1 + ((*DataPtr & (BIT7|BIT6)) >> 6); + + // + // Jump over BufferSize + // + if (*(DataPtr + NewPkgLength) == AML_BYTE_PREFIX) { + NewPkgLength += 2; + } else if (*(DataPtr + NewPkgLength) == AML_WORD_PREFIX) { + NewPkgLength += 3; + } else if (*(DataPtr + NewPkgLength) == AML_DWORD_PREFIX) { + NewPkgLength += 5; + } else { + ASSERT(FALSE); + return EFI_UNSUPPORTED; + } + } else { + ASSERT(FALSE); + return EFI_UNSUPPORTED; + } + + // + // Include Memory32Fixed Descriptor (12 Bytes) + Interrupt Descriptor header(5 Bytes) + End Tag(2 Bytes) + // + NewPkgLength += 19 + IrqBuffserSize; + + if (NewPkgLength > OrignalPkgLength) { + ASSERT(FALSE); + return EFI_INVALID_PARAMETER; + } + + // + // 2.1 Patch PkgLength. Only patch PkgLeadByte and first ByteData + // + *DataPtr = (UINT8)((*DataPtr) & 0xF0) | (NewPkgLength & 0x0F); + *(DataPtr + 1) = (UINT8)((NewPkgLength & 0xFF0) >> 4); + + // + // 2.2 Patch BufferSize = sizeof(Memory32Fixed Descriptor + Interrupt Descriptor + End Tag). + // It is Little endian. Only patch lowest byte of BufferSize due to current interrupt number limit. + // + *(DataPtr + 2 + ((*DataPtr & (BIT7|BIT6)) >> 6)) = (UINT8)(IrqBuffserSize + 19); + + // + // Notify _PRS to report long formed ResourceTemplate + // + *IsShortFormPkgLength = FALSE; + break; + } + } + } + + if (DataPtr >= (UINT8 *) ((UINT8 *) Table + Table->Length - (TPM_PRS_RES_NAME_SIZE + TPM_POS_RES_TEMPLATE_MIN_SIZE))) { + return EFI_NOT_FOUND; + } + + // + // 3. Move DataPtr to Interrupt descriptor header and patch interrupt descriptor. + // 5 bytes for interrupt descriptor header, 2 bytes for End Tag + // + DataPtr += NewPkgLength - (5 + IrqBuffserSize + 2); + // + // 3.1 Patch Length bit[7:0] of Interrupt descriptor patch interrupt descriptor + // + *(DataPtr + 1) = (UINT8)(2 + IrqBuffserSize); + // + // 3.2 Patch Interrupt Table Length + // + *(DataPtr + 4) = (UINT8)(IrqBuffserSize / sizeof(UINT32)); + // + // 3.3 Copy patched InterruptNumBuffer + // + CopyMem(DataPtr + 5, IrqBuffer, IrqBuffserSize); + + // + // 4. Jump over Interrupt descriptor and Patch END Tag, set Checksum field to 0 + // + DataPtr += 5 + IrqBuffserSize; + *DataPtr = ACPI_END_TAG_DESCRIPTOR; + *(DataPtr + 1) = 0; + + // + // 5. Jump over new ResourceTemplate. Stuff rest bytes to NOOP + // + DataPtr += 2; + if (DataPtr < DataEndPtr) { + SetMem(DataPtr, (UINTN)DataEndPtr - (UINTN)DataPtr, AML_NOOP_OP); + } + + return EFI_SUCCESS; +} + +/** + 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((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; + } + + // + // 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((DEBUG_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; + UINT32 *PossibleIrqNumBuf; + UINT32 PossibleIrqNumBufSize; + BOOLEAN IsShortFormPkgLength; + + IsShortFormPkgLength = FALSE; + + 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. + // The measurement has to be done before any update. + // Otherwise, the PCR record would be different after TPM FW update + // or the PCD configuration change. + // + TpmMeasureAndLogData( + 0, + EV_POST_CODE, + EV_POSTCODE_INFO_ACPI_DATA, + ACPI_DATA_LEN, + Table, + TableSize + ); + + // + // 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 after measuring it to PCR + // + Status = UpdateHID(Table); + if (EFI_ERROR(Status)) { + return Status; + } + + if (PcdGet32(PcdTpm2CurrentIrqNum) != 0) { + // + // Patch _PRS interrupt resource only when TPM interrupt is supported + // + PossibleIrqNumBuf = (UINT32 *)PcdGetPtr(PcdTpm2PossibleIrqNumBuf); + PossibleIrqNumBufSize = (UINT32)PcdGetSize(PcdTpm2PossibleIrqNumBuf); + + if (PossibleIrqNumBufSize <= MAX_PRS_INT_BUF_SIZE && (PossibleIrqNumBufSize % sizeof(UINT32)) == 0) { + Status = UpdatePossibleResource(Table, PossibleIrqNumBuf, PossibleIrqNumBufSize, &IsShortFormPkgLength); + DEBUG (( + DEBUG_INFO, + "UpdatePossibleResource status - %x. TPM2 service may not ready in OS.\n", + Status + )); + } else { + DEBUG (( + DEBUG_INFO, + "PcdTpm2PossibleIrqNumBuf size %x is not correct. TPM2 service may not ready in OS.\n", + PossibleIrqNumBufSize + )); + } + } + + 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); + mTcgNvs->TpmIrqNum = PcdGet32(PcdTpm2CurrentIrqNum); + mTcgNvs->IsShortFormPkgLength = IsShortFormPkgLength; + + Status = ExchangeCommonBuffer (mTcgNvs); + + // + // Publish the TPM ACPI table. Table is re-checksummed. + // + 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; + TPM2_PTP_INTERFACE_TYPE InterfaceType; + + // + // Measure to PCR[0] with event EV_POST_CODE ACPI DATA. + // The measurement has to be done before any update. + // Otherwise, the PCR record would be different after event log update + // or the PCD configuration change. + // + TpmMeasureAndLogData( + 0, + EV_POST_CODE, + EV_POSTCODE_INFO_ACPI_DATA, + ACPI_DATA_LEN, + &mTpm2AcpiTemplate, + mTpm2AcpiTemplate.Header.Length + ); + + 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))); + } + + mTpm2AcpiTemplate.Laml = PcdGet32(PcdTpm2AcpiTableLaml); + mTpm2AcpiTemplate.Lasa = PcdGet64(PcdTpm2AcpiTableLasa); + if ((mTpm2AcpiTemplate.Header.Revision < EFI_TPM2_ACPI_TABLE_REVISION_4) || + (mTpm2AcpiTemplate.Laml == 0) || (mTpm2AcpiTemplate.Lasa == 0)) { + // + // If version is smaller than 4 or Laml/Lasa is not valid, rollback to original Length. + // + mTpm2AcpiTemplate.Header.Length = sizeof(EFI_TPM2_ACPI_TABLE); + } + + InterfaceType = PcdGet8(PcdActiveTpmInterfaceType); + switch (InterfaceType) { + case Tpm2PtpInterfaceCrb: + 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 Tpm2PtpInterfaceFifo: + case Tpm2PtpInterfaceTis: + break; + default: + DEBUG((DEBUG_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, + mTpm2AcpiTemplate.Header.Length, + &TableKey + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} + +/** + The driver's entry point. + + It patches and installs ACPI tables used for handling TPM physical presence + and Memory Clear requests through ACPI method. + + @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 +InitializeTcgAcpi ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + if (!CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceTpm20DtpmGuid)){ + DEBUG ((DEBUG_ERROR, "No TPM2 DTPM instance required!\n")); + return EFI_UNSUPPORTED; + } + + Status = PublishAcpiTable (); + ASSERT_EFI_ERROR (Status); + + // + // Set TPM2 ACPI table + // + Status = PublishTpm2 (); + ASSERT_EFI_ERROR (Status); + + return EFI_SUCCESS; +} + diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Acpi/Tcg2Acpi.inf b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Acpi/Tcg2Acpi.inf new file mode 100644 index 00000000..7f7fe098 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Acpi/Tcg2Acpi.inf @@ -0,0 +1,94 @@ +## @file +# Provides ACPI methods for TPM 2.0 support +# +# Spec Compliance Info: +# "TCG ACPI Specification Version 1.2 Revision 8" +# "Physical Presence Interface Specification Version 1.30 Revision 00.52" +# along with +# "Errata Version 0.4 for TCG PC Client Platform Physical Presence Interface Specification" +# "Platform Reset Attack Mitigation Specification Version 1.00" +# TPM2.0 ACPI device object +# "TCG PC Client Platform Firmware Profile Specification for TPM Family 2.0 Level 00 Revision 1.03 v51" +# along with +# "Errata for PC Client Specific Platform Firmware Profile Specification Version 1.0 Revision 1.03" +# +# This driver implements TPM 2.0 definition block in ACPI table and +# populates registered SMI callback functions for Tcg2 physical presence +# and MemoryClear to handle the requests for ACPI method. It needs to be +# used together with Tcg2 MM drivers to exchange information on registered +# SwSmiValue and allocated NVS region address. +# +# 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 - 2019, Intel Corporation. All rights reserved.
+# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = Tcg2Acpi + FILE_GUID = 0D4BBF18-C2CC-4C23-BD63-BFDAD4C710D0 + MODULE_TYPE = DXE_DRIVER + PI_SPECIFICATION_VERSION = 0x0001000A + VERSION_STRING = 1.0 + ENTRY_POINT = InitializeTcgAcpi + +[Sources] + Tcg2Acpi.c + Tpm.asl + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + UefiDriverEntryPoint + UefiBootServicesTableLib + DebugLib + DxeServicesLib + TpmMeasurementLib + Tpm2CommandLib + Tcg2PhysicalPresenceLib + PcdLib + MmUnblockMemoryLib + +[Guids] + gEfiTpmDeviceInstanceTpm20DtpmGuid ## PRODUCES ## GUID # TPM device identifier + gTpmNvsMmGuid ## CONSUMES + gEdkiiPiSmmCommunicationRegionTableGuid ## CONSUMES + +[Protocols] + gEfiAcpiTableProtocolGuid ## CONSUMES + gEfiMmCommunicationProtocolGuid ## CONSUMES + +[FixedPcd] + gEfiSecurityPkgTokenSpaceGuid.PcdSmiCommandIoPort ## 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 + gEfiSecurityPkgTokenSpaceGuid.PcdTpm2CurrentIrqNum ## CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdTpm2PossibleIrqNumBuf ## CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdActiveTpmInterfaceType ## CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdTpm2AcpiTableLaml ## CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdTpm2AcpiTableLasa ## CONSUMES + +[Depex] + gEfiAcpiTableProtocolGuid AND + gTcg2MmSwSmiRegisteredGuid AND + gEfiTcg2ProtocolGuid diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Acpi/Tpm.asl b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Acpi/Tpm.asl new file mode 100644 index 00000000..7b24ae65 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Acpi/Tpm.asl @@ -0,0 +1,517 @@ +/** @file + The TPM2 definition block in ACPI table for TCG2 physical presence + and MemoryClear. + +Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.
+(c)Copyright 2016 HP Development Company, L.P.
+Copyright (c) Microsoft Corporation.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +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")) + + // + // Operational region for Smi port access + // + OperationRegion (SMIP, SystemIO, FixedPcdGet16 (PcdSmiCommandIoPort), 1) + Field (SMIP, ByteAcc, NoLock, Preserve) + { + IOPN, 8 + } + + // + // Operational region for TPM access + // + OperationRegion (TPMR, SystemMemory, 0xfed40000, 0x5000) + Field (TPMR, AnyAcc, NoLock, Preserve) + { + ACC0, 8, // TPM_ACCESS_0 + Offset(0x8), + INTE, 32, // TPM_INT_ENABLE_0 + INTV, 8, // TPM_INT_VECTOR_0 + Offset(0x10), + INTS, 32, // TPM_INT_STATUS_0 + INTF, 32, // TPM_INTF_CAPABILITY_0 + STS0, 32, // TPM_STS_0 + Offset(0x24), + FIFO, 32, // TPM_DATA_FIFO_0 + Offset(0x30), + TID0, 32, // TPM_INTERFACE_ID_0 + // ignore the rest + } + + // + // 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 parameter + 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 parameter + MORD, 32, // Memory Overwrite Request Data + MRET, 32, // Memory Overwrite function return code + UCRQ, 32, // Physical Presence request operation to Get User Confirmation Status + IRQN, 32, // IRQ Number for _CRS + SFRB, 8 // Is shortformed Pkglength for resource buffer + } + + // + // Possible resource settings returned by _PRS method + // RESS : ResourceTemplate with PkgLength <=63 + // RESL : ResourceTemplate with PkgLength > 63 + // + // The format of the data has to follow the same format as + // _CRS (according to ACPI spec). + // + Name (RESS, ResourceTemplate() { + Memory32Fixed (ReadWrite, 0xfed40000, 0x5000) + Interrupt(ResourceConsumer, Level, ActiveLow, Shared, , , ) {1,2,3,4,5,6,7,8,9,10} + }) + + Name (RESL, ResourceTemplate() { + Memory32Fixed (ReadWrite, 0xfed40000, 0x5000) + Interrupt(ResourceConsumer, Level, ActiveLow, Shared, , , ) {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15} + }) + + // + // Current resource settings for _CRS method + // + Name(RES0, ResourceTemplate () { + Memory32Fixed (ReadWrite, 0xfed40000, 0x5000, REG0) + Interrupt(ResourceConsumer, Level, ActiveLow, Shared, , , INTR) {12} + }) + + Name(RES1, ResourceTemplate () { + Memory32Fixed (ReadWrite, 0xfed40000, 0x5000, REG1) + }) + + + // + // Return the resource consumed by TPM device. + // + Method(_CRS,0,Serialized) + { + // + // IRQNum = 0 means disable IRQ support + // + If (LEqual(IRQN, 0)) { + Return (RES1) + } + Else + { + CreateDWordField(RES0, ^INTR._INT, LIRQ) + Store(IRQN, LIRQ) + Return (RES0) + } + } + + // + // Set resources consumed by the TPM device. This is used to + // assign an interrupt number to the device. The input byte stream + // has to be the same as returned by _CRS (according to ACPI spec). + // + // Platform may choose to override this function with specific interrupt + // programing logic to replace FIFO/TIS SIRQ registers programing + // + Method(_SRS,1,Serialized) + { + // + // Do not configure Interrupt if IRQ Num is configured 0 by default + // + If (LNotEqual(IRQN, 0)) { + // + // Update resource descriptor + // Use the field name to identify the offsets in the argument + // buffer and RES0 buffer. + // + CreateDWordField(Arg0, ^INTR._INT, IRQ0) + CreateDWordField(RES0, ^INTR._INT, LIRQ) + Store(IRQ0, LIRQ) + Store(IRQ0, IRQN) + + CreateBitField(Arg0, ^INTR._HE, ITRG) + CreateBitField(RES0, ^INTR._HE, LTRG) + Store(ITRG, LTRG) + + CreateBitField(Arg0, ^INTR._LL, ILVL) + CreateBitField(RES0, ^INTR._LL, LLVL) + Store(ILVL, LLVL) + + // + // Update TPM FIFO PTP/TIS interface only, identified by TPM_INTERFACE_ID_x lowest + // nibble. + // 0000 - FIFO interface as defined in PTP for TPM 2.0 is active + // 1111 - FIFO interface as defined in TIS1.3 is active + // + If (LOr(LEqual (And (TID0, 0x0F), 0x00), LEqual (And (TID0, 0x0F), 0x0F))) { + // + // If FIFO interface, interrupt vector register is + // available. TCG PTP specification allows only + // values 1..15 in this field. For other interrupts + // the field should stay 0. + // + If (LLess (IRQ0, 16)) { + Store (And(IRQ0, 0xF), INTV) + } + // + // Interrupt enable register (TPM_INT_ENABLE_x) bits 3:4 + // contains settings for interrupt polarity. + // The other bits of the byte enable individual interrupts. + // They should be all be zero, but to avoid changing the + // configuration, the other bits are be preserved. + // 00 - high level + // 01 - low level + // 10 - rising edge + // 11 - falling edge + // + // ACPI spec definitions: + // _HE: '1' is Edge, '0' is Level + // _LL: '1' is ActiveHigh, '0' is ActiveLow (inverted from TCG spec) + // + If (LEqual (ITRG, 1)) { + Or(INTE, 0x00000010, INTE) + } Else { + And(INTE, 0xFFFFFFEF, INTE) + } + if (LEqual (ILVL, 0)) { + Or(INTE, 0x00000008, INTE) + } Else { + And(INTE, 0xFFFFFFF7, INTE) + } + } + } + } + + Method(_PRS,0,Serialized) + { + // + // IRQNum = 0 means disable IRQ support + // + If (LEqual(IRQN, 0)) { + Return (RES1) + } ElseIf(LEqual(SFRB, 0)) { + // + // Long format. Possible resources PkgLength > 63 + // + Return (RESL) + } Else { + // + // Short format. Possible resources PkgLength <=63 + // + Return (RESS) + } + } + + 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))) + { + // + // Trigger the SMI through ACPI _PTS method. + // + Store (0x02, MCIP) + + // + // Trigger the SMI interrupt + // + Store (MCIN, IOPN) + } + } + Return (0) + } + + Method (_STA, 0) + { + if (LEqual (ACC0, 0xff)) + { + Return (0) + } + Return (0x0f) + } + + // + // TCG Hardware Information + // + Method (HINF, 1, Serialized, 0, {BuffObj, PkgObj}, {UnknownObj}) // IntObj + { + // + // Switch by function index + // + Switch (ToInteger(Arg0)) + { + 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, 2, Serialized, 0, {BuffObj, PkgObj, IntObj, StrObj}, {UnknownObj, UnknownObj}) // IntObj, PkgObj + { + // + // Switch by function index + // + Switch (ToInteger(Arg0)) + { + 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 (Arg1, 0x00)), PPRQ) + Store (0, PPRM) + Store (0x02, PPIP) + + // + // Trigger the SMI interrupt + // + Store (PPIN, IOPN) + 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) + + // + // Trigger the SMI interrupt + // + Store (PPIN, IOPN) + + 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 (Arg1, 0x00)), PPRQ) + Store (0, PPRM) + If (LEqual (PPRQ, 23)) { + Store (DerefOf (Index (Arg1, 0x01)), PPRM) + } + + // + // Trigger the SMI interrupt + // + Store (PPIN, IOPN) + Return (FRET) + } + Case (8) + { + // + // e) Get User Confirmation Status for Operation + // + Store (8, PPIP) + Store (DerefOf (Index (Arg1, 0x00)), UCRQ) + + // + // Trigger the SMI interrupt + // + Store (PPIN, IOPN) + + Return (FRET) + } + + Default {BreakPoint} + } + Return (1) + } + + Method (TMCI, 2, Serialized, 0, IntObj, {UnknownObj, UnknownObj}) // IntObj, PkgObj + { + // + // Switch by function index + // + Switch (ToInteger (Arg0)) + { + 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 (Arg1, 0x00)), MORD) + + // + // Trigger the SMI through ACPI _DSM method. + // + Store (0x01, MCIP) + + // + // Trigger the SMI interrupt + // + Store (MCIN, IOPN) + 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 (Arg2)) + } + + // + // TCG Physical Presence Interface + // + If(LEqual(Arg0, ToUUID ("3dddfaa6-361b-4eb4-a424-8d10089d1653"))) + { + Return (TPPI (Arg2, Arg3)) + } + + // + // TCG Memory Clear Interface + // + If(LEqual(Arg0, ToUUID ("376054ed-cc13-4675-901c-4756d7f2d45d"))) + { + Return (TMCI (Arg2, Arg3)) + } + + Return (Buffer () {0}) + } + } + } +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2Config.vfr b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2Config.vfr new file mode 100644 index 00000000..8ea8e9ce --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2Config.vfr @@ -0,0 +1,246 @@ +/** @file + VFR file used by the TCG2 configuration component. + +Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#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 attributes 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 attributes 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 attributes 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; + suppressif ideqval TCG2_CONFIGURATION_INFO.ChangeEPSSupported == 0; + option text = STRING_TOKEN(STR_TCG2_CHANGE_EPS), value = TCG2_PHYSICAL_PRESENCE_CHANGE_EPS, flags = RESET_REQUIRED; + endif + 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/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDriver.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDriver.c new file mode 100644 index 00000000..f2a4b00b --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDriver.c @@ -0,0 +1,455 @@ +/** @file + The module entry point for Tcg2 configuration module. + +Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#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_SUCCESS 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/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDxe.inf b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDxe.inf new file mode 100644 index 00000000..10664565 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDxe.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) 2015 - 2018, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[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 EBC +# + +[Sources] + Tcg2ConfigDriver.c + Tcg2ConfigImpl.c + Tcg2ConfigImpl.h + Tcg2Config.vfr + Tcg2ConfigStrings.uni + Tcg2ConfigNvData.h + Tcg2Internal.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 + gEfiSecurityPkgTokenSpaceGuid.PcdActiveTpmInterfaceType ## CONSUMES + +[Depex] + gEfiTcg2ProtocolGuid AND + gEfiHiiConfigRoutingProtocolGuid AND + gEfiHiiDatabaseProtocolGuid AND + gEfiVariableArchProtocolGuid AND + gEfiVariableWriteArchProtocolGuid + +[UserExtensions.TianoCore."ExtraFiles"] + Tcg2ConfigDxeExtra.uni diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDxe.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDxe.uni new file mode 100644 index 00000000..80bb3fdf --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDxe.uni @@ -0,0 +1,17 @@ +// /** @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.
+// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + + +#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/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDxeExtra.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDxeExtra.uni new file mode 100644 index 00000000..f263afc8 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDxeExtra.uni @@ -0,0 +1,14 @@ +// /** @file +// Tcg2ConfigDxe Localized Strings and Content +// +// Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.
+// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_PROPERTIES_MODULE_NAME +#language en-US +"TCG2 (Trusted Computing Group) Configuration DXE" + + diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigImpl.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigImpl.c new file mode 100644 index 00000000..e7b51213 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigImpl.c @@ -0,0 +1,1004 @@ +/** @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 - 2018, Intel Corporation. All rights reserved.
+(C) Copyright 2018 Hewlett Packard Enterprise Development LP
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "Tcg2ConfigImpl.h" +#include +#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 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. + Do not update PcdActiveTpmInterfaceType here because interface change only happens on next _TPM_INIT + + @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 + ) +{ + TPM2_PTP_INTERFACE_TYPE PtpInterfaceCurrent; + PTP_CRB_INTERFACE_IDENTIFIER InterfaceId; + + PtpInterfaceCurrent = PcdGet8(PcdActiveTpmInterfaceType); + if ((PtpInterfaceCurrent != Tpm2PtpInterfaceFifo) && + (PtpInterfaceCurrent != Tpm2PtpInterfaceCrb)) { + return EFI_UNSUPPORTED; + } + InterfaceId.Uint32 = MmioRead32 ((UINTN)&((PTP_CRB_REGISTERS *)Register)->InterfaceId); + if (InterfaceId.Bits.IntfSelLock != 0) { + return EFI_WRITE_PROTECTED; + } + + switch (PtpInterface) { + case Tpm2PtpInterfaceFifo: + 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 Tpm2PtpInterfaceCrb: + 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; + } + + *Progress = Configuration; + + 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; + TPM2_PTP_INTERFACE_TYPE TpmDeviceInterfaceDetected; + BOOLEAN IsCmdImp = FALSE; + + 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); + } + + Status = Tpm2GetCapabilityIsCommandImplemented (TPM_CC_ChangeEPS, &IsCmdImp); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Tpm2GetCapabilityIsCmdImpl fails %r\n", Status)); + } + Tcg2ConfigInfo.ChangeEPSSupported = IsCmdImp; + + 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 = PcdGet8(PcdActiveTpmInterfaceType); + switch (TpmDeviceInterfaceDetected) { + case Tpm2PtpInterfaceTis: + HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_TCG2_DEVICE_INTERFACE_STATE_CONTENT), L"TIS", NULL); + break; + case Tpm2PtpInterfaceFifo: + HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_TCG2_DEVICE_INTERFACE_STATE_CONTENT), L"PTP FIFO", NULL); + break; + case Tpm2PtpInterfaceCrb: + 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 Tpm2PtpInterfaceTis: + Tcg2ConfigInfo.TpmDeviceInterfacePtpFifoSupported = FALSE; + Tcg2ConfigInfo.TpmDeviceInterfacePtpCrbSupported = FALSE; + HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_TCG2_DEVICE_INTERFACE_CAPABILITY_CONTENT), L"TIS", NULL); + break; + case Tpm2PtpInterfaceFifo: + case Tpm2PtpInterfaceCrb: + 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/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigImpl.h b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigImpl.h new file mode 100644 index 00000000..3dc80f0b --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigImpl.h @@ -0,0 +1,198 @@ +/** @file + The header file of HII Config Access protocol implementation of TCG2 + configuration module. + +Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#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" +#include "Tcg2Internal.h" + +#define TCG2_PROTOCOL_VERSION_DEFAULT 0x0001 + +// +// 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/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigNvData.h b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigNvData.h new file mode 100644 index 00000000..5460a767 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigNvData.h @@ -0,0 +1,89 @@ +/** @file + Header file for NV data structure definition. + +Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __TCG2_CONFIG_NV_DATA_H__ +#define __TCG2_CONFIG_NV_DATA_H__ + +#include +#include +#include + +#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_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; + BOOLEAN ChangeEPSSupported; +} 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" + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPei.inf b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPei.inf new file mode 100644 index 00000000..861ffa52 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPei.inf @@ -0,0 +1,71 @@ +## @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 - 2018, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[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 EBC +# +# [BootMode] +# S3_RESUME ## SOMETIMES_CONSUMES +# + +[Sources] + Tcg2ConfigPeim.c + Tcg2ConfigNvData.h + Tcg2Internal.h + TpmDetection.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + 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 + +[Depex] + gEfiPeiMasterBootModePpiGuid AND + gEfiPeiReadOnlyVariable2PpiGuid + +[UserExtensions.TianoCore."ExtraFiles"] + Tcg2ConfigPeiExtra.uni diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPei.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPei.uni new file mode 100644 index 00000000..17b05e89 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPei.uni @@ -0,0 +1,18 @@ +// /** @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.
+// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + + +#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/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPeiExtra.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPeiExtra.uni new file mode 100644 index 00000000..f263afc8 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPeiExtra.uni @@ -0,0 +1,14 @@ +// /** @file +// Tcg2ConfigDxe Localized Strings and Content +// +// Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.
+// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_PROPERTIES_MODULE_NAME +#language en-US +"TCG2 (Trusted Computing Group) Configuration DXE" + + diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPeim.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPeim.c new file mode 100644 index 00000000..823b9c20 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPeim.c @@ -0,0 +1,154 @@ +/** @file + The module entry point for Tcg2 configuration module. + +Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "Tcg2ConfigNvData.h" +#include "Tcg2Internal.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_SUCCESS 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 guarantee 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 install 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/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigStrings.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigStrings.uni new file mode 100644 index 00000000..ee7fa081 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigStrings.uni @@ -0,0 +1,132 @@ +/** @file + String definitions for TCG2 configuration form. + +Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#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/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2Internal.h b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2Internal.h new file mode 100644 index 00000000..70d54ec4 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2Internal.h @@ -0,0 +1,26 @@ +/** @file + The internal header file defines the common structures for PEI and DXE modules. + +Copyright (c) 2019, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __TCG2_INTERNAL_H__ +#define __TCG2_INTERNAL_H__ + +#define EFI_TCG2_EVENT_LOG_FORMAT_DEFAULT EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2 +#define EFI_TCG2_EVENT_LOG_FORMAT_ALL (EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2 | EFI_TCG2_EVENT_LOG_FORMAT_TCG_2) + +#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}, \ +} + +typedef struct { + GUID TpmInstanceGuid; + UINT8 TpmDevice; +} TPM_INSTANCE_ID; + +#endif diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/TpmDetection.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/TpmDetection.c new file mode 100644 index 00000000..c4fe7f38 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/TpmDetection.c @@ -0,0 +1,100 @@ +/** @file + TPM1.2/dTPM2.0 auto detection. + +Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Tcg2ConfigNvData.h" +#include "Tcg2Internal.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/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Dxe/MeasureBootPeCoff.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Dxe/MeasureBootPeCoff.c new file mode 100644 index 00000000..2b062069 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Dxe/MeasureBootPeCoff.c @@ -0,0 +1,406 @@ +/** @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 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#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 Digest 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; + 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 + // + + // + // 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 (Hdr.Pe32->OptionalHeader.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 (Hdr.Pe32->OptionalHeader.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 (Hdr.Pe32->OptionalHeader.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 (Hdr.Pe32->OptionalHeader.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 (Hdr.Pe32->OptionalHeader.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 (Hdr.Pe32->OptionalHeader.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/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c new file mode 100644 index 00000000..9d4142ba --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c @@ -0,0 +1,2801 @@ +/** @file + This module implements Tcg2 Protocol. + +Copyright (c) 2015 - 2019, Intel Corporation. All rights reserved.
+(C) Copyright 2016 Hewlett Packard Enterprise Development LP
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#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 +#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; + UINTN Next800155EventOffset; +} 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 Digest 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; +} + +/** + Return if this is a Tcg800155PlatformIdEvent. + + @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 TRUE This is a Tcg800155PlatformIdEvent. + @retval FALSE This is NOT a Tcg800155PlatformIdEvent. + +**/ +BOOLEAN +Is800155Event ( + IN VOID *NewEventHdr, + IN UINT32 NewEventHdrSize, + IN UINT8 *NewEventData, + IN UINT32 NewEventSize + ) +{ + if ((((TCG_PCR_EVENT2_HDR *)NewEventHdr)->EventType == EV_NO_ACTION) && + (NewEventSize >= sizeof(TCG_Sp800_155_PlatformId_Event2)) && + (CompareMem (NewEventData, TCG_Sp800_155_PlatformId_Event2_SIGNATURE, + sizeof(TCG_Sp800_155_PlatformId_Event2_SIGNATURE) - 1) == 0)) { + return TRUE; + } + return FALSE; +} + +/** + Add a new entry to the Event Log. + + @param[in, out] EventLogAreaStruct The event log area data structure + @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 TCG_EVENT_LOG_AREA_STRUCT *EventLogAreaStruct, + IN VOID *NewEventHdr, + IN UINT32 NewEventHdrSize, + IN UINT8 *NewEventData, + IN UINT32 NewEventSize + ) +{ + UINTN NewLogSize; + BOOLEAN Record800155Event; + + if (NewEventSize > MAX_ADDRESS - NewEventHdrSize) { + return EFI_OUT_OF_RESOURCES; + } + + NewLogSize = NewEventHdrSize + NewEventSize; + + if (NewLogSize > MAX_ADDRESS - EventLogAreaStruct->EventLogSize) { + return EFI_OUT_OF_RESOURCES; + } + + if (NewLogSize + EventLogAreaStruct->EventLogSize > EventLogAreaStruct->Laml) { + DEBUG ((DEBUG_INFO, " Laml - 0x%x\n", EventLogAreaStruct->Laml)); + DEBUG ((DEBUG_INFO, " NewLogSize - 0x%x\n", NewLogSize)); + DEBUG ((DEBUG_INFO, " LogSize - 0x%x\n", EventLogAreaStruct->EventLogSize)); + DEBUG ((DEBUG_INFO, "TcgCommLogEvent - %r\n", EFI_OUT_OF_RESOURCES)); + return EFI_OUT_OF_RESOURCES; + } + + // + // Check 800-155 event + // Record to 800-155 event offset only. + // If the offset is 0, no need to record. + // + Record800155Event = Is800155Event (NewEventHdr, NewEventHdrSize, NewEventData, NewEventSize); + if (Record800155Event) { + if (EventLogAreaStruct->Next800155EventOffset != 0) { + CopyMem ( + (UINT8 *)(UINTN)EventLogAreaStruct->Lasa + EventLogAreaStruct->Next800155EventOffset + NewLogSize, + (UINT8 *)(UINTN)EventLogAreaStruct->Lasa + EventLogAreaStruct->Next800155EventOffset, + EventLogAreaStruct->EventLogSize - EventLogAreaStruct->Next800155EventOffset + ); + + CopyMem ( + (UINT8 *)(UINTN)EventLogAreaStruct->Lasa + EventLogAreaStruct->Next800155EventOffset, + NewEventHdr, + NewEventHdrSize + ); + CopyMem ( + (UINT8 *)(UINTN)EventLogAreaStruct->Lasa + EventLogAreaStruct->Next800155EventOffset + NewEventHdrSize, + NewEventData, + NewEventSize + ); + + EventLogAreaStruct->Next800155EventOffset += NewLogSize; + EventLogAreaStruct->LastEvent += NewLogSize; + EventLogAreaStruct->EventLogSize += NewLogSize; + } + return EFI_SUCCESS; + } + + EventLogAreaStruct->LastEvent = (UINT8 *)(UINTN)EventLogAreaStruct->Lasa + EventLogAreaStruct->EventLogSize; + EventLogAreaStruct->EventLogSize += NewLogSize; + CopyMem (EventLogAreaStruct->LastEvent, NewEventHdr, NewEventHdrSize); + CopyMem ( + EventLogAreaStruct->LastEvent + 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; + } + + Status = TcgCommLogEvent ( + EventLogAreaStruct, + 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; + } + + Status = TcgCommLogEvent ( + EventLogAreaStruct, + 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; + TCG_PCR_EVENT2_HDR NoActionEvent; + + if (!mTcgDxeData.BsCap.TPMPresentFlag) { + return EFI_DEVICE_ERROR; + } + + if (NewEventHdr->EventType == EV_NO_ACTION) { + // + // Do not do TPM extend for EV_NO_ACTION + // + Status = EFI_SUCCESS; + InitNoActionEvent (&NoActionEvent, NewEventHdr->EventSize); + if ((Flags & EFI_TCG2_EXTEND_ONLY) == 0) { + Status = TcgDxeLogHashEvent (&(NoActionEvent.Digests), NewEventHdr, NewEventData); + } + + return Status; + } + + 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) || (Event == NULL)) { + return EFI_INVALID_PARAMETER; + } + // + // Do not check hash data size for EV_NO_ACTION event. + // + if ((Event->Header.EventType != EV_NO_ACTION) && (DataToHash == 0)) { + 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; + if (PcdGet8(PcdTpm2AcpiTableRev) >= 4) { + Status = gBS->AllocatePages ( + AllocateAnyPages, + EfiACPIMemoryNVS, + EFI_SIZE_TO_PAGES (PcdGet32 (PcdTcgLogAreaMinLen)), + &Lasa + ); + } else { + 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); + mTcgDxeData.EventLogAreaStruct[Index].Next800155EventOffset = 0; + + if ((PcdGet8(PcdTpm2AcpiTableRev) >= 4) || + (mTcg2EventInfo[Index].LogFormat == EFI_TCG2_EVENT_LOG_FORMAT_TCG_2)) { + // + // Report TCG2 event log address and length, so that they can be reported in TPM2 ACPI table. + // Ignore the return status, because those fields are optional. + // + PcdSet32S(PcdTpm2AcpiTableLaml, (UINT32)mTcgDxeData.EventLogAreaStruct[Index].Laml); + PcdSet64S(PcdTpm2AcpiTableLasa, mTcgDxeData.EventLogAreaStruct[Index].Lasa); + } + + // + // 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 = (UINT8)PcdGet32(PcdTcgPfpMeasurementRevision); + 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 + ); + // + // record the offset at the end of 800-155 event. + // the future 800-155 event can be inserted here. + // + mTcgDxeData.EventLogAreaStruct[Index].Next800155EventOffset = \ + mTcgDxeData.EventLogAreaStruct[Index].EventLogSize; + + // + // Tcg800155PlatformIdEvent. Event format is TCG_PCR_EVENT2 + // + GuidHob.Guid = GetFirstGuidHob (&gTcg800155PlatformIdEventHobGuid); + while (GuidHob.Guid != NULL) { + InitNoActionEvent(&NoActionEvent, GET_GUID_HOB_DATA_SIZE (GuidHob.Guid)); + + Status = TcgDxeLogEvent ( + mTcg2EventInfo[Index].LogFormat, + &NoActionEvent, + sizeof(NoActionEvent.PCRIndex) + sizeof(NoActionEvent.EventType) + GetDigestListBinSize (&NoActionEvent.Digests) + sizeof(NoActionEvent.EventSize), + GET_GUID_HOB_DATA (GuidHob.Guid), + GET_GUID_HOB_DATA_SIZE (GuidHob.Guid) + ); + + GuidHob.Guid = GET_NEXT_HOB (GuidHob); + GuidHob.Guid = GetNextGuidHob (&gTcg800155PlatformIdEventHobGuid, GuidHob.Guid); + } + + // + // 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; + mTcgDxeData.FinalEventLogAreaStruct[Index].Next800155EventOffset = 0; + + // + // 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; + mTcgDxeData.FinalEventLogAreaStruct[Index].Next800155EventOffset = 0; + } + } + } + + // + // 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_APPLICATION + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "%a not Measured. Error!\n", EFI_RETURNING_FROM_EFI_APPLICATION)); + } + + // + // 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)); + } + +} + +/** + This routine is called to properly shutdown the TPM before system reset. + It follow chapter "12.2.3 Startup State" in Trusted Platform Module Library + Part 1: Architecture, Revision 01.16. + + @param[in] ResetType The type of reset to perform. + @param[in] ResetStatus The status code for the reset. + @param[in] DataSize The size, in bytes, of ResetData. + @param[in] ResetData For a ResetType of EfiResetCold, EfiResetWarm, or + EfiResetShutdown the data buffer starts with a Null-terminated + string, optionally followed by additional binary data. + The string is a description that the caller may use to further + indicate the reason for the system reset. + For a ResetType of EfiResetPlatformSpecific the data buffer + also starts with a Null-terminated string that is followed + by an EFI_GUID that describes the specific type of reset to perform. +**/ +VOID +EFIAPI +ShutdownTpmOnReset ( + IN EFI_RESET_TYPE ResetType, + IN EFI_STATUS ResetStatus, + IN UINTN DataSize, + IN VOID *ResetData OPTIONAL + ) +{ + EFI_STATUS Status; + Status = Tpm2Shutdown (TPM_SU_CLEAR); + DEBUG ((DEBUG_VERBOSE, "Tpm2Shutdown (SU_CLEAR) - %r\n", Status)); +} + +/** + Hook the system reset to properly shutdown TPM. + It follow chapter "12.2.3 Startup State" in Trusted Platform Module Library + Part 1: Architecture, Revision 01.16. + + @param[in] Event Event whose notification function is being invoked + @param[in] Context Pointer to the notification function's context +**/ +VOID +EFIAPI +OnResetNotificationInstall ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + EFI_RESET_NOTIFICATION_PROTOCOL *ResetNotify; + + Status = gBS->LocateProtocol (&gEfiResetNotificationProtocolGuid, NULL, (VOID **) &ResetNotify); + if (!EFI_ERROR (Status)) { + Status = ResetNotify->RegisterResetNotify (ResetNotify, ShutdownTpmOnReset); + ASSERT_EFI_ERROR (Status); + DEBUG ((DEBUG_VERBOSE, "TCG2: Hook system reset to properly shutdown TPM.\n")); + + gBS->CloseEvent (Event); + } +} + +/** + 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); + + // + // Hook the system reset to properly shutdown TPM. + // + EfiCreateProtocolNotifyEvent (&gEfiResetNotificationProtocolGuid, TPL_CALLBACK, OnResetNotificationInstall, NULL, &Registration); + } + + // + // Install Tcg2Protocol + // + Status = InstallTcg2 (); + DEBUG ((EFI_D_INFO, "InstallTcg2 - %r\n", Status)); + + return Status; +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.inf b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.inf new file mode 100644 index 00000000..0b839ad2 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.inf @@ -0,0 +1,119 @@ +## @file +# Produces Tcg2 protocol and measure boot environment +# +# Spec Compliance Info: +# "TCG PC Client Platform Firmware Profile Specification for TPM Family 2.0 Level 00 Revision 1.03 v51" +# along with +# "Errata for PC Client Specific Platform Firmware Profile Specification Version 1.0 Revision 1.03" +# "TCG EFI Protocol Specification" "Family 2.0" "Level 00 Revision 00.13" +# along with +# "Errata Version 0.5 for TCG EFI Protocol Specification" +# +# 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 - 2019, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[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 +# + +[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 + gTcg800155PlatformIdEventHobGuid ## SOMETIMES_CONSUMES ## HOB + +[Protocols] + gEfiTcg2ProtocolGuid ## PRODUCES + gEfiTcg2FinalEventsTableGuid ## PRODUCES + gEfiMpServiceProtocolGuid ## SOMETIMES_CONSUMES + gEfiVariableWriteArchProtocolGuid ## NOTIFY + gEfiResetNotificationProtocolGuid ## CONSUMES + +[Pcd] + gEfiSecurityPkgTokenSpaceGuid.PcdTpmPlatformClass ## SOMETIMES_CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdFirmwareDebuggerInitialized ## SOMETIMES_CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdTpmInstanceGuid ## CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdStatusCodeSubClassTpmDevice ## SOMETIMES_CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdTcg2HashAlgorithmBitmap ## CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdTcg2NumberOfPCRBanks ## CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdTcgLogAreaMinLen ## CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdTcg2FinalLogAreaLen ## CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdTpm2AcpiTableRev ## CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdTpm2AcpiTableLaml ## PRODUCES + gEfiSecurityPkgTokenSpaceGuid.PcdTpm2AcpiTableLasa ## PRODUCES + gEfiMdeModulePkgTokenSpaceGuid.PcdTcgPfpMeasurementRevision ## CONSUMES + +[Depex] + # According to PcdTpm2AcpiTableRev definition in SecurityPkg.dec + # This PCD should be configured at DynamicHii or DynamicHiiEx. + # So, this PCD read operation depends on GetVariable service. + # Add VariableArch protocol dependency to make sure PCD read works. + gEfiVariableArchProtocolGuid + +[UserExtensions.TianoCore."ExtraFiles"] + Tcg2DxeExtra.uni diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.uni new file mode 100644 index 00000000..b07c5243 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.uni @@ -0,0 +1,21 @@ +// /** @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 - 2018, Intel Corporation. All rights reserved.
+// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + + +#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/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Dxe/Tcg2DxeExtra.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Dxe/Tcg2DxeExtra.uni new file mode 100644 index 00000000..99b0ff0f --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Dxe/Tcg2DxeExtra.uni @@ -0,0 +1,12 @@ +// /** @file +// Tcg2Dxe Localized Strings and Content +// +// Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.
+// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_PROPERTIES_MODULE_NAME +#language en-US +"TCG2 (Trusted Computing Group) DXE" diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.c new file mode 100644 index 00000000..a54a0b2f --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.c @@ -0,0 +1,1124 @@ +/** @file + Initialize TPM2 device and measure FVs before handing off control to DXE. + +Copyright (c) 2015 - 2020, Intel Corporation. All rights reserved.
+Copyright (c) 2017, Microsoft Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#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_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 +}; + +/** + 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] This Indicates the calling context + @param[in] Flags Bitmap providing additional information. + @param[in] HashData If BIT0 of Flags is 0, it is physical address of the + start of the data buffer to be hashed, extended, and logged. + If BIT0 of Flags is 1, it is physical address of the + start of the pre-hash data buffter to be extended, and logged. + The pre-hash data format is TPML_DIGEST_VALUES. + @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 +EFIAPI +HashLogExtendEvent ( + IN EDKII_TCG_PPI *This, + IN UINT64 Flags, + IN UINT8 *HashData, + IN UINTN HashDataLen, + IN TCG_PCR_EVENT_HDR *NewEventHdr, + IN UINT8 *NewEventData + ); + +EDKII_TCG_PPI mEdkiiTcgPpi = { + HashLogExtendEvent +}; + +EFI_PEI_PPI_DESCRIPTOR mTcgPpiList = { + EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, + &gEdkiiTcgPpiGuid, + &mEdkiiTcgPpi +}; + +// +// Number of firmware blobs to grow by each time we run out of room +// +#define FIRMWARE_BLOB_GROWTH_STEP 4 + +EFI_PLATFORM_FIRMWARE_BLOB *mMeasuredBaseFvInfo; +UINT32 mMeasuredMaxBaseFvIndex = 0; +UINT32 mMeasuredBaseFvIndex = 0; + +EFI_PLATFORM_FIRMWARE_BLOB *mMeasuredChildFvInfo; +UINT32 mMeasuredMaxChildFvIndex = 0; +UINT32 mMeasuredChildFvIndex = 0; + +#pragma pack (1) + +#define FV_HANDOFF_TABLE_DESC "Fv(XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX)" +typedef struct { + UINT8 BlobDescriptionSize; + UINT8 BlobDescription[sizeof(FV_HANDOFF_TABLE_DESC)]; + EFI_PHYSICAL_ADDRESS BlobBase; + UINT64 BlobLength; +} FV_HANDOFF_TABLE_POINTERS2; + +#pragma pack () + +/** + Measure and record the Firmware Volume 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 +FirmwareVolumeInfoPpiNotifyCallback ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, + IN VOID *Ppi + ); + +/** + Record all measured Firmware Volume 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, + FirmwareVolumeInfoPpiNotifyCallback + }, + { + EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK, + &gEfiPeiFirmwareVolumeInfo2PpiGuid, + FirmwareVolumeInfoPpiNotifyCallback + }, + { + (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gEfiEndOfPeiSignalPpiGuid, + EndofPeiSignalNotifyCallBack + } +}; + + +/** + Record all measured Firmware Volume 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; + + PERF_CALLBACK_BEGIN (&gEfiEndOfPeiSignalPpiGuid); + + // + // 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)); + } + + PERF_CALLBACK_END (&gEfiEndOfPeiSignalPpiGuid); + + 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); + if (Tpm2PcrMask == 0) { + // + // if PcdTPm2HashMask is zero, use ActivePcr setting + // + PcdSet32S (PcdTpm2HashMask, TpmActivePcrBanks); + Tpm2PcrMask = TpmActivePcrBanks; + } + + // + // 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] This Indicates the calling context + @param[in] Flags Bitmap providing additional information. + @param[in] HashData If BIT0 of Flags is 0, it is physical address of the + start of the data buffer to be hashed, extended, and logged. + If BIT0 of Flags is 1, it is physical address of the + start of the pre-hash data buffter to be extended, and logged. + The pre-hash data format is TPML_DIGEST_VALUES. + @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 +EFIAPI +HashLogExtendEvent ( + IN EDKII_TCG_PPI *This, + 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; + } + + if ((Flags & EDKII_TCG_PRE_HASH) != 0 || (Flags & EDKII_TCG_PRE_HASH_LOG_ONLY) != 0) { + ZeroMem (&DigestList, sizeof(DigestList)); + CopyMem (&DigestList, HashData, sizeof(DigestList)); + Status = EFI_SUCCESS; + if ((Flags & EDKII_TCG_PRE_HASH) !=0 ) { + Status = Tpm2PcrExtend ( + NewEventHdr->PCRIndex, + &DigestList + ); + } + } else { + Status = HashAndExtend ( + NewEventHdr->PCRIndex, + HashData, + HashDataLen, + &DigestList + ); + } + if (!EFI_ERROR (Status)) { + 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 ( + &mEdkiiTcgPpi, + 0, + (UINT8*)PcdGetPtr (PcdFirmwareVersionString), + TcgEventHdr.EventSize, + &TcgEventHdr, + (UINT8*)PcdGetPtr (PcdFirmwareVersionString) + ); +} + +/** + Get the FvName from the FV header. + + Causion: The FV is untrusted input. + + @param[in] FvBase Base address of FV image. + @param[in] FvLength Length of FV image. + + @return FvName pointer + @retval NULL FvName is NOT found +**/ +VOID * +GetFvName ( + IN EFI_PHYSICAL_ADDRESS FvBase, + IN UINT64 FvLength + ) +{ + EFI_FIRMWARE_VOLUME_HEADER *FvHeader; + EFI_FIRMWARE_VOLUME_EXT_HEADER *FvExtHeader; + + if (FvBase >= MAX_ADDRESS) { + return NULL; + } + if (FvLength >= MAX_ADDRESS - FvBase) { + return NULL; + } + if (FvLength < sizeof(EFI_FIRMWARE_VOLUME_HEADER)) { + return NULL; + } + + FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)FvBase; + if (FvHeader->ExtHeaderOffset < sizeof(EFI_FIRMWARE_VOLUME_HEADER)) { + return NULL; + } + if (FvHeader->ExtHeaderOffset + sizeof(EFI_FIRMWARE_VOLUME_EXT_HEADER) > FvLength) { + return NULL; + } + FvExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *)(UINTN)(FvBase + FvHeader->ExtHeaderOffset); + + return &FvExtHeader->FvName; +} + +/** + 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; + FV_HANDOFF_TABLE_POINTERS2 FvBlob2; + VOID *EventData; + VOID *FvName; + TCG_PCR_EVENT_HDR TcgEventHdr; + UINT32 Instance; + UINT32 Tpm2HashMask; + TPML_DIGEST_VALUES DigestList; + UINT32 DigestCount; + EFI_PEI_FIRMWARE_VOLUME_INFO_MEASUREMENT_EXCLUDED_PPI *MeasurementExcludedFvPpi; + EDKII_PEI_FIRMWARE_VOLUME_INFO_PREHASHED_FV_PPI *PrehashedFvPpi; + HASH_INFO *PreHashInfo; + UINT32 HashAlgoMask; + EFI_PHYSICAL_ADDRESS FvOrgBase; + EFI_PHYSICAL_ADDRESS FvDataBase; + EFI_PEI_HOB_POINTERS Hob; + EDKII_MIGRATED_FV_INFO *MigratedFvInfo; + + // + // Check Excluded FV list + // + Instance = 0; + do { + Status = PeiServicesLocatePpi( + &gEfiPeiFirmwareVolumeInfoMeasurementExcludedPpiGuid, + Instance, + NULL, + (VOID**)&MeasurementExcludedFvPpi + ); + if (!EFI_ERROR(Status)) { + for (Index = 0; Index < MeasurementExcludedFvPpi->Count; Index ++) { + if (MeasurementExcludedFvPpi->Fv[Index].FvBase == FvBase + && MeasurementExcludedFvPpi->Fv[Index].FvLength == FvLength) { + 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; + } + } + + Instance++; + } + } while (!EFI_ERROR(Status)); + + // + // Check measured FV list + // + for (Index = 0; Index < mMeasuredBaseFvIndex; Index ++) { + if (mMeasuredBaseFvInfo[Index].BlobBase == FvBase && mMeasuredBaseFvInfo[Index].BlobLength == FvLength) { + DEBUG ((DEBUG_INFO, "The FV which is already measured by Tcg2Pei starts at: 0x%x\n", FvBase)); + DEBUG ((DEBUG_INFO, "The FV which is already measured by Tcg2Pei has the size: 0x%x\n", FvLength)); + return EFI_SUCCESS; + } + } + + // + // Check pre-hashed FV list + // + Instance = 0; + Tpm2HashMask = PcdGet32 (PcdTpm2HashMask); + do { + Status = PeiServicesLocatePpi ( + &gEdkiiPeiFirmwareVolumeInfoPrehashedFvPpiGuid, + Instance, + NULL, + (VOID**)&PrehashedFvPpi + ); + if (!EFI_ERROR(Status) && PrehashedFvPpi->FvBase == FvBase && PrehashedFvPpi->FvLength == FvLength) { + ZeroMem (&DigestList, sizeof(TPML_DIGEST_VALUES)); + + // + // The FV is prehashed, check against TPM hash mask + // + PreHashInfo = (HASH_INFO *)(PrehashedFvPpi + 1); + for (Index = 0, DigestCount = 0; Index < PrehashedFvPpi->Count; Index++) { + DEBUG((DEBUG_INFO, "Hash Algo ID in PrehashedFvPpi=0x%x\n", PreHashInfo->HashAlgoId)); + HashAlgoMask = GetHashMaskFromAlgo(PreHashInfo->HashAlgoId); + if ((Tpm2HashMask & HashAlgoMask) != 0 ) { + // + // Hash is required, copy it to DigestList + // + WriteUnaligned16(&(DigestList.digests[DigestCount].hashAlg), PreHashInfo->HashAlgoId); + CopyMem ( + &DigestList.digests[DigestCount].digest, + PreHashInfo + 1, + PreHashInfo->HashSize + ); + DigestCount++; + // + // Clean the corresponding Hash Algo mask bit + // + Tpm2HashMask &= ~HashAlgoMask; + } + PreHashInfo = (HASH_INFO *)((UINT8 *)(PreHashInfo + 1) + PreHashInfo->HashSize); + } + + WriteUnaligned32(&DigestList.count, DigestCount); + + break; + } + Instance++; + } while (!EFI_ERROR(Status)); + + // + // Search the matched migration FV info + // + FvOrgBase = FvBase; + FvDataBase = FvBase; + Hob.Raw = GetFirstGuidHob (&gEdkiiMigratedFvInfoGuid); + while (Hob.Raw != NULL) { + MigratedFvInfo = GET_GUID_HOB_DATA (Hob); + if ((MigratedFvInfo->FvNewBase == (UINT32) FvBase) && (MigratedFvInfo->FvLength == (UINT32) FvLength)) { + // + // Found the migrated FV info + // + FvOrgBase = (EFI_PHYSICAL_ADDRESS) (UINTN) MigratedFvInfo->FvOrgBase; + FvDataBase = (EFI_PHYSICAL_ADDRESS) (UINTN) MigratedFvInfo->FvDataBase; + break; + } + Hob.Raw = GET_NEXT_HOB (Hob); + Hob.Raw = GetNextGuidHob (&gEdkiiMigratedFvInfoGuid, Hob.Raw); + } + + // + // Init the log event for FV measurement + // + if (PcdGet32(PcdTcgPfpMeasurementRevision) >= TCG_EfiSpecIDEventStruct_SPEC_ERRATA_TPM2_REV_105) { + FvBlob2.BlobDescriptionSize = sizeof(FvBlob2.BlobDescription); + CopyMem (FvBlob2.BlobDescription, FV_HANDOFF_TABLE_DESC, sizeof(FvBlob2.BlobDescription)); + FvName = GetFvName (FvBase, FvLength); + if (FvName != NULL) { + AsciiSPrint ((CHAR8 *)FvBlob2.BlobDescription, sizeof(FvBlob2.BlobDescription), "Fv(%g)", FvName); + } + FvBlob2.BlobBase = FvOrgBase; + FvBlob2.BlobLength = FvLength; + TcgEventHdr.PCRIndex = 0; + TcgEventHdr.EventType = EV_EFI_PLATFORM_FIRMWARE_BLOB2; + TcgEventHdr.EventSize = sizeof (FvBlob2); + EventData = &FvBlob2; + } else { + FvBlob.BlobBase = FvOrgBase; + FvBlob.BlobLength = FvLength; + TcgEventHdr.PCRIndex = 0; + TcgEventHdr.EventType = EV_EFI_PLATFORM_FIRMWARE_BLOB; + TcgEventHdr.EventSize = sizeof (FvBlob); + EventData = &FvBlob; + } + + if (Tpm2HashMask == 0) { + // + // FV pre-hash algos comply with current TPM hash requirement + // Skip hashing step in measure, only extend DigestList to PCR and log event + // + Status = HashLogExtendEvent ( + &mEdkiiTcgPpi, + EDKII_TCG_PRE_HASH, + (UINT8*) &DigestList, // HashData + (UINTN) sizeof(DigestList), // HashDataLen + &TcgEventHdr, // EventHdr + EventData // EventData + ); + DEBUG ((DEBUG_INFO, "The pre-hashed FV which is extended & logged by Tcg2Pei starts at: 0x%x\n", FvBase)); + DEBUG ((DEBUG_INFO, "The pre-hashed FV which is extended & logged by Tcg2Pei has the size: 0x%x\n", FvLength)); + } else { + // + // Hash the FV, extend digest to the TPM and log TCG event + // + Status = HashLogExtendEvent ( + &mEdkiiTcgPpi, + 0, + (UINT8*) (UINTN) FvDataBase, // HashData + (UINTN) FvLength, // HashDataLen + &TcgEventHdr, // EventHdr + EventData // EventData + ); + DEBUG ((DEBUG_INFO, "The FV which is measured by Tcg2Pei starts at: 0x%x\n", FvBase)); + DEBUG ((DEBUG_INFO, "The FV which is measured by Tcg2Pei has the size: 0x%x\n", FvLength)); + } + + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_ERROR, "The FV which failed to be measured starts at: 0x%x\n", FvBase)); + return Status; + } + + // + // Add new FV into the measured FV list. + // + if (mMeasuredBaseFvIndex >= mMeasuredMaxBaseFvIndex) { + mMeasuredBaseFvInfo = ReallocatePool ( + sizeof (EFI_PLATFORM_FIRMWARE_BLOB) * mMeasuredMaxBaseFvIndex, + sizeof (EFI_PLATFORM_FIRMWARE_BLOB) * (mMeasuredMaxBaseFvIndex + FIRMWARE_BLOB_GROWTH_STEP), + mMeasuredBaseFvInfo + ); + ASSERT (mMeasuredBaseFvInfo != NULL); + mMeasuredMaxBaseFvIndex = mMeasuredMaxBaseFvIndex + FIRMWARE_BLOB_GROWTH_STEP; + } + + 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; + 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); + + // + // Only measure BFV at the very beginning. Other parts of Static Core Root of + // Trust for Measurement(S-CRTM) will be measured later on FvInfoNotify. + // BFV is processed without installing FV Info Ppi. Other FVs either inside BFV or + // reported by platform will be installed with Fv Info Ppi + // This firmware volume measure policy can be modified/enhanced by special + // platform for special CRTM TPM measuring. + // + Status = PeiServicesFfsFindNextVolume (0, &VolumeHandle); + ASSERT_EFI_ERROR (Status); + + // + // 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 + ); + ASSERT_EFI_ERROR (Status); + + Status = MeasureFvImage ((EFI_PHYSICAL_ADDRESS) (UINTN) VolumeInfo.FvStart, VolumeInfo.FvSize); + + PERF_END_EX (mFileHandle, "EventRec", "Tcg2Pei", 0, PERF_ID_TCG2_PEI + 1); + + return Status; +} + +/** + Measure and record the Firmware Volume 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 +FirmwareVolumeInfoPpiNotifyCallback ( + 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 ) { + + if (mMeasuredChildFvIndex >= mMeasuredMaxChildFvIndex) { + mMeasuredChildFvInfo = ReallocatePool ( + sizeof (EFI_PLATFORM_FIRMWARE_BLOB) * mMeasuredMaxChildFvIndex, + sizeof (EFI_PLATFORM_FIRMWARE_BLOB) * (mMeasuredMaxChildFvIndex + FIRMWARE_BLOB_GROWTH_STEP), + mMeasuredChildFvInfo + ); + ASSERT (mMeasuredChildFvInfo != NULL); + mMeasuredMaxChildFvIndex = mMeasuredMaxChildFvIndex + FIRMWARE_BLOB_GROWTH_STEP; + } + // + // 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; + + // + // install Tcg Services + // + Status = PeiServicesInstallPpi (&mTcgPpiList); + ASSERT_EFI_ERROR (Status); + + if (PcdGet8 (PcdTpm2ScrtmPolicy) == 1) { + Status = MeasureCRTMVersion (); + } + + Status = MeasureMainBios (); + if (EFI_ERROR(Status)) { + return Status; + } + + // + // 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(&mEdkiiTcgPpi, 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 install 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 install 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/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.inf b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.inf new file mode 100644 index 00000000..dc2ce364 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.inf @@ -0,0 +1,95 @@ +## @file +# Initializes TPM 2.0 device and measure FVs in PEI phase +# +# Spec Compliance Info: +# "TCG PC Client Platform Firmware Profile Specification for TPM Family 2.0 Level 00 Revision 1.03 v51" +# along with +# "Errata for PC Client Specific Platform Firmware Profile Specification Version 1.0 Revision 1.03" +# +# This module will initialize TPM device, measure reported FVs and BIOS version. +# +# Copyright (c) 2015 - 2020, Intel Corporation. All rights reserved.
+# Copyright (c) 2017, Microsoft Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[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 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 + ResetSystemLib + PrintLib + +[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 + gEdkiiMigratedFvInfoGuid ## SOMETIMES_CONSUMES ## HOB + +[Ppis] + gEfiPeiFirmwareVolumeInfoPpiGuid ## SOMETIMES_CONSUMES ## NOTIFY + gEfiPeiFirmwareVolumeInfo2PpiGuid ## SOMETIMES_CONSUMES ## NOTIFY + gEfiPeiFirmwareVolumeInfoMeasurementExcludedPpiGuid ## SOMETIMES_CONSUMES + gPeiTpmInitializedPpiGuid ## SOMETIMES_PRODUCES + gPeiTpmInitializationDonePpiGuid ## PRODUCES + gEfiEndOfPeiSignalPpiGuid ## SOMETIMES_CONSUMES ## NOTIFY + gEdkiiPeiFirmwareVolumeInfoPrehashedFvPpiGuid ## SOMETIMES_CONSUMES + gEdkiiTcgPpiGuid ## PRODUCES + +[Pcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdFirmwareVersionString ## SOMETIMES_CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdTcgPfpMeasurementRevision ## CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdTpmInstanceGuid ## CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdTpm2InitializationPolicy ## CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdTpm2SelfTestPolicy ## SOMETIMES_CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdTpm2ScrtmPolicy ## CONSUMES + gEfiSecurityPkgTokenSpaceGuid.PcdStatusCodeSubClassTpmDevice ## SOMETIMES_CONSUMES + ## SOMETIMES_CONSUMES + ## SOMETIMES_PRODUCES + gEfiSecurityPkgTokenSpaceGuid.PcdTpm2HashMask + +[Depex] + gEfiPeiMasterBootModePpiGuid AND + gEfiTpmDeviceSelectedGuid + +[UserExtensions.TianoCore."ExtraFiles"] + Tcg2PeiExtra.uni diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.uni new file mode 100644 index 00000000..bdc7beb0 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.uni @@ -0,0 +1,16 @@ +// /** @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.
+// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + + +#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/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Pei/Tcg2PeiExtra.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Pei/Tcg2PeiExtra.uni new file mode 100644 index 00000000..984850ee --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Pei/Tcg2PeiExtra.uni @@ -0,0 +1,14 @@ +// /** @file +// Tcg2Pei Localized Strings and Content +// +// Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.
+// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_PROPERTIES_MODULE_NAME +#language en-US +"TCG2 (Trusted Computing Group) PEI" + + diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Smm/Tcg2MmDependencyDxe.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Smm/Tcg2MmDependencyDxe.c new file mode 100644 index 00000000..27143698 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Smm/Tcg2MmDependencyDxe.c @@ -0,0 +1,48 @@ +/** @file + Runtime DXE part corresponding to StandaloneMM Tcg2 module. + +This module installs gTcg2MmSwSmiRegisteredGuid to notify readiness of +StandaloneMM Tcg2 module. + +Copyright (c) 2019 - 2021, Arm Ltd. All rights reserved. +Copyright (c) Microsoft Corporation. + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include + +#include +#include + +/** + The constructor function installs gTcg2MmSwSmiRegisteredGuid to notify + readiness of StandaloneMM Tcg2 module. + + @param ImageHandle The firmware allocated handle for the EFI image. + @param SystemTable A pointer to the Management mode System Table. + + @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS. + +**/ +EFI_STATUS +EFIAPI +Tcg2MmDependencyDxeEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_HANDLE Handle; + + Handle = NULL; + Status = gBS->InstallProtocolInterface ( + &Handle, + &gTcg2MmSwSmiRegisteredGuid, + EFI_NATIVE_INTERFACE, + NULL + ); + ASSERT_EFI_ERROR (Status); + return EFI_SUCCESS; +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Smm/Tcg2MmDependencyDxe.inf b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Smm/Tcg2MmDependencyDxe.inf new file mode 100644 index 00000000..e99b900f --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Smm/Tcg2MmDependencyDxe.inf @@ -0,0 +1,43 @@ +## @file +# Runtime DXE part corresponding to StandaloneMM Tcg2 module. +# +# This module installs gTcg2MmSwSmiRegisteredGuid to notify readiness of +# StandaloneMM Tcg2 module. +# +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x0001001A + BASE_NAME = Tcg2MmDependencyDxe + FILE_GUID = 94C210EA-3113-4563-ADEB-76FE759C2F46 + MODULE_TYPE = DXE_DRIVER + ENTRY_POINT = Tcg2MmDependencyDxeEntryPoint + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# +# + +[Sources] + Tcg2MmDependencyDxe.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + DebugLib + UefiBootServicesTableLib + UefiDriverEntryPoint + +[Guids] + gTcg2MmSwSmiRegisteredGuid ## PRODUCES ## GUID # Install protocol + +[Depex] + gEfiMmCommunication2ProtocolGuid diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.c new file mode 100644 index 00000000..5d14d3a1 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.c @@ -0,0 +1,375 @@ +/** @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 - 2018, Intel Corporation. All rights reserved.
+Copyright (c) Microsoft Corporation. +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "Tcg2Smm.h" + +EFI_SMM_VARIABLE_PROTOCOL *mSmmVariable = NULL; +TCG_NVS *mTcgNvs = NULL; +UINTN mPpSoftwareSmi; +UINTN mMcSoftwareSmi; +EFI_HANDLE mReadyToLockHandle; + +/** + Communication service SMI Handler entry. + + This handler takes requests to exchange Mmi channel and Nvs address between MM and DXE. + + Caution: This function may receive untrusted input. + Communicate buffer and buffer size are external input, so this function will do basic validation. + + @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister(). + @param[in] RegisterContext Points to an optional handler context which was specified when the + handler was registered. + @param[in, out] CommBuffer A pointer to a collection of data in memory that will + be conveyed from a non-SMM environment into an SMM environment. + @param[in, out] CommBufferSize The size of the CommBuffer. + + @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers + should still be called. + @retval EFI_UNSUPPORTED An unknown test function was requested. + @retval EFI_ACCESS_DENIED Part of the communication buffer lies in an invalid region. + +**/ +EFI_STATUS +EFIAPI +TpmNvsCommunciate ( + IN EFI_HANDLE DispatchHandle, + IN CONST VOID *RegisterContext, + IN OUT VOID *CommBuffer, + IN OUT UINTN *CommBufferSize + ) +{ + EFI_STATUS Status; + UINTN TempCommBufferSize; + TPM_NVS_MM_COMM_BUFFER *CommParams; + + DEBUG ((DEBUG_VERBOSE, "%a()\n", __FUNCTION__)); + + // + // If input is invalid, stop processing this SMI + // + if (CommBuffer == NULL || CommBufferSize == NULL) { + return EFI_SUCCESS; + } + + TempCommBufferSize = *CommBufferSize; + + if(TempCommBufferSize != sizeof (TPM_NVS_MM_COMM_BUFFER)) { + DEBUG ((DEBUG_ERROR, "[%a] MM Communication buffer size is invalid for this handler!\n", __FUNCTION__)); + return EFI_ACCESS_DENIED; + } + if (!IsBufferOutsideMmValid ((UINTN) CommBuffer, TempCommBufferSize)) { + DEBUG ((DEBUG_ERROR, "[%a] - MM Communication buffer in invalid location!\n", __FUNCTION__)); + return EFI_ACCESS_DENIED; + } + + // + // Farm out the job to individual functions based on what was requested. + // + CommParams = (TPM_NVS_MM_COMM_BUFFER*) CommBuffer; + Status = EFI_SUCCESS; + switch (CommParams->Function) { + case TpmNvsMmExchangeInfo: + DEBUG ((DEBUG_VERBOSE, "[%a] - Function requested: MM_EXCHANGE_NVS_INFO\n", __FUNCTION__)); + CommParams->RegisteredPpSwiValue = mPpSoftwareSmi; + CommParams->RegisteredMcSwiValue = mMcSoftwareSmi; + mTcgNvs = (TCG_NVS*) (UINTN) CommParams->TargetAddress; + break; + + default: + DEBUG ((DEBUG_INFO, "[%a] - Unknown function %d!\n", __FUNCTION__, CommParams->Function)); + Status = EFI_UNSUPPORTED; + break; + } + + CommParams->ReturnStatus = (UINT64) Status; + return EFI_SUCCESS; +} + +/** + 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; + } else { + mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_GENERAL_FAILURE; + DEBUG ((EFI_D_ERROR, "[TPM] MOR Parameter error! Parameter = %x\n", mTcgNvs->MemoryClear.Parameter)); + return EFI_SUCCESS; + } + + 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; +} + +/** + Notification for SMM ReadyToLock 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 +TcgMmReadyToLock ( + IN CONST EFI_GUID *Protocol, + IN VOID *Interface, + IN EFI_HANDLE Handle +) +{ + EFI_STATUS Status; + + Status = EFI_SUCCESS; + + if (mReadyToLockHandle != NULL) { + Status = gMmst->MmiHandlerUnRegister (mReadyToLockHandle); + mReadyToLockHandle = NULL; + } + return Status; +} + +/** + The driver's common initialization routine. + + It install callbacks for TPM physical presence and MemoryClear, and locate + SMM variable to be used in the callback function. + + @retval EFI_SUCCESS The entry point is executed successfully. + @retval Others Some error occurs when executing this entry point. + +**/ +EFI_STATUS +InitializeTcgCommon ( + VOID + ) +{ + EFI_STATUS Status; + EFI_SMM_SW_DISPATCH2_PROTOCOL *SwDispatch; + EFI_SMM_SW_REGISTER_CONTEXT SwContext; + EFI_HANDLE PpSwHandle; + EFI_HANDLE McSwHandle; + EFI_HANDLE NotifyHandle; + + if (!CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceTpm20DtpmGuid)){ + DEBUG ((EFI_D_ERROR, "No TPM2 DTPM instance required!\n")); + return EFI_UNSUPPORTED; + } + + // Initialize variables first + mReadyToLockHandle = NULL; + SwDispatch = NULL; + PpSwHandle = NULL; + McSwHandle = NULL; + NotifyHandle = NULL; + + // Register a root handler to communicate the NVS region and SMI channel between MM and DXE + Status = gMmst->MmiHandlerRegister (TpmNvsCommunciate, &gTpmNvsMmGuid, &mReadyToLockHandle); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "[%a] Failed to register NVS communicate as root MM handler - %r!\n", __FUNCTION__, Status)); + goto Cleanup; + } + + // + // Get the Sw dispatch protocol and register SMI callback functions. + // + Status = gMmst->MmLocateProtocol (&gEfiSmmSwDispatch2ProtocolGuid, NULL, (VOID**)&SwDispatch); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "[%a] Failed to locate Sw dispatch protocol - %r!\n", __FUNCTION__, Status)); + goto Cleanup; + } + + SwContext.SwSmiInputValue = (UINTN) -1; + Status = SwDispatch->Register (SwDispatch, PhysicalPresenceCallback, &SwContext, &PpSwHandle); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "[%a] Failed to register PP callback as SW MM handler - %r!\n", __FUNCTION__, Status)); + goto Cleanup; + } + mPpSoftwareSmi = SwContext.SwSmiInputValue; + + SwContext.SwSmiInputValue = (UINTN) -1; + Status = SwDispatch->Register (SwDispatch, MemoryClearCallback, &SwContext, &McSwHandle); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "[%a] Failed to register MC callback as SW MM handler - %r!\n", __FUNCTION__, Status)); + goto Cleanup; + } + mMcSoftwareSmi = SwContext.SwSmiInputValue; + + // + // Locate SmmVariableProtocol. + // + Status = gMmst->MmLocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID**)&mSmmVariable); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + // Should not happen + DEBUG ((DEBUG_ERROR, "[%a] Failed to locate SMM variable protocol - %r!\n", __FUNCTION__, Status)); + goto Cleanup; + } + + // Turn off the light before leaving the room... at least, take a remote... + Status = gMmst->MmRegisterProtocolNotify (&gEfiMmReadyToLockProtocolGuid, TcgMmReadyToLock, &NotifyHandle); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "[%a] Failed to register ready to lock notification - %r!\n", __FUNCTION__, Status)); + goto Cleanup; + } + + Tcg2NotifyMmReady (); + +Cleanup: + if (EFI_ERROR (Status)) { + // Something is whacked, clean up the mess... + if (NotifyHandle != NULL) { + gMmst->MmRegisterProtocolNotify (&gEfiMmReadyToLockProtocolGuid, NULL, &NotifyHandle); + } + if (McSwHandle != NULL && SwDispatch != NULL) { + SwDispatch->UnRegister (SwDispatch, McSwHandle); + } + if (PpSwHandle != NULL && SwDispatch != NULL) { + SwDispatch->UnRegister (SwDispatch, PpSwHandle); + } + if (mReadyToLockHandle != NULL) { + gMmst->MmiHandlerUnRegister (mReadyToLockHandle); + } + } + + return Status; +} + diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.h b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.h new file mode 100644 index 00000000..8293bb49 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.h @@ -0,0 +1,87 @@ +/** @file + The header file for Tcg2 SMM driver. + +Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.
+Copyright (c) Microsoft Corporation. +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#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 + +// +// 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 + +/** + Notify the system that the SMM variable driver is ready. +**/ +VOID +Tcg2NotifyMmReady ( + VOID + ); + +/** + This function is an abstraction layer for implementation specific Mm buffer validation routine. + + @param Buffer The buffer start address to be checked. + @param Length The buffer length to be checked. + + @retval TRUE This buffer is valid per processor architecture and not overlap with SMRAM. + @retval FALSE This buffer is not valid per processor architecture or overlap with SMRAM. +**/ +BOOLEAN +IsBufferOutsideMmValid ( + IN EFI_PHYSICAL_ADDRESS Buffer, + IN UINT64 Length + ); + +/** + The driver's common initialization routine. + + It install callbacks for TPM physical presence and MemoryClear, and locate + SMM variable to be used in the callback function. + + @retval EFI_SUCCESS The entry point is executed successfully. + @retval Others Some error occurs when executing this entry point. + +**/ +EFI_STATUS +InitializeTcgCommon ( + VOID + ); + +#endif // __TCG_SMM_H__ diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.inf b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.inf new file mode 100644 index 00000000..e2870130 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.inf @@ -0,0 +1,86 @@ +## @file +# Provides ACPI methods for TPM 2.0 support +# +# Spec Compliance Info: +# "TCG ACPI Specification Version 1.2 Revision 8" +# "Physical Presence Interface Specification Version 1.30 Revision 00.52" +# along with +# "Errata Version 0.4 for TCG PC Client Platform Physical Presence Interface Specification" +# "Platform Reset Attack Mitigation Specification Version 1.00" +# TPM2.0 ACPI device object +# "TCG PC Client Platform Firmware Profile Specification for TPM Family 2.0 Level 00 Revision 1.03 v51" +# along with +# "Errata for PC Client Specific Platform Firmware Profile Specification Version 1.0 Revision 1.03" +# +# 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 - 2019, Intel Corporation. All rights reserved.
+# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[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 + Tcg2TraditionalMm.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + SecurityPkg/SecurityPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + UefiDriverEntryPoint + MmServicesTableLib + UefiBootServicesTableLib + DebugLib + DxeServicesLib + TpmMeasurementLib + Tpm2CommandLib + Tcg2PhysicalPresenceLib + PcdLib + SmmMemLib + +[Guids] + ## SOMETIMES_PRODUCES ## Variable:L"MemoryOverwriteRequestControl" + ## SOMETIMES_CONSUMES ## Variable:L"MemoryOverwriteRequestControl" + gEfiMemoryOverwriteControlDataGuid + + gEfiTpmDeviceInstanceTpm20DtpmGuid ## PRODUCES ## GUID # TPM device identifier + gTcg2MmSwSmiRegisteredGuid ## PRODUCES + gTpmNvsMmGuid ## CONSUMES + +[Protocols] + gEfiSmmSwDispatch2ProtocolGuid ## CONSUMES + gEfiSmmVariableProtocolGuid ## CONSUMES + gEfiMmReadyToLockProtocolGuid ## CONSUMES + +[Pcd] + gEfiSecurityPkgTokenSpaceGuid.PcdTpmInstanceGuid ## CONSUMES + +[Depex] + gEfiSmmSwDispatch2ProtocolGuid AND + gEfiSmmVariableProtocolGuid AND + gEfiTcg2ProtocolGuid + +[UserExtensions.TianoCore."ExtraFiles"] + Tcg2SmmExtra.uni diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.uni new file mode 100644 index 00000000..d6e047d7 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.uni @@ -0,0 +1,23 @@ +// /** @file +// Provides ACPI methods 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 - 2018, Intel Corporation. All rights reserved.
+// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + + +#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/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Smm/Tcg2SmmExtra.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Smm/Tcg2SmmExtra.uni new file mode 100644 index 00000000..37363763 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Smm/Tcg2SmmExtra.uni @@ -0,0 +1,14 @@ +// /** @file +// Tcg2Smm Localized Strings and Content +// +// Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.
+// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_PROPERTIES_MODULE_NAME +#language en-US +"TCG2 (Trusted Computing Group) SMM" + + diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Smm/Tcg2StandaloneMm.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Smm/Tcg2StandaloneMm.c new file mode 100644 index 00000000..c194a132 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Smm/Tcg2StandaloneMm.c @@ -0,0 +1,71 @@ +/** @file + TCG2 Standalone MM driver that 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 - 2018, Intel Corporation. All rights reserved.
+Copyright (c) Microsoft Corporation. +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "Tcg2Smm.h" +#include + +/** + Notify the system that the SMM variable driver is ready. +**/ +VOID +Tcg2NotifyMmReady ( + VOID + ) +{ + // Do nothing +} + +/** + This function is an abstraction layer for implementation specific Mm buffer validation routine. + + @param Buffer The buffer start address to be checked. + @param Length The buffer length to be checked. + + @retval TRUE This buffer is valid per processor architecture and not overlap with SMRAM. + @retval FALSE This buffer is not valid per processor architecture or overlap with SMRAM. +**/ +BOOLEAN +IsBufferOutsideMmValid ( + IN EFI_PHYSICAL_ADDRESS Buffer, + IN UINT64 Length + ) +{ + return MmIsBufferOutsideMmValid (Buffer, Length); +} + +/** + 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 +InitializeTcgStandaloneMm ( + IN EFI_HANDLE ImageHandle, + IN EFI_MM_SYSTEM_TABLE *SystemTable + ) +{ + return InitializeTcgCommon (); +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Smm/Tcg2StandaloneMm.inf b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Smm/Tcg2StandaloneMm.inf new file mode 100644 index 00000000..7dcfa88c --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Smm/Tcg2StandaloneMm.inf @@ -0,0 +1,77 @@ +## @file +# Provides ACPI methods for TPM 2.0 support +# +# Spec Compliance Info: +# "TCG ACPI Specification Version 1.2 Revision 8" +# "Physical Presence Interface Specification Version 1.30 Revision 00.52" +# along with +# "Errata Version 0.4 for TCG PC Client Platform Physical Presence Interface Specification" +# "Platform Reset Attack Mitigation Specification Version 1.00" +# TPM2.0 ACPI device object +# "TCG PC Client Platform Firmware Profile Specification for TPM Family 2.0 Level 00 Revision 1.03 v51" +# along with +# "Errata for PC Client Specific Platform Firmware Profile Specification Version 1.0 Revision 1.03" +# +# 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 - 2019, Intel Corporation. All rights reserved.
+# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = Tcg2StandaloneMm + FILE_GUID = D40F321F-5349-4724-B667-131670587861 + MODULE_TYPE = MM_STANDALONE + PI_SPECIFICATION_VERSION = 0x00010032 + VERSION_STRING = 1.0 + ENTRY_POINT = InitializeTcgStandaloneMm + +[Sources] + Tcg2Smm.h + Tcg2Smm.c + Tcg2StandaloneMm.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + SecurityPkg/SecurityPkg.dec + StandaloneMmPkg/StandaloneMmPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + StandaloneMmDriverEntryPoint + MmServicesTableLib + DebugLib + Tcg2PhysicalPresenceLib + PcdLib + MemLib + +[Guids] + ## SOMETIMES_PRODUCES ## Variable:L"MemoryOverwriteRequestControl" + ## SOMETIMES_CONSUMES ## Variable:L"MemoryOverwriteRequestControl" + gEfiMemoryOverwriteControlDataGuid + + gEfiTpmDeviceInstanceTpm20DtpmGuid ## PRODUCES ## GUID # TPM device identifier + gTpmNvsMmGuid ## CONSUMES + +[Protocols] + gEfiSmmSwDispatch2ProtocolGuid ## CONSUMES + gEfiSmmVariableProtocolGuid ## CONSUMES + gEfiMmReadyToLockProtocolGuid ## CONSUMES + +[Pcd] + gEfiSecurityPkgTokenSpaceGuid.PcdTpmInstanceGuid ## CONSUMES + +[Depex] + gEfiSmmSwDispatch2ProtocolGuid AND + gEfiSmmVariableProtocolGuid diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Smm/Tcg2TraditionalMm.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Smm/Tcg2TraditionalMm.c new file mode 100644 index 00000000..f72f9c71 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Smm/Tcg2TraditionalMm.c @@ -0,0 +1,82 @@ +/** @file + TCG2 SMM driver that 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 - 2018, Intel Corporation. All rights reserved.
+Copyright (c) Microsoft Corporation. +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "Tcg2Smm.h" +#include +#include + +/** + Notify the system that the SMM variable driver is ready. +**/ +VOID +Tcg2NotifyMmReady ( + VOID + ) +{ + EFI_STATUS Status; + EFI_HANDLE Handle; + + Handle = NULL; + Status = gBS->InstallProtocolInterface ( + &Handle, + &gTcg2MmSwSmiRegisteredGuid, + EFI_NATIVE_INTERFACE, + NULL + ); + ASSERT_EFI_ERROR (Status); +} + +/** + This function is an abstraction layer for implementation specific Mm buffer validation routine. + + @param Buffer The buffer start address to be checked. + @param Length The buffer length to be checked. + + @retval TRUE This buffer is valid per processor architecture and not overlap with SMRAM. + @retval FALSE This buffer is not valid per processor architecture or overlap with SMRAM. +**/ +BOOLEAN +IsBufferOutsideMmValid ( + IN EFI_PHYSICAL_ADDRESS Buffer, + IN UINT64 Length + ) +{ + return SmmIsBufferOutsideSmmValid (Buffer, Length); +} + +/** + 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 + ) +{ + return InitializeTcgCommon (); +} diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgConfigDxe/TcgConfig.vfr b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgConfigDxe/TcgConfig.vfr new file mode 100644 index 00000000..d42b4c8b --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgConfigDxe/TcgConfig.vfr @@ -0,0 +1,72 @@ +/** @file + VFR file used by the TCG configuration component. + +Copyright (c) 2011 - 2019, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#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, + // + // Default the form to NO ACTION to allow toggling other options + // + option text = STRING_TOKEN(STR_NO_ACTION), value = PHYSICAL_PRESENCE_NO_ACTION, flags = DEFAULT; + // + // 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 = 0; + 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/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDriver.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDriver.c new file mode 100644 index 00000000..3733cb01 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDriver.c @@ -0,0 +1,150 @@ +/** @file + The module entry point for Tcg configuration module. + +Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#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_SUCCESS 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/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDxe.inf b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDxe.inf new file mode 100644 index 00000000..b4dbca62 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDxe.inf @@ -0,0 +1,77 @@ +## @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 - 2018, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[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 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 + + ## 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/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDxe.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDxe.uni new file mode 100644 index 00000000..027b9591 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDxe.uni @@ -0,0 +1,16 @@ +// /** @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.
+// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + + +#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/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDxeExtra.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDxeExtra.uni new file mode 100644 index 00000000..3b26169e --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDxeExtra.uni @@ -0,0 +1,14 @@ +// /** @file +// TcgConfigDxe Localized Strings and Content +// +// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.
+// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_PROPERTIES_MODULE_NAME +#language en-US +"TCG (Trusted Computing Group) Config DXE" + + diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigImpl.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigImpl.c new file mode 100644 index 00000000..5b1f4136 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigImpl.c @@ -0,0 +1,503 @@ +/** @file + HII Config Access protocol implementation of TCG configuration module. + +Copyright (c) 2011 - 2019, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#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_NO_ACTION; + + // + // 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/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigImpl.h b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigImpl.h new file mode 100644 index 00000000..d82e1821 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigImpl.h @@ -0,0 +1,188 @@ +/** @file + The header file of HII Config Access protocol implementation of TCG + configuration module. + +Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#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/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigNvData.h b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigNvData.h new file mode 100644 index 00000000..188621fe --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigNvData.h @@ -0,0 +1,33 @@ +/** @file + Header file for NV data structure definition. + +Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#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/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigStrings.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigStrings.uni new file mode 100644 index 00000000..b5bb8998 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigStrings.uni @@ -0,0 +1,35 @@ +/** @file + String definitions for TCG configuration form. + +Copyright (c) 2011 - 2019, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#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_NO_ACTION #language en-US "No Action" +#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" diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgDxe/TcgDxe.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgDxe/TcgDxe.c new file mode 100644 index 00000000..e4341b86 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgDxe/TcgDxe.c @@ -0,0 +1,1459 @@ +/** @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 - 2018, Intel Corporation. All rights reserved.
+(C) Copyright 2016 Hewlett Packard Enterprise Development LP
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#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 connects 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_APPLICATION + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "%a not Measured. Error!\n", EFI_RETURNING_FROM_EFI_APPLICATION)); + } + } + + 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 checksummed 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 checksummed 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, + "DriverEntry: TPM not working properly\n" + )); + 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/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgDxe/TcgDxe.inf b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgDxe/TcgDxe.inf new file mode 100644 index 00000000..63a9b548 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgDxe/TcgDxe.inf @@ -0,0 +1,81 @@ +## @file +# Produces TCG protocol and measures boot environment +# This module will produce TCG protocol and measure boot environment. +# +# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[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 +# + +[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 + diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgDxe/TcgDxe.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgDxe/TcgDxe.uni new file mode 100644 index 00000000..2262d2fb --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgDxe/TcgDxe.uni @@ -0,0 +1,16 @@ +// /** @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.
+// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + + +#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/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgDxe/TcgDxeExtra.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgDxe/TcgDxeExtra.uni new file mode 100644 index 00000000..68767537 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgDxe/TcgDxeExtra.uni @@ -0,0 +1,14 @@ +// /** @file +// TcgDxe Localized Strings and Content +// +// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.
+// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_PROPERTIES_MODULE_NAME +#language en-US +"TCG (Trusted Computing Group) DXE" + + diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgPei/TcgPei.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgPei/TcgPei.c new file mode 100644 index 00000000..ad29affa --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgPei/TcgPei.c @@ -0,0 +1,931 @@ +/** @file + Initialize TPM device and measure FVs before handing off control to DXE. + +Copyright (c) 2005 - 2020, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#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 + +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 +}; + +/** + 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] This Indicates the calling context + @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 +EFIAPI +HashLogExtendEvent ( + IN EDKII_TCG_PPI *This, + IN UINT64 Flags, + IN UINT8 *HashData, + IN UINTN HashDataLen, + IN TCG_PCR_EVENT_HDR *NewEventHdr, + IN UINT8 *NewEventData + ); + +EDKII_TCG_PPI mEdkiiTcgPpi = { + HashLogExtendEvent +}; + +EFI_PEI_PPI_DESCRIPTOR mTcgPpiList = { + EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, + &gEdkiiTcgPpiGuid, + &mEdkiiTcgPpi +}; + +// +// Number of firmware blobs to grow by each time we run out of room +// +#define FIRMWARE_BLOB_GROWTH_STEP 4 + +EFI_PLATFORM_FIRMWARE_BLOB *mMeasuredBaseFvInfo; +UINT32 mMeasuredMaxBaseFvIndex = 0; +UINT32 mMeasuredBaseFvIndex = 0; + +EFI_PLATFORM_FIRMWARE_BLOB *mMeasuredChildFvInfo; +UINT32 mMeasuredMaxChildFvIndex = 0; +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 Volume 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 +FirmwareVolumeInfoPpiNotifyCallback ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, + IN VOID *Ppi + ); + +/** + Record all measured Firmware Volume 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, + FirmwareVolumeInfoPpiNotifyCallback + }, + { + EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK, + &gEfiPeiFirmwareVolumeInfo2PpiGuid, + FirmwareVolumeInfoPpiNotifyCallback + }, + { + (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gEfiEndOfPeiSignalPpiGuid, + EndofPeiSignalNotifyCallBack + } +}; + +/** + Record all measured Firmware Volume 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; + + PERF_CALLBACK_BEGIN (&gEfiEndOfPeiSignalPpiGuid); + + // + // 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)); + } + + PERF_CALLBACK_END (&gEfiEndOfPeiSignalPpiGuid); + + 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] This Indicates the calling context. + @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 +EFIAPI +HashLogExtendEvent ( + IN EDKII_TCG_PPI *This, + IN UINT64 Flags, + 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 ( + &mEdkiiTcgPpi, + 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 +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; + EFI_PHYSICAL_ADDRESS FvOrgBase; + EFI_PHYSICAL_ADDRESS FvDataBase; + EFI_PEI_HOB_POINTERS Hob; + EDKII_MIGRATED_FV_INFO *MigratedFvInfo; + + // + // 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; + } + } + + // + // Search the matched migration FV info + // + FvOrgBase = FvBase; + FvDataBase = FvBase; + Hob.Raw = GetFirstGuidHob (&gEdkiiMigratedFvInfoGuid); + while (Hob.Raw != NULL) { + MigratedFvInfo = GET_GUID_HOB_DATA (Hob); + if ((MigratedFvInfo->FvNewBase == (UINT32) FvBase) && (MigratedFvInfo->FvLength == (UINT32) FvLength)) { + // + // Found the migrated FV info + // + FvOrgBase = (EFI_PHYSICAL_ADDRESS) (UINTN) MigratedFvInfo->FvOrgBase; + FvDataBase = (EFI_PHYSICAL_ADDRESS) (UINTN) MigratedFvInfo->FvDataBase; + break; + } + Hob.Raw = GET_NEXT_HOB (Hob); + Hob.Raw = GetNextGuidHob (&gEdkiiMigratedFvInfoGuid, Hob.Raw); + } + + // + // Measure and record the FV to the TPM + // + FvBlob.BlobBase = FvOrgBase; + 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 ( + &mEdkiiTcgPpi, + 0, + (UINT8*) (UINTN) FvDataBase, + (UINTN) FvBlob.BlobLength, + &TcgEventHdr, + (UINT8*) &FvBlob + ); + + // + // Add new FV into the measured FV list. + // + if (mMeasuredBaseFvIndex >= mMeasuredMaxBaseFvIndex) { + mMeasuredBaseFvInfo = ReallocatePool ( + sizeof (EFI_PLATFORM_FIRMWARE_BLOB) * mMeasuredMaxBaseFvIndex, + sizeof (EFI_PLATFORM_FIRMWARE_BLOB) * (mMeasuredMaxBaseFvIndex + FIRMWARE_BLOB_GROWTH_STEP), + mMeasuredBaseFvInfo + ); + ASSERT (mMeasuredBaseFvInfo != NULL); + mMeasuredMaxBaseFvIndex = mMeasuredMaxBaseFvIndex + FIRMWARE_BLOB_GROWTH_STEP; + } + + 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 Volume 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 +FirmwareVolumeInfoPpiNotifyCallback ( + 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 ) { + + if (mMeasuredChildFvIndex >= mMeasuredMaxChildFvIndex) { + mMeasuredChildFvInfo = ReallocatePool ( + sizeof (EFI_PLATFORM_FIRMWARE_BLOB) * mMeasuredMaxChildFvIndex, + sizeof (EFI_PLATFORM_FIRMWARE_BLOB) * (mMeasuredMaxChildFvIndex + FIRMWARE_BLOB_GROWTH_STEP), + mMeasuredChildFvInfo + ); + ASSERT (mMeasuredChildFvInfo != NULL); + mMeasuredMaxChildFvIndex = mMeasuredMaxChildFvIndex + FIRMWARE_BLOB_GROWTH_STEP; + } + // + // 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 activated 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 + + 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); + + // + // install Tcg Services + // + Status = PeiServicesInstallPpi (&mTcgPpiList); + 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 install 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 install 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/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgPei/TcgPei.inf b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgPei/TcgPei.inf new file mode 100644 index 00000000..32c2c08c --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgPei/TcgPei.inf @@ -0,0 +1,89 @@ +## @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 - 2020, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[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 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 + PerformanceLib + +[Guids] + gTcgEventEntryHobGuid ## PRODUCES ## HOB + gTpmErrorHobGuid ## SOMETIMES_PRODUCES ## HOB + gMeasuredFvHobGuid ## PRODUCES ## HOB + gEfiTpmDeviceInstanceTpm12Guid ## PRODUCES ## GUID # TPM device identifier + gEdkiiMigratedFvInfoGuid ## SOMETIMES_CONSUMES ## HOB + +[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 + gEdkiiTcgPpiGuid ## PRODUCES + +[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 + gEfiSecurityPkgTokenSpaceGuid.PcdStatusCodeSubClassTpmDevice ## SOMETIMES_CONSUMES + +[Depex] + gEfiPeiMasterBootModePpiGuid AND + gEfiTpmDeviceSelectedGuid + +[UserExtensions.TianoCore."ExtraFiles"] + TcgPeiExtra.uni + diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgPei/TcgPei.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgPei/TcgPei.uni new file mode 100644 index 00000000..c7a9dbc9 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgPei/TcgPei.uni @@ -0,0 +1,17 @@ +// /** @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.
+// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + + +#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/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgPei/TcgPeiExtra.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgPei/TcgPeiExtra.uni new file mode 100644 index 00000000..c602e1d6 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgPei/TcgPeiExtra.uni @@ -0,0 +1,14 @@ +// /** @file +// TcgPei Localized Strings and Content +// +// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.
+// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_PROPERTIES_MODULE_NAME +#language en-US +"TCG (Trusted Computing Group) PEI" + + diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgSmm/TcgSmm.c b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgSmm/TcgSmm.c new file mode 100644 index 00000000..48f6058b --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgSmm/TcgSmm.c @@ -0,0 +1,463 @@ +/** @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 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#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; + } else { + mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_GENERAL_FAILURE; + DEBUG ((EFI_D_ERROR, "[TPM] MOR Parameter error! Parameter = %x\n", mTcgNvs->MemoryClear.Parameter)); + return EFI_SUCCESS; + } + + 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/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgSmm/TcgSmm.h b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgSmm/TcgSmm.h new file mode 100644 index 00000000..c40f4317 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgSmm/TcgSmm.h @@ -0,0 +1,99 @@ +/** @file + The header file for TCG SMM driver. + +Copyright (c) 2012 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#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/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgSmm/TcgSmm.inf b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgSmm/TcgSmm.inf new file mode 100644 index 00000000..1a48c18f --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgSmm/TcgSmm.inf @@ -0,0 +1,82 @@ +## @file +# Implements ACPI methods 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 - 2018, Intel Corporation. All rights reserved.
+# Copyright (c) Microsoft Corporation.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[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 + +[FixedPcd] + gEfiSecurityPkgTokenSpaceGuid.PcdSmiCommandIoPort ## CONSUMES + +[Pcd] + gEfiSecurityPkgTokenSpaceGuid.PcdTpmInstanceGuid ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemId ## SOMETIMES_CONSUMES + +[Depex] + gEfiAcpiTableProtocolGuid AND + gEfiSmmSwDispatch2ProtocolGuid AND + gEfiSmmVariableProtocolGuid AND + gEfiTcgProtocolGuid + +[UserExtensions.TianoCore."ExtraFiles"] + TcgSmmExtra.uni + diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgSmm/TcgSmm.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgSmm/TcgSmm.uni new file mode 100644 index 00000000..a3abb3ad --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgSmm/TcgSmm.uni @@ -0,0 +1,22 @@ +// /** @file +// Implements ACPI methods 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 - 2018, Intel Corporation. All rights reserved.
+// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + + +#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/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgSmm/TcgSmmExtra.uni b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgSmm/TcgSmmExtra.uni new file mode 100644 index 00000000..03808d66 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgSmm/TcgSmmExtra.uni @@ -0,0 +1,14 @@ +// /** @file +// TcgSmm Localized Strings and Content +// +// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.
+// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_PROPERTIES_MODULE_NAME +#language en-US +"TCG (Trusted Computing Group) SMM" + + diff --git a/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgSmm/Tpm.asl b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgSmm/Tpm.asl new file mode 100644 index 00000000..d79fcc97 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgSmm/Tpm.asl @@ -0,0 +1,351 @@ +/** @file + The TPM definition block in ACPI table for physical presence + and MemoryClear. + +Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.
+Copyright (c) Microsoft Corporation.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +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, FixedPcdGet16 (PcdSmiCommandIoPort), 1) + Field (SMIP, ByteAcc, NoLock, Preserve) + { + IOPN, 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 parameter + 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 parameter + MORD, 32, // Memory Overwrite Request Data + MRET, 32, // Memory Overwrite function return code + UCRQ, 32 // Physical 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))) + { + // + // Trigger the SMI through ACPI _PTS method. + // + Store (0x02, MCIP) + + // + // Trigger the SMI interrupt + // + Store (MCIN, IOPN) + } + } + Return (0) + } + + Method (_STA, 0) + { + if (LEqual (ACC0, 0xff)) + { + Return (0) + } + Return (0x0f) + } + + // + // TCG Hardware Information + // + Method (HINF, 1, Serialized, 0, {BuffObj, PkgObj}, {UnknownObj}) // IntObj + { + // + // Switch by function index + // + Switch (ToInteger(Arg0)) + { + 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, 2, Serialized, 0, {BuffObj, PkgObj, IntObj, StrObj}, {UnknownObj, UnknownObj}) // IntObj, PkgObj + { + // + // Switch by function index + // + Switch (ToInteger(Arg0)) + { + 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 (Arg1, 0x00)), PPRQ) + Store (0x02, PPIP) + + // + // Trigger the SMI interrupt + // + Store (PPIN, IOPN) + 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) + + // + // Trigger the SMI interrupt + // + Store (PPIN, IOPN) + + 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 (Arg1, 0x00)), PPRQ) + + // + // Trigger the SMI interrupt + // + Store (PPIN, IOPN) + Return (FRET) + } + Case (8) + { + // + // e) Get User Confirmation Status for Operation + // + Store (8, PPIP) + Store (DerefOf (Index (Arg1, 0x00)), UCRQ) + + // + // Trigger the SMI interrupt + // + Store (PPIN, IOPN) + + Return (FRET) + } + + Default {BreakPoint} + } + Return (1) + } + + Method (TMCI, 2, Serialized, 0, IntObj, {UnknownObj, UnknownObj}) // IntObj, PkgObj + { + // + // Switch by function index + // + Switch (ToInteger (Arg0)) + { + 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 (Arg1, 0x00)), MORD) + + // + // Trigger the SMI through ACPI _DSM method. + // + Store (0x01, MCIP) + + // + // Trigger the SMI interrupt + // + Store (MCIN, IOPN) + 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 (Arg2)) + } + + // + // TCG Physical Presence Interface + // + If(LEqual(Arg0, ToUUID ("3dddfaa6-361b-4eb4-a424-8d10089d1653"))) + { + Return (TPPI (Arg2, Arg3)) + } + + // + // TCG Memory Clear Interface + // + If(LEqual(Arg0, ToUUID ("376054ed-cc13-4675-901c-4756d7f2d45d"))) + { + Return (TMCI (Arg2, Arg3)) + } + + Return (Buffer () {0}) + } + } + } +} -- cgit v1.2.3