summaryrefslogtreecommitdiffstats
path: root/src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-11 08:17:27 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-11 08:17:27 +0000
commitf215e02bf85f68d3a6106c2a1f4f7f063f819064 (patch)
tree6bb5b92c046312c4e95ac2620b10ddf482d3fa8b /src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg
parentInitial commit. (diff)
downloadvirtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.tar.xz
virtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.zip
Adding upstream version 7.0.14-dfsg.upstream/7.0.14-dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg')
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.c375
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.h42
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.inf61
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMor.uni16
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/MemoryOverwriteControl/TcgMorExtra.uni14
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLock.c191
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLock.h131
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLock.uni16
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLockExtra.uni14
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLockSmm.c152
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/MemoryOverwriteRequestControlLock/TcgMorLockSmm.inf65
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/ComponentName.c392
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalDriver.c2966
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalDriver.h616
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalHii.c1283
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalHii.h375
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalHiiCallbacks.c112
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalHiiFormStrings.uni80
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalHiiFormValues.h109
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordCommon.h38
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordDxe.inf77
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordForm.vfr303
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordPei.c472
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordPei.h60
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Opal/OpalPassword/OpalPasswordPei.inf51
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePei.c128
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePei.inf59
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePei.uni18
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/PhysicalPresencePei/PhysicalPresencePeiExtra.uni14
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Acpi/Tcg2Acpi.c902
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Acpi/Tcg2Acpi.inf94
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Acpi/Tpm.asl517
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2Config.vfr246
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDriver.c455
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDxe.inf88
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDxe.uni17
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigDxeExtra.uni14
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigImpl.c1004
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigImpl.h198
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigNvData.h89
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPei.inf71
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPei.uni18
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPeiExtra.uni14
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigPeim.c154
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2ConfigStrings.uni132
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/Tcg2Internal.h26
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Config/TpmDetection.c100
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Dxe/MeasureBootPeCoff.c406
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.c2801
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.inf119
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Dxe/Tcg2Dxe.uni21
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Dxe/Tcg2DxeExtra.uni12
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.c1124
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.inf95
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Pei/Tcg2Pei.uni16
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Pei/Tcg2PeiExtra.uni14
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Smm/Tcg2MmDependencyDxe.c48
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Smm/Tcg2MmDependencyDxe.inf43
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.c375
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.h87
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.inf86
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.uni23
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Smm/Tcg2SmmExtra.uni14
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Smm/Tcg2StandaloneMm.c71
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Smm/Tcg2StandaloneMm.inf77
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/Tcg2Smm/Tcg2TraditionalMm.c82
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgConfigDxe/TcgConfig.vfr72
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDriver.c150
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDxe.inf77
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDxe.uni16
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigDxeExtra.uni14
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigImpl.c503
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigImpl.h188
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigNvData.h33
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgConfigDxe/TcgConfigStrings.uni35
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgDxe/TcgDxe.c1459
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgDxe/TcgDxe.inf81
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgDxe/TcgDxe.uni16
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgDxe/TcgDxeExtra.uni14
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgPei/TcgPei.c931
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgPei/TcgPei.inf89
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgPei/TcgPei.uni17
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgPei/TcgPeiExtra.uni14
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgSmm/TcgSmm.c463
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgSmm/TcgSmm.h99
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgSmm/TcgSmm.inf82
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgSmm/TcgSmm.uni22
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgSmm/TcgSmmExtra.uni14
-rw-r--r--src/VBox/Devices/EFI/Firmware/SecurityPkg/Tcg/TcgSmm/Tpm.asl351
89 files changed, 22623 insertions, 0 deletions
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.<BR>
+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.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __TCG_MOR_H__
+#define __TCG_MOR_H__
+
+#include <PiDxe.h>
+
+#include <Guid/MemoryOverwriteControl.h>
+
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+#include <Protocol/StorageSecurityCommand.h>
+#include <Protocol/BlockIo.h>
+
+//
+// Supported Security Protocols List Description.
+// Refer to ATA8-ACS Spec 7.57.6.2 Table 69 or SPC4 7.7.1.3 Table 511.
+//
+typedef struct {
+ UINT8 Reserved1[6];
+ UINT8 SupportedSecurityListLength[2];
+ UINT8 SupportedSecurityProtocol[1];
+} SUPPORTED_SECURITY_PROTOCOLS_PARAMETER_DATA;
+
+#define SECURITY_PROTOCOL_TCG 0x02
+#define SECURITY_PROTOCOL_IEEE1667 0xEE
+
+#define ROUNDUP512(x) (((x) % 512 == 0) ? (x) : ((x) / 512 + 1) * 512)
+
+#endif
+
diff --git a/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.<BR>
+# 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.<BR>
+//
+// 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.<BR>
+//
+// 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.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Guid/MemoryOverwriteControl.h>
+#include <IndustryStandard/MemoryOverwriteRequestControlLock.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include "TcgMorLock.h"
+
+typedef struct {
+ CHAR16 *VariableName;
+ EFI_GUID *VendorGuid;
+} VARIABLE_TYPE;
+
+VARIABLE_TYPE mMorVariableType[] = {
+ {MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME, &gEfiMemoryOverwriteControlDataGuid},
+ {MEMORY_OVERWRITE_REQUEST_CONTROL_LOCK_NAME, &gEfiMemoryOverwriteRequestControlLockGuid},
+};
+
+/**
+ Returns if this is MOR related variable.
+
+ @param VariableName the name of the vendor's variable, it's a Null-Terminated Unicode String
+ @param VendorGuid Unify identifier for vendor.
+
+ @retval TRUE The variable is MOR related.
+ @retval FALSE The variable is NOT MOR related.
+**/
+BOOLEAN
+IsAnyMorVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < sizeof(mMorVariableType)/sizeof(mMorVariableType[0]); Index++) {
+ if ((StrCmp (VariableName, mMorVariableType[Index].VariableName) == 0) &&
+ (CompareGuid (VendorGuid, mMorVariableType[Index].VendorGuid))) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/**
+ Returns if this is MOR lock variable.
+
+ @param VariableName the name of the vendor's variable, it's a Null-Terminated Unicode String
+ @param VendorGuid Unify identifier for vendor.
+
+ @retval TRUE The variable is MOR lock variable.
+ @retval FALSE The variable is NOT MOR lock variable.
+**/
+BOOLEAN
+IsMorLockVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid
+ )
+{
+ if ((StrCmp (VariableName, MEMORY_OVERWRITE_REQUEST_CONTROL_LOCK_NAME) == 0) &&
+ (CompareGuid (VendorGuid, &gEfiMemoryOverwriteRequestControlLockGuid))) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ This service is a checker handler for the UEFI Runtime Service SetVariable()
+
+ @param VariableName the name of the vendor's variable, as a
+ Null-Terminated Unicode String
+ @param VendorGuid Unify identifier for vendor.
+ @param Attributes Point to memory location to return the attributes of variable. If the point
+ is NULL, the parameter would be ignored.
+ @param DataSize The size in bytes of Data-Buffer.
+ @param Data Point to the content of the variable.
+
+ @retval EFI_SUCCESS The firmware has successfully stored the variable and its data as
+ defined by the Attributes.
+ @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied, or the
+ DataSize exceeds the maximum allowed.
+ @retval EFI_INVALID_PARAMETER VariableName is an empty Unicode string.
+ @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the variable and its data.
+ @retval EFI_DEVICE_ERROR The variable could not be saved due to a hardware failure.
+ @retval EFI_WRITE_PROTECTED The variable in question is read-only.
+ @retval EFI_WRITE_PROTECTED The variable in question cannot be deleted.
+ @retval EFI_SECURITY_VIOLATION The variable could not be written due to EFI_VARIABLE_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.<BR>
+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.<BR>
+//
+// 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.<BR>
+//
+// 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.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiSmm.h>
+#include <Library/SmmServicesTableLib.h>
+#include <Library/DebugLib.h>
+#include <Protocol/SmmVarCheck.h>
+#include <Protocol/SmmVariable.h>
+#include "TcgMorLock.h"
+
+EFI_SMM_VARIABLE_PROTOCOL *mSmmVariable;
+
+/**
+ This service is a wrapper for the UEFI Runtime Service GetVariable().
+
+ @param VariableName the name of the vendor's variable, it's a Null-Terminated Unicode String
+ @param VendorGuid Unify identifier for vendor.
+ @param Attributes Point to memory location to return the attributes of variable. If the point
+ is NULL, the parameter would be ignored.
+ @param DataSize As input, point to the maximum size of return Data-Buffer.
+ As output, point to the actual size of the returned Data-Buffer.
+ @param Data Point to return Data-Buffer.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_NOT_FOUND The variable was not found.
+ @retval EFI_BUFFER_TOO_SMALL The DataSize is too small for the result. DataSize has
+ been updated with the size needed to complete the request.
+ @retval EFI_INVALID_PARAMETER VariableName is NULL.
+ @retval EFI_INVALID_PARAMETER VendorGuid is NULL.
+ @retval EFI_INVALID_PARAMETER DataSize is NULL.
+ @retval EFI_INVALID_PARAMETER The DataSize is not too small and Data is NULL.
+ @retval EFI_DEVICE_ERROR The variable could not be retrieved due to a hardware error.
+ @retval EFI_SECURITY_VIOLATION The variable could not be retrieved due to an authentication failure.
+**/
+EFI_STATUS
+EFIAPI
+InternalGetVariable (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ OUT UINT32 *Attributes OPTIONAL,
+ IN OUT UINTN *DataSize,
+ OUT VOID *Data
+ )
+{
+ return mSmmVariable->SmmGetVariable (
+ VariableName,
+ VendorGuid,
+ Attributes,
+ DataSize,
+ Data
+ );
+}
+
+/**
+ This service is a wrapper for the UEFI Runtime Service SetVariable()
+
+ @param VariableName the name of the vendor's variable, as a
+ Null-Terminated Unicode String
+ @param VendorGuid Unify identifier for vendor.
+ @param Attributes Point to memory location to return the attributes of variable. If the point
+ is NULL, the parameter would be ignored.
+ @param DataSize The size in bytes of Data-Buffer.
+ @param Data Point to the content of the variable.
+
+ @retval EFI_SUCCESS The firmware has successfully stored the variable and its data as
+ defined by the Attributes.
+ @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied, or the
+ DataSize exceeds the maximum allowed.
+ @retval EFI_INVALID_PARAMETER VariableName is an empty Unicode string.
+ @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the variable and its data.
+ @retval EFI_DEVICE_ERROR The variable could not be saved due to a hardware failure.
+ @retval EFI_WRITE_PROTECTED The variable in question is read-only.
+ @retval EFI_WRITE_PROTECTED The variable in question cannot be deleted.
+ @retval EFI_SECURITY_VIOLATION The variable could not be written due to EFI_VARIABLE_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.<BR>
+# 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.<BR>
+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.<BR>
+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.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _OPAL_DRIVER_H_
+#define _OPAL_DRIVER_H_
+
+#include <PiDxe.h>
+
+#include <IndustryStandard/Pci.h>
+
+#include <Protocol/PciIo.h>
+#include <Protocol/SmmCommunication.h>
+#include <Protocol/BlockIo.h>
+#include <Protocol/LoadedImage.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/DevicePathToText.h>
+#include <Protocol/StorageSecurityCommand.h>
+
+#include <Guid/EventGroup.h>
+#include <Guid/S3StorageDeviceInitList.h>
+
+#include <Library/UefiLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseLib.h>
+#include <Library/PrintLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/HiiLib.h>
+#include <Library/UefiHiiServicesLib.h>
+#include <Library/PciLib.h>
+#include <Library/LockBoxLib.h>
+#include <Library/TcgStorageOpalLib.h>
+#include <Library/Tcg2PhysicalPresenceLib.h>
+
+#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.<BR>
+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 <ConfigResp>
+ format.
+ @param Progress A pointer to a string filled in with the offset of
+ the most recent '&' before the first failing
+ name/value pair (or the beginning of the string if
+ the failure is in the first name/value pair) or
+ the terminating NULL if all was successful.
+
+ @retval EFI_SUCCESS The Results is processed successfully.
+ @retval EFI_INVALID_PARAMETER Configuration is NULL.
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in this
+ driver.
+
+**/
+EFI_STATUS
+EFIAPI
+RouteConfig(
+ CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ CONST EFI_STRING Configuration,
+ EFI_STRING *Progress
+ )
+{
+ if (Configuration == NULL || Progress == NULL) {
+ return (EFI_INVALID_PARAMETER);
+ }
+
+ *Progress = Configuration;
+ if (!HiiIsConfigHdrMatch (Configuration, &gHiiSetupVariableGuid, OpalPasswordStorageName)) {
+ return EFI_NOT_FOUND;
+ }
+
+ *Progress = Configuration + StrLen (Configuration);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function allows a caller to extract the current configuration for one
+ or more named elements from the target driver.
+
+ @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param Request A null-terminated Unicode string in
+ <ConfigRequest> format.
+ @param Progress On return, points to a character in the Request
+ string. Points to the string's null terminator if
+ request was successful. Points to the most recent
+ '&' before the first failing name/value pair (or
+ the beginning of the string if the failure is in
+ the first name/value pair) if the request was not
+ successful.
+ @param Results A null-terminated Unicode string in
+ <ConfigAltResp> format which has all values filled
+ in for the names in the Request string. String to
+ be allocated by the called function.
+
+ @retval EFI_SUCCESS The Results is filled with the requested values.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results.
+ @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name.
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in this
+ driver.
+
+**/
+EFI_STATUS
+EFIAPI
+ExtractConfig(
+ CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ CONST EFI_STRING Request,
+ EFI_STRING *Progress,
+ EFI_STRING *Results
+ )
+{
+ EFI_STATUS Status;
+ 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 <ConfigHdr> 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 <ConfigResp> 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.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _OPAL_HII_H_
+#define _OPAL_HII_H_
+
+#include <Protocol/HiiConfigAccess.h>
+
+#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 <ConfigResp>
+ format.
+ @param Progress A pointer to a string filled in with the offset of
+ the most recent '&' before the first failing
+ name/value pair (or the beginning of the string if
+ the failure is in the first name/value pair) or
+ the terminating NULL if all was successful.
+
+ @retval EFI_SUCCESS The Results is processed successfully.
+ @retval EFI_INVALID_PARAMETER Configuration is NULL.
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in this
+ driver.
+
+**/
+EFI_STATUS
+EFIAPI
+RouteConfig(
+ CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ CONST EFI_STRING Configuration,
+ EFI_STRING *Progress
+ );
+
+/**
+ This function allows a caller to extract the current configuration for one
+ or more named elements from the target driver.
+
+ @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param Request A null-terminated Unicode string in
+ <ConfigRequest> format.
+ @param Progress On return, points to a character in the Request
+ string. Points to the string's null terminator if
+ request was successful. Points to the most recent
+ '&' before the first failing name/value pair (or
+ the beginning of the string if the failure is in
+ the first name/value pair) if the request was not
+ successful.
+ @param Results A null-terminated Unicode string in
+ <ConfigAltResp> format which has all values filled
+ in for the names in the Request string. String to
+ be allocated by the called function.
+
+ @retval EFI_SUCCESS The Results is filled with the requested values.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results.
+ @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name.
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in this
+ driver.
+
+**/
+EFI_STATUS
+EFIAPI
+ExtractConfig(
+ CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ CONST EFI_STRING Request,
+ EFI_STRING *Progress,
+ EFI_STRING *Results
+ );
+
+/**
+ This function processes the results of changes in configuration.
+
+ @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param Action Specifies the type of action taken by the browser.
+ @param QuestionId A unique value which is sent to the original
+ exporting driver so that it can identify the type
+ of data to expect.
+ @param Type The type of value for the question.
+ @param Value A pointer to the data being sent to the original
+ exporting driver.
+ @param ActionRequest On return, points to the action requested by the
+ callback function.
+
+ @retval EFI_SUCCESS The callback successfully handled the action.
+ @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the
+ variable and its data.
+ @retval EFI_DEVICE_ERROR The variable could not be saved.
+ @retval EFI_UNSUPPORTED The specified Action is not supported by the
+ callback.
+
+**/
+EFI_STATUS
+EFIAPI
+DriverCallback(
+ CONST EFI_HII_CONFIG_ACCESS_PROTOCOL* This,
+ EFI_BROWSER_ACTION Action,
+ EFI_QUESTION_ID QuestionId,
+ UINT8 Type,
+ EFI_IFR_TYPE_VALUE* Value,
+ EFI_BROWSER_ACTION_REQUEST* ActionRequest
+ );
+
+/**
+
+ Pass the current system state to the bios via the hii_G_Configuration.
+
+**/
+VOID
+OpalHiiSetBrowserData (
+ VOID
+ );
+
+/**
+
+ Populate the hii_g_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.<BR>
+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.<BR>
+//
+// 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.<BR>
+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.<BR>
+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.<BR>
+# 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.<BR>
+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.<BR>
+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.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _OPAL_PASSWORD_PEI_H_
+#define _OPAL_PASSWORD_PEI_H_
+
+#include <PiPei.h>
+
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/PciLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PeimEntryPoint.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/LockBoxLib.h>
+#include <Library/TcgStorageOpalLib.h>
+#include <Library/Tcg2PhysicalPresenceLib.h>
+#include <Library/PeiServicesTablePointerLib.h>
+
+#include <Protocol/StorageSecurityCommand.h>
+
+#include <Ppi/IoMmu.h>
+#include <Ppi/StorageSecurityCommand.h>
+
+#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.<BR>
+# 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.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiPei.h>
+#include <Ppi/LockPhysicalPresence.h>
+#include <Ppi/ReadOnlyVariable2.h>
+#include <Guid/PhysicalPresenceData.h>
+#include <Library/PcdLib.h>
+#include <Library/PeiServicesLib.h>
+
+/**
+ This interface returns whether TPM physical presence needs be locked or not.
+
+ @param[in] PeiServices The pointer to the PEI Services Table.
+
+ @retval TRUE The TPM physical presence should be locked.
+ @retval FALSE The TPM physical presence cannot be locked.
+
+**/
+BOOLEAN
+EFIAPI
+LockTpmPhysicalPresence (
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ );
+
+//
+// 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.<BR>
+# 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.<BR>
+//
+// 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.<BR>
+//
+// 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.<BR>
+Copyright (c) Microsoft Corporation.
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+
+#include <IndustryStandard/Tpm2Acpi.h>
+
+#include <Guid/TpmInstance.h>
+#include <Guid/TpmNvsMm.h>
+#include <Guid/PiSmmCommunicationRegionTable.h>
+
+#include <Protocol/AcpiTable.h>
+#include <Protocol/Tcg2Protocol.h>
+#include <Protocol/MmCommunication.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DxeServicesLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PrintLib.h>
+#include <Library/TpmMeasurementLib.h>
+#include <Library/Tpm2DeviceLib.h>
+#include <Library/Tpm2CommandLib.h>
+#include <Library/UefiLib.h>
+#include <Library/MmUnblockMemoryLib.h>
+
+//
+// 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 ByteData> |
+ // <PkgLeadByte ByteData ByteData> |
+ // <PkgLeadByte ByteData ByteData ByteData>
+ //
+ // PkgLeadByte := <bit 7-6: ByteData count that follows (0-3)>
+ // <bit 5-4: Only used if PkgLength <= 63 >
+ // <bit 3-0: Least significant package length nybble>
+ //
+ //==============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.<BR>
+# Copyright (c) Microsoft Corporation.<BR>
+# 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.<BR>
+(c)Copyright 2016 HP Development Company, L.P.<BR>
+Copyright (c) Microsoft Corporation.<BR>
+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.<BR>
+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.<BR>
+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.<BR>
+# 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.<BR>
+//
+// 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.<BR>
+//
+// 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.<BR>
+(C) Copyright 2018 Hewlett Packard Enterprise Development LP<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Tcg2ConfigImpl.h"
+#include <Library/PcdLib.h>
+#include <Library/Tpm2CommandLib.h>
+#include <Library/Tpm2DeviceLib.h>
+#include <Library/IoLib.h>
+
+#include <Guid/TpmInstance.h>
+
+#include <IndustryStandard/TpmPtp.h>
+
+#define EFI_TCG2_EVENT_LOG_FORMAT_ALL (EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2 | EFI_TCG2_EVENT_LOG_FORMAT_TCG_2)
+
+TPM_INSTANCE_ID mTpmInstanceId[TPM_DEVICE_MAX + 1] = TPM_INSTANCE_ID_LIST;
+
+TCG2_CONFIG_PRIVATE_DATA *mTcg2ConfigPrivateDate;
+TCG2_CONFIG_PRIVATE_DATA mTcg2ConfigPrivateDateTemplate = {
+ TCG2_CONFIG_PRIVATE_DATA_SIGNATURE,
+ {
+ Tcg2ExtractConfig,
+ Tcg2RouteConfig,
+ Tcg2Callback
+ }
+};
+
+HII_VENDOR_DEVICE_PATH mTcg2HiiVendorDevicePath = {
+ {
+ {
+ HARDWARE_DEVICE_PATH,
+ HW_VENDOR_DP,
+ {
+ (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
+ (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
+ }
+ },
+ TCG2_CONFIG_FORM_SET_GUID
+ },
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ (UINT8) (END_DEVICE_PATH_LENGTH),
+ (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
+ }
+ }
+};
+
+UINT8 mCurrentPpRequest;
+
+/**
+ Return 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
+ <ConfigRequest> format.
+ @param[out] Progress On return, points to a character in the Request
+ string. Points to the string's null terminator if
+ request was successful. Points to the most recent
+ '&' before the first failing name/value pair (or
+ the beginning of the string if the failure is in
+ the first name/value pair) if the request was not
+ successful.
+ @param[out] Results A null-terminated Unicode string in
+ <ConfigAltResp> format which has all values filled
+ in for the names in the Request string. String to
+ be allocated by the called function.
+
+ @retval EFI_SUCCESS The Results is filled with the requested values.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results.
+ @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name.
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in this
+ driver.
+
+**/
+EFI_STATUS
+EFIAPI
+Tcg2ExtractConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Request,
+ OUT EFI_STRING *Progress,
+ OUT EFI_STRING *Results
+ )
+{
+ if (Progress == NULL || Results == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *Progress = Request;
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Save TPM request to variable space.
+
+ @param[in] PpRequest Physical Presence request command.
+
+ @retval EFI_SUCCESS The operation is finished successfully.
+ @retval Others Other errors as indicated.
+
+**/
+EFI_STATUS
+SaveTcg2PpRequest (
+ IN UINT8 PpRequest
+ )
+{
+ UINT32 ReturnCode;
+ EFI_STATUS Status;
+
+ ReturnCode = Tcg2PhysicalPresenceLibSubmitRequestToPreOSFunction (PpRequest, 0);
+ if (ReturnCode == TCG_PP_SUBMIT_REQUEST_TO_PREOS_SUCCESS) {
+ mCurrentPpRequest = PpRequest;
+ Status = EFI_SUCCESS;
+ } else if (ReturnCode == TCG_PP_SUBMIT_REQUEST_TO_PREOS_GENERAL_FAILURE) {
+ Status = EFI_OUT_OF_RESOURCES;
+ } else if (ReturnCode == TCG_PP_SUBMIT_REQUEST_TO_PREOS_NOT_IMPLEMENTED) {
+ Status = EFI_UNSUPPORTED;
+ } else {
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ return Status;
+}
+
+/**
+ Save TPM request to variable space.
+
+ @param[in] PpRequestParameter Physical Presence request parameter.
+
+ @retval EFI_SUCCESS The operation is finished successfully.
+ @retval Others Other errors as indicated.
+
+**/
+EFI_STATUS
+SaveTcg2PpRequestParameter (
+ IN UINT32 PpRequestParameter
+ )
+{
+ UINT32 ReturnCode;
+ EFI_STATUS Status;
+
+ ReturnCode = Tcg2PhysicalPresenceLibSubmitRequestToPreOSFunction (mCurrentPpRequest, PpRequestParameter);
+ if (ReturnCode == TCG_PP_SUBMIT_REQUEST_TO_PREOS_SUCCESS) {
+ Status = EFI_SUCCESS;
+ } else if (ReturnCode == TCG_PP_SUBMIT_REQUEST_TO_PREOS_GENERAL_FAILURE) {
+ Status = EFI_OUT_OF_RESOURCES;
+ } else if (ReturnCode == TCG_PP_SUBMIT_REQUEST_TO_PREOS_NOT_IMPLEMENTED) {
+ Status = EFI_UNSUPPORTED;
+ } else {
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ return Status;
+}
+
+/**
+ Save Tcg2 PCR Banks request request to variable space.
+
+ @param[in] PCRBankIndex PCR Bank Index.
+ @param[in] Enable Enable or disable this PCR Bank.
+
+ @retval EFI_SUCCESS The operation is finished successfully.
+ @retval Others Other errors as indicated.
+
+**/
+EFI_STATUS
+SaveTcg2PCRBanksRequest (
+ IN UINTN PCRBankIndex,
+ IN BOOLEAN Enable
+ )
+{
+ UINT32 ReturnCode;
+ EFI_STATUS Status;
+
+ if (Enable) {
+ mTcg2ConfigPrivateDate->PCRBanksDesired |= (0x1 << PCRBankIndex);
+ } else {
+ mTcg2ConfigPrivateDate->PCRBanksDesired &= ~(0x1 << PCRBankIndex);
+ }
+
+ ReturnCode = Tcg2PhysicalPresenceLibSubmitRequestToPreOSFunction (TCG2_PHYSICAL_PRESENCE_SET_PCR_BANKS, mTcg2ConfigPrivateDate->PCRBanksDesired);
+ if (ReturnCode == TCG_PP_SUBMIT_REQUEST_TO_PREOS_SUCCESS) {
+ Status = EFI_SUCCESS;
+ } else if (ReturnCode == TCG_PP_SUBMIT_REQUEST_TO_PREOS_GENERAL_FAILURE) {
+ Status = EFI_OUT_OF_RESOURCES;
+ } else if (ReturnCode == TCG_PP_SUBMIT_REQUEST_TO_PREOS_NOT_IMPLEMENTED) {
+ Status = EFI_UNSUPPORTED;
+ } else {
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ return Status;
+}
+
+/**
+ This function processes the results of changes in configuration.
+
+ @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param[in] Configuration A null-terminated Unicode string in <ConfigResp>
+ format.
+ @param[out] Progress A pointer to a string filled in with the offset of
+ the most recent '&' before the first failing
+ name/value pair (or the beginning of the string if
+ the failure is in the first name/value pair) or
+ the terminating NULL if all was successful.
+
+ @retval EFI_SUCCESS The Results is processed successfully.
+ @retval EFI_INVALID_PARAMETER Configuration is NULL.
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in this
+ driver.
+
+**/
+EFI_STATUS
+EFIAPI
+Tcg2RouteConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Configuration,
+ OUT EFI_STRING *Progress
+ )
+{
+ if (Configuration == NULL || Progress == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *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.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __TCG2_CONFIG_IMPL_H__
+#define __TCG2_CONFIG_IMPL_H__
+
+#include <Uefi.h>
+
+#include <IndustryStandard/Tpm2Acpi.h>
+
+#include <Protocol/HiiConfigAccess.h>
+#include <Protocol/HiiConfigRouting.h>
+#include <Protocol/Tcg2Protocol.h>
+#include <Protocol/VariableLock.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiHiiServicesLib.h>
+#include <Library/UefiLib.h>
+#include <Library/HiiLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PrintLib.h>
+#include <Library/Tcg2PhysicalPresenceLib.h>
+
+#include <Guid/MdeModuleHii.h>
+
+#include "Tcg2ConfigNvData.h"
+#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
+ <ConfigRequest> format.
+ @param[out] Progress On return, points to a character in the Request
+ string. Points to the string's null terminator if
+ request was successful. Points to the most recent
+ '&' before the first failing name/value pair (or
+ the beginning of the string if the failure is in
+ the first name/value pair) if the request was not
+ successful.
+ @param[out] Results A null-terminated Unicode string in
+ <ConfigAltResp> format which has all values filled
+ in for the names in the Request string. String to
+ be allocated by the called function.
+
+ @retval EFI_SUCCESS The Results is filled with the requested values.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results.
+ @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name.
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in this
+ driver.
+
+**/
+EFI_STATUS
+EFIAPI
+Tcg2ExtractConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Request,
+ OUT EFI_STRING *Progress,
+ OUT EFI_STRING *Results
+ );
+
+/**
+ This function processes the results of changes in configuration.
+
+ @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param[in] Configuration A null-terminated Unicode string in <ConfigResp>
+ format.
+ @param[out] Progress A pointer to a string filled in with the offset of
+ the most recent '&' before the first failing
+ name/value pair (or the beginning of the string if
+ the failure is in the first name/value pair) or
+ the terminating NULL if all was successful.
+
+ @retval EFI_SUCCESS The Results is processed successfully.
+ @retval EFI_INVALID_PARAMETER Configuration is NULL.
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in this
+ driver.
+
+**/
+EFI_STATUS
+EFIAPI
+Tcg2RouteConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Configuration,
+ OUT EFI_STRING *Progress
+ );
+
+/**
+ This function processes the results of changes in configuration.
+
+ @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param[in] Action Specifies the type of action taken by the browser.
+ @param[in] QuestionId A unique value which is sent to the original
+ exporting driver so that it can identify the type
+ of data to expect.
+ @param[in] Type The type of value for the question.
+ @param[in] Value A pointer to the data being sent to the original
+ exporting driver.
+ @param[out] ActionRequest On return, points to the action requested by the
+ callback function.
+
+ @retval EFI_SUCCESS The callback successfully handled the action.
+ @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the
+ variable and its data.
+ @retval EFI_DEVICE_ERROR The variable could not be saved.
+ @retval EFI_UNSUPPORTED The specified Action is not supported by the
+ callback.
+
+**/
+EFI_STATUS
+EFIAPI
+Tcg2Callback (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN EFI_BROWSER_ACTION Action,
+ IN EFI_QUESTION_ID QuestionId,
+ IN UINT8 Type,
+ IN EFI_IFR_TYPE_VALUE *Value,
+ OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
+ );
+
+#endif
diff --git a/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.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __TCG2_CONFIG_NV_DATA_H__
+#define __TCG2_CONFIG_NV_DATA_H__
+
+#include <Guid/HiiPlatformSetupFormset.h>
+#include <Guid/Tcg2ConfigHii.h>
+#include <IndustryStandard/TcgPhysicalPresence.h>
+
+#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.<BR>
+# 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.<BR>
+//
+// 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.<BR>
+//
+// 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.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include <PiPei.h>
+
+#include <Guid/TpmInstance.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/PcdLib.h>
+
+#include <Ppi/ReadOnlyVariable2.h>
+#include <Ppi/TpmInitialized.h>
+#include <Protocol/Tcg2Protocol.h>
+
+#include "Tcg2ConfigNvData.h"
+#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.<BR>
+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 <Enter> to select TCG2 Setup options."
+
+#string STR_TCG2_DEVICE_STATE_PROMPT #language en-US "Current TPM Device"
+#string STR_TCG2_DEVICE_STATE_HELP #language en-US "Current TPM Device: Disable, TPM1.2, or TPM2.0"
+#string STR_TCG2_DEVICE_STATE_CONTENT #language en-US ""
+
+#string STR_TCG2_DEVICE_PROMPT #language en-US "Attempt TPM Device"
+#string STR_TCG2_DEVICE_HELP #language en-US "Attempt TPM Device: TPM1.2, or TPM2.0"
+#string STR_TCG2_DEVICE_CONTENT #language en-US ""
+
+#string STR_TCG2_PPI_VERSION_STATE_PROMPT #language en-US "Current PPI Version"
+#string STR_TCG2_PPI_VERSION_STATE_HELP #language en-US "Current PPI Version: 1.2 or 1.3"
+#string STR_TCG2_PPI_VERSION_STATE_CONTENT #language en-US ""
+
+#string STR_TCG2_PPI_VERSION_PROMPT #language en-US "Attempt PPI Version"
+#string STR_TCG2_PPI_VERSION_HELP #language en-US "Attempt PPI Version: 1.2 or 1.3\n"
+ "PcdTcgPhysicalPresenceInterfaceVer needs to be DynamicHii type and map to this option\n"
+ "Otherwise the version configuring by this setup option will not work"
+
+#string STR_TPM2_ACPI_HID_PROMPT #language en-US "HID from TPM2 ACPI Table"
+#string STR_TPM2_ACPI_HID_HELP #language en-US "HID from TPM2 ACPI Table: ManufacturerID + FirmwareVersion_1"
+#string STR_TPM2_ACPI_HID_CONTENT #language en-US ""
+
+#string STR_TPM2_ACPI_REVISION_STATE_PROMPT #language en-US "Current Rev of TPM2 ACPI Table"
+#string STR_TPM2_ACPI_REVISION_STATE_HELP #language en-US "Current Rev of TPM2 ACPI Table: Rev 3 or Rev 4"
+#string STR_TPM2_ACPI_REVISION_STATE_CONTENT #language en-US ""
+
+#string STR_TPM2_ACPI_REVISION_PROMPT #language en-US "Attempt Rev of TPM2 ACPI Table"
+#string STR_TPM2_ACPI_REVISION_HELP #language en-US "Rev 3 or Rev 4 (Rev 4 is defined in TCG ACPI Spec 00.37)"
+ "PcdTpm2AcpiTableRev needs to be DynamicHii type and map to this option\n"
+ "Otherwise the version configuring by this setup option will not work"
+
+#string STR_TCG2_DEVICE_INTERFACE_STATE_PROMPT #language en-US "Current TPM Device Interface"
+#string STR_TCG2_DEVICE_INTERFACE_STATE_HELP #language en-US "Current TPM Device Interface: TIS, PTP FIFO, PTP CRB"
+#string STR_TCG2_DEVICE_INTERFACE_STATE_CONTENT #language en-US ""
+
+#string STR_TCG2_DEVICE_INTERFACE_CAPABILITY_PROMPT #language en-US "PTP TPM Device Interface Capability"
+#string STR_TCG2_DEVICE_INTERFACE_CAPABILITY_HELP #language en-US "PTP TPM Device Interface Capability: PTP FIFO, PTP CRB"
+#string STR_TCG2_DEVICE_INTERFACE_CAPABILITY_CONTENT #language en-US ""
+
+#string STR_TCG2_DEVICE_INTERFACE_PROMPT #language en-US "Attempt PTP TPM Device Interface"
+#string STR_TCG2_DEVICE_INTERFACE_HELP #language en-US "Attempt PTP TPM Device Interface: PTP FIFO, PTP CRB"
+#string STR_TCG2_DEVICE_INTERFACE_CONTENT #language en-US ""
+
+#string STR_TCG2_DEVICE_INTERFACE_TIS #language en-US "TIS"
+#string STR_TCG2_DEVICE_INTERFACE_PTP_FIFO #language en-US "PTP FIFO"
+#string STR_TCG2_DEVICE_INTERFACE_PTP_CRB #language en-US "PTP CRB"
+
+#string STR_TCG2_PP_OPERATION #language en-US "TPM2 Physical Presence Operation"
+
+#string STR_TCG2_OPERATION #language en-US "TPM2 Operation"
+#string STR_TCG2_OPERATION_HELP #language en-US "Select one of the supported operation to change TPM2 state."
+
+#string STR_TCG2_NO_ACTION #language en-US "No Action"
+#string STR_TCG2_ENABLE #language en-US "TPM2 HierarchyControl (TPM_RH_OWNER YES, TPM_RH_ENDORSEMENT YES)"
+#string STR_TCG2_DISABLE #language en-US "TPM2 HierarchyControl (TPM_RH_OWNER NO, TPM_RH_ENDORSEMENT NO)"
+#string STR_TCG2_CLEAR #language en-US "TPM2 ClearControl(NO) + Clear"
+#string STR_TCG2_SET_PCD_BANKS #language en-US "TPM2 PCR_Allocate(Algorithm IDs)"
+#string STR_TCG2_CHANGE_EPS #language en-US "TPM2 ChangeEPS"
+#string STR_TCG2_LOG_ALL_DIGESTS #language en-US "TCG2 LogAllDigests"
+#string STR_TCG2_DISABLE_ENDORSEMENT_ENABLE_STORAGE_HIERARCHY #language en-US "TPM2 HierarchyControl (TPM_RH_OWNER NO, TPM_RH_ENDORSEMENT YES)"
+
+#string STR_TCG2_OPERATION_PARAMETER #language en-US "TPM2 Operation Parameter"
+#string STR_TCG2_OPERATION_PARAMETER_HELP #language en-US "Additional TPM2 Operation Parameter need be sent with Operation Code (required for SetPCRBanks)"
+
+#string STR_TCG2_TPM_1_2 #language en-US "TPM 1.2"
+#string STR_TCG2_TPM_2_0_DTPM #language en-US "TPM 2.0"
+
+#string STR_TPM2_ACPI_REVISION_3 #language en-US "Rev 3"
+#string STR_TPM2_ACPI_REVISION_4 #language en-US "Rev 4"
+
+#string STR_TCG2_PPI_VERSION_1_2 #language en-US "1.2"
+#string STR_TCG2_PPI_VERSION_1_3 #language en-US "1.3"
+
+#string STR_TPM2_ACTIVE_HASH_ALGO #language en-US "TPM2 Active PCR Hash Algorithm"
+#string STR_TPM2_ACTIVE_HASH_ALGO_HELP #language en-US "TPM2 Active PCR Hash Algorithm: SHA1, SHA256, SHA384, SHA512, SM3_256"
+#string STR_TPM2_ACTIVE_HASH_ALGO_CONTENT #language en-US ""
+
+#string STR_TPM2_SUPPORTED_HASH_ALGO #language en-US "TPM2 Hardware Supported Hash Algorithm"
+#string STR_TPM2_SUPPORTED_HASH_ALGO_HELP #language en-US "TPM2 Hardware Supported Hash Algorithm: SHA1, SHA256, SHA384, SHA512, SM3_256"
+#string STR_TPM2_SUPPORTED_HASH_ALGO_CONTENT #language en-US ""
+
+#string STR_BIOS_HASH_ALGO #language en-US "BIOS Supported Hash Algorithm"
+#string STR_BIOS_HASH_ALGO_HELP #language en-US "BIOS Supported Hash Algorithm: SHA1, SHA256, SHA384, SHA512, SM3_256"
+#string STR_BIOS_HASH_ALGO_CONTENT #language en-US ""
+
+#string STR_TCG2_CONFIGURATION #language en-US "TCG2 Protocol Configuration"
+
+#string STR_TCG2_PROTOCOL_VERSION #language en-US "TCG2 Protocol Version"
+#string STR_TCG2_PROTOCOL_VERSION_HELP #language en-US "TCG2 Protocol Version: 1.0 or 1.1"
+#string STR_TCG2_PROTOCOL_VERSION_1_0 #language en-US "1.0"
+#string STR_TCG2_PROTOCOL_VERSION_1_1 #language en-US "1.1"
+
+#string STR_TCG2_SUPPORTED_EVENT_LOG_FORMAT #language en-US "Supported Event Log Format"
+#string STR_TCG2_SUPPORTED_EVENT_LOG_FORMAT_HELP #language en-US "TCG2 Supported Event Log Format: TCG_1_2, TCG_2"
+#string STR_TCG2_SUPPORTED_EVENT_LOG_FORMAT_CONTENT #language en-US ""
+
+#string STR_TCG2_HASH_ALGO_BITMAP #language en-US "Hash Algorithm Bitmap"
+#string STR_TCG2_HASH_ALGO_BITMAP_HELP #language en-US "TCG2 Supported Hash Algorithm Bitmap: SHA1, SHA256, SHA384, SHA512"
+#string STR_TCG2_HASH_ALGO_BITMAP_CONTENT #language en-US ""
+
+#string STR_TCG2_NUMBER_OF_PCR_BANKS #language en-US "Number of PCR Banks"
+#string STR_TCG2_NUMBER_OF_PCR_BANKS_HELP #language en-US "TCG2 Number of PCR Banks"
+#string STR_TCG2_NUMBER_OF_PCR_BANKS_CONTENT #language en-US ""
+
+#string STR_TCG2_ACTIVE_PCR_BANKS #language en-US "Active PCR Banks"
+#string STR_TCG2_ACTIVE_PCR_BANKS_HELP #language en-US "TCG2 Active PCR Banks: SHA1, SHA256, SHA384, SHA512"
+#string STR_TCG2_ACTIVE_PCR_BANKS_CONTENT #language en-US ""
+
+#string STR_TCG2_PCR_BANK_SHA1 #language en-US " PCR Bank: SHA1"
+#string STR_TCG2_PCR_BANK_SHA1_HELP #language en-US "TCG2 Request PCR Bank: SHA1"
+#string STR_TCG2_PCR_BANK_SHA256 #language en-US " PCR Bank: SHA256"
+#string STR_TCG2_PCR_BANK_SHA256_HELP #language en-US "TCG2 Request PCR Bank: SHA256"
+#string STR_TCG2_PCR_BANK_SHA384 #language en-US " PCR Bank: SHA384"
+#string STR_TCG2_PCR_BANK_SHA384_HELP #language en-US "TCG2 Request PCR Bank: SHA384"
+#string STR_TCG2_PCR_BANK_SHA512 #language en-US " PCR Bank: SHA512"
+#string STR_TCG2_PCR_BANK_SHA512_HELP #language en-US "TCG2 Request PCR Bank: SHA512"
+#string STR_TCG2_PCR_BANK_SM3_256 #language en-US " PCR Bank: SM3_256"
+#string STR_TCG2_PCR_BANK_SM3_256_HELP #language en-US "TCG2 Request PCR Bank: SM3_256"
+
+#string STR_NULL #language en-US ""
diff --git a/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.<BR>
+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.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include <PiPei.h>
+#include <Ppi/ReadOnlyVariable2.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/PcdLib.h>
+#include <Library/Tpm12DeviceLib.h>
+#include <Library/Tpm12CommandLib.h>
+#include <IndustryStandard/Tpm12.h>
+
+#include "Tcg2ConfigNvData.h"
+#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.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/PeCoffLib.h>
+#include <Library/Tpm2CommandLib.h>
+#include <Library/HashLib.h>
+
+UINTN mTcg2DxeImageSize = 0;
+
+/**
+ Reads contents of a PE/COFF image in memory buffer.
+
+ Caution: This function may receive untrusted input.
+ PE/COFF image is external input, so this function will make sure the PE/COFF image content
+ read is within the image buffer.
+
+ @param FileHandle Pointer to the file handle to read the PE/COFF image.
+ @param FileOffset Offset into the PE/COFF image to begin the read operation.
+ @param ReadSize On input, the size in bytes of the requested read operation.
+ On output, the number of bytes actually read.
+ @param Buffer Output buffer that contains the data read from the PE/COFF image.
+
+ @retval EFI_SUCCESS The specified portion of the PE/COFF image was read and the size
+**/
+EFI_STATUS
+EFIAPI
+Tcg2DxeImageRead (
+ IN VOID *FileHandle,
+ IN UINTN FileOffset,
+ IN OUT UINTN *ReadSize,
+ OUT VOID *Buffer
+ )
+{
+ UINTN EndPosition;
+
+ if (FileHandle == NULL || ReadSize == NULL || Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (MAX_ADDRESS - FileOffset < *ReadSize) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ EndPosition = FileOffset + *ReadSize;
+ if (EndPosition > mTcg2DxeImageSize) {
+ *ReadSize = (UINT32)(mTcg2DxeImageSize - FileOffset);
+ }
+
+ if (FileOffset >= mTcg2DxeImageSize) {
+ *ReadSize = 0;
+ }
+
+ CopyMem (Buffer, (UINT8 *)((UINTN) FileHandle + FileOffset), *ReadSize);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Measure PE image into TPM log based on the authenticode image hashing in
+ PE/COFF Specification 8.0 Appendix A.
+
+ Caution: This function may receive untrusted input.
+ PE/COFF image is external input, so this function will validate its data structure
+ within this image buffer before use.
+
+ Notes: PE/COFF image is checked by BasePeCoffLib PeCoffLoaderGetImageInfo().
+
+ @param[in] PCRIndex TPM PCR index
+ @param[in] ImageAddress Start address of image buffer.
+ @param[in] ImageSize Image size
+ @param[out] DigestList 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.<BR>
+(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <IndustryStandard/Acpi.h>
+#include <IndustryStandard/PeImage.h>
+#include <IndustryStandard/TcpaAcpi.h>
+
+#include <Guid/GlobalVariable.h>
+#include <Guid/HobList.h>
+#include <Guid/TcgEventHob.h>
+#include <Guid/EventGroup.h>
+#include <Guid/EventExitBootServiceFailed.h>
+#include <Guid/ImageAuthentication.h>
+#include <Guid/TpmInstance.h>
+
+#include <Protocol/DevicePath.h>
+#include <Protocol/MpService.h>
+#include <Protocol/VariableWrite.h>
+#include <Protocol/Tcg2Protocol.h>
+#include <Protocol/TrEEProtocol.h>
+#include <Protocol/ResetNotification.h>
+
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/HobLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/BaseLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PrintLib.h>
+#include <Library/Tpm2CommandLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiLib.h>
+#include <Library/Tpm2DeviceLib.h>
+#include <Library/HashLib.h>
+#include <Library/PerformanceLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/Tcg2PhysicalPresenceLib.h>
+
+#define PERF_ID_TCG2_DXE 0x3120
+
+typedef struct {
+ CHAR16 *VariableName;
+ EFI_GUID *VendorGuid;
+} VARIABLE_TYPE;
+
+#define TCG2_DEFAULT_MAX_COMMAND_SIZE 0x1000
+#define TCG2_DEFAULT_MAX_RESPONSE_SIZE 0x1000
+
+typedef struct {
+ EFI_GUID *EventGuid;
+ EFI_TCG2_EVENT_LOG_FORMAT LogFormat;
+} TCG2_EVENT_INFO_STRUCT;
+
+TCG2_EVENT_INFO_STRUCT mTcg2EventInfo[] = {
+ {&gTcgEventEntryHobGuid, EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2},
+ {&gTcgEvent2EntryHobGuid, EFI_TCG2_EVENT_LOG_FORMAT_TCG_2},
+};
+
+#define TCG_EVENT_LOG_AREA_COUNT_MAX 2
+
+typedef struct {
+ EFI_TCG2_EVENT_LOG_FORMAT EventLogFormat;
+ EFI_PHYSICAL_ADDRESS Lasa;
+ UINT64 Laml;
+ UINTN EventLogSize;
+ UINT8 *LastEvent;
+ BOOLEAN EventLogStarted;
+ BOOLEAN EventLogTruncated;
+ 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.<BR>
+# 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.<BR>
+//
+// 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.<BR>
+//
+// 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.<BR>
+Copyright (c) 2017, Microsoft Corporation. All rights reserved. <BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiPei.h>
+
+#include <IndustryStandard/UefiTcgPlatform.h>
+#include <Ppi/FirmwareVolumeInfo.h>
+#include <Ppi/FirmwareVolumeInfo2.h>
+#include <Ppi/TpmInitialized.h>
+#include <Ppi/FirmwareVolume.h>
+#include <Ppi/EndOfPeiPhase.h>
+#include <Ppi/FirmwareVolumeInfoMeasurementExcluded.h>
+#include <Ppi/FirmwareVolumeInfoPrehashedFV.h>
+#include <Ppi/Tcg.h>
+
+#include <Guid/TcgEventHob.h>
+#include <Guid/MeasuredFvHob.h>
+#include <Guid/TpmInstance.h>
+#include <Guid/MigratedFvInfo.h>
+
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/PeimEntryPoint.h>
+#include <Library/Tpm2CommandLib.h>
+#include <Library/Tpm2DeviceLib.h>
+#include <Library/HashLib.h>
+#include <Library/HobLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PeiServicesTablePointerLib.h>
+#include <Protocol/Tcg2Protocol.h>
+#include <Library/PerformanceLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/ResetSystemLib.h>
+#include <Library/PrintLib.h>
+
+#define PERF_ID_TCG2_PEI 0x3080
+
+typedef struct {
+ EFI_GUID *EventGuid;
+ EFI_TCG2_EVENT_LOG_FORMAT LogFormat;
+} TCG2_EVENT_INFO_STRUCT;
+
+TCG2_EVENT_INFO_STRUCT mTcg2EventInfo[] = {
+ {&gTcgEventEntryHobGuid, EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2},
+ {&gTcgEvent2EntryHobGuid, EFI_TCG2_EVENT_LOG_FORMAT_TCG_2},
+};
+
+BOOLEAN mImageInMemory = FALSE;
+EFI_PEI_FILE_HANDLE mFileHandle;
+
+EFI_PEI_PPI_DESCRIPTOR mTpmInitializedPpiList = {
+ EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
+ &gPeiTpmInitializedPpiGuid,
+ NULL
+};
+
+EFI_PEI_PPI_DESCRIPTOR mTpmInitializationDonePpiList = {
+ EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
+ &gPeiTpmInitializationDonePpiGuid,
+ NULL
+};
+
+/**
+ 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.<BR>
+# Copyright (c) 2017, Microsoft Corporation. All rights reserved. <BR>
+# 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.<BR>
+//
+// 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.<BR>
+//
+// 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 <PiDxe.h>
+
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+/**
+ 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.<BR>
+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.<BR>
+Copyright (c) Microsoft Corporation.
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __TCG2_SMM_H__
+#define __TCG2_SMM_H__
+
+#include <PiMm.h>
+
+#include <Guid/MemoryOverwriteControl.h>
+#include <Guid/TpmInstance.h>
+#include <Guid/TpmNvsMm.h>
+
+#include <Protocol/MmReadyToLock.h>
+#include <Protocol/SmmSwDispatch2.h>
+#include <Protocol/AcpiTable.h>
+#include <Protocol/SmmVariable.h>
+#include <Protocol/Tcg2Protocol.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MmServicesTableLib.h>
+#include <Library/Tpm2CommandLib.h>
+#include <Library/Tcg2PhysicalPresenceLib.h>
+#include <Library/IoLib.h>
+#include <Library/PcdLib.h>
+#include <Library/Tpm2DeviceLib.h>
+
+#include <IndustryStandard/TpmPtp.h>
+
+//
+// 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.<BR>
+# Copyright (c) Microsoft Corporation.<BR>
+# 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.<BR>
+//
+// 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.<BR>
+//
+// 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.<BR>
+Copyright (c) Microsoft Corporation.
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Tcg2Smm.h"
+#include <Library/StandaloneMmMemLib.h>
+
+/**
+ 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.<BR>
+# Copyright (c) Microsoft Corporation.<BR>
+# 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.<BR>
+Copyright (c) Microsoft Corporation.
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "Tcg2Smm.h"
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/SmmMemLib.h>
+
+/**
+ 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.<BR>
+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.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "TcgConfigImpl.h"
+#include <Guid/TpmInstance.h>
+
+/**
+ The entry point for Tcg configuration driver.
+
+ @param[in] ImageHandle The image handle of the driver.
+ @param[in] SystemTable The system table.
+
+ @retval EFI_ALREADY_STARTED The driver already exists in system.
+ @retval EFI_OUT_OF_RESOURCES Fail to execute entry point due to lack of resources.
+ @retval EFI_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.<BR>
+# 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.<BR>
+//
+// 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.<BR>
+//
+// 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.<BR>
+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
+ <ConfigRequest> format.
+ @param[out] Progress On return, points to a character in the Request
+ string. Points to the string's null terminator if
+ request was successful. Points to the most recent
+ '&' before the first failing name/value pair (or
+ the beginning of the string if the failure is in
+ the first name/value pair) if the request was not
+ successful.
+ @param[out] Results A null-terminated Unicode string in
+ <ConfigAltResp> format which has all values filled
+ in for the names in the Request string. String to
+ be allocated by the called function.
+
+ @retval EFI_SUCCESS The Results is filled with the requested values.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results.
+ @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name.
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in this
+ driver.
+
+**/
+EFI_STATUS
+EFIAPI
+TcgExtractConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Request,
+ OUT EFI_STRING *Progress,
+ OUT EFI_STRING *Results
+ )
+{
+ EFI_STATUS Status;
+ TCG_CONFIG_PRIVATE_DATA *PrivateData;
+ EFI_STRING ConfigRequestHdr;
+ EFI_STRING ConfigRequest;
+ BOOLEAN AllocatedRequest;
+ UINTN Size;
+ BOOLEAN TpmEnable;
+ BOOLEAN TpmActivate;
+
+ if (Progress == NULL || Results == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *Progress = Request;
+ if ((Request != NULL) && !HiiIsConfigHdrMatch (Request, &gTcgConfigFormSetGuid, mTcgStorageName)) {
+ return EFI_NOT_FOUND;
+ }
+
+ ConfigRequestHdr = NULL;
+ ConfigRequest = NULL;
+ AllocatedRequest = FALSE;
+ Size = 0;
+
+ PrivateData = TCG_CONFIG_PRIVATE_DATA_FROM_THIS (This);
+
+ //
+ // Convert buffer data to <ConfigResp> by helper function BlockToConfig()
+ //
+ PrivateData->Configuration->TpmOperation = PHYSICAL_PRESENCE_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 <ConfigHdr> template
+ // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator
+ //
+ ConfigRequestHdr = HiiConstructConfigHdr (&gTcgConfigFormSetGuid, mTcgStorageName, PrivateData->DriverHandle);
+ Size = (StrLen (ConfigRequestHdr) + 32 + 1) * sizeof (CHAR16);
+ ConfigRequest = AllocateZeroPool (Size);
+ ASSERT (ConfigRequest != NULL);
+ AllocatedRequest = TRUE;
+ UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", ConfigRequestHdr, sizeof (TCG_CONFIGURATION));
+ FreePool (ConfigRequestHdr);
+ }
+
+ Status = gHiiConfigRouting->BlockToConfig (
+ gHiiConfigRouting,
+ ConfigRequest,
+ (UINT8 *) PrivateData->Configuration,
+ sizeof (TCG_CONFIGURATION),
+ Results,
+ Progress
+ );
+ //
+ // Free the allocated config request string.
+ //
+ if (AllocatedRequest) {
+ FreePool (ConfigRequest);
+ }
+ //
+ // Set Progress string to the original request string.
+ //
+ if (Request == NULL) {
+ *Progress = NULL;
+ } else if (StrStr (Request, L"OFFSET") == NULL) {
+ *Progress = Request + StrLen (Request);
+ }
+
+ return Status;
+}
+
+/**
+ This function processes the results of changes in configuration.
+
+ @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param[in] Configuration A null-terminated Unicode string in <ConfigResp>
+ format.
+ @param[out] Progress A pointer to a string filled in with the offset of
+ the most recent '&' before the first failing
+ name/value pair (or the beginning of the string if
+ the failure is in the first name/value pair) or
+ the terminating NULL if all was successful.
+
+ @retval EFI_SUCCESS The Results is processed successfully.
+ @retval EFI_INVALID_PARAMETER Configuration is NULL.
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in this
+ driver.
+
+**/
+EFI_STATUS
+EFIAPI
+TcgRouteConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Configuration,
+ OUT EFI_STRING *Progress
+ )
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+ TCG_CONFIGURATION TcgConfiguration;
+
+ if (Configuration == NULL || Progress == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *Progress = Configuration;
+ if (!HiiIsConfigHdrMatch (Configuration, &gTcgConfigFormSetGuid, mTcgStorageName)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Convert <ConfigResp> to buffer data by helper function ConfigToBlock()
+ //
+ BufferSize = sizeof (TCG_CONFIGURATION);
+ Status = gHiiConfigRouting->ConfigToBlock (
+ gHiiConfigRouting,
+ Configuration,
+ (UINT8 *) &TcgConfiguration,
+ &BufferSize,
+ Progress
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Save TPM request to variable space.
+
+ @param[in] PpRequest Physical Presence request command.
+
+ @retval EFI_SUCCESS The operation is finished successfully.
+ @retval Others Other errors as indicated.
+
+**/
+EFI_STATUS
+SavePpRequest (
+ IN UINT8 PpRequest
+ )
+{
+ EFI_STATUS Status;
+ UINTN DataSize;
+ EFI_PHYSICAL_PRESENCE PpData;
+
+ //
+ // Save TPM command to variable.
+ //
+ DataSize = sizeof (EFI_PHYSICAL_PRESENCE);
+ Status = gRT->GetVariable (
+ PHYSICAL_PRESENCE_VARIABLE,
+ &gEfiPhysicalPresenceGuid,
+ NULL,
+ &DataSize,
+ &PpData
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ PpData.PPRequest = PpRequest;
+ Status = gRT->SetVariable (
+ PHYSICAL_PRESENCE_VARIABLE,
+ &gEfiPhysicalPresenceGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ DataSize,
+ &PpData
+ );
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function processes the results of changes in configuration.
+
+ @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param[in] Action Specifies the type of action taken by the browser.
+ @param[in] QuestionId A unique value which is sent to the original
+ exporting driver so that it can identify the type
+ of data to expect.
+ @param[in] Type The type of value for the question.
+ @param[in] Value A pointer to the data being sent to the original
+ exporting driver.
+ @param[out] ActionRequest On return, points to the action requested by the
+ callback function.
+
+ @retval EFI_SUCCESS The callback successfully handled the action.
+ @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the
+ variable and its data.
+ @retval EFI_DEVICE_ERROR The variable could not be saved.
+ @retval EFI_UNSUPPORTED The specified Action is not supported by the
+ callback.
+
+**/
+EFI_STATUS
+EFIAPI
+TcgCallback (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN EFI_BROWSER_ACTION Action,
+ IN EFI_QUESTION_ID QuestionId,
+ IN UINT8 Type,
+ IN EFI_IFR_TYPE_VALUE *Value,
+ OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
+ )
+{
+ TCG_CONFIG_PRIVATE_DATA *PrivateData;
+ CHAR16 State[32];
+
+ if ((This == NULL) || (Value == NULL) || (ActionRequest == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Action == EFI_BROWSER_ACTION_FORM_OPEN) {
+ if (QuestionId == KEY_TPM_ACTION) {
+
+ PrivateData = TCG_CONFIG_PRIVATE_DATA_FROM_THIS (This);
+ UnicodeSPrint (
+ State,
+ sizeof (State),
+ L"%s, and %s",
+ PrivateData->Configuration->TpmEnable ? L"Enabled" : L"Disabled",
+ PrivateData->Configuration->TpmActivate ? L"Activated" : L"Deactivated"
+ );
+ HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_TPM_STATE_CONTENT), State, NULL);
+ }
+ return EFI_SUCCESS;
+ }
+
+ if ((Action != EFI_BROWSER_ACTION_CHANGED) || (QuestionId != KEY_TPM_ACTION)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ SavePpRequest (Value->u8);
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function publish the TCG configuration Form for TPM device.
+
+ @param[in, out] PrivateData Points to TCG configuration private data.
+
+ @retval EFI_SUCCESS HII Form is installed for this network device.
+ @retval EFI_OUT_OF_RESOURCES Not enough resource for HII Form installation.
+ @retval Others Other errors as indicated.
+
+**/
+EFI_STATUS
+InstallTcgConfigForm (
+ IN OUT TCG_CONFIG_PRIVATE_DATA *PrivateData
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_HANDLE HiiHandle;
+ EFI_HANDLE DriverHandle;
+ EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
+
+ DriverHandle = NULL;
+ ConfigAccess = &PrivateData->ConfigAccess;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &DriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mTcgHiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ ConfigAccess,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ PrivateData->DriverHandle = DriverHandle;
+
+ //
+ // Publish the HII package list
+ //
+ HiiHandle = HiiAddPackages (
+ &gTcgConfigFormSetGuid,
+ DriverHandle,
+ TcgConfigDxeStrings,
+ TcgConfigBin,
+ NULL
+ );
+ if (HiiHandle == NULL) {
+ gBS->UninstallMultipleProtocolInterfaces (
+ DriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mTcgHiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ ConfigAccess,
+ NULL
+ );
+
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ PrivateData->HiiHandle = HiiHandle;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function removes TCG configuration Form.
+
+ @param[in, out] PrivateData Points to TCG configuration private data.
+
+**/
+VOID
+UninstallTcgConfigForm (
+ IN OUT TCG_CONFIG_PRIVATE_DATA *PrivateData
+ )
+{
+ //
+ // Uninstall HII package list
+ //
+ if (PrivateData->HiiHandle != NULL) {
+ HiiRemovePackages (PrivateData->HiiHandle);
+ PrivateData->HiiHandle = NULL;
+ }
+
+ //
+ // Uninstall HII Config Access Protocol
+ //
+ if (PrivateData->DriverHandle != NULL) {
+ gBS->UninstallMultipleProtocolInterfaces (
+ PrivateData->DriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mTcgHiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ &PrivateData->ConfigAccess,
+ NULL
+ );
+ PrivateData->DriverHandle = NULL;
+ }
+
+ if (PrivateData->Configuration != NULL) {
+ FreePool(PrivateData->Configuration);
+ }
+ FreePool (PrivateData);
+}
diff --git a/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.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __TCG_CONFIG_IMPL_H__
+#define __TCG_CONFIG_IMPL_H__
+
+#include <Uefi.h>
+
+#include <Protocol/HiiConfigAccess.h>
+#include <Protocol/HiiConfigRouting.h>
+#include <Protocol/TcgService.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiHiiServicesLib.h>
+#include <Library/UefiLib.h>
+#include <Library/HiiLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PrintLib.h>
+#include <Library/Tpm12DeviceLib.h>
+
+#include <Guid/MdeModuleHii.h>
+
+#include "TcgConfigNvData.h"
+
+//
+// Tool generated IFR binary data and String package data
+//
+extern UINT8 TcgConfigBin[];
+extern UINT8 TcgConfigDxeStrings[];
+
+///
+/// HII specific Vendor Device Path definition.
+///
+typedef struct {
+ VENDOR_DEVICE_PATH VendorDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} HII_VENDOR_DEVICE_PATH;
+
+typedef struct {
+ UINTN Signature;
+
+ EFI_HII_CONFIG_ACCESS_PROTOCOL ConfigAccess;
+ EFI_HII_HANDLE HiiHandle;
+ EFI_HANDLE DriverHandle;
+
+ TCG_CONFIGURATION *Configuration;
+ EFI_TCG_PROTOCOL *TcgProtocol;
+} TCG_CONFIG_PRIVATE_DATA;
+
+extern TCG_CONFIG_PRIVATE_DATA mTcgConfigPrivateDateTemplate;
+
+#define TCG_CONFIG_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('T', 'C', 'G', 'D')
+#define TCG_CONFIG_PRIVATE_DATA_FROM_THIS(a) CR (a, TCG_CONFIG_PRIVATE_DATA, ConfigAccess, TCG_CONFIG_PRIVATE_DATA_SIGNATURE)
+
+
+/**
+ This function publish the TCG configuration Form for TPM device.
+
+ @param[in, out] PrivateData Points to TCG configuration private data.
+
+ @retval EFI_SUCCESS HII Form is installed for this network device.
+ @retval EFI_OUT_OF_RESOURCES Not enough resource for HII Form installation.
+ @retval Others Other errors as indicated.
+
+**/
+EFI_STATUS
+InstallTcgConfigForm (
+ IN OUT TCG_CONFIG_PRIVATE_DATA *PrivateData
+ );
+
+/**
+ This function removes TCG configuration Form.
+
+ @param[in, out] PrivateData Points to TCG configuration private data.
+
+**/
+VOID
+UninstallTcgConfigForm (
+ IN OUT TCG_CONFIG_PRIVATE_DATA *PrivateData
+ );
+
+/**
+ This function allows a caller to extract the current configuration for one
+ or more named elements from the target driver.
+
+ @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param[in] Request A null-terminated Unicode string in
+ <ConfigRequest> format.
+ @param[out] Progress On return, points to a character in the Request
+ string. Points to the string's null terminator if
+ request was successful. Points to the most recent
+ '&' before the first failing name/value pair (or
+ the beginning of the string if the failure is in
+ the first name/value pair) if the request was not
+ successful.
+ @param[out] Results A null-terminated Unicode string in
+ <ConfigAltResp> format which has all values filled
+ in for the names in the Request string. String to
+ be allocated by the called function.
+
+ @retval EFI_SUCCESS The Results is filled with the requested values.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results.
+ @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name.
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in this
+ driver.
+
+**/
+EFI_STATUS
+EFIAPI
+TcgExtractConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Request,
+ OUT EFI_STRING *Progress,
+ OUT EFI_STRING *Results
+ );
+
+/**
+ This function processes the results of changes in configuration.
+
+ @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param[in] Configuration A null-terminated Unicode string in <ConfigResp>
+ format.
+ @param[out] Progress A pointer to a string filled in with the offset of
+ the most recent '&' before the first failing
+ name/value pair (or the beginning of the string if
+ the failure is in the first name/value pair) or
+ the terminating NULL if all was successful.
+
+ @retval EFI_SUCCESS The Results is processed successfully.
+ @retval EFI_INVALID_PARAMETER Configuration is NULL.
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in this
+ driver.
+
+**/
+EFI_STATUS
+EFIAPI
+TcgRouteConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Configuration,
+ OUT EFI_STRING *Progress
+ );
+
+/**
+ This function processes the results of changes in configuration.
+
+ @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param[in] Action Specifies the type of action taken by the browser.
+ @param[in] QuestionId A unique value which is sent to the original
+ exporting driver so that it can identify the type
+ of data to expect.
+ @param[in] Type The type of value for the question.
+ @param[in] Value A pointer to the data being sent to the original
+ exporting driver.
+ @param[out] ActionRequest On return, points to the action requested by the
+ callback function.
+
+ @retval EFI_SUCCESS The callback successfully handled the action.
+ @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the
+ variable and its data.
+ @retval EFI_DEVICE_ERROR The variable could not be saved.
+ @retval EFI_UNSUPPORTED The specified Action is not supported by the
+ callback.
+
+**/
+EFI_STATUS
+EFIAPI
+TcgCallback (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN EFI_BROWSER_ACTION Action,
+ IN EFI_QUESTION_ID QuestionId,
+ IN UINT8 Type,
+ IN EFI_IFR_TYPE_VALUE *Value,
+ OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
+ );
+
+#endif
diff --git a/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.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __TCG_CONFIG_NV_DATA_H__
+#define __TCG_CONFIG_NV_DATA_H__
+
+#include <Guid/HiiPlatformSetupFormset.h>
+#include <Guid/PhysicalPresenceData.h>
+#include <Guid/TcgConfigHii.h>
+
+#define TCG_CONFIGURATION_VARSTORE_ID 0x0001
+#define TCG_CONFIGURATION_FORM_ID 0x0001
+
+#define KEY_TPM_ACTION 0x3000
+
+#define LABEL_TCG_CONFIGURATION_TPM_OPERATION 0x0001
+#define LABEL_END 0xffff
+
+//
+// Nv Data structure referenced by IFR
+//
+typedef struct {
+ UINT8 TpmOperation;
+ BOOLEAN TpmEnable;
+ BOOLEAN TpmActivate;
+} TCG_CONFIGURATION;
+
+#endif
diff --git a/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.<BR>
+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 <Enter> to select TCG Setup options."
+#string STR_TPM_STATE_PROMPT #language en-US "Current TPM State"
+#string STR_TPM_STATE_HELP #language en-US "Current TPM device state: enabled or disabled; activated or deactivated."
+#string STR_TPM_STATE_CONTENT #language en-US ""
+
+#string STR_TPM_OPERATION #language en-US "TPM Operation"
+#string STR_TPM_OPERATION_HELP #language en-US "Select one of the supported operation to change TPM state."
+
+#string STR_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.<BR>
+(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <IndustryStandard/Tpm12.h>
+#include <IndustryStandard/Acpi.h>
+#include <IndustryStandard/PeImage.h>
+#include <IndustryStandard/TcpaAcpi.h>
+
+#include <Guid/GlobalVariable.h>
+#include <Guid/HobList.h>
+#include <Guid/TcgEventHob.h>
+#include <Guid/EventGroup.h>
+#include <Guid/EventExitBootServiceFailed.h>
+#include <Guid/TpmInstance.h>
+
+#include <Protocol/DevicePath.h>
+#include <Protocol/TcgService.h>
+#include <Protocol/AcpiTable.h>
+#include <Protocol/MpService.h>
+
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/HobLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/BaseLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PrintLib.h>
+#include <Library/Tpm12DeviceLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/Tpm12CommandLib.h>
+#include <Library/BaseCryptLib.h>
+
+#define TCG_DXE_DATA_FROM_THIS(this) \
+ BASE_CR (this, TCG_DXE_DATA, TcgProtocol)
+
+typedef struct _TCG_DXE_DATA {
+ EFI_TCG_PROTOCOL TcgProtocol;
+ TCG_EFI_BOOT_SERVICE_CAPABILITY BsCap;
+ EFI_TCG_CLIENT_ACPI_TABLE *TcgClientAcpiTable;
+ EFI_TCG_SERVER_ACPI_TABLE *TcgServerAcpiTable;
+ UINTN EventLogSize;
+ UINT8 *LastEvent;
+} TCG_DXE_DATA;
+
+
+
+EFI_TCG_CLIENT_ACPI_TABLE mTcgClientAcpiTemplate = {
+ {
+ EFI_ACPI_3_0_TRUSTED_COMPUTING_PLATFORM_ALLIANCE_CAPABILITIES_TABLE_SIGNATURE,
+ sizeof (mTcgClientAcpiTemplate),
+ 0x02 //Revision
+ //
+ // Compiler initializes the remaining bytes to 0
+ // These fields should be filled in in production
+ //
+ },
+ 0, // 0 for PC Client Platform Class
+ 0, // Log Area Max Length
+ (EFI_PHYSICAL_ADDRESS) (SIZE_4GB - 1) // Log Area Start Address
+};
+
+//
+// The following EFI_TCG_SERVER_ACPI_TABLE default setting is just one example,
+// the TPM device 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.<BR>
+# 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.<BR>
+//
+// 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.<BR>
+//
+// 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.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiPei.h>
+
+#include <IndustryStandard/Tpm12.h>
+#include <IndustryStandard/UefiTcgPlatform.h>
+#include <Ppi/FirmwareVolumeInfo.h>
+#include <Ppi/FirmwareVolumeInfo2.h>
+#include <Ppi/LockPhysicalPresence.h>
+#include <Ppi/TpmInitialized.h>
+#include <Ppi/FirmwareVolume.h>
+#include <Ppi/EndOfPeiPhase.h>
+#include <Ppi/FirmwareVolumeInfoMeasurementExcluded.h>
+#include <Ppi/Tcg.h>
+
+#include <Guid/TcgEventHob.h>
+#include <Guid/MeasuredFvHob.h>
+#include <Guid/TpmInstance.h>
+#include <Guid/MigratedFvInfo.h>
+
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/PeimEntryPoint.h>
+#include <Library/HobLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PeiServicesTablePointerLib.h>
+#include <Library/BaseLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/Tpm12DeviceLib.h>
+#include <Library/Tpm12CommandLib.h>
+#include <Library/BaseCryptLib.h>
+#include <Library/PerformanceLib.h>
+
+BOOLEAN mImageInMemory = FALSE;
+
+EFI_PEI_PPI_DESCRIPTOR mTpmInitializedPpiList = {
+ EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
+ &gPeiTpmInitializedPpiGuid,
+ NULL
+};
+
+EFI_PEI_PPI_DESCRIPTOR mTpmInitializationDonePpiList = {
+ EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
+ &gPeiTpmInitializationDonePpiGuid,
+ NULL
+};
+
+/**
+ 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.<BR>
+# 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.<BR>
+//
+// 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.<BR>
+//
+// 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.<BR>
+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.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __TCG_SMM_H__
+#define __TCG_SMM_H__
+
+#include <PiDxe.h>
+#include <IndustryStandard/Acpi.h>
+#include <IndustryStandard/UefiTcgPlatform.h>
+
+#include <Guid/PhysicalPresenceData.h>
+#include <Guid/MemoryOverwriteControl.h>
+#include <Guid/TpmInstance.h>
+
+#include <Protocol/SmmSwDispatch2.h>
+#include <Protocol/AcpiTable.h>
+#include <Protocol/SmmVariable.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/SmmServicesTableLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DxeServicesLib.h>
+#include <Library/TpmMeasurementLib.h>
+#include <Library/PcdLib.h>
+#include <Library/TcgPpVendorLib.h>
+
+#pragma pack(1)
+typedef struct {
+ UINT8 SoftwareSmi;
+ UINT32 Parameter;
+ UINT32 Response;
+ UINT32 Request;
+ UINT32 LastRequest;
+ UINT32 ReturnCode;
+} PHYSICAL_PRESENCE_NVS;
+
+typedef struct {
+ UINT8 SoftwareSmi;
+ UINT32 Parameter;
+ UINT32 Request;
+ UINT32 ReturnCode;
+} MEMORY_CLEAR_NVS;
+
+typedef struct {
+ PHYSICAL_PRESENCE_NVS PhysicalPresence;
+ MEMORY_CLEAR_NVS MemoryClear;
+ UINT32 PPRequestUserConfirm;
+} TCG_NVS;
+
+typedef struct {
+ UINT8 OpRegionOp;
+ UINT32 NameString;
+ UINT8 RegionSpace;
+ UINT8 DWordPrefix;
+ UINT32 RegionOffset;
+ UINT8 BytePrefix;
+ UINT8 RegionLen;
+} AML_OP_REGION_32_8;
+#pragma pack()
+
+//
+// The definition for TCG physical presence ACPI function
+//
+#define ACPI_FUNCTION_GET_PHYSICAL_PRESENCE_INTERFACE_VERSION 1
+#define ACPI_FUNCTION_SUBMIT_REQUEST_TO_BIOS 2
+#define ACPI_FUNCTION_GET_PENDING_REQUEST_BY_OS 3
+#define ACPI_FUNCTION_GET_PLATFORM_ACTION_TO_TRANSITION_TO_BIOS 4
+#define ACPI_FUNCTION_RETURN_REQUEST_RESPONSE_TO_OS 5
+#define ACPI_FUNCTION_SUBMIT_PREFERRED_USER_LANGUAGE 6
+#define ACPI_FUNCTION_SUBMIT_REQUEST_TO_BIOS_2 7
+#define ACPI_FUNCTION_GET_USER_CONFIRMATION_STATUS_FOR_REQUEST 8
+
+//
+// The return code for Return TPM Operation Response to OS Environment
+//
+#define PP_RETURN_TPM_OPERATION_RESPONSE_SUCCESS 0
+#define PP_RETURN_TPM_OPERATION_RESPONSE_FAILURE 1
+
+//
+// The definition for TCG MOR
+//
+#define ACPI_FUNCTION_DSM_MEMORY_CLEAR_INTERFACE 1
+#define ACPI_FUNCTION_PTS_CLEAR_MOR_BIT 2
+
+//
+// The return code for Memory Clear Interface Functions
+//
+#define MOR_REQUEST_SUCCESS 0
+#define MOR_REQUEST_GENERAL_FAILURE 1
+
+#endif // __TCG_SMM_H__
diff --git a/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.<BR>
+# Copyright (c) Microsoft Corporation.<BR>
+# 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.<BR>
+//
+// 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.<BR>
+//
+// 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.<BR>
+Copyright (c) Microsoft Corporation.<BR>
+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})
+ }
+ }
+ }
+}