983 lines
29 KiB
C
983 lines
29 KiB
C
/** @file
|
|
This file contains an implementation of the function call interfaces
|
|
required by the main TXT DXE file. Future platform porting
|
|
tasks should be mostly limited to modifying the functions in this file.
|
|
|
|
@copyright
|
|
INTEL CONFIDENTIAL
|
|
Copyright 1999 - 2020 Intel Corporation.
|
|
|
|
The source code contained or described herein and all documents related to the
|
|
source code ("Material") are owned by Intel Corporation or its suppliers or
|
|
licensors. Title to the Material remains with Intel Corporation or its suppliers
|
|
and licensors. The Material may contain trade secrets and proprietary and
|
|
confidential information of Intel Corporation and its suppliers and licensors,
|
|
and is protected by worldwide copyright and trade secret laws and treaty
|
|
provisions. No part of the Material may be used, copied, reproduced, modified,
|
|
published, uploaded, posted, transmitted, distributed, or disclosed in any way
|
|
without Intel's prior express written permission.
|
|
|
|
No license under any patent, copyright, trade secret or other intellectual
|
|
property right is granted to or conferred upon you by disclosure or delivery
|
|
of the Materials, either expressly, by implication, inducement, estoppel or
|
|
otherwise. Any license under such intellectual property rights must be
|
|
express and approved by Intel in writing.
|
|
|
|
Unless otherwise agreed by Intel in writing, you may not remove or alter
|
|
this notice or any other notice embedded in Materials by Intel or
|
|
Intel's suppliers or licensors in any way.
|
|
|
|
This file contains an 'Intel Peripheral Driver' and is 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.
|
|
|
|
@par Specification Reference:
|
|
**/
|
|
|
|
#include <CpuRegs.h>
|
|
#include <Txt.h>
|
|
#include "TxtDxeLib.h"
|
|
#include <Library/BaseLib.h>
|
|
#include <Library/HobLib.h>
|
|
#include <Library/S3BootScriptLib.h>
|
|
#include <Library/DxeServicesTableLib.h>
|
|
#include <Library/PcdLib.h>
|
|
#include <Library/LocalApicLib.h>
|
|
#include <Register/Intel/LocalApic.h>
|
|
#include <Protocol/FirmwareVolume2.h>
|
|
#include <Library/PmcLib.h>
|
|
#include <Register/PmcRegs.h>
|
|
#include <Register/CommonMsr.h>
|
|
|
|
|
|
GLOBAL_REMOVE_IF_UNREFERENCED UINT64 mAcmBase;
|
|
GLOBAL_REMOVE_IF_UNREFERENCED UINT64 mApMtrrTab[2 * ((MSR_IA32_MTRR_PHYSMASK9 - MSR_IA32_MTRR_PHYSBASE0 + 1) + 1) ];
|
|
GLOBAL_REMOVE_IF_UNREFERENCED UINT64 mApIdt[2];
|
|
GLOBAL_REMOVE_IF_UNREFERENCED UINT64 mApCr4;
|
|
GLOBAL_REMOVE_IF_UNREFERENCED UINT64 mApSavedIa32ThermInterruptMSR[2];
|
|
GLOBAL_REMOVE_IF_UNREFERENCED 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_NOT_FOUND - 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;
|
|
|
|
TxtDxeCtx->ImageHandle = ImageHandle;
|
|
TxtDxeCtx->SystemTable = SystemTable;
|
|
|
|
///
|
|
/// Find the MpService Protocol
|
|
///
|
|
Status = gBS->LocateProtocol (
|
|
&gEfiMpServiceProtocolGuid,
|
|
NULL,
|
|
(VOID **) &(TxtDxeCtx->MpService)
|
|
);
|
|
|
|
ASSERT_EFI_ERROR (Status);
|
|
///
|
|
/// Initialize CpuCount info. Current implemetation of
|
|
/// GetNumberOfProcessors doesn't honor optionality of arguments. Don't use
|
|
/// NULL pointers.
|
|
///
|
|
Status = TxtDxeCtx->MpService->GetNumberOfProcessors (
|
|
TxtDxeCtx->MpService,
|
|
&(TxtDxeCtx->CpuCount),
|
|
&tmp
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
///
|
|
/// Find TxtInfoHob
|
|
///
|
|
HobList = GetFirstGuidHob (&gTxtInfoHobGuid);
|
|
if (HobList == NULL) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
TxtInfoHob = (TXT_INFO_HOB *) HobList;
|
|
TxtDxeCtx->TxtInfoData = &(TxtInfoHob->Data);
|
|
|
|
///
|
|
/// Print out the TxtInfo HOB
|
|
///
|
|
DEBUG ((DEBUG_INFO, "TXTDXE: TxtInfoHob passed from platform as:\n"));
|
|
DEBUG ((DEBUG_INFO, "TXTDXE: ChipsetIsTxtCapable = %x\n", TxtDxeCtx->TxtInfoData->ChipsetIsTxtCapable));
|
|
DEBUG ((DEBUG_INFO, "TXTDXE: TxtMode = %x\n", TxtDxeCtx->TxtInfoData->TxtMode));
|
|
DEBUG ((DEBUG_INFO, "TXTDXE: ResetAux = %x\n", TxtDxeCtx->TxtInfoData->ResetAux));
|
|
DEBUG ((DEBUG_INFO, "TXTDXE: AcpiBase = %x\n", TxtDxeCtx->TxtInfoData->AcpiBase));
|
|
DEBUG ((DEBUG_INFO, "TXTDXE: SinitMemorySize = %x\n", TxtDxeCtx->TxtInfoData->SinitMemorySize));
|
|
DEBUG ((DEBUG_INFO, "TXTDXE: TxtHeapMemorySize = %x\n", TxtDxeCtx->TxtInfoData->TxtHeapMemorySize));
|
|
DEBUG ((DEBUG_INFO, "TXTDXE: TxtDprMemoryBase = %x\n", TxtDxeCtx->TxtInfoData->TxtDprMemoryBase));
|
|
DEBUG ((DEBUG_INFO, "TXTDXE: TxtDprMemorySize = %x\n", TxtDxeCtx->TxtInfoData->TxtDprMemorySize));
|
|
DEBUG ((DEBUG_INFO, "TXTDXE: BiosAcmBase = %x\n", TxtDxeCtx->TxtInfoData->BiosAcmBase));
|
|
DEBUG ((DEBUG_INFO, "TXTDXE: BiosAcmSize = %x\n", TxtDxeCtx->TxtInfoData->BiosAcmSize));
|
|
DEBUG ((DEBUG_INFO, "TXTDXE: SinitAcmBase = %x\n", TxtDxeCtx->TxtInfoData->SinitAcmBase));
|
|
DEBUG ((DEBUG_INFO, "TXTDXE: SinitAcmSize = %x\n", TxtDxeCtx->TxtInfoData->SinitAcmSize));
|
|
DEBUG ((DEBUG_INFO, "TXTDXE: TgaSize = %x\n", TxtDxeCtx->TxtInfoData->TgaSize));
|
|
DEBUG ((DEBUG_INFO, "TXTDXE: TxtLcpPdBase = %x\n", TxtDxeCtx->TxtInfoData->TxtLcpPdBase));
|
|
DEBUG ((DEBUG_INFO, "TXTDXE: TxtLcpPdSize = %x\n", TxtDxeCtx->TxtInfoData->TxtLcpPdSize));
|
|
DEBUG ((DEBUG_INFO, "TXTDXE: Flags = %x\n", TxtDxeCtx->TxtInfoData->Flags));
|
|
DEBUG ((DEBUG_INFO, "TXTDXE: CpuCount = %x\n", TxtDxeCtx->CpuCount));
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
This routine is a dummy return function required when waking APs from WFS.
|
|
**/
|
|
|
|
VOID
|
|
EFIAPI
|
|
DummyWakupFunc (
|
|
IN OUT VOID *Buffer
|
|
)
|
|
{
|
|
return;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
IsSptPtt (
|
|
VOID
|
|
)
|
|
{
|
|
UINT32 RegRead;
|
|
|
|
RegRead = MmioRead32 (TXT_PUBLIC_BASE + TXT_PTT_FTIF_OFF);
|
|
DEBUG ((DEBUG_INFO, "IsSptPtt: LT FTIF = %x\n", RegRead));
|
|
RegRead = RegRead & TXT_PTT_PRESENT;
|
|
if (RegRead == TXT_PTT_PRESENT) {
|
|
DEBUG ((DEBUG_INFO, "IsSptPtt: PTT cycle\n"));
|
|
return TRUE;
|
|
} else {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
/**
|
|
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
|
|
)
|
|
{
|
|
UINT8 AccessReg;
|
|
UINT16 TimeOutCount;
|
|
|
|
///
|
|
/// TO-DO: We might locate TCG protocol to access TPM status
|
|
///
|
|
if (IsSptPtt ()) {
|
|
return FALSE;
|
|
}
|
|
|
|
///
|
|
/// Set TPM.ACCESS polling timeout about 750ms
|
|
///
|
|
TimeOutCount = TPM_TIME_OUT;
|
|
do {
|
|
///
|
|
/// Read TPM status register
|
|
///
|
|
AccessReg = MmioRead8 ((UINT64) TPM_STATUS_REG_ADDRESS);
|
|
///
|
|
/// 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
|
|
///
|
|
MicroSecondDelay (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 ((DEBUG_ERROR, "TXTDXE: TPM Valid Status is not set!! TPM.ACCESS=%x\n", AccessReg));
|
|
ASSERT (FALSE);
|
|
CpuDeadLoop ();
|
|
}
|
|
///
|
|
/// 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 POISON bit is set in status register
|
|
|
|
@param[in] TxtDxeCtx - A pointer to an initialized TXT DXE Context data structure
|
|
|
|
@retval TRUE - If the TPM reset bit is asserted.
|
|
@retval FALSE - If the TPM reset bit is unasserted.
|
|
**/
|
|
BOOLEAN
|
|
IsTxtResetSet (
|
|
IN TXT_DXE_LIB_CONTEXT *TxtDxeCtx
|
|
)
|
|
{
|
|
UINT8 EstsReg;
|
|
|
|
///
|
|
/// TO-DO: We might locate TCG protocol to access TPM status
|
|
///
|
|
if (IsSptPtt ()) {
|
|
return FALSE;
|
|
}
|
|
|
|
///
|
|
/// Read TPM status register
|
|
///
|
|
EstsReg = MmioRead8 ((UINT64) TXT_PUBLIC_BASE + TXT_ERROR_STATUS_REG_OFF);
|
|
|
|
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);
|
|
DEBUG ((DEBUG_INFO, "TXTDXE: MSR_IA32_FEATURE_CONTROL=%x\n", Ia32FeatureControl));
|
|
|
|
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
|
|
)
|
|
{
|
|
CPUID_VERSION_INFO_ECX Ecx;
|
|
|
|
AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, &Ecx.Uint32, NULL);
|
|
|
|
DEBUG ((DEBUG_INFO, "TXTDXE: CPUID = %x\n", Ecx.Uint32));
|
|
|
|
return (BOOLEAN) (Ecx.Bits.SMX == 1);
|
|
}
|
|
|
|
/**
|
|
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.
|
|
**/
|
|
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);
|
|
|
|
S3BootScriptSaveMemWrite (
|
|
S3BootScriptWidthUint32,
|
|
(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);
|
|
|
|
S3BootScriptSaveMemWrite (
|
|
S3BootScriptWidthUint32,
|
|
(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);
|
|
|
|
S3BootScriptSaveMemWrite (
|
|
S3BootScriptWidthUint32,
|
|
(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);
|
|
|
|
S3BootScriptSaveMemWrite (
|
|
S3BootScriptWidthUint32,
|
|
(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);
|
|
|
|
S3BootScriptSaveMemWrite (
|
|
S3BootScriptWidthUint32,
|
|
(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 = 0;
|
|
if (BiosOsDataRegion->Version >= 6) { // From CBNT, version = 6
|
|
// Note: BiosOsDataRegion->Flags is 64 bit : MLE flags (32:63) | SINIT flags (0:31)
|
|
// offset 28: SINTIFlags - currently none defined (0)
|
|
// offset 32: Version >=5 with updates in Version 6
|
|
// MLE flags Field:
|
|
// Bit [0] TXT/VT-x/VT-d ACPI PPI specification
|
|
// Bit [2:1]:
|
|
// 00: legacy state / platform undefined
|
|
// 01: client platform, client SINIT is required
|
|
// 10: server platform, server SINIT is required
|
|
// 11: Reserved/illegal, must be ignored
|
|
// MSR_BOOT_GUARD_SACM_INFO 0x13A [Bit 34 - LT_SX_FUSE] : 1 = server, 0 = client
|
|
if ((AsmReadMsr64 (MSR_BOOT_GUARD_SACM_INFO) & BIT34) == 0) {
|
|
BiosOsDataRegion->Flags = ((UINT64)BIT1 << 32);
|
|
} else {
|
|
BiosOsDataRegion->Flags = ((UINT64)BIT2 << 32);
|
|
}
|
|
}
|
|
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;
|
|
}
|
|
|
|
/**
|
|
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 NumberOfProcessors;
|
|
UINTN NumberOfEnabledProcessors;
|
|
UINTN CpuCount;
|
|
UINTN MyCpuNumber;
|
|
UINTN Index;
|
|
EFI_MP_SERVICES_PROTOCOL *MpService;
|
|
EFI_PHYSICAL_ADDRESS AlignedAddr;
|
|
EFI_PROCESSOR_INFORMATION ProcContext;
|
|
UINT8 *ValidProcList;
|
|
|
|
///
|
|
/// Initialize local variables
|
|
///
|
|
CpuCount = TxtDxeCtx->CpuCount;
|
|
MpService = TxtDxeCtx->MpService;
|
|
AlignedAddr = 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 - assert.
|
|
///
|
|
DEBUG ((DEBUG_ERROR, "TXTDXE: BiosAcmBase and BiosAcmSize = 0 from HOB, can not load\n"));
|
|
ASSERT (FALSE);
|
|
return EFI_NOT_FOUND;
|
|
} else {
|
|
///
|
|
/// Use address passed from PEI
|
|
///
|
|
AlignedAddr = TxtDxeCtx->TxtInfoData->BiosAcmBase;
|
|
}
|
|
|
|
Status = MpService->GetNumberOfProcessors (MpService, &NumberOfProcessors, &NumberOfEnabledProcessors);
|
|
if (EFI_ERROR (Status)) {
|
|
///
|
|
/// If unable to retrieve the Number of Processors - assert.
|
|
///
|
|
DEBUG ((DEBUG_INFO, "TXTDXE: Unable to retrieve Number of Processors\n"));
|
|
ASSERT (FALSE);
|
|
return Status;
|
|
}
|
|
|
|
///
|
|
/// Check max cpu number
|
|
///
|
|
if (CpuCount > NumberOfProcessors) {
|
|
DEBUG ((DEBUG_ERROR, "TXTDXE: Unsupported configuration: Number of logical CPU =%d\n",CpuCount));
|
|
ASSERT (FALSE);
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
ValidProcList = AllocatePool (NumberOfProcessors * sizeof (UINT8));
|
|
if (ValidProcList == NULL){
|
|
///
|
|
/// If unable to allocate pool for ValidProcList - assert.
|
|
///
|
|
DEBUG ((DEBUG_INFO, "TXTDXE: ValidProcList = NULL\n"));
|
|
ASSERT (FALSE);
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
for (Index = 0; Index < NumberOfProcessors; Index ++) {
|
|
ValidProcList[Index] = 0;
|
|
}
|
|
|
|
///
|
|
/// Create a list of enabled processors (logical) and store it for future use.
|
|
///
|
|
for (Index = 0; Index < CpuCount; Index ++) {
|
|
Status = MpService->GetProcessorInfo (
|
|
MpService,
|
|
Index,
|
|
&ProcContext
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
///
|
|
/// If unable to Get Processor Information- assert.
|
|
///
|
|
DEBUG ((DEBUG_INFO, "TXTDXE: Unable to GetProcessorInfo\n"));
|
|
FreePool (ValidProcList);
|
|
ASSERT (FALSE);
|
|
return Status;
|
|
}
|
|
if (ProcContext.StatusFlag & PROCESSOR_ENABLED_BIT) {
|
|
ValidProcList[Index] = 1;
|
|
}
|
|
}
|
|
|
|
DisableSmiSources (TxtDxeCtx, TRUE);
|
|
|
|
///
|
|
/// Disable all enabled APs and put in WFS state
|
|
///
|
|
for (Index = 0; Index < CpuCount; Index++) {
|
|
if ((Index != MyCpuNumber) & (ValidProcList[Index])) {
|
|
///
|
|
/// Halt CPU otherwise it will not be re-enabled
|
|
///
|
|
DEBUG ((DEBUG_INFO, "TXTDXE: disable AP Index=%x\n", Index));
|
|
Status = MpService->EnableDisableAP (
|
|
MpService,
|
|
Index,
|
|
FALSE,
|
|
NULL
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
}
|
|
}
|
|
SendInitIpiAllExcludingSelf();
|
|
|
|
// Give the APs time to enter wait-for-SIPI state
|
|
MicroSecondDelay (10 * STALL_ONE_MILLI_SECOND);
|
|
|
|
///
|
|
/// Launch the BIOS ACM to run the requested function
|
|
///
|
|
DEBUG ((DEBUG_INFO, "TXTDXE::Running of LaunchBiosAcm\n"));
|
|
OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
|
|
LaunchBiosAcm (AlignedAddr, AcmFunction);
|
|
gBS->RestoreTPL (OldTpl);
|
|
|
|
///
|
|
/// Restart APs that were enabled before this function was called
|
|
///
|
|
for (Index = 0; Index < CpuCount; Index++) {
|
|
if ((Index != MyCpuNumber) & (ValidProcList[Index])) {
|
|
DEBUG ((DEBUG_INFO, "TXTDXE: restart AP Index=%x\n", Index));
|
|
Status = MpService->EnableDisableAP (
|
|
MpService,
|
|
Index,
|
|
TRUE,
|
|
NULL
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
}
|
|
}
|
|
|
|
DisableSmiSources (TxtDxeCtx, FALSE);
|
|
|
|
FreePool (ValidProcList);
|
|
|
|
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
|
|
)
|
|
{
|
|
UINT64 GlobalSmiControlIoAddr;
|
|
UINT32 LocalApicBaseAddr;
|
|
STATIC UINT64 SavedIa32ThermInterruptMSR;
|
|
STATIC UINT32 SavedSmiControl;
|
|
MSR_PIC_LVT_THERM_REGISTER MsrPicLvtTherm;
|
|
STATIC MSR_PIC_LVT_THERM_REGISTER SavedMsrPicLvtTherm;
|
|
BOOLEAN x2ApicEnabled;
|
|
|
|
|
|
//
|
|
// Sanity check. This callback must execute before SMI_LOCK is set.
|
|
//
|
|
if (PmcIsSmiLockSet ()) {
|
|
DEBUG ((DEBUG_ERROR, "TXTDXE: Unable to disable SMI sources\n"));
|
|
}
|
|
|
|
x2ApicEnabled = (BOOLEAN) (((AsmReadMsr64 (MSR_IA32_APIC_BASE)) & (BIT11 + BIT10)) == BIT11 + BIT10);
|
|
GlobalSmiControlIoAddr = TxtDxeCtx->TxtInfoData->AcpiBase + 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) MSR_IA32_THERM_INTERRUPT);
|
|
AsmWriteMsr64 (
|
|
(UINT32) MSR_IA32_THERM_INTERRUPT,
|
|
(UINT64) (SavedIa32ThermInterruptMSR & ~(BIT0 + BIT1 + BIT2 + BIT4 + BIT15 + BIT23))
|
|
);
|
|
///
|
|
/// Save THERMAL LVT in local APIC and mask THERMAL LVT
|
|
///
|
|
if (x2ApicEnabled) {
|
|
SavedMsrPicLvtTherm.Uint32 = (UINT32) AsmReadMsr64 (MSR_PIC_LVT_THERM);
|
|
MsrPicLvtTherm.Uint32 = SavedMsrPicLvtTherm.Uint32;
|
|
MsrPicLvtTherm.Bits.Vector = 0;
|
|
MsrPicLvtTherm.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_SMI;
|
|
MsrPicLvtTherm.Bits.Mask = 1;
|
|
AsmWriteMsr64 (MSR_PIC_LVT_THERM, MsrPicLvtTherm.Uint32);
|
|
} else {
|
|
SavedMsrPicLvtTherm.Uint32 = *(UINT32 *) (UINTN) (LocalApicBaseAddr + LOCAL_APIC_THERMAL_DEF);
|
|
MsrPicLvtTherm.Uint32 = SavedMsrPicLvtTherm.Uint32;
|
|
MsrPicLvtTherm.Bits.Vector = 0;
|
|
MsrPicLvtTherm.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_SMI;
|
|
MsrPicLvtTherm.Bits.Mask = 1;
|
|
*(UINT32 *) (UINTN) (LocalApicBaseAddr + LOCAL_APIC_THERMAL_DEF) = MsrPicLvtTherm.Uint32;
|
|
}
|
|
|
|
///
|
|
/// Save SMI control register
|
|
///
|
|
SavedSmiControl = IoRead32 ((UINTN) GlobalSmiControlIoAddr);
|
|
IoWrite32 (
|
|
(UINTN) GlobalSmiControlIoAddr,
|
|
(UINT32) (SavedSmiControl & (UINT32)(~B_ACPI_IO_SMI_EN_GBL_SMI))
|
|
);
|
|
|
|
} else {
|
|
///
|
|
/// Restore SMI control register
|
|
///
|
|
IoWrite32 (
|
|
(UINTN) GlobalSmiControlIoAddr,
|
|
(UINT32) (SavedSmiControl)
|
|
);
|
|
|
|
///
|
|
/// Restore IA32_THERMAL_INTERRUPT MSR
|
|
///
|
|
AsmWriteMsr64 (
|
|
(UINT32) MSR_IA32_THERM_INTERRUPT,
|
|
(UINT64) SavedIa32ThermInterruptMSR
|
|
);
|
|
if (x2ApicEnabled) {
|
|
AsmWriteMsr64 (MSR_PIC_LVT_THERM, SavedMsrPicLvtTherm.Uint32);
|
|
} else {
|
|
*(UINT32 *) (UINTN) (LocalApicBaseAddr + LOCAL_APIC_THERMAL_DEF) = SavedMsrPicLvtTherm.Uint32;
|
|
}
|
|
}
|
|
|
|
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;
|
|
|
|
///
|
|
///
|
|
///
|
|
if (TxtDxeCtx->TxtInfoData->ResetAux == 1) {
|
|
DEBUG ((DEBUG_INFO, "TXTDXE: Reset AUX content\n"));
|
|
Status = TxtDxeLibLaunchBiosAcm (TxtDxeCtx, TXT_RESET_AUX);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|