diff options
Diffstat (limited to 'ReferenceCode/ME/Ptt/Smm/PttHciSmm.c')
-rw-r--r-- | ReferenceCode/ME/Ptt/Smm/PttHciSmm.c | 847 |
1 files changed, 847 insertions, 0 deletions
diff --git a/ReferenceCode/ME/Ptt/Smm/PttHciSmm.c b/ReferenceCode/ME/Ptt/Smm/PttHciSmm.c new file mode 100644 index 0000000..570a554 --- /dev/null +++ b/ReferenceCode/ME/Ptt/Smm/PttHciSmm.c @@ -0,0 +1,847 @@ +/** @file + It updates TPM2 items in ACPI table and registers SMI2 callback + functions for TrEE physical presence, ClearMemory, and sample + for dTPM StartMethod. + + Caution: This module requires additional review when modified. + This driver will have external input - variable and ACPINvs data in SMM mode. + This external input must be validated carefully to avoid security issue. + + PhysicalPresenceCallback() and MemoryClearCallback() will receive untrusted input and do some check. + +@copyright + Copyright (c) 2012 - 2013 Intel Corporation. All rights reserved + This software and associated documentation (if any) is furnished + under a license and may only be used or copied in accordance + with the terms of the license. Except as permitted by such + license, no part of this software or documentation may be + reproduced, stored in a retrieval system, or transmitted in any + form or by any means without the express written consent of + Intel Corporation. + + This file contains an 'Intel Peripheral Driver' and uniquely + identified as "Intel Reference Module" and is + licensed for Intel CPUs and chipsets under the terms of your + license agreement with Intel or your vendor. This file may + be modified by the user, subject to additional terms of the + license agreement + +**/ + +#include "PttHciSmm.h" +#include "MeAccess.h" +#include "HeciRegs.h" + +EFI_GUID gTpm2AcpiTableStorageGuid = TPM2_ACPI_TABLE_STORAGE_GUID; +EFI_GUID gEfiTrEEPhysicalPresenceGuid = EFI_TREE_PHYSICAL_PRESENCE_DATA_GUID; +EFI_GUID gEfiMemoryOverwriteControlDataGuid = MEMORY_ONLY_RESET_CONTROL_GUID; +EFI_GUID gEfiSmmVariableProtocolGuid = EFI_SMM_VARIABLE_PROTOCOL_GUID; +EFI_GUID gMeGlobalNvsAreaProtocolGuid = ME_GLOBAL_NVS_AREA_PROTOCOL_GUID; +EFI_GUID gMeSsdtAcpiTableStorageGuid = ME_SSDT_ACPI_TABLE_STORAGE_GUID; + +EFI_TPM2_ACPI_TABLE mTpm2AcpiTemplate = { + { + EFI_ACPI_5_0_TRUSTED_COMPUTING_PLATFORM_2_TABLE_SIGNATURE, + sizeof (mTpm2AcpiTemplate), + EFI_TPM2_ACPI_TABLE_REVISION, + // + // Compiler initializes the remaining bytes to 0 + // These fields should be filled in in production + // + }, + 0, // Flags + (EFI_PHYSICAL_ADDRESS)(UINTN)0xFFFFFFFF, // Control Area + EFI_TPM2_ACPI_TABLE_START_METHOD_ACPI, +}; + +EFI_SMM_VARIABLE_PROTOCOL *mSmmVariable; +TCG_NVS *mTcgNvs; +EFI_TPM2_ACPI_CONTROL_AREA mControlArea; // Smm copy, because we need cache Command & Response address +ME_GLOBAL_NVS_AREA_PROTOCOL mMeGlobalNvsAreaProtocol; +//<AMI_OVERRIDE> >>> +#define EFI_SMM_RUNTIME_SERVICES_TABLE_GUID \ + { 0x395c33fe, 0x287f, 0x413e, { 0xa0, 0x55, 0x80, 0x88, 0xc0, 0xe1, 0xd4, 0x3e } } + +EFI_RUNTIME_SERVICES *mRuntimeServices; + +EFI_STATUS +GetSmmRtTable ( + VOID + ) +{ + EFI_STATUS Status; + EFI_GUID SmmRtServTableGuid = EFI_SMM_RUNTIME_SERVICES_TABLE_GUID; + EFI_SMM_BASE_PROTOCOL *SmmBase = NULL; + EFI_SMM_SYSTEM_TABLE *Smst = NULL; + EFI_CONFIGURATION_TABLE *Table = NULL; + UINTN Count = 0; + + Status = gBS->LocateProtocol( + &gEfiSmmBaseProtocolGuid, + NULL, + &SmmBase ); + if( EFI_ERROR(Status) ) return Status; + + Status = SmmBase->GetSmstLocation( SmmBase, &Smst ); + if( EFI_ERROR(Status) ) return Status; + + Table = Smst->SmmConfigurationTable; + Count = Smst->NumberOfTableEntries; + + mRuntimeServices = NULL; + for( ; Count ; --Count, ++Table ) + { + if( CompareGuid( &Table->VendorGuid, &SmmRtServTableGuid ) ) + { + mRuntimeServices = (EFI_RUNTIME_SERVICES*)Table->VendorTable; + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} +//<AMI_OVERRIDE> <<< + +/** + 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. + + @retval EFI_SUCCESS The interrupt was handled successfully. +**/ +EFI_STATUS +EFIAPI +PhysicalPresenceCallback ( + IN EFI_HANDLE DispatchHandle, + IN EFI_SMM_SW_DISPATCH_CONTEXT *DispatchContext + ) +{ + EFI_STATUS Status; + UINTN DataSize; + EFI_TREE_PHYSICAL_PRESENCE PpData; + UINT8 Flags; + BOOLEAN RequestConfirmed; + + // + // Get the Physical Presence variable + // + DataSize = sizeof (EFI_TREE_PHYSICAL_PRESENCE); +//<AMI_OVERRIDE> >>> + Status = mRuntimeServices->GetVariable ( + TREE_PHYSICAL_PRESENCE_VARIABLE, + &gEfiTrEEPhysicalPresenceGuid, + NULL, + &DataSize, + &PpData + ); +//<AMI_OVERRIDE> <<< + if (EFI_ERROR (Status)) { + return EFI_SUCCESS; + } + + DEBUG ((EFI_D_INFO, "[TPM2] PP callback, Parameter = %x\n", mTcgNvs->PhysicalPresence.Parameter)); + if (mTcgNvs->PhysicalPresence.Parameter == ACPI_FUNCTION_RETURN_REQUEST_RESPONSE_TO_OS) { + 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 (PpData.PPRequest != mTcgNvs->PhysicalPresence.Request) { + PpData.PPRequest = (UINT8) mTcgNvs->PhysicalPresence.Request; + DataSize = sizeof (EFI_TREE_PHYSICAL_PRESENCE); +//<AMI_OVERRIDE> >>> + Status = mRuntimeServices->SetVariable ( + TREE_PHYSICAL_PRESENCE_VARIABLE, + &gEfiTrEEPhysicalPresenceGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + DataSize, + &PpData + ); +//<AMI_OVERRIDE> <<< + } + + if (EFI_ERROR (Status)) { + mTcgNvs->PhysicalPresence.ReturnCode = PP_SUBMIT_REQUEST_GENERAL_FAILURE; + return EFI_SUCCESS; + } + mTcgNvs->PhysicalPresence.ReturnCode = PP_SUBMIT_REQUEST_SUCCESS; + } else if (mTcgNvs->PhysicalPresence.Parameter == ACPI_FUNCTION_GET_USER_CONFIRMATION_STATUS_FOR_REQUEST) { + Flags = PpData.Flags; + RequestConfirmed = FALSE; + + switch (mTcgNvs->PhysicalPresence.Request) { + + case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR: + case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_2: + case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_3: + case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_4: + if ((Flags & TREE_FLAG_NO_PPI_CLEAR) != 0) { + RequestConfirmed = TRUE; + } + break; + + case TREE_PHYSICAL_PRESENCE_SET_NO_PPI_CLEAR_FALSE: + RequestConfirmed = TRUE; + break; + + case TREE_PHYSICAL_PRESENCE_SET_NO_PPI_CLEAR_TRUE: + break; + + default: + if (mTcgNvs->PhysicalPresence.Request <= TREE_PHYSICAL_PRESENCE_NO_ACTION_MAX) { + RequestConfirmed = TRUE; + } + break; + } + + if (RequestConfirmed) { + mTcgNvs->PhysicalPresence.ReturnCode = PP_REQUEST_ALLOWED_AND_PPUSER_NOT_REQUIRED; + } else { + mTcgNvs->PhysicalPresence.ReturnCode = PP_REQUEST_ALLOWED_AND_PPUSER_REQUIRED; + } + } + + 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. + + @retval EFI_SUCCESS The interrupt was handled successfully. +**/ +EFI_STATUS +EFIAPI +MemoryClearCallback ( + IN EFI_HANDLE DispatchHandle, + IN EFI_SMM_SW_DISPATCH_CONTEXT *DispatchContext + ) +{ + 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); +//<AMI_OVERRIDE> >>> + Status = mRuntimeServices->GetVariable ( + MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME, + &gEfiMemoryOverwriteControlDataGuid, + NULL, + &DataSize, + &MorControl + ); +//<AMI_OVERRIDE> <<< + if (EFI_ERROR (Status)) { + return EFI_SUCCESS; + } + + if (MOR_CLEAR_MEMORY_VALUE (MorControl) == 0x0) { + return EFI_SUCCESS; + } + MorControl &= ~MOR_CLEAR_MEMORY_BIT_MASK; + } + + DataSize = sizeof (UINT8); +//<AMI_OVERRIDE> >>> + Status = mRuntimeServices->SetVariable ( + MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME, + &gEfiMemoryOverwriteControlDataGuid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, + DataSize, + &MorControl + ); +//<AMI_OVERRIDE> <<< + if (EFI_ERROR (Status)) { + mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_GENERAL_FAILURE; + } + + 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 = 0xFFFFFFFF; + + // + // 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; +} + +VOID * +GetTpm2AcpiTableFromFv ( + VOID + ) +{ + EFI_STATUS Status; + EFI_HANDLE *HandleBuffer; + UINTN NumberOfHandles; + EFI_FV_FILETYPE FileType; + UINT32 FvStatus; + EFI_FV_FILE_ATTRIBUTES Attributes; + UINTN Size; + UINTN Index; + INTN Instance; + EFI_ACPI_COMMON_HEADER *CurrentTable; + EFI_FIRMWARE_VOLUME_PROTOCOL *FwVol; + + /// + /// Locate protocol. + /// There is little chance we can't find an FV protocol + /// + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiFirmwareVolumeProtocolGuid, + NULL, + &NumberOfHandles, + &HandleBuffer + ); + ASSERT_EFI_ERROR (Status); + + FwVol = NULL; + /// + /// Looking for FV with ACPI storage file + /// + for (Index = 0; Index < NumberOfHandles; Index++) { + /// + /// Get the protocol on this handle + /// This should not fail because of LocateHandleBuffer + /// + Status = gBS->HandleProtocol ( + HandleBuffer[Index], + &gEfiFirmwareVolumeProtocolGuid, + &FwVol + ); + ASSERT_EFI_ERROR (Status); + + /// + /// See if it has the ACPI storage file + /// + Size = 0; + FvStatus = 0; + Status = FwVol->ReadFile ( + FwVol, + &gTpm2AcpiTableStorageGuid, + NULL, + &Size, + &FileType, + &Attributes, + &FvStatus + ); + + /// + /// If we found it, then we are done + /// + if (Status == EFI_SUCCESS) { + break; + } else { + FwVol = NULL; + } + } + + if ((Index == NumberOfHandles) || (FwVol == NULL)) { + return NULL; + } + + Instance = 0; + CurrentTable = NULL; + + while (Status == EFI_SUCCESS) { + Status = FwVol->ReadSection ( + FwVol, + &gTpm2AcpiTableStorageGuid, + EFI_SECTION_RAW, + Instance, + &CurrentTable, + &Size, + &FvStatus + ); + + if (!EFI_ERROR (Status)) { + /// + /// Check the Signature ID to modify the table + /// + if ((((EFI_ACPI_DESCRIPTION_HEADER *) CurrentTable)->Signature == EFI_SIGNATURE_32 ('S', 'S', 'D', 'T')) && + (((EFI_ACPI_DESCRIPTION_HEADER *) CurrentTable)->OemTableId == EFI_SIGNATURE_64 ('T', 'p', 'm', '2', 'T', 'a', 'b', 'l'))) { + // + // Find it. + // + break; + } + /// + /// Increment the instance + /// + Instance++; + CurrentTable = NULL; + } + } + + /// + /// Our exit status is determined by the success of the previous operations + /// If the protocol was found, Instance already points to it. + /// + /// + /// Free any allocated buffers + /// + (gBS->FreePool) (HandleBuffer); + + return CurrentTable; +} + +/** + 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; + + Table = GetTpm2AcpiTableFromFv (); + ASSERT (Table != NULL); + + if (Table == NULL) { + return EFI_NOT_FOUND; + } + + TableSize = Table->Length; + + ASSERT (Table->OemTableId == EFI_SIGNATURE_64 ('T', 'p', 'm', '2', 'T', 'a', 'b', 'l')); + mTcgNvs = AssignOpRegion (Table, EFI_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; +} + +EFI_STATUS +PublishFtpmAcpiTable ( + VOID + ) +/** + 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 Status; + EFI_ACPI_TABLE_PROTOCOL *AcpiTable; + UINTN TableKey; + EFI_TPM2_ACPI_CONTROL_AREA *ControlArea; + ME_DATA_HOB *MeDataHob; + EFI_GUID gMeDataHobGuid = ME_DATA_HOB_GUID; + + /// + /// Construct ACPI table + /// + Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTable); + ASSERT_EFI_ERROR (Status); + + MeDataHob = NULL; + MeDataHob = GetFirstGuidHob (&gMeDataHobGuid); + if (MeDataHob != NULL) { + (UINTN)mTpm2AcpiTemplate.AddressOfControlArea = MeDataHob->FtpmBufferAddress; + } else { + (UINTN) mTpm2AcpiTemplate.AddressOfControlArea = 0xFED70000; + } + + ControlArea = (EFI_TPM2_ACPI_CONTROL_AREA *)(UINTN)mTpm2AcpiTemplate.AddressOfControlArea; + ZeroMem (ControlArea, sizeof(*ControlArea)); + ControlArea->CommandSize = 0xF80; + ControlArea->ResponseSize = 0xF80; + ControlArea->Command = (UINTN)mTpm2AcpiTemplate.AddressOfControlArea + 0x80; + ControlArea->Response = (UINTN)mTpm2AcpiTemplate.AddressOfControlArea + 0x80; + CopyMem (&mControlArea, ControlArea, sizeof(mControlArea)); + + DEBUG ((EFI_D_INFO, "Ftpm Windows Buffer Control Area Address = %x\n", mTpm2AcpiTemplate.AddressOfControlArea)); + DEBUG ((EFI_D_INFO, "Ftpm Windows Command/Response Buffer Address = %x\n", ControlArea->Command)); + + Status = AcpiTable->InstallAcpiTable ( + AcpiTable, + &mTpm2AcpiTemplate, + sizeof(mTpm2AcpiTemplate), + &TableKey + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} + +BOOLEAN +IsFtpmEnabled ( + VOID + ) +{ + UINT32 IsPttEnabled; + UINT32 IsPttReady; + UINT32 MeFwSts4; + + IsPttEnabled = ( B_PTT_HCI_STS_ENABLED & MmioRead32((UINTN)(R_PTT_HCI_BASE_ADDRESS + R_PTT_HCI_STS)) ); + /// + /// Read ME FWSTS4 to check if TPM_DISCONNECT_ALL BIT[12] is set + /// + MeFwSts4 = HeciPciRead32(R_ME_HFS_4); + + /// + /// Read Ready Bit to identify if PTT is ready for accepting OS Commands + /// + IsPttReady = (B_PTT_HCI_STS_READY & MmioRead32((UINTN)(R_PTT_HCI_BASE_ADDRESS + R_PTT_HCI_STS))); + + if ( (IsPttEnabled == 0) || (MeFwSts4 & BIT12) || (IsPttReady == 0) ) { + return FALSE; + } + + return TRUE; +} + +EFI_STATUS +InitializeMeSsdtAcpiTables ( +IN EFI_HANDLE ImageHandle + ) +/** +@brief + Initialize MEFW SSDT ACPI tables + + @retval EFI_SUCCESS ACPI tables are initialized successfully + @retval EFI_NOT_FOUND ACPI tables not found +**/ +{ + EFI_STATUS Status; + EFI_HANDLE *HandleBuffer; + UINTN NumberOfHandles; + EFI_FV_FILETYPE FileType; + UINT32 FvStatus; + EFI_FV_FILE_ATTRIBUTES Attributes; + UINTN Size; + UINTN i; + EFI_FIRMWARE_VOLUME_PROTOCOL *FwVol; + INTN Instance; + EFI_ACPI_COMMON_HEADER *CurrentTable; + UINTN AcpiTableKey; + UINT8 *CurrPtr; + UINT8 *EndPtr; + UINT32 *Signature; + EFI_ACPI_DESCRIPTION_HEADER *MeAcpiTable; + EFI_ACPI_TABLE_PROTOCOL *AcpiTable; + + Status = (gBS->AllocatePool) (EfiReservedMemoryType, sizeof (ME_GLOBAL_NVS_AREA), (VOID **) &mMeGlobalNvsAreaProtocol.Area); + ASSERT_EFI_ERROR (Status); + ZeroMem ((VOID *) mMeGlobalNvsAreaProtocol.Area, sizeof (ME_GLOBAL_NVS_AREA)); + + FwVol = NULL; + MeAcpiTable = NULL; + + /// + /// Locate ACPI Table protocol + /// + DEBUG ((EFI_D_INFO, "Init ME SSDT table\n")); + Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, &AcpiTable); + if (Status != EFI_SUCCESS) { + DEBUG ((EFI_D_ERROR, "Fail to locate EfiAcpiTableProtocol.\n")); + return EFI_NOT_FOUND; + } + + /// + /// Locate protocol. + /// There is little chance we can't find an FV protocol + /// + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiFirmwareVolumeProtocolGuid, + NULL, + &NumberOfHandles, + &HandleBuffer + ); + ASSERT_EFI_ERROR (Status); + /// + /// Looking for FV with ACPI storage file + /// + for (i = 0; i < NumberOfHandles; i++) { + /// + /// Get the protocol on this handle + /// This should not fail because of LocateHandleBuffer + /// + Status = gBS->HandleProtocol ( + HandleBuffer[i], + &gEfiFirmwareVolumeProtocolGuid, + &FwVol + ); + ASSERT_EFI_ERROR (Status); + + /// + /// See if it has the ACPI storage file + /// + Size = 0; + FvStatus = 0; + Status = FwVol->ReadFile ( + FwVol, + &gMeSsdtAcpiTableStorageGuid, + NULL, + &Size, + &FileType, + &Attributes, + &FvStatus + ); + + /// + /// If we found it, then we are done + /// + if (Status == EFI_SUCCESS) { + break; + } + } + /// + /// Free any allocated buffers + /// + FreePool (HandleBuffer); + + /// + /// Sanity check that we found our data file + /// + ASSERT (FwVol != NULL); + if (FwVol == NULL) { + DEBUG ((EFI_D_INFO, "ME Global NVS table not found\n")); + return EFI_NOT_FOUND; + } + /// + /// Our exit status is determined by the success of the previous operations + /// If the protocol was found, Instance already points to it. + /// Read tables from the storage file. + /// + Instance = 0; + CurrentTable = NULL; + while (Status == EFI_SUCCESS) { + Status = FwVol->ReadSection ( + FwVol, + &gMeSsdtAcpiTableStorageGuid, + EFI_SECTION_RAW, + Instance, + &CurrentTable, + &Size, + &FvStatus + ); + + if (!EFI_ERROR (Status)) { + /// + /// Check the table ID to modify the table + /// + if (((EFI_ACPI_DESCRIPTION_HEADER *) CurrentTable)->OemTableId == EFI_SIGNATURE_64 ('M', 'e', 'S', 's', 'd', 't', ' ', 0)) { + MeAcpiTable = (EFI_ACPI_DESCRIPTION_HEADER *) CurrentTable; + /// + /// Locate the SSDT package + /// + CurrPtr = (UINT8 *) MeAcpiTable; + EndPtr = CurrPtr + MeAcpiTable->Length; + + for (; CurrPtr <= EndPtr; CurrPtr++) { + Signature = (UINT32 *) (CurrPtr + 3); + if (*Signature == EFI_SIGNATURE_32 ('M', 'E', 'N', 'V')) { + ASSERT_EFI_ERROR (*(UINT32 *) (CurrPtr + 3 + sizeof (*Signature) + 2) == 0xFFFF0000); + ASSERT_EFI_ERROR (*(UINT16 *) (CurrPtr + 3 + sizeof (*Signature) + 2 + sizeof (UINT32) + 1) == 0xAA55); + /// + /// ME Global NVS Area address + /// + + *(UINT32 *) (CurrPtr + 3 + sizeof (*Signature) + 2) = (UINT32) (UINTN) mMeGlobalNvsAreaProtocol.Area; + /// + /// ME Global NVS Area size + /// + *(UINT16 *) (CurrPtr + 3 + sizeof (*Signature) + 2 + sizeof (UINT32) + 1) = + sizeof (ME_GLOBAL_NVS_AREA); + + AcpiTableKey = 0; + Status = AcpiTable->InstallAcpiTable ( + AcpiTable, + MeAcpiTable, + MeAcpiTable->Length, + &AcpiTableKey + ); + ASSERT_EFI_ERROR (Status); + + Status = gBS->InstallMultipleProtocolInterfaces ( + &ImageHandle, + &gMeGlobalNvsAreaProtocolGuid, + &mMeGlobalNvsAreaProtocol, + NULL + ); + ASSERT_EFI_ERROR (Status); + return EFI_SUCCESS; + } + } + } + /// + /// Increment the instance + /// + Instance++; + CurrentTable = NULL; + } + } + + 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 +InitializeFtpmSmm ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_SMM_SW_DISPATCH_PROTOCOL *SwDispatch; + EFI_SMM_SW_DISPATCH_CONTEXT SwContext; + EFI_HANDLE SwHandle; + ME_GLOBAL_NVS_AREA_PROTOCOL *MeGlobalNvsAreaProtocol; + ME_GLOBAL_NVS_AREA *MeGlobalNvsArea; + + if (!IsFtpmEnabled ()) { + DEBUG ((EFI_D_ERROR, "InitializeFtpmSmm - FTPM not enabled\n")); + return EFI_SUCCESS; + } + +if (GetCpuFamily() == EnumCpuHswUlt) { + Status = PublishAcpiTable (); + ASSERT_EFI_ERROR (Status); + + // + // Get the Sw dispatch protocol and register SMI callback functions. + // + Status = gBS->LocateProtocol (&gEfiSmmSwDispatchProtocolGuid, NULL, (VOID**)&SwDispatch); + ASSERT_EFI_ERROR (Status); + SwContext.SwSmiInputValue = EFI_TPM2_PP_SW_SMI; + 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 = EFI_TPM2_MOR_SW_SMI; + Status = SwDispatch->Register (SwDispatch, MemoryClearCallback, &SwContext, &SwHandle); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + return Status; + } + mTcgNvs->MemoryClear.SoftwareSmi = (UINT8) SwContext.SwSmiInputValue; + +//<AMI_OVERRIDE> >>> + /// + /// Locate SmmVariableProtocol. + /// + //Status = gBS->LocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID**)&mSmmVariable); + //ASSERT_EFI_ERROR (Status); + + //We don't install SmmVariableProtocol in gBS, use gRT's variable + //service directly. + Status = GetSmmRtTable(); + ASSERT_EFI_ERROR (Status); +//<AMI_OVERRIDE> <<< + + Status = InitializeMeSsdtAcpiTables(ImageHandle); + ASSERT_EFI_ERROR (Status); + + /// + /// Publish TPM2 ACPI table + /// + Status = PublishFtpmAcpiTable(); + ASSERT_EFI_ERROR (Status); + + /// + /// Locate Global NVS and update PTT Buffer Address + /// + Status = gBS->LocateProtocol (&gMeGlobalNvsAreaProtocolGuid, NULL, (VOID **) &MeGlobalNvsAreaProtocol); + ASSERT_EFI_ERROR (Status); + + MeGlobalNvsArea = MeGlobalNvsAreaProtocol->Area; + MeGlobalNvsArea->PTTAddress = mTpm2AcpiTemplate.AddressOfControlArea; +} + + return EFI_SUCCESS; +} + |