diff options
Diffstat (limited to 'ReferenceCode/Haswell/Txt/TxtInit/Dxe/TxtDxeLib.c')
-rw-r--r-- | ReferenceCode/Haswell/Txt/TxtInit/Dxe/TxtDxeLib.c | 1080 |
1 files changed, 1080 insertions, 0 deletions
diff --git a/ReferenceCode/Haswell/Txt/TxtInit/Dxe/TxtDxeLib.c b/ReferenceCode/Haswell/Txt/TxtInit/Dxe/TxtDxeLib.c new file mode 100644 index 0000000..6aef615 --- /dev/null +++ b/ReferenceCode/Haswell/Txt/TxtInit/Dxe/TxtDxeLib.c @@ -0,0 +1,1080 @@ +/** @file + This file contains an implementation of the function call interfaces + required by the main TXT DXE file. Hopefully, future platform porting + tasks will be mostly limited to modifying the functions in this file. + +@copyright + Copyright (c) 1999 - 2012 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 + +**/ + +/// +/// External include files do NOT need to be explicitly specified in real EDKII +/// environment +/// +#if !defined(EDK_RELEASE_VERSION) || (EDK_RELEASE_VERSION < 0x00020000) +#include "EdkIIGlueDxe.h" +#include "Txt.h" +#include "TxtDxeLib.h" +#include "EfiScriptLib.h" +#include EFI_PROTOCOL_DEFINITION (PciIo) +#include EFI_PROTOCOL_DEFINITION (PciRootBridgeIo) +#include EFI_PROTOCOL_DEPENDENCY (FirmwareVolume) +#endif + +EFI_GUID mTxtBiosAcmPeiFileGuid = PEI_BIOS_ACM_FILE_GUID; + +UINT64 mMcuAddr; +UINT64 mAcmBase; +UINT64 mApMtrrTab[2 * (IA32_MTRR_PHYSMASK9 - IA32_MTRR_PHYSBASE0 + 1) + 1]; +UINT64 mApIdt[2]; +UINT64 mApCr4; +UINT64 mApSavedIa32ThermInterruptMSR[2]; +UINT32 mApSavedApicThermalValue; + +/** + This routine initializes and collects all Protocols and data required + by the routines in this file. + + @param[in] ImageHandle - A pointer to the Image Handle for this file. + @param[in] SystemTable - A pointer to the EFI System Table + @param[in] TxtDxeCtx - A pointer to a caller allocated data structure that contains + all of the Protocols and data required by the routines + in this file. + + @retval EFI_SUCCESS - Return EFI_SUCCESS if no error happen + @retval EFI_UNLOAD_IMAGE - If TxtInfoHob is not found +**/ +EFI_STATUS +InitializeTxtDxeLib ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable, + IN OUT TXT_DXE_LIB_CONTEXT *TxtDxeCtx + ) +{ + EFI_STATUS Status; + VOID *HobList; + TXT_INFO_HOB *TxtInfoHob; + UINTN tmp; + + INITIALIZE_SCRIPT (ImageHandle, SystemTable); + + TxtDxeCtx->ImageHandle = ImageHandle; + TxtDxeCtx->SystemTable = SystemTable; + + /// + /// Find the TxtPolicyprotocol + /// + Status = gBS->LocateProtocol ( + &gDxeCpuPlatformPolicyProtocolGuid, + NULL, + (VOID **) &(TxtDxeCtx->CpuPlatformPolicy) + ); + + if (EFI_ERROR (Status)) { + TxtDxeCtx->CpuPlatformPolicy = NULL; + } + /// + /// Find the CpuIo protocol + /// + Status = gBS->LocateProtocol ( + &gEfiCpuIoProtocolGuid, + NULL, + (VOID **) &(TxtDxeCtx->CpuIo) + ); + + ASSERT_EFI_ERROR (Status); + /// + /// Find the MpService Protocol + /// + Status = gBS->LocateProtocol ( + &gEfiMpServiceProtocolGuid, + NULL, + (VOID **) &(TxtDxeCtx->MpService) + ); + + ASSERT_EFI_ERROR (Status); + /// + /// Initialize CpuCount info. Current implemetation of + /// GetGeneralMPInfo doesn't honor optionality of arguments. Don't use + /// NULL pointers. + /// + Status = TxtDxeCtx->MpService->GetGeneralMPInfo ( + TxtDxeCtx->MpService, + &(TxtDxeCtx->CpuCount), + &tmp, + &tmp, + &tmp, + &tmp + ); + ASSERT_EFI_ERROR (Status); + + /// + /// Find TxtInfoHob + /// + HobList = GetFirstGuidHob (&gTxtInfoHobGuid); + if (HobList == NULL) { + return EFI_UNLOAD_IMAGE; + } + + TxtInfoHob = (TXT_INFO_HOB *) HobList; + TxtDxeCtx->TxtInfoData = &(TxtInfoHob->Data); + + /// + /// Print out the TxtInfo HOB + /// + DEBUG ((EFI_D_INFO, "TXTDXE: TxtInfoHob passed from platform as:\n")); + DEBUG ((EFI_D_INFO, "TXTDXE: ChipsetIsTxtCapable = %x\n", TxtDxeCtx->TxtInfoData->ChipsetIsTxtCapable)); + DEBUG ((EFI_D_INFO, "TXTDXE: TxtMode = %x\n", TxtDxeCtx->TxtInfoData->TxtMode)); + DEBUG ((EFI_D_INFO, "TXTDXE: PmBase = %x\n", TxtDxeCtx->TxtInfoData->PmBase)); + DEBUG ((EFI_D_INFO, "TXTDXE: SinitMemorySize = %x\n", TxtDxeCtx->TxtInfoData->SinitMemorySize)); + DEBUG ((EFI_D_INFO, "TXTDXE: TxtHeapMemorySize = %x\n", TxtDxeCtx->TxtInfoData->TxtHeapMemorySize)); + DEBUG ((EFI_D_INFO, "TXTDXE: TxtDprMemoryBase = %x\n", TxtDxeCtx->TxtInfoData->TxtDprMemoryBase)); + DEBUG ((EFI_D_INFO, "TXTDXE: TxtDprMemorySize = %x\n", TxtDxeCtx->TxtInfoData->TxtDprMemorySize)); + DEBUG ((EFI_D_INFO, "TXTDXE: BiosAcmBase = %x\n", TxtDxeCtx->TxtInfoData->BiosAcmBase)); + DEBUG ((EFI_D_INFO, "TXTDXE: BiosAcmSize = %x\n", TxtDxeCtx->TxtInfoData->BiosAcmSize)); + DEBUG ((EFI_D_INFO, "TXTDXE: McuUpdateDataAddr = %x\n", TxtDxeCtx->TxtInfoData->McuUpdateDataAddr)); + DEBUG ((EFI_D_INFO, "TXTDXE: SinitAcmBase = %x\n", TxtDxeCtx->TxtInfoData->SinitAcmBase)); + DEBUG ((EFI_D_INFO, "TXTDXE: SinitAcmSize = %x\n", TxtDxeCtx->TxtInfoData->SinitAcmSize)); + DEBUG ((EFI_D_INFO, "TXTDXE: TgaSize = %x\n", TxtDxeCtx->TxtInfoData->TgaSize)); + DEBUG ((EFI_D_INFO, "TXTDXE: TxtLcpPdBase = %x\n", TxtDxeCtx->TxtInfoData->TxtLcpPdBase)); + DEBUG ((EFI_D_INFO, "TXTDXE: TxtLcpPdSize = %x\n", TxtDxeCtx->TxtInfoData->TxtLcpPdSize)); + DEBUG ((EFI_D_INFO, "TXTDXE: Flags = %x\n", TxtDxeCtx->TxtInfoData->Flags)); + return EFI_SUCCESS; +} + +/** + Determines whether or not the platform has executed an TXT launch by + examining the TPM Establishment bit. + + @param[in] TxtDxeCtx - A pointer to an initialized TXT DXE Context data structure + + @retval TRUE - If the TPM establishment bit is asserted. + @retval FALSE - If the TPM establishment bit is unasserted. +**/ +BOOLEAN +IsTxtEstablished ( + IN TXT_DXE_LIB_CONTEXT *TxtDxeCtx + ) +{ + EFI_STATUS Status; + UINT8 AccessReg; + UINT16 TimeOutCount; + + /// + /// TO-DO: We might locate TCG protocol to access TPM status + /// + /// + /// Set TPM.ACCESS polling timeout about 750ms + /// + TimeOutCount = TPM_TIME_OUT; + do { + /// + /// Read TPM status register + /// + Status = TxtDxeCtx->CpuIo->Mem.Read ( + TxtDxeCtx->CpuIo, + EfiCpuIoWidthUint8, + (UINT64) TPM_STATUS_REG_ADDRESS, + 1, + &AccessReg + ); + ASSERT_EFI_ERROR (Status); + /// + /// if TPM.Access == 0xFF, TPM is not present + /// + if (AccessReg == 0xFF) { + return FALSE; + } + /// + /// Check tpmRegValidSts bit before checking establishment bit + /// + if ((AccessReg & 0x80) != 0x80) { + /// + /// Delay 1ms and read again + /// + gBS->Stall (1000); + } else { + /// + /// tpmRegValidSts set, we can check establishment bit now. + /// + break; + } + + TimeOutCount--; + } while (TimeOutCount != 0); + + /// + /// if tpmRegValidSts is not set, TPM is not usable + /// + if ((AccessReg & 0x80) != 0x80) { + DEBUG ((EFI_D_ERROR, "TXTDXE: TPM Valid Status is not set!! TPM.ACCESS=%x\n", AccessReg)); + ASSERT (TRUE); + EFI_DEADLOOP (); + } + /// + /// The bit we're interested in uses negative logic: + /// If bit 0 == 1 then return False + /// Else return True + /// + return (AccessReg & 0x1) ? FALSE : TRUE; +} + +/** + Determines whether or not the platform has executed an TXT launch by + examining the TPM Establishment bit. + + @param[in] TxtDxeCtx - A pointer to an initialized TXT DXE Context data structure + + @retval TRUE - If the TPM establishment bit is asserted. + @retval FALSE - If the TPM establishment bit is unasserted. +**/ +BOOLEAN +IsTxtResetSet ( + IN TXT_DXE_LIB_CONTEXT *TxtDxeCtx + ) +{ + EFI_STATUS Status; + UINT8 EstsReg; + + /// + /// TO-DO: We might locate TCG protocol to access TPM status + /// + /// + /// Read TPM status register + /// + Status = TxtDxeCtx->CpuIo->Mem.Read ( + TxtDxeCtx->CpuIo, + EfiCpuIoWidthUint8, + (UINT64) TXT_PUBLIC_BASE + TXT_ERROR_STATUS_REG_OFF, + 1, + &EstsReg + ); + ASSERT_EFI_ERROR (Status); + + return (EstsReg & 0x1) ? TRUE : FALSE; +} + +/** + Determines whether or not the platform requires initialization for TXT use. + + @param[in] TxtDxeCtx - A pointer to an initialized TXT DXE Context data structure + + @retval TRUE - If the the platoform should be configured for TXT. + @retval FALSE - If TXT is not to be used. +**/ +BOOLEAN +IsTxtEnabled ( + IN TXT_DXE_LIB_CONTEXT *TxtDxeCtx + ) +{ + + UINT64 Ia32FeatureControl; + TXT_INFO_DATA *TxtInfoData; + + TxtInfoData = TxtDxeCtx->TxtInfoData; + + /// + /// If TxtInfoHob reported TXT disabled, return FALSE to indicate TXT should be be used + /// + if (TxtInfoData->TxtMode == 0) { + return FALSE; + } + + Ia32FeatureControl = AsmReadMsr64 (MSR_IA32_FEATURE_CONTROL); + + return ((Ia32FeatureControl & TXT_OPT_IN_VMX_AND_SMX_MSR_VALUE) == TXT_OPT_IN_VMX_AND_SMX_MSR_VALUE) ? TRUE : FALSE; +} + +/** + Determines whether or not the current processor is TXT Capable. + + @retval TRUE - If the current processor supports TXT + @retval FALSE - If the current processor does not support TXT +**/ +BOOLEAN +IsTxtProcessor ( + VOID + ) +{ + EFI_CPUID_REGISTER CpuidRegs; + + AsmCpuid (1, &CpuidRegs.RegEax, &CpuidRegs.RegEbx, &CpuidRegs.RegEcx, &CpuidRegs.RegEdx); + + return (CpuidRegs.RegEcx & B_CPUID_VERSION_INFO_ECX_SME) ? TRUE : FALSE; +} + +/** + Add extened elements to BiosOsData + + @param[in] TxtDxeCtx - A pointer to an initialized TXT DXE Context data structure + @param[in] Type - The element's type + @param[in] Buffer - A pointer to buffer which need to append the element + @param[in] Size - return the size of the appened element. + + @retval None +**/ +VOID +AppendElement ( + IN TXT_DXE_LIB_CONTEXT *TxtDxeCtx, + IN UINT32 Type, + IN VOID *Buffer, + OUT UINT32 *Size + ) +{ + VOID *Element; + UINT32 NumberOfAcm; + UINT64 *AcmBase; + + NumberOfAcm = 1; + AcmBase = NULL; + Element = NULL; + *Size = 0; + + switch (Type) { + case HEAP_EXTDATA_TYPE_BIOS_SPEC_VER: + /// + /// Fill BIOS spec ver element + /// + Element = AllocatePool (sizeof (HEAP_BIOS_SPEC_VER_ELEMENT)); + + if (Element != NULL) { + *Size = sizeof (HEAP_BIOS_SPEC_VER_ELEMENT); + ((HEAP_BIOS_SPEC_VER_ELEMENT *) Element)->Header.Type = HEAP_EXTDATA_TYPE_BIOS_SPEC_VER; + ((HEAP_BIOS_SPEC_VER_ELEMENT *) Element)->Header.Size = sizeof (HEAP_BIOS_SPEC_VER_ELEMENT); + ((HEAP_BIOS_SPEC_VER_ELEMENT *) Element)->SpecVerMajor = TXT_BIOS_SPEC_VER_MAJOR; + ((HEAP_BIOS_SPEC_VER_ELEMENT *) Element)->SpecVerMinor = TXT_BIOS_SPEC_VER_MINOR; + ((HEAP_BIOS_SPEC_VER_ELEMENT *) Element)->SpecVerRevision = TXT_BIOS_SPEC_VER_REVISION; + } + break; + + case HEAP_EXTDATA_TYPE_BIOSACM: + /// + /// Fill BIOS ACM element + /// + Element = AllocatePool (sizeof (HEAP_BIOSACM_ELEMENT) + NumberOfAcm * sizeof (UINT64)); + + if (Element != NULL) { + *Size = sizeof (HEAP_BIOSACM_ELEMENT) + sizeof (UINT64) * NumberOfAcm; + ((HEAP_BIOSACM_ELEMENT *) Element)->Header.Type = HEAP_EXTDATA_TYPE_BIOSACM; + ((HEAP_BIOSACM_ELEMENT *) Element)->Header.Size = sizeof (HEAP_BIOSACM_ELEMENT) + NumberOfAcm * sizeof (UINT64); + ((HEAP_BIOSACM_ELEMENT *) Element)->NumAcms = NumberOfAcm; + AcmBase = (UINT64 *) ((UINTN) Element + sizeof (HEAP_BIOSACM_ELEMENT)); + *AcmBase = TxtDxeCtx->TxtInfoData->BiosAcmBase; + } + break; + + case HEAP_EXTDATA_TYPE_END: + /// + /// Fill end type element + /// + Element = AllocatePool (sizeof (HEAP_EXT_DATA_ELEMENT)); + + if (Element != NULL) { + *Size = sizeof (HEAP_EXT_DATA_ELEMENT); + ((HEAP_EXT_DATA_ELEMENT *) Element)->Type = HEAP_EXTDATA_TYPE_END; + ((HEAP_EXT_DATA_ELEMENT *) Element)->Size = sizeof (HEAP_EXT_DATA_ELEMENT); + } + break; + + default: + break; + } + + if (Element != NULL) { + CopyMem (Buffer, Element, *Size); + FreePool (Element); + } +} + +/** + Allocates 1 MB of 1MB-aligned memory for use as TXT Device Memory. Records + the location of TXT Device Memory in TXT Chipset registers and then adds + programming instructions for these registers into BootScript. + + @param[in] TxtDxeCtx - A pointer to an initialized TXT DXE Context data structure + + @retval EFI_SUCCESS - TXT Device memory has been successfully initialized. + @exception EFI_UNSUPPORTED - TXT Device memory not available. +**/ +EFI_STATUS +SetupTxtDeviceMemory ( + IN TXT_DXE_LIB_CONTEXT *TxtDxeCtx + ) +{ + EFI_PHYSICAL_ADDRESS TopAddr; + UINT64 *Ptr64; + UINT64 Value64; + UINT32 Value32; + UINT64 TxtHeapMemoryBase; + UINT64 TxtSinitMemoryBase; + BOOLEAN Locked; + BIOS_OS_DATA_REGION *BiosOsDataRegion; + TXT_INFO_DATA *TxtInfoData; + UINT8 *Ptr8; + + TxtHeapMemoryBase = 0; + TxtSinitMemoryBase = 0; + Locked = FALSE; + Ptr8 = NULL; + Value32 = 0; + + TxtInfoData = TxtDxeCtx->TxtInfoData; + + if ((TxtInfoData == 0) || + (TxtInfoData->TxtDprMemoryBase == 0) || + (TxtInfoData->TxtDprMemorySize == 0) || + (TxtInfoData->TxtHeapMemorySize == 0) || + (TxtInfoData->SinitMemorySize == 0) + ) { + return EFI_UNSUPPORTED; + } else { + /// + /// Use address passed from PEI + /// + TopAddr = TxtInfoData->TxtDprMemoryBase + TxtInfoData->TxtDprMemorySize; + + TxtHeapMemoryBase = (UINT64) (TopAddr - TxtInfoData->TxtHeapMemorySize); + + TxtSinitMemoryBase = TxtHeapMemoryBase - TxtInfoData->SinitMemorySize; + } + /// + /// Program TXT Device Memory Chipset Registers and record them in + /// BootScript so they will be saved and restored on S3 + /// + ASSERT ((TopAddr & 0x0FFFFF) == 0); + + /// + /// DPR registers + /// + Ptr64 = (UINT64 *) (UINTN) (TXT_PUBLIC_BASE + TXT_DPR_SIZE_REG_OFF); + Value64 = RShiftU64 (TxtInfoData->TxtDprMemorySize, 16) | 1; + *Ptr64 = Value64 | TopAddr; + /// + /// Assert error if programmed value is different from requested. This + /// means error is requested size. + /// + Value64 = *Ptr64; + ASSERT ((LShiftU64 ((Value64 & 0xFFE), 16)) == TxtInfoData->TxtDprMemorySize); + + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINT64) (UINTN) (Ptr64), + 2, + &Value64 + ); + + /// + /// HEAP Registers + /// Program size register first + /// + Ptr64 = (UINT64 *) (UINTN) (TXT_PUBLIC_BASE + TXT_HEAP_SIZE_REG_OFF); + + /// + /// Test register locked status. If locked, skip programming since + /// this will be done by BIOS ACM + /// + *Ptr64 = TEST_PATTERN; + Value64 = *Ptr64; + if (Value64 != TEST_PATTERN) { + Locked = TRUE; + } else { + /// + /// To be safe invert pattern and try again + /// + *Ptr64 = (UINT64) ~TEST_PATTERN; + Value64 = *Ptr64; + if (Value64 != (UINT64) ~TEST_PATTERN) { + Locked = TRUE; + } + } + + if (!Locked) { + + *Ptr64 = TxtInfoData->TxtHeapMemorySize; + /// + /// Assert error if programmed value is different from requested. This + /// means error is requested size. + /// + Value64 = *Ptr64; + ASSERT (Value64 == TxtInfoData->TxtHeapMemorySize); + + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINT64) (UINTN) (Ptr64), + 2, + &Value64 + ); + + /// + /// Program base register. + /// + Ptr64 = (UINT64 *) (UINTN) (TXT_PUBLIC_BASE + TXT_HEAP_BASE_REG_OFF); + *Ptr64 = TxtHeapMemoryBase; + + /// + /// Assert error if programmed value is different from requested. This + /// means error is requested size. + /// + Value64 = *Ptr64; + ASSERT (Value64 == TxtHeapMemoryBase); + + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINT64) (UINTN) (Ptr64), + 2, + &Value64 + ); + } + /// + /// SINIT Registers + /// Program size register first + /// + Ptr64 = (UINT64 *) (UINTN) (TXT_PUBLIC_BASE + TXT_SINIT_SIZE_REG_OFF); + *Ptr64 = TxtInfoData->SinitMemorySize; + /// + /// Assert error if programmed value is different from requested. This + /// means error is requested size. + /// + Value64 = *Ptr64; + ASSERT (Value64 == TxtInfoData->SinitMemorySize); + + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINT64) (UINTN) (Ptr64), + 2, + &Value64 + ); + + /// + /// Program base register + /// + Ptr64 = (UINT64 *) (UINTN) (TXT_PUBLIC_BASE + TXT_SINIT_BASE_REG_OFF); + *Ptr64 = TxtSinitMemoryBase; + /// + /// Assert error if programmed value is different from requested. This + /// means error is requested size. + /// + Value64 = *Ptr64; + ASSERT (Value64 == TxtSinitMemoryBase); + + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINT64) (UINTN) (Ptr64), + 2, + &Value64 + ); + + /// + /// Make sure TXT Device Memory has been zeroed + /// + ZeroMem ( + (VOID *) ((UINTN) TxtSinitMemoryBase), + (UINTN) (TopAddr - TxtSinitMemoryBase) + ); + + if (TxtInfoData->TgaSize) { + ; + /// + /// Placeholder for Trusted graphics support + /// + } + + Ptr64 = (UINT64 *) TxtHeapMemoryBase; + *Ptr64 = sizeof (BIOS_OS_DATA_REGION); + /// + /// BiosOsDataSize plus sizew of data size feld itself + /// + BiosOsDataRegion = (BIOS_OS_DATA_REGION *) (Ptr64 + 1); + BiosOsDataRegion->Version = BIOS_OS_DATAREGION_VERSION; + BiosOsDataRegion->BiosSinitSize = 0; + BiosOsDataRegion->LcpPdBase = TxtInfoData->TxtLcpPdBase; + BiosOsDataRegion->LcpPdSize = TxtInfoData->TxtLcpPdSize; + BiosOsDataRegion->NumOfLogicalProcessors = (UINT32) (TxtDxeCtx->CpuCount); + BiosOsDataRegion->Flags = TxtInfoData->Flags; + Ptr8 = (UINT8 *) (UINTN) &(BiosOsDataRegion->ExtData); + AppendElement (TxtDxeCtx, HEAP_EXTDATA_TYPE_BIOS_SPEC_VER, Ptr8, &Value32); + Ptr8 += Value32; + AppendElement (TxtDxeCtx, HEAP_EXTDATA_TYPE_BIOSACM, Ptr8, &Value32); + Ptr8 += Value32; + AppendElement (TxtDxeCtx, HEAP_EXTDATA_TYPE_END, Ptr8, &Value32); + Value64 = (UINT64) Ptr8 - TxtHeapMemoryBase + Value32; + *Ptr64 = Value64; + + return EFI_SUCCESS; +} + +/** + Adds and allocates architecturally defined TXT Configuration Space memory + region to GCD. + + @param[in] TxtDxeCtx - A pointer to an initialized TXT DXE Context data structure + + @retval EFI_SUCCESS - Always. +**/ +EFI_STATUS +ReserveTxtConfigSpace ( + IN TXT_DXE_LIB_CONTEXT *TxtDxeCtx + ) +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS BaseAddr; + + BaseAddr = TXT_PRIVATE_BASE; + Status = gDS->AddMemorySpace ( + EfiGcdMemoryTypeReserved, + TXT_PRIVATE_BASE, + TXT_CONFIG_SPACE_LENGTH, + 0 + ); + + ASSERT_EFI_ERROR (Status); + + Status = gDS->AllocateMemorySpace ( + EfiGcdAllocateAddress, + EfiGcdMemoryTypeReserved, + 12, ///< 4K Boundary + TXT_CONFIG_SPACE_LENGTH, + &BaseAddr, + TxtDxeCtx->ImageHandle, + NULL + ); + ASSERT_EFI_ERROR (Status); + + return EFI_SUCCESS; +} + +/** + Invokes TxtDxeLibLaunchBiosAcm to execute the SCHECK function. + + @param[in] TxtDxeCtx - A pointer to an initialized TXT DXE Context data structure + + @retval EFI_SUCCESS - Always. +**/ +EFI_STATUS +DoScheck ( + IN TXT_DXE_LIB_CONTEXT *TxtDxeCtx + ) +{ + return TxtDxeLibLaunchBiosAcm (TxtDxeCtx, TXT_LAUNCH_SCHECK); +} + +/** + Invokes TxtDxeLibLaunchBiosAcm to reset the TPM's establishment bit. + + @param[in] TxtDxeCtx - A pointer to an initialized TXT DXE Context data structure + + @retval EFI_SUCCESS - Always. +**/ +EFI_STATUS +ResetTpmEstBit ( + IN TXT_DXE_LIB_CONTEXT *TxtDxeCtx + ) +{ + return TxtDxeLibLaunchBiosAcm (TxtDxeCtx, TXT_RESET_EST_BIT); +} + +/** + Sets up the system and then launches the TXT BIOS ACM to run the function + requested by AcmFunction. + + @param[in] AcmFunction - Constant that represents the function from the BIOS ACM + that should be executed. + @param[in] TxtDxeCtx - A pointer to an initialized TXT DXE Context data structure + + @retval EFI_SUCCESS - BIOS ACM is set up. + @retval EFI_INVALID_PARAMETER - Wrong data in TxtInfoHob. + @retval EFI_NOT_FOUND - BIOS ACM is not found +**/ +EFI_STATUS +TxtDxeLibLaunchBiosAcm ( + IN TXT_DXE_LIB_CONTEXT *TxtDxeCtx, + IN UINT64 AcmFunction + ) +{ + EFI_STATUS Status; + EFI_TPL OldTpl; + UINTN CpuCount; + UINTN MyCpuNumber; + UINTN Index; + UINTN i; + EFI_MP_SERVICES_PROTOCOL *MpService; + + UINTN NoHandles; + EFI_HANDLE *Buffer; + UINTN Size; + UINT32 FvStatus; + EFI_FV_FILETYPE FileType; + EFI_FIRMWARE_VOLUME_PROTOCOL *FwVol; + EFI_FV_FILE_ATTRIBUTES Attributes; + UINTN NumPages; + EFI_PHYSICAL_ADDRESS Addr; + EFI_PHYSICAL_ADDRESS AlignedAddr; + + FwVol = NULL; + /// + /// Initialize local variables + /// + CpuCount = TxtDxeCtx->CpuCount; + MpService = TxtDxeCtx->MpService; + Size = 0; + FvStatus = 0; + NumPages = 0; + Addr = 0; + + if (TxtDxeCtx->TxtInfoData == NULL) { + return EFI_INVALID_PARAMETER; + } + /// + /// Get current running CPU number + /// + Status = MpService->WhoAmI ( + MpService, + &MyCpuNumber + ); + ASSERT_EFI_ERROR (Status); + + if ((TxtDxeCtx->TxtInfoData->BiosAcmBase == 0) || (TxtDxeCtx->TxtInfoData->BiosAcmSize == 0)) { + /// + /// If no information about placement of TXT BIOS ACM has been + /// passed from PEI - find it and load into memory dynamically. + /// + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiFirmwareVolumeProtocolGuid, + NULL, + &NoHandles, + &Buffer + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + for (i = 0; i < NoHandles; i++) { + + Status = gBS->HandleProtocol ( + Buffer[i], + &gEfiFirmwareVolumeProtocolGuid, + (VOID **) &FwVol + ); + + ASSERT_EFI_ERROR (Status); + + /// + /// No output buffer - get size only + /// + Status = FwVol->ReadFile ( + FwVol, + &mTxtBiosAcmPeiFileGuid, + NULL, + &Size, + &FileType, + &Attributes, + &FvStatus + ); + if (Status == EFI_SUCCESS) { + break; + } + } + + ASSERT (Size); + /// + /// Assert if file not found. + /// + FreePool (Buffer); + + if (FwVol == NULL) { + return EFI_NOT_FOUND; + } + /// + /// Allocate 4K aligned memory to load BIOS ACM. For this allocate + /// 1 page more than BIOS ACM size. + /// + NumPages = (Size + EFI_PAGE_SIZE - 1) / EFI_PAGE_SIZE; + + /// + /// Allocate buffer for BIOS ACM + /// + Status = (gBS->AllocatePages) (AllocateAnyPages, EfiRuntimeServicesData, NumPages, &Addr); + + ASSERT_EFI_ERROR (Status); + + AlignedAddr = Addr &~(EFI_PAGE_SIZE - 1); + AlignedAddr = AlignedAddr < Addr ? (AlignedAddr + EFI_PAGE_SIZE) : AlignedAddr; + + /// + /// Read BIOS ACM into prepared buffer. + /// + Status = FwVol->ReadFile ( + FwVol, + &mTxtBiosAcmPeiFileGuid, + ((VOID **) &AlignedAddr), + &Size, + &FileType, + &Attributes, + &FvStatus + ); + } else { + /// + /// Use address passed from PEI + /// + AlignedAddr = TxtDxeCtx->TxtInfoData->BiosAcmBase; + } + /// + /// Save AP configuration. Run on one AP since all must be programmed + /// identically + /// + MpService->StartupThisAP ( + MpService, + (EFI_AP_PROCEDURE) ApSaveConfig, + 1, + NULL, + 0, + NULL + ); + + /// + /// Initialize APs. Prepare data for DoApInit + /// + mAcmBase = AlignedAddr; + mMcuAddr = TxtDxeCtx->TxtInfoData->McuUpdateDataAddr; + + DisableSmiSources (TxtDxeCtx, TRUE); + +#if defined(TXT_RLP_INIT) && (TXT_RLP_INIT == 1) + /// + /// Execute DoApInit on every AP + /// + MpService->StartupAllAPs ( + MpService, + (EFI_AP_PROCEDURE) DoApInit, + TRUE, + NULL, + MP_TIMEOUT_FOR_STARTUP_ALL_APS, + NULL, + NULL + ); +#endif + /// + /// Disable every AP and put in WFS state + /// + for (Index = 0; Index < CpuCount; Index++) { + if (Index != MyCpuNumber) { + /// + /// Halt CPU otherwise it will not be re-enabled + /// + Status = MpService->EnableDisableAP ( + MpService, + Index, + FALSE, + NULL + ); + ASSERT_EFI_ERROR (Status); + + Status = MpService->SendIPI ( + MpService, + Index, + 0, + DELIVERY_MODE_INIT + ); + ASSERT_EFI_ERROR (Status); + } + } + /// + /// Launch the BIOS ACM to run the requested function + /// + OldTpl = gBS->RaiseTPL (EFI_TPL_HIGH_LEVEL); + + LaunchBiosAcm (AlignedAddr, AcmFunction); + + gBS->RestoreTPL (OldTpl); + + /// + /// Free memory only if it was allocated + /// + if (Addr != 0) { + (gBS->FreePages)(Addr, NumPages); + } + /// + /// Restart APs + /// + for (Index = 0; Index < CpuCount; Index++) { + if (Index != MyCpuNumber) { + Status = MpService->EnableDisableAP ( + MpService, + Index, + TRUE, + NULL + ); + ASSERT_EFI_ERROR (Status); + } + } + /// + /// Restore AP configuration + /// + Status = MpService->StartupAllAPs ( + MpService, + (EFI_AP_PROCEDURE) ApRestoreConfig, + TRUE, + NULL, + MP_TIMEOUT_FOR_STARTUP_ALL_APS, + NULL, + NULL + ); + + ASSERT_EFI_ERROR (Status); + + DisableSmiSources (TxtDxeCtx, FALSE); + + return EFI_SUCCESS; +} + +/** + Disable or restore possible SMI sources before or after POST SCHECK + + @param[in] TxtDxeCtx - A pointer to an initialized TXT DXE Context data structure + @param[in] Operation - Boolean value telling what operation is requested: + TRUE - to save and then disable possible SMI sources + FALSE - to restore original SMI settings + + @retval EFI_SUCCESS - always return EFI_SUCCESS +**/ +EFI_STATUS +DisableSmiSources ( + IN TXT_DXE_LIB_CONTEXT *TxtDxeCtx, + IN BOOLEAN Operation + ) +{ + EFI_STATUS Status; + UINT64 GlobalSmiControlIoAddr; + UINT32 LocalApicBaseAddr; + static UINT64 SavedIa32ThermInterruptMSR; + static UINT32 SavedSmiControl; + static UINT32 SavedApicThermalValue; + BOOLEAN x2ApicEnabled; + + x2ApicEnabled = (BOOLEAN) (((AsmReadMsr64 (MSR_IA32_APIC_BASE)) & (BIT11 + BIT10)) == BIT11 + BIT10); + GlobalSmiControlIoAddr = TxtDxeCtx->TxtInfoData->PmBase + 0x30; + LocalApicBaseAddr = ((UINT32) AsmReadMsr64 (MSR_IA32_APIC_BASE)) & BASE_ADDR_MASK; + + if (Operation == TRUE) { + /// + /// Save IA32_THERMAL_INTERRUPT MSR and disable the interrupts + /// + SavedIa32ThermInterruptMSR = AsmReadMsr64 ((UINT32) IA32_THERM_INTERRUPT); + AsmWriteMsr64 ( + (UINT32) IA32_THERM_INTERRUPT, + (UINT64) (SavedIa32ThermInterruptMSR &~(BIT0 + BIT1 + BIT2 + BIT4 + BIT15 + BIT23)) + ); + /// + /// Save THERMAL LVT in local APIC and mask THERMAL LVT + /// + if (x2ApicEnabled) { + SavedApicThermalValue = (UINT32) AsmReadMsr64 (MSR_EXT_XAPIC_LVT_THERM); + AsmWriteMsr64 ( + MSR_EXT_XAPIC_LVT_THERM, + ((SavedApicThermalValue &~(B_INTERRUPT_MASK | B_DELIVERY_MODE | B_VECTOR)) | (B_INTERRUPT_MASK | V_MODE_SMI)) + ); + } else { + SavedApicThermalValue = *(UINT32 *) (UINTN) (LocalApicBaseAddr + LOCAL_APIC_THERMAL_DEF); + *(UINT32 *) (UINTN) (LocalApicBaseAddr + LOCAL_APIC_THERMAL_DEF) = (UINT32) ((SavedApicThermalValue &~(B_INTERRUPT_MASK | B_DELIVERY_MODE | B_VECTOR)) | (B_INTERRUPT_MASK | V_MODE_SMI)); + } + /// + /// Save SMI control register and try to disable all SMIs indivitually. + /// + SavedSmiControl = IoRead32 ((UINTN) GlobalSmiControlIoAddr); + /// + /// We can not disable Global SMI since it should be locked after SCHECK. we can only disable SMI sources indivitually. + /// Call to TxtDxeOemDisableSmi() for platform specific SMIs. + /// + Status = TxtDxeOemDisableSmi (TxtDxeCtx, TRUE); + ASSERT_EFI_ERROR (Status); + + IoWrite32 ( + (UINTN) GlobalSmiControlIoAddr, + (UINT32) (SavedSmiControl & 0x01) + ); + } else { + /// + /// We can not disable Global SMI since it should be locked after SCHECK. we can only disable SMI sources indivitually. + /// Restore original SMI setting after SCHECK + /// Call to TxtDxeOemDisableSmi() for platform specific SMIs. + /// + Status = TxtDxeOemDisableSmi (TxtDxeCtx, FALSE); + ASSERT_EFI_ERROR (Status); + + IoWrite32 ( + (UINTN) GlobalSmiControlIoAddr, + (UINT32) (SavedSmiControl) + ); + /// + /// Restore IA32_THERMAL_INTERRUPT MSR + /// + AsmWriteMsr64 ( + (UINT32) IA32_THERM_INTERRUPT, + (UINT64) SavedIa32ThermInterruptMSR + ); + if (x2ApicEnabled) { + AsmWriteMsr64 (MSR_EXT_XAPIC_LVT_THERM, SavedApicThermalValue); + } else { + *(UINT32 *) (UINTN) (LocalApicBaseAddr + LOCAL_APIC_THERMAL_DEF) = (UINT32) SavedApicThermalValue; + + } + } + + return EFI_SUCCESS; +} + +/** + Read policy protocol to reset AUX content + + @param[in] TxtDxeCtx - A pointer to an initialized TXT DXE Context data structure + + @retval EFI_SUCCESS - No error happend + @retval EFI_NOT_FOUND - TxtPolicyProtocol is not found +**/ +EFI_STATUS +ResetTpmAux ( + IN TXT_DXE_LIB_CONTEXT *TxtDxeCtx + ) +{ + EFI_STATUS Status; + + Status = EFI_SUCCESS; + + /// + /// Check if TxtPolicy protocol installed + /// + if (TxtDxeCtx->CpuPlatformPolicy == NULL) { + return EFI_NOT_FOUND; + } + /// + /// + /// + if (TxtDxeCtx->CpuPlatformPolicy->SecurityConfig->TxtFunctionConfig->ResetAux == 1) { + DEBUG ((EFI_D_INFO, "TXTDXE: Reset AUX content\n")); + Status = TxtDxeLibLaunchBiosAcm (TxtDxeCtx, TXT_RESET_AUX); + } + + return Status; +} |