diff options
author | raywu <raywu0301@gmail.com> | 2018-06-15 00:00:50 +0800 |
---|---|---|
committer | raywu <raywu0301@gmail.com> | 2018-06-15 00:00:50 +0800 |
commit | b7c51c9cf4864df6aabb99a1ae843becd577237c (patch) | |
tree | eebe9b0d0ca03062955223097e57da84dd618b9a /ReferenceCode/ME/Heci | |
download | zprj-master.tar.xz |
Diffstat (limited to 'ReferenceCode/ME/Heci')
35 files changed, 9413 insertions, 0 deletions
diff --git a/ReferenceCode/ME/Heci/Dxe/HeciDxe.cif b/ReferenceCode/ME/Heci/Dxe/HeciDxe.cif new file mode 100644 index 0000000..bd3469d --- /dev/null +++ b/ReferenceCode/ME/Heci/Dxe/HeciDxe.cif @@ -0,0 +1,18 @@ +<component> + name = "HeciDxe" + category = ModulePart + LocalRoot = "ReferenceCode\ME\Heci\Dxe\" + RefName = "HeciDxe" +[files] +"HeciDxe.sdl" +"HeciDxe.mak" +"Hecicore.c" +"Hecicore.h" +"Hecidrv.c" +"Hecidrv.h" +"Hecidrv.dxs" +"HeciHpet.c" +"HeciHpet.h" +"Hecidrv.inf" +"MeFvi.c" +<endComponent> diff --git a/ReferenceCode/ME/Heci/Dxe/HeciDxe.mak b/ReferenceCode/ME/Heci/Dxe/HeciDxe.mak new file mode 100644 index 0000000..e343b51 --- /dev/null +++ b/ReferenceCode/ME/Heci/Dxe/HeciDxe.mak @@ -0,0 +1,65 @@ +# MAK file for the ModulePart:HeciDxe +all : HeciDxe + +HeciDxe : $(BUILD_DIR)\HeciDxe.mak HeciDxeBin + +$(BUILD_DIR)\HeciDxe.mak : $(HeciDxe_DIR)\$(@B).cif $(HeciDxe_DIR)\$(@B).mak $(BUILD_RULES) + $(CIF2MAK) $(HeciDxe_DIR)\$(@B).cif $(CIF2MAK_DEFAULTS) + +HeciDxe_INCLUDES= \ + $(EDK_INCLUDES)\ + $(EdkIIGlueLib_INCLUDES)\ + $(ME_INCLUDES)\ + $(INTEL_PCH_INCLUDES) + +HeciDxe_LIBS=\ + $(EDKPROTOCOLLIB)\ + $(MeProtocolLib_LIB)\ + $(MeLibDxe_LIB)\ + $(MeChipsetDxeLib_LIB)\ + $(MeGuidLib_LIB)\ + $(EFISCRIPTLIB)\ + $(EDKFRAMEWORKPROTOCOLLIB)\ + $(EFIGUIDLIB)\ + $(EdkIIGlueBaseLib_LIB)\ +!IF "$(x64_BUILD)"=="1" + $(EdkIIGlueBaseLibX64_LIB)\ +!ELSE + $(EdkIIGlueBaseLibIA32_LIB)\ +!ENDIF + $(EdkIIGlueBaseIoLibIntrinsic_LIB)\ + $(EdkIIGlueDxeReportStatusCodeLib_LIB)\ + $(EdkIIGlueDxeDebugLibReportStatusCode_LIB)\ + $(EdkIIGlueUefiBootServicesTableLib_LIB)\ + $(EdkIIGlueUefiLib_LIB)\ + $(EdkIIGlueBasePciLibPciExpress_LIB)\ + $(EdkIIGlueDxeServicesTableLib_LIB)\ + $(EdkIIGlueBasePrintLib_LIB)\ + $(EFIDRIVERLIB)\ + $(RcFviDxeLib_LIB)\ + $(PchPlatformDxeLib_LIB)\ + $(INTEL_PCH_PROTOCOL_LIB)\ + +HeciDxe_DEFINES=$(MY_DEFINES)\ + /D"__EDKII_GLUE_MODULE_ENTRY_POINT__=InitializeHECI"\ + /D __EDKII_GLUE_BASE_IO_LIB_INTRINSIC__ \ + /D __EDKII_GLUE_DXE_REPORT_STATUS_CODE_LIB__ \ + /D __EDKII_GLUE_DXE_DEBUG_LIB_REPORT_STATUS_CODE__ \ + /D __EDKII_GLUE_UEFI_BOOT_SERVICES_TABLE_LIB__ \ + /D __EDKII_GLUE_UEFI_LIB__\ + /D __EDKII_GLUE_BASE_PCI_LIB_PCI_EXPRESS__ \ + /D __EDKII_GLUE_DXE_SERVICES_TABLE_LIB__ \ +# /D iFFS_FLAG \ + +HeciDxeBin : $(HeciDxe_LIBS) + $(MAKE) /$(MAKEFLAGS) $(EDKIIGLUE_DEFAULTS)\ + /f $(BUILD_DIR)\HeciDxe.mak all\ + "MY_INCLUDES=$(HeciDxe_INCLUDES)"\ + "MY_DEFINES=$(HeciDxe_DEFINES)"\ + GUID=55E76644-78A5-4a82-A900-7126A5798892 \ + ENTRY_POINT=_ModuleEntryPoint \ + EDKIIModule=DXEDRIVER\ + TYPE=BS_DRIVER \ + DEPEX1=$(HeciDxe_DIR)\Hecidrv.dxs \ + DEPEX1_TYPE=EFI_SECTION_DXE_DEPEX \ + COMPRESS=1\ diff --git a/ReferenceCode/ME/Heci/Dxe/HeciDxe.sdl b/ReferenceCode/ME/Heci/Dxe/HeciDxe.sdl new file mode 100644 index 0000000..f547413 --- /dev/null +++ b/ReferenceCode/ME/Heci/Dxe/HeciDxe.sdl @@ -0,0 +1,24 @@ +TOKEN + Name = "HeciDxe_SUPPORT" + Value = "1" + TokenType = Boolean + TargetEQU = Yes + TargetMAK = Yes + Master = Yes + Help = "Main switch to enable HeciDxe support in Project" +End +MODULE + Help = "Includes HeciDxe.mak to Project" + File = "HeciDxe.mak" +End + +ELINK + Name = "$(BUILD_DIR)\HeciDxe.ffs" + Parent = "FV_MAIN" + InvokeOrder = AfterParent +End + +PATH + Name = "HeciDxe_DIR" + Help = "iAMT Hec Driver files source directory" +End
\ No newline at end of file diff --git a/ReferenceCode/ME/Heci/Dxe/HeciHpet.c b/ReferenceCode/ME/Heci/Dxe/HeciHpet.c new file mode 100644 index 0000000..318757c --- /dev/null +++ b/ReferenceCode/ME/Heci/Dxe/HeciHpet.c @@ -0,0 +1,168 @@ +/** @file + Definitions for HECI driver + +@copyright + Copyright (c) 2006 - 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 +**/ +#include "HeciDrv.h" +#include "HeciHpet.h" +#include "HeciRegs.h" +#include "HeciCore.h" + +// +// Extern for shared HECI data and protocols +// +extern HECI_INSTANCE *mHeciContext; +VOLATILE UINT32 mSaveHpetConfigReg; + +/** + Store the value of High Performance Timer + + @param[in] None + + @retval None +**/ +VOID +SaveHpet ( + VOID + ) +{ + mSaveHpetConfigReg = MmioRead32 (PCH_RCRB_BASE + R_PCH_RCRB_HPTC); +} + +/** + Restore the value of High Performance Timer + + @param[in] None + + @retval None +**/ +VOID +RestoreHpet ( + VOID + ) +{ + MmioWrite32 (PCH_RCRB_BASE + R_PCH_RCRB_HPTC, mSaveHpetConfigReg); +} + +/** + Used for calculating timeouts + + @param[out] Start Snapshot of the HPET timer + @param[out] End Calculated time when timeout period will be done + @param[in] Time Timeout period in microseconds + + @retval None +**/ +VOID +StartTimer ( + OUT UINT32 *Start, + OUT UINT32 *End, + IN UINT32 Time + ) +{ + UINT32 Ticks; + + /// + /// Make sure that HPET is enabled and running + /// + EnableHpet (); + + /// + /// Read current timer value into start time from HPET + /// + *Start = mHeciContext->HpetTimer[HPET_MAIN_COUNTER_LOW]; + + /// + /// Convert microseconds into 70ns timer ticks + /// + Ticks = Time * HPET_TICKS_PER_MICRO; + + /// + /// Compute end time + /// + *End = *Start + Ticks; + + return ; +} + +/** + Used to determine if a timeout has occured. + + @param[in] Start Snapshot of the HPET timer when the timeout period started. + @param[in] End Calculated time when timeout period will be done. + + @retval EFI_TIMEOUT Timeout occured. + @retval EFI_SUCCESS Not yet timed out +**/ +EFI_STATUS +Timeout ( + IN UINT32 Start, + IN UINT32 End + ) +{ + UINT32 Current; + + /// + /// Read HPET and assign the value as the current time. + /// + Current = mHeciContext->HpetTimer[HPET_MAIN_COUNTER_LOW]; + + /// + /// Test basic case (no overflow) + /// + if ((Start < End) && (End <= Current)) { + return EFI_TIMEOUT; + } + /// + /// Test basic start/end conditions with overflowed timer + /// + if ((Start < End) && (Current < Start)) { + return EFI_TIMEOUT; + } + /// + /// Test for overflowed start/end condition + /// + if ((Start > End) && ((Current < Start) && (Current > End))) { + return EFI_TIMEOUT; + } + /// + /// Catch corner case of broken arguments + /// + if (Start == End) { + return EFI_TIMEOUT; + } + /// + /// Else, we have not yet timed out + /// + return EFI_SUCCESS; +} + +/** + Delay for at least the request number of microseconds + + @param[in] delayTime Number of microseconds to delay. + + @retval None +**/ +VOID +IoDelay ( + IN UINT32 delayTime + ) +{ + gBS->Stall (delayTime); +} diff --git a/ReferenceCode/ME/Heci/Dxe/HeciHpet.h b/ReferenceCode/ME/Heci/Dxe/HeciHpet.h new file mode 100644 index 0000000..8743b3a --- /dev/null +++ b/ReferenceCode/ME/Heci/Dxe/HeciHpet.h @@ -0,0 +1,115 @@ +/** @file + Definitions for HECI driver + +@copyright + Copyright (c) 2006 - 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 +**/ +#ifndef _HECI_HPET_H +#define _HECI_HPET_H + +#include "EdkIIGlueDxe.h" +#include "MeAccess.h" +#include "HeciRegs.h" +#include "Pci22.h" + +/** + Store the value of High Performance Timer + + @param[in] None + + @retval None +**/ +VOID +SaveHpet ( + VOID + ) +; + +/** + Restore the value of High Performance Timer + + @param[in] None + + @retval None +**/ + +VOID +RestoreHpet ( + VOID + ) +; + +/** + Used for calculating timeouts + + @param[out] Start Snapshot of the HPET timer + @param[out] End Calculated time when timeout period will be done + @param[in] Time Timeout period in microseconds + + @retval None +**/ +VOID +StartTimer ( + OUT UINT32 *Start, + OUT UINT32 *End, + IN UINT32 Time + ) +; + +/** + Used to determine if a timeout has occured. + + @param[in] Start Snapshot of the HPET timer when the timeout period started. + @param[in] End Calculated time when timeout period will be done. + + @retval EFI_TIMEOUT Timeout occured. + @retval EFI_SUCCESS Not yet timed out +**/ +EFI_STATUS +Timeout ( + IN UINT32 Start, + IN UINT32 End + ) +; + +/** + Enable Hpet function. + + @param[in] None. + + @retval None +**/ +VOID +EnableHpet ( + VOID + ) +; + +/** + Delay for at least the request number of microseconds + + @param[in] delayTime Number of microseconds to delay. + + @retval None +**/ +VOID +IoDelay ( + IN UINT32 delayTime + ) +; + +#endif // _HECI_HPET_H diff --git a/ReferenceCode/ME/Heci/Dxe/Hecicore.c b/ReferenceCode/ME/Heci/Dxe/Hecicore.c new file mode 100644 index 0000000..176fbed --- /dev/null +++ b/ReferenceCode/ME/Heci/Dxe/Hecicore.c @@ -0,0 +1,1461 @@ +/** @file + Heci driver core. For Dxe Phase, determines the HECI device and initializes it. + +@copyright + Copyright (c) 2007 - 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 + +**/ +#include "HeciDrv.h" +#include "HeciHpet.h" +#include "HeciCore.h" +#include "HeciRegs.h" +#include "MeState.h" + +// +// Globals used in Heci driver +// +UINT16 HECICtlrBDF; +static UINT64 HeciMBAR = 0; + +// +// Extern for shared HECI data and protocols +// +extern HECI_INSTANCE *mHeciContext; + +/** + The routing of MmIo Read Dword + + @param[in] a The address of Mmio + + @retval Return the valut of MmIo Read +**/ +UINT32 +MmIoReadDword ( + IN UINT64 a + ) +{ + volatile HECI_HOST_CONTROL_REGISTER *HeciRegHCsrPtr; + + HeciRegHCsrPtr = (HECI_HOST_CONTROL_REGISTER *) a; + return HeciRegHCsrPtr->ul; +} + +/** + The routing of MmIo Write Dword + + @param[in] a The address of Mmio + @param[in] b Value revised + + @retval None +**/ +VOID +MmIoWriteDword ( + IN UINT64 a, + IN UINT32 b + ) +{ + volatile HECI_HOST_CONTROL_REGISTER *HeciRegHCsrPtr; + + HeciRegHCsrPtr = (HECI_HOST_CONTROL_REGISTER *) a; + + HeciRegHCsrPtr->ul = b; +} + +// +// Macro definition for function used in Heci driver +// +#define MMIOREADDWORD(a) MmIoReadDword (a) +#define MMIOWRITEDWORD(a, b) MmIoWriteDword (a, b) + +#ifdef EFI_DEBUG + +/** + For serial debugger used, it will show the buffer message line by line to serial console. + + @param[in] Message the address point of buffer message + @param[in] Length message length + + @retval None +**/ +VOID +ShowBuffer ( + IN UINT8 *Message, + IN UINT32 Length + ) +{ + UINT32 Index; + UINT32 Offset; + CHAR16 Buffer[51]; // To construct a line needs 51 chars. + + Index = 0; + Offset = 0; + ZeroMem (Buffer, sizeof (Buffer)); + + while (Length-- > 0) { + // + // Get the corresponding offset value from the index of buffer message. + // + Offset = ((Index & 0x0F) > 7) ? (((Index & 0x0F) * 3) + 2) : ((Index & 0x0F) * 3); + + // + // Print "- " at the half of a line increases the readability of debug message. + // + if ((Index & 0x0F) == 0x08) { + UnicodeSPrint (&Buffer[24], 3 * sizeof (CHAR16), L"- "); + } + + // + // Collect the data of buffer message. + // + UnicodeSPrint (&Buffer[Offset], 4 * sizeof (CHAR16), L"%02x ", Message[Index]); + + // + // A line contains 16 bytes of buffer message. If a line is complete, it will be shown through DEBUG macro. + // + if (Offset == 47) { + DEBUG ((EFI_D_ERROR, "%02x: %s\n", (Index & 0xF0), Buffer)); + } + + Index++; + } + + // + // If a line isn't complete, show the remaining data. + // + if (Offset != 47) { + DEBUG ((EFI_D_ERROR, "%02x: %s\n", (Index & 0xF0), Buffer)); + } + return ; +} + +#endif // End Of EFI_DEBUG + +// +// Heci driver function definitions +// + +/** + Determines if the HECI device is present and, if present, initializes it for + use by the BIOS. + + @param[in] None. + + @retval EFI_SUCCESS HECI device is present and initialized. + @retval EFI_DEVICE_ERROR No HECI controller. + @exception EFI_UNSUPPORTED HECI MSG is unsupported because ME MODE is in ME ALT Disabled & + SECOVR JMPR + @retval EFI_TIMEOUT ME is not ready +**/ +EFI_STATUS +InitializeHeciPrivate ( + VOID + ) +{ + HECI_HOST_CONTROL_REGISTER HeciRegHCsr; + VOLATILE HECI_HOST_CONTROL_REGISTER *HeciRegHCsrPtr; + EFI_STATUS Status; + HECI_FWS_REGISTER MeFirmwareStatus; + + Status = EFI_SUCCESS; + + SaveHpet (); + do { + /// + /// Store HECI vendor and device information away + /// + mHeciContext->DeviceInfo = HeciPciRead16 (PCI_DEVICE_ID_OFFSET); + + /// + /// Check for HECI-1 PCI device availability + /// + if (mHeciContext->DeviceInfo == 0xFFFF) { + Status = EFI_DEVICE_ERROR; + break; + } + + MeFirmwareStatus.ul = HeciPciRead32 (R_FWSTATE); + + /// + /// Check for ME FPT Bad + /// + if (MeFirmwareStatus.r.FptBad) { + Status = EFI_DEVICE_ERROR; + break; + } + /// + /// Check for ME error status + /// + if (MeFirmwareStatus.r.ErrorCode) { + Status = EFI_NOT_READY; + if (MeFirmwareStatus.r.ErrorCode == ME_ERROR_CODE_UNKNOWN || MeFirmwareStatus.r.ErrorCode == ME_ERROR_CODE_IMAGE_FAILURE) { + /// + /// ME failed to start so no HECI + /// + Status = EFI_DEVICE_ERROR; + break; + } + } + /// + /// HECI MSG is unsupported if ME MODE is in ME ALT Disabled & SECOVR JMPR + /// + if ((MeFirmwareStatus.r.MeOperationMode == ME_OPERATION_MODE_SECOVR_JMPR) || + (MeFirmwareStatus.r.MeOperationMode == ME_OPERATION_MODE_DEBUG) + ) { + Status = EFI_UNSUPPORTED; + break; + } + /// + /// Store HECI revision ID + /// + mHeciContext->RevisionInfo = HeciPciRead8 (PCI_REVISION_ID_OFFSET); + + /// + /// Check if Base register is 64 bits wide. + /// + if (HeciPciRead32 (R_HECIMBAR) & 0x4) { + mHeciContext->HeciMBAR = (((UINT64) HeciPciRead32 (R_HECIMBAR + 4) << 32) | + (UINT64) HeciPciRead32 (R_HECIMBAR)) & 0xFFFFFFF0; + } else { + mHeciContext->HeciMBAR = (UINT64) HeciPciRead32 (R_HECIMBAR) & 0xFFFFFFF0; + } + /// + /// Get HECI_MBAR and see if it is programmed + /// to a useable value + /// + HeciMBAR = mHeciContext->HeciMBAR; + + /// + /// Load temporary address for HECI_MBAR if one is not assigned + /// + if (mHeciContext->HeciMBAR == 0) { + DEBUG ((EFI_D_ERROR, "Heci MMIO Bar not programmed in DXE phase\n")); + } + /// + /// Enable HECI BME and MSE + /// + HeciPciOr8 ( + PCI_COMMAND_OFFSET, + EFI_PCI_COMMAND_MEMORY_SPACE | EFI_PCI_COMMAND_BUS_MASTER + ); + + /// + /// Set HECI interrupt delivery mode. + /// HECI-1 using legacy/MSI interrupt + /// + HeciPciAnd8 (R_HIDM, 0xFC); + + /// + /// Need to do following on ME init: + /// + /// 1) wait for ME_CSR_HA reg ME_RDY bit set + /// + if (WaitForMEReady () != EFI_SUCCESS) { + Status = EFI_TIMEOUT; + break; + } + /// + /// 2) setup H_CSR reg as follows: + /// a) Make sure H_RST is clear + /// b) Set H_RDY + /// c) Set H_IG + /// + HeciRegHCsrPtr = (VOID *) (UINTN) (mHeciContext->HeciMBAR + H_CSR); + HeciRegHCsr.ul = HeciRegHCsrPtr->ul; + if (HeciRegHCsrPtr->r.H_RDY == 0) { + HeciRegHCsr.r.H_RST = 0; + HeciRegHCsr.r.H_RDY = 1; + HeciRegHCsr.r.H_IG = 1; + HeciRegHCsrPtr->ul = HeciRegHCsr.ul; + } + } while (Status != EFI_SUCCESS && Status != EFI_NOT_READY); + + RestoreHpet (); + + return Status; +} + +/** + Waits for the ME to report that it is ready for communication over the HECI + interface. + + @param[in] None. + + @retval EFI_SUCCESS ME is ready + @retval EFI_TIMEOUT ME is not ready +**/ +EFI_STATUS +WaitForMEReady ( + VOID + ) +{ + UINT32 TimerStart; + UINT32 TimerEnd; + HECI_ME_CONTROL_REGISTER HeciRegMeCsrHa; + + /// + /// Wait for ME ready + /// + /// + /// Check for ME ready status + /// + StartTimer (&TimerStart, &TimerEnd, HECI_INIT_TIMEOUT); + HeciRegMeCsrHa.ul = MMIOREADDWORD (HeciMBAR + ME_CSR_HA); + while (HeciRegMeCsrHa.r.ME_RDY_HRA == 0) { + /// + /// If 5 second timeout has expired, return fail + /// + if (Timeout (TimerStart, TimerEnd) != EFI_SUCCESS) { + return EFI_TIMEOUT; + } + /// + /// Perform IO delay + /// + IoDelay (HECI_WAIT_DELAY); + + HeciRegMeCsrHa.ul = MMIOREADDWORD (HeciMBAR + ME_CSR_HA); + } + /// + /// ME ready!!! + /// + return EFI_SUCCESS; +} + +/** + Checks if HECI reset has occured. + + @param[in] None. + + @retval TRUE HECI reset occurred + @retval FALSE No HECI reset occurred +**/ +BOOLEAN +CheckForHeciReset ( + VOID + ) +{ + HECI_HOST_CONTROL_REGISTER HeciRegHCsr; + HECI_ME_CONTROL_REGISTER HeciRegMeCsrHa; + + /// + /// Init Host & ME CSR + /// + HeciRegHCsr.ul = MMIOREADDWORD (HeciMBAR + H_CSR); + HeciRegMeCsrHa.ul = MMIOREADDWORD (HeciMBAR + ME_CSR_HA); + + if ((HeciRegMeCsrHa.r.ME_RDY_HRA == 0) || (HeciRegHCsr.r.H_RDY == 0)) { + return TRUE; + } + + return FALSE; +} + +/** + Determines if the HECI device is present and, if present, initializes it for + use by the BIOS. + + @param[in] None. + + @retval EFI_SUCCESS HECI device is present and initialized + @retval EFI_TIMEOUT ME is not ready +**/ +EFI_STATUS +EFIAPI +HeciInitialize ( + VOID + ) +{ + HECI_HOST_CONTROL_REGISTER HeciRegHCsr; + + /// + /// Make sure that HECI device BAR is correct and device is enabled. + /// + HeciMBAR = CheckAndFixHeciForAccess (); + + /// + /// Need to do following on ME init: + /// + /// 1) wait for ME_CSR_HA reg ME_RDY bit set + /// + if (WaitForMEReady () != EFI_SUCCESS) { + return EFI_TIMEOUT; + } + /// + /// 2) setup H_CSR reg as follows: + /// a) Make sure H_RST is clear + /// b) Set H_RDY + /// c) Set H_IG + /// + HeciRegHCsr.ul = MMIOREADDWORD (HeciMBAR + H_CSR); + if (HeciRegHCsr.r.H_RDY == 0) { + HeciRegHCsr.r.H_RST = 0; + HeciRegHCsr.r.H_RDY = 1; + HeciRegHCsr.r.H_IG = 1; + MMIOWRITEDWORD (HeciMBAR + H_CSR, HeciRegHCsr.ul); + } + + return EFI_SUCCESS; +} + +/** + Heci Re-initializes it for Host + + @param[in] None. + + @retval EFI_TIMEOUT ME is not ready + @retval EFI_STATUS Status code returned by ResetHeciInterface +**/ +EFI_STATUS +EFIAPI +HeciReInitialize ( + VOID + ) +{ + HECI_HOST_CONTROL_REGISTER HeciRegHCsr; + EFI_STATUS Status; + + Status = EFI_SUCCESS; + /// + /// Need to do following on ME init: + /// + /// 1) wait for HOST_CSR_HA reg H_RDY bit set + /// + /// if (WaitForHostReady() != EFI_SUCCESS) { + /// + if (MeResetWait (HECI_INIT_TIMEOUT) != EFI_SUCCESS) { + return EFI_TIMEOUT; + } + + HeciRegHCsr.ul = MMIOREADDWORD (HeciMBAR + H_CSR); + if (HeciRegHCsr.r.H_RDY == 0) { + Status = ResetHeciInterface (); + + } + + return Status; +} + +/** + Heci Re-initializes it for Me + + @param[in] None. + + @retval EFI_TIMEOUT ME is not ready + @retval EFI_SUCCESS Re-initialization done +**/ +EFI_STATUS +EFIAPI +HeciReInitialize2 ( + VOID + ) +{ + HECI_ME_CONTROL_REGISTER HeciRegMeCsrHa; + EFI_STATUS Status; + UINT32 TimerStart; + UINT32 TimerEnd; + + Status = EFI_SUCCESS; + /// + /// Need to do following on ME init: + /// + /// 1) wait for HOST_CSR_HA reg H_RDY bit set + /// + /// if (WaitForHostReady() != EFI_SUCCESS) { + /// + StartTimer (&TimerStart, &TimerEnd, HECI_INIT_TIMEOUT); + HeciRegMeCsrHa.ul = MMIOREADDWORD (HeciMBAR + ME_CSR_HA); + while (HeciRegMeCsrHa.r.ME_RDY_HRA == 1) { + /// + /// If 5 second timeout has expired, return fail + /// + if (Timeout (TimerStart, TimerEnd) != EFI_SUCCESS) { + return EFI_TIMEOUT; + } + + IoDelay (HECI_WAIT_DELAY); + + HeciRegMeCsrHa.ul = MMIOREADDWORD (HeciMBAR + ME_CSR_HA); + } + + if (WaitForMEReady () != EFI_SUCCESS) { + return EFI_TIMEOUT; + } + + return Status; +} + +/** + Function to pull one messsage packet off the HECI circular buffer. + Corresponds to HECI HPS (part of) section 4.2.4 + + @param[in] Blocking Used to determine if the read is BLOCKING or NON_BLOCKING. + @param[out] MessageHeader Pointer to a buffer for the message header. + @param[in] MessageData Pointer to a buffer to recieve the message in. + @param[in][out] Length On input is the size of the callers buffer in bytes. On + output this is the size of the packet in bytes. + + @retval EFI_SUCCESS One message packet read. + @retval EFI_DEVICE_ERROR The circular buffer is overflowed. + @retval EFI_NO_RESPONSE The circular buffer is empty + @retval EFI_TIMEOUT Failed to receive a full message + @retval EFI_BUFFER_TOO_SMALL Message packet is larger than caller's buffer +**/ +EFI_STATUS +HECIPacketRead ( + IN UINT32 Blocking, + OUT HECI_MESSAGE_HEADER *MessageHeader, + OUT UINT32 *MessageData, + IN OUT UINT32 *Length + ) +{ + BOOLEAN GotMessage; + UINT32 TimerStart; + UINT32 TimerEnd; + UINT32 TimerStart1; + UINT32 TimerEnd1; + UINT32 i; + UINT32 LengthInDwords; + HECI_ME_CONTROL_REGISTER HeciRegMeCsrHa; + HECI_HOST_CONTROL_REGISTER HeciRegHCsr; + + GotMessage = FALSE; + /// + /// Initialize memory mapped register pointers + /// + /// VOLATILE HECI_HOST_CONTROL_REGISTER *HeciRegHCsrPtr = (VOID*)(mHeciContext->HeciMBAR + H_CSR); + /// VOLATILE HECI_ME_CONTROL_REGISTER *HeciRegMeCsrHaPtr = (VOID*)(mHeciContext->HeciMBAR + ME_CSR_HA); + /// VOLATILE UINT32 *HeciRegMeCbrwPtr = (VOID*)(mHeciContext->HeciMBAR + ME_CB_RW); + /// + /// clear Interrupt Status bit + /// + HeciRegHCsr.ul = MMIOREADDWORD (HeciMBAR + H_CSR); + HeciRegHCsr.r.H_IS = 1; + + /// + /// test for circular buffer overflow + /// + HeciRegMeCsrHa.ul = MMIOREADDWORD (HeciMBAR + ME_CSR_HA); + if (OverflowCB ( + HeciRegMeCsrHa.r.ME_CBRP_HRA, + HeciRegMeCsrHa.r.ME_CBWP_HRA, + HeciRegMeCsrHa.r.ME_CBD_HRA + ) != EFI_SUCCESS) { + /// + /// if we get here, the circular buffer is overflowed + /// + *Length = 0; + return EFI_DEVICE_ERROR; + } + /// + /// If NON_BLOCKING, exit if the circular buffer is empty + /// + HeciRegMeCsrHa.ul = MMIOREADDWORD (HeciMBAR + ME_CSR_HA);; + if ((FilledSlots (HeciRegMeCsrHa.r.ME_CBRP_HRA, HeciRegMeCsrHa.r.ME_CBWP_HRA) == 0) && (Blocking == NON_BLOCKING)) { + *Length = 0; + return EFI_NO_RESPONSE; + } + /// + /// Start timeout counter + /// + StartTimer (&TimerStart, &TimerEnd, HECI_READ_TIMEOUT); + + /// + /// loop until we get a message packet + /// + while (!GotMessage) { + /// + /// If 1 second timeout has expired, return fail as we have not yet received a full message. + /// + if (Timeout (TimerStart, TimerEnd) != EFI_SUCCESS) { + *Length = 0; + return EFI_TIMEOUT; + } + /// + /// Read one message from HECI buffer and advance read pointer. Make sure + /// that we do not pass the write pointer. + /// + HeciRegMeCsrHa.ul = MMIOREADDWORD (HeciMBAR + ME_CSR_HA);; + if (FilledSlots (HeciRegMeCsrHa.r.ME_CBRP_HRA, HeciRegMeCsrHa.r.ME_CBWP_HRA) > 0) { + /// + /// Eat the HECI Message header + /// + MessageHeader->Data = MMIOREADDWORD (HeciMBAR + ME_CB_RW); + + /// + /// Compute required message length in DWORDS + /// + LengthInDwords = ((MessageHeader->Fields.Length + 3) / 4); + + /// + /// Just return success if Length is 0 + /// + if (MessageHeader->Fields.Length == 0) { + /// + /// Set Interrupt Generate bit and return + /// + MMIOREADDWORD (HeciMBAR + H_CSR); + HeciRegHCsr.r.H_IG = 1; + MMIOWRITEDWORD (HeciMBAR + H_CSR, HeciRegHCsr.ul); + *Length = 0; + return EFI_SUCCESS; + } + /// + /// Make sure that the message does not overflow the circular buffer. + /// + HeciRegMeCsrHa.ul = MMIOREADDWORD (HeciMBAR + ME_CSR_HA); + if ((MessageHeader->Fields.Length + sizeof (HECI_MESSAGE_HEADER)) > (HeciRegMeCsrHa.r.ME_CBD_HRA * 4)) { + *Length = 0; + return EFI_DEVICE_ERROR; + } + /// + /// Make sure that the callers buffer can hold the correct number of DWORDS + /// + if ((MessageHeader->Fields.Length) <= *Length) { + /// + /// Start timeout counter for inner loop + /// + StartTimer (&TimerStart1, &TimerEnd1, HECI_READ_TIMEOUT); + + /// + /// Wait here until entire message is present in circular buffer + /// + HeciRegMeCsrHa.ul = MMIOREADDWORD (HeciMBAR + ME_CSR_HA); + while (LengthInDwords > FilledSlots (HeciRegMeCsrHa.r.ME_CBRP_HRA, HeciRegMeCsrHa.r.ME_CBWP_HRA)) { + /// + /// If 1 second timeout has expired, return fail as we have not yet received a full message + /// + if (Timeout (TimerStart1, TimerEnd1) != EFI_SUCCESS) { + *Length = 0; + return EFI_TIMEOUT; + } + /// + /// Wait before we read the register again + /// + IoDelay (HECI_WAIT_DELAY); + + /// + /// Read the register again + /// + HeciRegMeCsrHa.ul = MMIOREADDWORD (HeciMBAR + ME_CSR_HA); + } + /// + /// copy rest of message + /// + for (i = 0; i < LengthInDwords; i++) { + MessageData[i] = MMIOREADDWORD (HeciMBAR + ME_CB_RW); + } + /// + /// Update status and length + /// + GotMessage = TRUE; + *Length = MessageHeader->Fields.Length; + + } else { + /// + /// Message packet is larger than caller's buffer + /// + *Length = 0; + return EFI_BUFFER_TOO_SMALL; + } + } + /// + /// Wait before we try to get a message again + /// + IoDelay (HECI_WAIT_DELAY); + } + /// + /// Read ME_CSR_HA. If the ME_RDY bit is 0, then an ME reset occurred during the + /// transaction and the message should be discarded as bad data may have been retrieved + /// from the host's circular buffer + /// + HeciRegMeCsrHa.ul = MMIOREADDWORD (HeciMBAR + ME_CSR_HA); + if (HeciRegMeCsrHa.r.ME_RDY_HRA == 0) { + *Length = 0; + return EFI_DEVICE_ERROR; + } + /// + /// Set Interrupt Generate bit + /// + HeciRegHCsr.ul = MMIOREADDWORD (HeciMBAR + H_CSR); + HeciRegHCsr.r.H_IG = 1; + MMIOWRITEDWORD (HeciMBAR + H_CSR, HeciRegHCsr.ul); + + return EFI_SUCCESS; +} + +/** + Reads a message from the ME across HECI. + + @param[in] Blocking Used to determine if the read is BLOCKING or NON_BLOCKING. + @param[in][out] MessageBody Pointer to a buffer used to receive a message. + @param[in][out] Length Pointer to the length of the buffer on input and the length + of the message on return. (in bytes) + + @retval EFI_SUCCESS One message packet read. + @retval EFI_DEVICE_ERROR Failed to initialize HECI or zero-length message packet read + @retval EFI_TIMEOUT HECI is not ready for communication + @retval EFI_BUFFER_TOO_SMALL The caller's buffer was not large enough +**/ +EFI_STATUS +EFIAPI +HeciReceive ( + IN UINT32 Blocking, + IN OUT UINT32 *MessageBody, + IN OUT UINT32 *Length + ) +{ + HECI_MESSAGE_HEADER PacketHeader; + UINT32 CurrentLength; + UINT32 MessageComplete; + EFI_STATUS ReadError; + EFI_STATUS Status; + UINT32 PacketBuffer; + UINT32 timer_start; + UINT32 timer_end; + BOOLEAN QuitFlag; + + CurrentLength = 0; + MessageComplete = 0; + Status = EFI_SUCCESS; + QuitFlag = FALSE; + + SaveHpet (); + + do { + /// + /// Make sure that HECI device BAR is correct and device is enabled. + /// + HeciMBAR = CheckAndFixHeciForAccess (); + + /// + /// Make sure we do not have a HECI reset + /// + if (CheckForHeciReset ()) { + /// + /// if HECI reset than try to re-init HECI + /// + Status = HeciInitialize (); + + if (EFI_ERROR (Status)) { + Status = EFI_DEVICE_ERROR; + break; + } + } + /// + /// Make sure that HECI is ready for communication. + /// + if (WaitForMEReady () != EFI_SUCCESS) { + Status = EFI_TIMEOUT; + break; + } + /// + /// Set up timer for BIOS timeout. + /// + StartTimer (&timer_start, &timer_end, HECI_READ_TIMEOUT); + while ((CurrentLength < *Length) && (MessageComplete == 0)) { + /// + /// If 1 second timeout has expired, return fail as we have not yet received a full message + /// + if (Timeout (timer_start, timer_end) != EFI_SUCCESS) { + Status = EFI_TIMEOUT; + QuitFlag = TRUE; + break; + } + + PacketBuffer = *Length - CurrentLength; + ReadError = HECIPacketRead ( + Blocking, + &PacketHeader, + (UINT32 *) &MessageBody[CurrentLength / 4], + &PacketBuffer + ); + + /// + /// Check for error condition on read + /// + if (EFI_ERROR (ReadError)) { + *Length = 0; + Status = ReadError; + QuitFlag = TRUE; + break; + } + /// + /// Get completion status from the packet header + /// + MessageComplete = PacketHeader.Fields.MessageComplete; + + /// + /// Check for zero length messages + /// + if (PacketBuffer == 0) { + /// + /// If we are not in the middle of a message, and we see Message Complete, + /// this is a valid zero-length message. + /// + if ((CurrentLength == 0) && (MessageComplete == 1)) { + *Length = 0; + Status = EFI_SUCCESS; + QuitFlag = TRUE; + break; + } else { + /// + /// We should not expect a zero-length message packet except as described above. + /// + *Length = 0; + Status = EFI_DEVICE_ERROR; + QuitFlag = TRUE; + break; + } + } + /// + /// Track the length of what we have read so far + /// + CurrentLength += PacketBuffer; + + } + + if (QuitFlag == TRUE) { + break; + } + /// + /// If we get here the message should be complete, if it is not + /// the caller's buffer was not large enough. + /// + if (MessageComplete == 0) { + *Length = 0; + Status = EFI_BUFFER_TOO_SMALL; + break; + } + + *Length = CurrentLength; + + DEBUG ((EFI_D_ERROR, "HECI ReadMsg:\n")); +#ifdef EFI_DEBUG + DEBUG_CODE ( + ShowBuffer ((UINT8 *) MessageBody, *Length); + ); +#endif + } while (EFI_ERROR (Status)); + + RestoreHpet (); + + return Status; +} + +/** + Function sends one messsage (of any length) through the HECI circular buffer. + + @param[in] Message Pointer to the message data to be sent. + @param[in] Length Length of the message in bytes. + @param[in] HostAddress The address of the host processor. + @param[in] MeAddress Address of the ME subsystem the message is being sent to. + + @retval EFI_SUCCESS One message packet sent. + @retval EFI_DEVICE_ERROR Failed to initialize HECI + @retval EFI_TIMEOUT HECI is not ready for communication + @exception EFI_UNSUPPORTED Current ME mode doesn't support send message through HECI +**/ +EFI_STATUS +EFIAPI +HeciSend ( + IN UINT32 *Message, + IN UINT32 Length, + IN UINT8 HostAddress, + IN UINT8 MeAddress + ) +{ + UINT32 CBLength; + UINT32 SendLength; + UINT32 CurrentLength; + HECI_MESSAGE_HEADER MessageHeader; + EFI_STATUS WriteStatus; + EFI_STATUS Status; + HECI_HOST_CONTROL_REGISTER HeciRegHCsr; + UINT32 MeMode; + + CurrentLength = 0; + Status = EFI_SUCCESS; + + SaveHpet (); + + HeciGetMeMode (&MeMode); + do { + if (MeMode == ME_MODE_SECOVER) { + Status = EFI_UNSUPPORTED; + break; + } + /// + /// Make sure that HECI device BAR is correct and device is enabled. + /// + HeciMBAR = CheckAndFixHeciForAccess (); + + /// + /// Make sure we do not have a HECI reset + /// + if (CheckForHeciReset ()) { + /// + /// if HECI reset than try to re-init HECI + /// + Status = HeciInitialize (); + + if (EFI_ERROR (Status)) { + Status = EFI_DEVICE_ERROR; + break; + } + } + + DEBUG ((EFI_D_ERROR, "HECI SendMsg:\n")); +#ifdef EFI_DEBUG + DEBUG_CODE ( + ShowBuffer ((UINT8 *) Message, Length); + ); +#endif + /// + /// Make sure that HECI is ready for communication. + /// + if (WaitForMEReady () != EFI_SUCCESS) { + Status = EFI_TIMEOUT; + break; + } + /// + /// Set up memory mapped registers + /// + HeciRegHCsr.ul = MMIOREADDWORD (HeciMBAR + H_CSR); + + /// + /// Grab Circular Buffer length + /// + CBLength = HeciRegHCsr.r.H_CBD; + + /// + /// Prepare message header + /// + MessageHeader.Data = 0; + MessageHeader.Fields.MeAddress = MeAddress; + MessageHeader.Fields.HostAddress = HostAddress; + + /// + /// Break message up into CB-sized packets and loop until completely sent + /// + while (Length > CurrentLength) { + /// + /// Set the Message Complete bit if this is our last packet in the message. + /// Needs to be 'less than' to account for the header OR Needs to be exactly equal to CB depth. + /// + if (((((Length - CurrentLength) + 3) / 4) < CBLength) || + ((((((Length - CurrentLength) + 3) / 4) == CBLength) && ((((Length - CurrentLength) + 3) % 4) == 0))) + ) { + MessageHeader.Fields.MessageComplete = 1; + } + /// + /// Calculate length for Message Header + /// header length == smaller of circular buffer or remaining message (both account for the size of the header) + /// + SendLength = ((CBLength <= (((Length - CurrentLength) + 3) / 4)) ? ((CBLength - 1) * 4) : (Length - CurrentLength)); + MessageHeader.Fields.Length = SendLength; + + DEBUG ((EFI_D_ERROR, "HECI Header: %08x\n", MessageHeader.Data)); + + /// + /// send the current packet (CurrentLength can be treated as the index into the message buffer) + /// + WriteStatus = HeciPacketWrite (&MessageHeader, (UINT32 *) ((UINTN) Message + CurrentLength)); + if (EFI_ERROR (WriteStatus)) { + Status = WriteStatus; + break; + } + /// + /// Update the length information + /// + CurrentLength += SendLength; + } + + if (EFI_ERROR (Status)) { + break; + } + } while (EFI_ERROR (Status)); + + RestoreHpet (); + + return Status; + +} + +/** + Function sends one messsage packet through the HECI circular buffer + Corresponds to HECI HPS (part of) section 4.2.3 + + @param[in] MessageHeader Pointer to the message header. + @param[in] MessageData Pointer to the actual message data. + + @retval EFI_SUCCESS One message packet sent + @retval EFI_DEVICE_ERROR ME is not ready + @retval EFI_TIMEOUT HECI is not ready for communication +**/ +EFI_STATUS +HeciPacketWrite ( + IN HECI_MESSAGE_HEADER *MessageHeader, + IN UINT32 *MessageData + ) +{ + UINT32 timer_start; + UINT32 timer_end; + UINT32 i; + UINT32 LengthInDwords; + HECI_HOST_CONTROL_REGISTER HeciRegHCsr; + HECI_ME_CONTROL_REGISTER HeciRegMeCsrHa; + + /// + /// Make sure that HECI is ready for communication. + /// + if (WaitForMEReady () != EFI_SUCCESS) { + return EFI_TIMEOUT; + } + /// + /// Start timeout counter + /// + StartTimer (&timer_start, &timer_end, HECI_SEND_TIMEOUT); + + /// + /// Compute message length in DWORDS + /// + LengthInDwords = ((MessageHeader->Fields.Length + 3) / 4); + + /// + /// Wait until there is sufficient room in the circular buffer + /// Must have room for message and message header + /// + HeciRegHCsr.ul = MMIOREADDWORD (HeciMBAR + H_CSR); + while ((LengthInDwords + 1) > (HeciRegHCsr.r.H_CBD - FilledSlots (HeciRegHCsr.r.H_CBRP, HeciRegHCsr.r.H_CBWP))) { + /// + /// If 1 second timeout has expired, return fail as the circular buffer never emptied + /// + if (Timeout (timer_start, timer_end) != EFI_SUCCESS) { + return EFI_TIMEOUT; + } + /// + /// Wait before we read the register again + /// + IoDelay (HECI_WAIT_DELAY); + + /// + /// Read Host CSR for next iteration + /// + HeciRegHCsr.ul = MMIOREADDWORD (HeciMBAR + H_CSR); + } + /// + /// Write Message Header + /// + MMIOWRITEDWORD (HeciMBAR + H_CB_WW, MessageHeader->Data); + + /// + /// Write Message Body + /// + for (i = 0; i < LengthInDwords; i++) { + MMIOWRITEDWORD (HeciMBAR + H_CB_WW, MessageData[i]); + } + /// + /// Set Interrupt Generate bit + /// + HeciRegHCsr.ul = MMIOREADDWORD (HeciMBAR + H_CSR); + HeciRegHCsr.r.H_IG = 1; + MMIOWRITEDWORD (HeciMBAR + H_CSR, HeciRegHCsr.ul); + + /// + /// Test if ME Ready bit is set to 1, if set to 0 a fatal error occured during + /// the transmission of this message. + /// + HeciRegMeCsrHa.ul = MMIOREADDWORD (HeciMBAR + ME_CSR_HA); + if (HeciRegMeCsrHa.r.ME_RDY_HRA == 0) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +/** + Function sends one messsage through the HECI circular buffer and waits + for the corresponding ACK message. + + @param[in][out] Message Pointer to the message buffer. + @param[in] Length Length of the message in bytes. + @param[in][out] RecLength Length of the message response in bytes. + @param[in] HostAddress Address of the sending entity. + @param[in] MeAddress Address of the ME entity that should receive the message. + + @retval EFI_SUCCESS Command succeeded + @retval EFI_DEVICE_ERROR HECI Device error, command aborts abnormally + @retval EFI_TIMEOUT HECI does not return the bufferbefore timeout + @retval EFI_BUFFER_TOO_SMALL Message Buffer is too small for the Acknowledge + @exception EFI_UNSUPPORTED Current ME mode doesn't support send message through HECI +**/ +EFI_STATUS +EFIAPI +HeciSendwACK ( + IN OUT UINT32 *Message, + IN UINT32 Length, + IN OUT UINT32 *RecLength, + IN UINT8 HostAddress, + IN UINT8 MeAddress + ) +{ + EFI_STATUS Status; + UINT16 RetryCount; + UINT32 TempRecLength; + UINT32 MeMode; + + HeciGetMeMode (&MeMode); + if (MeMode == ME_MODE_SECOVER) { + return EFI_UNSUPPORTED; + } + /// + /// Send the message + /// + Status = HeciSend (Message, Length, HostAddress, MeAddress); + if (EFI_ERROR (Status)) { + return Status; + } + /// + /// Wait for ACK message + /// + TempRecLength = *RecLength; + for (RetryCount = 0; RetryCount < HECI_MAX_RETRY; RetryCount++) { + /// + /// Read Message + /// + Status = HeciReceive (BLOCKING, Message, &TempRecLength); + if (!EFI_ERROR (Status)) { + break; + } + /// + /// Reload receive length as it has been modified by the read function + /// + TempRecLength = *RecLength; + } + /// + /// Return read length and status + /// + *RecLength = TempRecLength; + return Status; +} + +/** + Me reset and waiting for ready + + @param[in] Delay The biggest waiting time + + @retval EFI_TIMEOUT ME is not ready + @retval EFI_SUCCESS Me is ready +**/ +EFI_STATUS +EFIAPI +MeResetWait ( + IN UINT32 Delay + ) +{ + HECI_HOST_CONTROL_REGISTER HeciRegHCsr; + UINT32 TimerStart; + UINT32 TimerEnd; + + /// + /// Make sure that HECI device BAR is correct and device is enabled. + /// + HeciMBAR = CheckAndFixHeciForAccess (); + + /// + /// Wait for the HOST Ready bit to be cleared to signal a reset + /// + StartTimer (&TimerStart, &TimerEnd, Delay); + HeciRegHCsr.ul = MMIOREADDWORD (HeciMBAR + H_CSR); + while (HeciRegHCsr.r.H_RDY == 1) { + /// + /// If timeout has expired, return fail + /// + if (Timeout (TimerStart, TimerEnd) != EFI_SUCCESS) { + return EFI_TIMEOUT; + } + + HeciRegHCsr.ul = MMIOREADDWORD (HeciMBAR + H_CSR); + } + + return EFI_SUCCESS; +} + +/** + Function forces a reinit of the heci interface by following the reset heci interface via host algorithm + in HPS 0.90 doc 4-17-06 njy + + @param[in] none + + @retval EFI_TIMEOUT ME is not ready + @retval EFI_SUCCESS Interface reset +**/ +EFI_STATUS +EFIAPI +ResetHeciInterface ( + VOID + ) +{ + HECI_HOST_CONTROL_REGISTER HeciRegHCsr; + HECI_ME_CONTROL_REGISTER HeciRegMeCsrHa; + UINT32 TimerStart; + UINT32 TimerEnd; + + /// + /// Make sure that HECI device BAR is correct and device is enabled. + /// + HeciMBAR = CheckAndFixHeciForAccess (); + + /// + /// Enable Reset + /// + HeciRegHCsr.ul = MMIOREADDWORD (HeciMBAR + H_CSR); + HeciRegHCsr.r.H_RST = 1; + HeciRegHCsr.r.H_IG = 1; + MMIOWRITEDWORD (HeciMBAR + H_CSR, HeciRegHCsr.ul); + + /// + /// Make sure that the reset started + /// + /// HeciRegHCsr.ul = MMIOREADDWORD(HeciMBAR + H_CSR); + /// + StartTimer (&TimerStart, &TimerEnd, HECI_INIT_TIMEOUT); + do { + /// + /// If 5 second timeout has expired, return fail + /// + if (Timeout (TimerStart, TimerEnd) != EFI_SUCCESS) { + return EFI_TIMEOUT; + } + /// + /// Read the ME CSR + /// + HeciRegHCsr.ul = MMIOREADDWORD (HeciMBAR + H_CSR); + } while (HeciRegHCsr.r.H_RDY == 1); + + /// + /// Wait for ME to perform reset + /// + /// HeciRegMeCsrHa.ul = MMIOREADDWORD(HeciMBAR + ME_CSR_HA); + /// + StartTimer (&TimerStart, &TimerEnd, HECI_INIT_TIMEOUT); + do { + /// + /// If 5 second timeout has expired, return fail + /// + if (Timeout (TimerStart, TimerEnd) != EFI_SUCCESS) { + return EFI_TIMEOUT; + } + /// + /// Read the ME CSR + /// + HeciRegMeCsrHa.ul = MMIOREADDWORD (HeciMBAR + ME_CSR_HA); + } while (HeciRegMeCsrHa.r.ME_RDY_HRA == 0); + + /// + /// Make sure IS has been signaled on the HOST side + /// + /// HeciRegHCsr.ul = MMIOREADDWORD(HeciMBAR + H_CSR); + /// + StartTimer (&TimerStart, &TimerEnd, HECI_INIT_TIMEOUT); + do { + /// + /// If 5 second timeout has expired, return fail + /// + if (Timeout (TimerStart, TimerEnd) != EFI_SUCCESS) { + return EFI_TIMEOUT; + } + /// + /// Read the ME CSR + /// + HeciRegHCsr.ul = MMIOREADDWORD (HeciMBAR + H_CSR); + } while (HeciRegHCsr.r.H_IS == 0); + + /// + /// Enable host side interface + /// + HeciRegHCsr.ul = MMIOREADDWORD (HeciMBAR + H_CSR);; + HeciRegHCsr.r.H_RST = 0; + HeciRegHCsr.r.H_IG = 1; + HeciRegHCsr.r.H_RDY = 1; + MMIOWRITEDWORD (HeciMBAR + H_CSR, HeciRegHCsr.ul); + + return EFI_SUCCESS; +} + +/** + Calculate if the circular buffer has overflowed. + Corresponds to HECI HPS (part of) section 4.2.1 + + @param[in] ReadPointer Location of the read pointer. + @param[in] WritePointer Location of the write pointer. + + @retval Number of filled slots. +**/ +UINT8 +FilledSlots ( + IN UINT32 ReadPointer, + IN UINT32 WritePointer + ) +{ + UINT8 FilledSlots; + + /// + /// Calculation documented in HECI HPS 0.68 section 4.2.1 + /// + FilledSlots = (((INT8) WritePointer) - ((INT8) ReadPointer)); + + return FilledSlots; +} + +/** + Calculate if the circular buffer has overflowed + Corresponds to HECI HPS (part of) section 4.2.1 + + @param[in] ReadPointer Value read from host/me read pointer + @param[in] WritePointer Value read from host/me write pointer + @param[in] BufferDepth Value read from buffer depth register + + @retval EFI_DEVICE_ERROR The circular buffer has overflowed + @retval EFI_SUCCESS The circular buffer does not overflowed +**/ +EFI_STATUS +OverflowCB ( + IN UINT32 ReadPointer, + IN UINT32 WritePointer, + IN UINT32 BufferDepth + ) +{ + UINT8 FilledSlots; + + /// + /// Calculation documented in HECI HPS 0.68 section 4.2.1 + /// + FilledSlots = (((INT8) WritePointer) - ((INT8) ReadPointer)); + + /// + /// test for overflow + /// + if (FilledSlots > ((UINT8) BufferDepth)) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +/** + Get an abstract Intel ME State from Firmware Status Register. + This is used to control BIOS flow for different Intel ME + functions + + @param[out] MeStatus Pointer for status report + see MeState.h - Abstract ME status definitions. + + @retval EFI_SUCCESS MeStatus copied + @retval EFI_INVALID_PARAMETER Pointer of MeStatus is invalid +**/ +EFI_STATUS +EFIAPI +HeciGetMeStatus ( + OUT UINT32 *MeStatus + ) +{ + HECI_FWS_REGISTER MeFirmwareStatus; + + if (MeStatus == NULL) { + return EFI_INVALID_PARAMETER; + } + + MeFirmwareStatus.ul = HeciPciRead32 (R_FWSTATE); + + if (MeFirmwareStatus.r.CurrentState == ME_STATE_NORMAL && MeFirmwareStatus.r.ErrorCode == ME_ERROR_CODE_NO_ERROR) { + *MeStatus = ME_READY; + } else if (MeFirmwareStatus.r.CurrentState == ME_STATE_RECOVERY) { + *MeStatus = ME_IN_RECOVERY_MODE; + } else if (MeFirmwareStatus.r.CurrentState == ME_STATE_INIT) { + *MeStatus = ME_INITIALIZING; + } else if (MeFirmwareStatus.r.CurrentState == ME_STATE_DISABLE_WAIT) { + *MeStatus = ME_DISABLE_WAIT; + } else if (MeFirmwareStatus.r.CurrentState == ME_STATE_TRANSITION) { + *MeStatus = ME_TRANSITION; + } else { + *MeStatus = ME_NOT_READY; + } + + if (MeFirmwareStatus.r.FwUpdateInprogress) { + *MeStatus |= ME_FW_UPDATES_IN_PROGRESS; + } + + if (MeFirmwareStatus.r.FwInitComplete == ME_FIRMWARE_COMPLETED) { + *MeStatus |= ME_FW_INIT_COMPLETE; + } + + if (MeFirmwareStatus.r.MeBootOptionsPresent == ME_BOOT_OPTIONS_PRESENT) { + *MeStatus |= ME_FW_BOOT_OPTIONS_PRESENT; + } + + DEBUG ((EFI_D_ERROR, "HECI MeStatus %X\n", MeFirmwareStatus.ul)); + + return EFI_SUCCESS; +} + +/** + Return ME Mode + + @param[out] MeMode Pointer for ME Mode report + + @retval EFI_SUCCESS MeMode copied + @retval EFI_INVALID_PARAMETER Pointer of MeMode is invalid +**/ +EFI_STATUS +EFIAPI +HeciGetMeMode ( + OUT UINT32 *MeMode + ) +{ + HECI_FWS_REGISTER MeFirmwareStatus; + + if (MeMode == NULL) { + return EFI_INVALID_PARAMETER; + } + + MeFirmwareStatus.ul = HeciPciRead32 (R_FWSTATE); + + switch (MeFirmwareStatus.r.MeOperationMode) { + case ME_OPERATION_MODE_NORMAL: + *MeMode = ME_MODE_NORMAL; + break; + + case ME_OPERATION_MODE_DEBUG: + *MeMode = ME_MODE_DEBUG; + break; + + case ME_OPERATION_MODE_SOFT_TEMP_DISABLE: + *MeMode = ME_MODE_TEMP_DISABLED; + break; + + case ME_OPERATION_MODE_SECOVR_JMPR: + case ME_OPERATION_MODE_SECOVR_HECI_MSG: + *MeMode = ME_MODE_SECOVER; + break; + + default: + *MeMode = ME_MODE_FAILED; + } + DEBUG ((EFI_D_ERROR, "HECI MeMode %X\n", MeFirmwareStatus.r.MeOperationMode)); + + return EFI_SUCCESS; +} diff --git a/ReferenceCode/ME/Heci/Dxe/Hecicore.h b/ReferenceCode/ME/Heci/Dxe/Hecicore.h new file mode 100644 index 0000000..4e60526 --- /dev/null +++ b/ReferenceCode/ME/Heci/Dxe/Hecicore.h @@ -0,0 +1,342 @@ +/** @file + Definitions for HECI driver + +@copyright + Copyright (c) 2006 - 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 + +**/ +#ifndef _HECI_CORE_H +#define _HECI_CORE_H + +#include "CoreBiosMsg.h" + +// +// HECI bus function version +// +#define HBM_MINOR_VERSION 0 +#define HBM_MAJOR_VERSION 1 + +// +// Prototypes +// + +/** + Determines if the HECI device is present and, if present, initializes it for + use by the BIOS. + + @param[in] None. + + @retval EFI_SUCCESS HECI device is present and initialized. + @retval EFI_DEVICE_ERROR No HECI controller. + @exception EFI_UNSUPPORTED HECI MSG is unsupported because ME MODE is in ME ALT Disabled & + SECOVR JMPR + @retval EFI_TIMEOUT ME is not ready +**/ +EFI_STATUS +InitializeHeciPrivate ( + VOID + ) +; +/** + Waits for the ME to report that it is ready for communication over the HECI + interface. + + @param[in] None. + + @retval EFI_SUCCESS ME is ready + @retval EFI_TIMEOUT ME is not ready +**/ +EFI_STATUS +WaitForMEReady ( + VOID + ) +; + +/** + Determines if the HECI device is present and, if present, initializes it for + use by the BIOS. + + @param[in] None. + + @retval EFI_SUCCESS HECI device is present and initialized + @retval EFI_TIMEOUT ME is not ready +**/ +EFI_STATUS +EFIAPI +HeciInitialize ( + VOID + ) +; + +/** + Heci Re-initializes it for Host + + @param[in] None. + + @retval EFI_TIMEOUT ME is not ready + @retval EFI_STATUS Status code returned by ResetHeciInterface +**/ +EFI_STATUS +EFIAPI +HeciReInitialize ( + VOID + ) +; + +/** + Heci Re-initializes it for Me + + @param[in] None. + + @retval EFI_TIMEOUT ME is not ready + @retval EFI_SUCCESS Re-initialization done +**/ +EFI_STATUS +EFIAPI +HeciReInitialize2 ( + VOID + ) +; + +/** + Function to pull one messsage packet off the HECI circular buffer. + Corresponds to HECI HPS (part of) section 4.2.4 + + @param[in] Blocking Used to determine if the read is BLOCKING or NON_BLOCKING. + @param[out] MessageHeader Pointer to a buffer for the message header. + @param[in] MessageData Pointer to a buffer to recieve the message in. + @param[in][out] Length On input is the size of the callers buffer in bytes. On + output this is the size of the packet in bytes. + + @retval EFI_SUCCESS One message packet read. + @retval EFI_DEVICE_ERROR The circular buffer is overflowed. + @retval EFI_NO_RESPONSE The circular buffer is empty + @retval EFI_TIMEOUT Failed to receive a full message + @retval EFI_BUFFER_TOO_SMALL Message packet is larger than caller's buffer +**/ +EFI_STATUS +HECIPacketRead ( + IN UINT32 Blocking, + OUT HECI_MESSAGE_HEADER *MessageHeader, + OUT UINT32 *MessageData, + IN OUT UINT32 *Length + ) +; + +/** + Reads a message from the ME across HECI. + + @param[in] Blocking Used to determine if the read is BLOCKING or NON_BLOCKING. + @param[in][out] MessageBody Pointer to a buffer used to receive a message. + @param[in][out] Length Pointer to the length of the buffer on input and the length + of the message on return. (in bytes) + + @retval EFI_SUCCESS One message packet read. + @retval EFI_DEVICE_ERROR Failed to initialize HECI or zero-length message packet read + @retval EFI_TIMEOUT HECI is not ready for communication + @retval EFI_BUFFER_TOO_SMALL The caller's buffer was not large enough +**/ +EFI_STATUS +EFIAPI +HeciReceive ( + IN UINT32 Blocking, + IN OUT UINT32 *MessageBody, + IN OUT UINT32 *Length + ) +; + +/** + Function sends one messsage (of any length) through the HECI circular buffer. + + @param[in] Message Pointer to the message data to be sent. + @param[in] Length Length of the message in bytes. + @param[in] HostAddress The address of the host processor. + @param[in] MeAddress Address of the ME subsystem the message is being sent to. + + @retval EFI_SUCCESS One message packet sent. + @retval EFI_DEVICE_ERROR Failed to initialize HECI + @retval EFI_TIMEOUT HECI is not ready for communication + @exception EFI_UNSUPPORTED Current ME mode doesn't support send message through HECI +**/ +EFI_STATUS +EFIAPI +HeciSend ( + IN UINT32 *Message, + IN UINT32 Length, + IN UINT8 HostAddress, + IN UINT8 MeAddress + ) +; +/** + Function sends one messsage packet through the HECI circular buffer + Corresponds to HECI HPS (part of) section 4.2.3 + + @param[in] MessageHeader Pointer to the message header. + @param[in] MessageData Pointer to the actual message data. + + @retval EFI_SUCCESS One message packet sent + @retval EFI_DEVICE_ERROR ME is not ready + @retval EFI_TIMEOUT HECI is not ready for communication +**/ +EFI_STATUS +HeciPacketWrite ( + IN HECI_MESSAGE_HEADER *MessageHeader, + IN UINT32 *MessageData + ) +; + +/** + Function sends one messsage through the HECI circular buffer and waits + for the corresponding ACK message. + + @param[in][out] Message Pointer to the message buffer. + @param[in] Length Length of the message in bytes. + @param[in][out] RecLength Length of the message response in bytes. + @param[in] HostAddress Address of the sending entity. + @param[in] MeAddress Address of the ME entity that should receive the message. + + @retval EFI_SUCCESS Command succeeded + @retval EFI_DEVICE_ERROR HECI Device error, command aborts abnormally + @retval EFI_TIMEOUT HECI does not return the bufferbefore timeout + @retval EFI_BUFFER_TOO_SMALL Message Buffer is too small for the Acknowledge + @exception EFI_UNSUPPORTED Current ME mode doesn't support send message through HECI +**/ +EFI_STATUS +EFIAPI +HeciSendwACK ( + IN OUT UINT32 *Message, + IN UINT32 Length, + IN OUT UINT32 *RecLength, + IN UINT8 HostAddress, + IN UINT8 MeAddress + ) +; + +/** + Me reset and waiting for ready + + @param[in] Delay The biggest waiting time + + @retval EFI_TIMEOUT ME is not ready + @retval EFI_SUCCESS Me is ready +**/ +EFI_STATUS +EFIAPI +MeResetWait ( + IN UINT32 Delay + ) +; + +/** + Function forces a reinit of the heci interface by following the reset heci interface via host algorithm + in HPS 0.90 doc 4-17-06 njy + + @param[in] none + + @retval EFI_TIMEOUT ME is not ready + @retval EFI_SUCCESS Interface reset +**/ +EFI_STATUS +EFIAPI +ResetHeciInterface ( + VOID + ) +; + +/** + Calculate if the circular buffer has overflowed. + Corresponds to HECI HPS (part of) section 4.2.1 + + @param[in] ReadPointer Location of the read pointer. + @param[in] WritePointer Location of the write pointer. + + @retval Number of filled slots. +**/ +UINT8 +FilledSlots ( + IN UINT32 ReadPointer, + IN UINT32 WritePointer + ) +; + +/** + Calculate if the circular buffer has overflowed + Corresponds to HECI HPS (part of) section 4.2.1 + + @param[in] ReadPointer Value read from host/me read pointer + @param[in] WritePointer Value read from host/me write pointer + @param[in] BufferDepth Value read from buffer depth register + + @retval EFI_DEVICE_ERROR The circular buffer has overflowed + @retval EFI_SUCCESS The circular buffer does not overflowed +**/ +EFI_STATUS +OverflowCB ( + IN UINT32 ReadPointer, + IN UINT32 WritePointer, + IN UINT32 BufferDepth + ) +; + +/** + Get an abstract Intel ME State from Firmware Status Register. + This is used to control BIOS flow for different Intel ME + functions + + @param[out] MeStatus Pointer for status report + see MeState.h - Abstract ME status definitions. + + @retval EFI_SUCCESS MeStatus copied + @retval EFI_INVALID_PARAMETER Pointer of MeStatus is invalid +**/ +EFI_STATUS +EFIAPI +HeciGetMeStatus ( + OUT UINT32 *MeStatus + ) +; + +/** + Return ME Mode + + @param[out] MeMode Pointer for ME Mode report + + @retval EFI_SUCCESS MeMode copied + @retval EFI_INVALID_PARAMETER Pointer of MeMode is invalid +**/ +EFI_STATUS +EFIAPI +HeciGetMeMode ( + OUT UINT32 *MeMode + ) +; + +/** + This function provides a standard way to verify the HECI cmd and MBAR regs + in its PCI cfg space are setup properly and that the local mHeciContext + variable matches this info. + + @param[in] None. + + @retval UINT64 HeciMar address +**/ +UINT64 +CheckAndFixHeciForAccess ( + VOID + ) +; +#endif // _HECI_CORE_H diff --git a/ReferenceCode/ME/Heci/Dxe/Hecidrv.c b/ReferenceCode/ME/Heci/Dxe/Hecidrv.c new file mode 100644 index 0000000..b34ea6f --- /dev/null +++ b/ReferenceCode/ME/Heci/Dxe/Hecidrv.c @@ -0,0 +1,1540 @@ +/** @file + HECI driver + +@copyright + Copyright (c) 2007 - 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 + +**/ + +// +// External include files do NOT need to be explicitly specified in real EDKII +// environment +// +#if !defined(EDK_RELEASE_VERSION) || (EDK_RELEASE_VERSION < 0x00020000) +#include "HeciDrv.h" +#include "HeciHpet.h" +#include "HeciCore.h" +#include "MeLib.h" +#include "EfiScriptLib.h" +#include "PchPlatformLib.h" + +#include EFI_GUID_DEFINITION (MePlatformReadyToBoot) +#include EFI_GUID_DEFINITION (MeBiosExtensionSetup) +#include EFI_PROTOCOL_DEFINITION (MeplatformPolicy) +#include EFI_PROTOCOL_DEFINITION (AmtReadyToBoot) +#include EFI_PROTOCOL_CONSUMER (ExitPmAuth) + +extern DXE_ME_POLICY_PROTOCOL *mDxePlatformMePolicy; + +#ifdef TCG_SUPPORT_FLAG +#include "Acpi1_0.h" +#include "Acpi2_0.h" +#include "Acpi3_0.h" +#include EFI_PROTOCOL_DEFINITION (TcgService) +#include "TpmPc.h" +#endif // TCG_SUPPORT_FLAG +#endif // EDK_RELEASE_VERSION +#define ONE_SECOND_TIMEOUT 1000000 +#define FWU_TIMEOUT 90 + +// +// Global driver data +// +HECI_INSTANCE *mHeciContext; +EFI_HANDLE mHeciDrv; +EFI_EVENT mExitBootServicesEvent; +EFI_EVENT mLegacyBootEvent; +DXE_MBP_DATA_PROTOCOL mMbpData; + +/** + This function provides a standard way to verify the HECI cmd and MBAR regs + in its PCI cfg space are setup properly and that the local mHeciContext + variable matches this info. + + @param[in] None. + + @retval UINT64 HeciMar address +**/ +UINT64 +CheckAndFixHeciForAccess ( + VOID + ) +{ + /// + /// Read HECI_MBAR in case it has changed + /// + /// + /// Check if Base register is 64 bits wide. + /// + if (HeciPciRead32 (R_HECIMBAR) & 0x4) { + mHeciContext->HeciMBAR = (((UINT64) HeciPciRead32 (R_HECIMBAR + 4) << 32) | + (UINT64) HeciPciRead32 (R_HECIMBAR)) & 0xFFFFFFF0; + } else { + mHeciContext->HeciMBAR = (UINT64) HeciPciRead32 (R_HECIMBAR) & 0xFFFFFFF0; + } + /// + /// Check if HECI_MBAR is disabled + /// + if ((HeciPciRead8 (PCI_COMMAND_OFFSET) & (EFI_PCI_COMMAND_MEMORY_SPACE | EFI_PCI_COMMAND_BUS_MASTER)) != + (EFI_PCI_COMMAND_MEMORY_SPACE | EFI_PCI_COMMAND_BUS_MASTER) + ) { + /// + /// If cmd reg in pci cfg space is not turned on turn it on. + /// + HeciPciOr8 ( + PCI_COMMAND_OFFSET, + EFI_PCI_COMMAND_MEMORY_SPACE | EFI_PCI_COMMAND_BUS_MASTER + ); + } + + return mHeciContext->HeciMBAR; +} + +/** + Enable Hpet function. + + @param[in] None. + + @retval None +**/ +VOID +EnableHpet ( + VOID + ) +{ + VOLATILE UINT32 *HpetConfigReg; + + HpetConfigReg = NULL; + /// + /// Get the High Precision Event Timer base address and enable the memory range + /// + HpetConfigReg = (UINT32 *) (UINTN) (PCH_RCRB_BASE + R_PCH_RCRB_HPTC); + switch (*HpetConfigReg & B_PCH_RCRB_HPTC_AS) { + case 0: + mHeciContext->HpetTimer = (VOID *) (UINTN) (HPET_ADDRESS_0); + break; + + case 1: + mHeciContext->HpetTimer = (VOID *) (UINTN) (HPET_ADDRESS_1); + break; + + case 2: + mHeciContext->HpetTimer = (VOID *) (UINTN) (HPET_ADDRESS_2); + break; + + case 3: + mHeciContext->HpetTimer = (VOID *) (UINTN) (HPET_ADDRESS_3); + break; + + default: + mHeciContext->HpetTimer = NULL; + break; + } + /// + /// Read this back to force the write-back. + /// + *HpetConfigReg = *HpetConfigReg | B_PCH_RCRB_HPTC_AE; + + /// + /// Start the timer so it is up and running + /// + mHeciContext->HpetTimer[HPET_GEN_CONFIG_LOW] = HPET_START; + mHeciContext->HpetTimer[HPET_GEN_CONFIG_LOW] = HPET_START; + + return ; +} + +#ifdef TCG_SUPPORT_FLAG + +/** + Perform measurement for HER register. + + @param[in] HerValue The value of HECI Extend Register. + @param[in] Index HerValue Size. + + @retval EFI_SUCCESS Measurement performed +**/ +EFI_STATUS +MeasureHer ( + IN UINT32 *HerValue, + IN UINT8 Index + ) +{ + EFI_STATUS Status; + EFI_TCG_PROTOCOL *TcgProtocol; + EFI_TCG_PCR_EVENT TcgEvent; + UINT32 EventNumber; + EFI_PHYSICAL_ADDRESS EventLogLastEntry; + + Status = gBS->LocateProtocol ( + &gEfiTcgProtocolGuid, + NULL, + (VOID **) &TcgProtocol + ); + if (EFI_ERROR (Status)) { + return Status; + } + /// + /// This below data will be stored in Tcg eventlog + /// + TcgEvent.Event.PostCode.PostCodeAddress = *HerValue; + TcgEvent.Event.PostCode.PostCodeLength = sizeof (UINT32); + + /// + /// Fill the TcgEvent Header + /// + TcgEvent.Header.PCRIndex = PCRi_CRTM_AND_POST_BIOS; + TcgEvent.Header.EventType = EV_S_CRTM_CONTENTS; + + TcgEvent.Header.EventDataSize = (Index * sizeof (UINT32)); + + Status = TcgProtocol->HashLogExtendEvent ( + TcgProtocol, + (EFI_PHYSICAL_ADDRESS) HerValue, + TcgEvent.Header.EventDataSize, + TPM_ALG_SHA, + (TCG_PCR_EVENT *) &TcgEvent, + &EventNumber, + &EventLogLastEntry + ); + return Status; +} + +/** + Me Measurement. + + @param[in] None. + + @retval EFI_NOT_READY Not ready for measurement. + @retval EFI_SUCCESS Measurement done +**/ +EFI_STATUS +MeMeasurement ( + VOID + ) +{ + EFI_STATUS Status; + DATA32_UNION Data32[7]; + UINT8 HerMax; + UINT8 HerIndex; + UINT8 Index; + + Index = 0; + /// + /// Measure HER + /// + HerMax = R_ME_HER5; + Data32[Index].Data32 = PciRead32 (PCI_LIB_ADDRESS (ME_BUS, ME_DEVICE_NUMBER, HECI_FUNCTION_NUMBER, R_ME_HERS)); + + if ((Data32[Index].Data32 & B_ME_EXTEND_REG_VALID) == B_ME_EXTEND_REG_VALID) { + if ((Data32[Index].Data8[0] & B_ME_EXTEND_REG_ALGORITHM) == V_ME_SHA_256) { + HerMax = R_ME_HER8; + } + + for (HerIndex = R_ME_HER1, Index = 0; HerIndex <= HerMax; HerIndex += 4, Index++) { + Data32[Index].Data32 = PciRead32 (PCI_LIB_ADDRESS (ME_BUS, ME_DEVICE_NUMBER, HECI_FUNCTION_NUMBER, HerIndex)); + } + + Status = MeasureHer (&Data32->Data32, Index); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "ME Measurement feature failed, Status is %r \n", Status)); + } + } else { + Status = EFI_NOT_READY; + } + + return Status; +} + +/** + Signal a event for last checking. + + @param[in] Event The event that triggered this notification function + @param[in] Context Pointer to the notification functions context + + @retval EFI_SUCCESS Event excuted and closed. +**/ +EFI_STATUS +MeMeasurementEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + MeMeasurement (); + + gBS->CloseEvent (Event); + + return EFI_SUCCESS; +} +#endif + +/** + Show warning message to user. + + @param[in] None. + + @retval EFI_SUCCESS Warning reported +**/ +EFI_STATUS +MeWarningMessage ( + VOID + ) +{ + HECI_FWS_REGISTER MeFirmwareStatus; + + MeFirmwareStatus.ul = HeciPciRead32 (R_FWSTATE); + + /// + /// Check for ME FPT Bad & FT BUP LD FLR + /// + if (MeFirmwareStatus.r.FptBad != 0 || MeFirmwareStatus.r.FtBupLdFlr != 0) { + MeReportError (MSG_ME_FW_UPDATE_FAILED); + } + + return EFI_SUCCESS; +} + +/** + Store the current value of DEVEN for S3 resume path + + @param[in] None + + @retval None +**/ +VOID +DeviceStatusSave ( + VOID + ) +{ + UINT32 Data; + + /// + /// Read RCBA register for saving + /// + Data = Mmio16 (PCH_RCRB_BASE, R_PCH_RCRB_FD2); + + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint16, + (UINTN) (PCH_RCRB_BASE + R_PCH_RCRB_FD2), + 1, + &Data + ); + Data = Mmio16 (PCH_RCRB_BASE, R_PCH_RCRB_FDSW); + + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint16, + (UINTN) (PCH_RCRB_BASE + R_PCH_RCRB_FDSW), + 1, + &Data + ); +} + +/** + ME BWG 1.0 5.3.1.1: IDER Workaround, perform this only when IDER device is present. + + @param[in] None + + @retval None +**/ +VOID +PerformIderWorkaround ( + VOID + ) +{ + EFI_STATUS Status; + UINT64 BaseAddress; + UINT64 BaseAddress2; + UINT64 Index; + BOOLEAN WorkaroundFlag; + + WorkaroundFlag = TRUE; + + Status = gDS->AllocateIoSpace ( + EfiGcdAllocateAnySearchBottomUp, + EfiGcdIoTypeIo, + 4, + 0x10, + &BaseAddress, + mHeciDrv, + NULL + ); + ASSERT_EFI_ERROR (Status); + + /// + /// Program BAR4 + /// + PciWrite32 (PCI_LIB_ADDRESS (ME_BUS, ME_DEVICE_NUMBER, IDER_FUNCTION_NUMBER, 0x20), (UINT32) BaseAddress); + + /// + /// Enable IDER IOE + /// + PciOr8 ( + PCI_LIB_ADDRESS (ME_BUS, + ME_DEVICE_NUMBER, + IDER_FUNCTION_NUMBER, + PCI_COMMAND_OFFSET), + EFI_PCI_COMMAND_IO_SPACE + ); + + /// + /// Perform the workaround if offset 3 bit 0 is not set + /// + if ((IoRead8 ((UINTN) BaseAddress + 3) & 0x01) == 00) { + Status = gDS->AllocateIoSpace ( + EfiGcdAllocateAnySearchBottomUp, + EfiGcdIoTypeIo, + 4, + 0x10, + &BaseAddress2, + mHeciDrv, + NULL + ); + ASSERT_EFI_ERROR (Status); + PciWrite32 (PCI_LIB_ADDRESS (ME_BUS, ME_DEVICE_NUMBER, IDER_FUNCTION_NUMBER, 0x10), (UINT32) BaseAddress2); + /// + /// check all ports to make sure all are 0x7f before running the workaround + /// + for (Index = 0; Index <= 7; Index++) { + if (IoRead8 ((UINTN) BaseAddress2 + (UINTN) Index) != 0x7f) { + WorkaroundFlag = FALSE; + break; + } + } + /// + /// Disable IDER IOE and clear BAR0 and BAR4 + /// + PciAnd8 ( + PCI_LIB_ADDRESS (ME_BUS, + ME_DEVICE_NUMBER, + IDER_FUNCTION_NUMBER, + PCI_COMMAND_OFFSET), + (UINT8)~EFI_PCI_COMMAND_IO_SPACE + ); + PciWrite32 (PCI_LIB_ADDRESS (ME_BUS, ME_DEVICE_NUMBER, IDER_FUNCTION_NUMBER, 0x10), 0); + PciWrite32 (PCI_LIB_ADDRESS (ME_BUS, ME_DEVICE_NUMBER, IDER_FUNCTION_NUMBER, 0x20), 0); + + if (WorkaroundFlag) { + IderDisable (); + } + + gDS->FreeIoSpace (BaseAddress2, (UINT64) 0x10); + } else { + PciAnd8 ( + PCI_LIB_ADDRESS (ME_BUS, + ME_DEVICE_NUMBER, + IDER_FUNCTION_NUMBER, + PCI_COMMAND_OFFSET), + (UINT8)~EFI_PCI_COMMAND_IO_SPACE + ); + PciWrite32 (PCI_LIB_ADDRESS (ME_BUS, ME_DEVICE_NUMBER, IDER_FUNCTION_NUMBER, 0x20), 0); + } + + gDS->FreeIoSpace (BaseAddress, (UINT64) 0x10); + return ; +} + +/** + Disable ME Devices when needed + + @param[in] None + + @retval EFI_SUCCESS Always return EFI_SUCCESS +**/ +EFI_STATUS +MeDeviceConfigure ( + VOID + ) +{ + UINT32 MeMode; + UINT16 VendorID; + UINT16 DeviceID; + + HeciGetMeMode (&MeMode); + if (MeMode == ME_MODE_NORMAL) { + if (mHeciContext->MeFwImageType != INTEL_ME_5MB_FW) { + /// + /// We will disable all AMT relevant devices in 1.5M SKU + /// + IderDisable (); + SolDisable (); + Usbr1Disable (); + Usbr2Disable (); + } else { + /// + /// ME BWG 1.0 5.3.1.1: IDER Workaround, perform this only when IDER device is present. + /// + VendorID = PciRead16 (PCI_LIB_ADDRESS (ME_BUS, ME_DEVICE_NUMBER, IDER_FUNCTION_NUMBER, 0x00)); + DeviceID = PciRead16 (PCI_LIB_ADDRESS (ME_BUS, ME_DEVICE_NUMBER, IDER_FUNCTION_NUMBER, 0x02)); + if ((VendorID == V_ME_IDER_VENDOR_ID) && IS_PCH_LPT_IDER_DEVICE_ID(DeviceID) + ) { + PerformIderWorkaround (); + } + } + } + + return EFI_SUCCESS; +} + +/** + Send ME the BIOS end of Post message. + + @param[in] None. + + @retval EFI_SUCCESS Always return EFI_SUCCESS except for policy initization failure. + @exception EFI_UNSUPPORTED Policy initization failure. +**/ +EFI_STATUS +MeEndOfPostEvent ( + VOID + ) +{ + EFI_STATUS Status; + EFI_HECI_PROTOCOL *Heci; + UINT32 MeStatus; + UINT8 EopSendRetries; + UINT32 HECI_BASE_ADDRESS; + HECI_HOST_CONTROL_REGISTER HeciRegHCsr; + VOLATILE HECI_HOST_CONTROL_REGISTER *HeciRegHCsrPtr; + VOLATILE HECI_ME_CONTROL_REGISTER *HeciRegMeCsrHaPtr; + + // + // Init ME Policy Library, continue to send EOP message even if can't find Me Platform Policy + // + if (mDxePlatformMePolicy == NULL) { + MePolicyLibInit (); + } + + Status = gBS->LocateProtocol ( + &gEfiHeciProtocolGuid, + NULL, + (VOID **) &Heci + ); + if (!EFI_ERROR (Status)) { + /// + /// Send EOP message when ME is ready. Do not care about if ME FW INIT is completed. + /// + Status = Heci->GetMeStatus (&MeStatus); + ASSERT_EFI_ERROR (Status); + + if (ME_STATUS_ME_STATE_ONLY (MeStatus) == ME_READY) { + + if (MeEndOfPostEnabled ()) { + DEBUG ((EFI_D_INFO, "Sending EOP...\n")); + + // + // Initialize pointers to control registers + // + HECI_BASE_ADDRESS = PciRead32 (PCI_LIB_ADDRESS (ME_BUS, ME_DEVICE_NUMBER, HECI_FUNCTION_NUMBER, R_HECIMBAR)) & 0xFFFFFFF0; + HeciRegHCsrPtr = (VOID *) (UINTN) (HECI_BASE_ADDRESS + H_CSR); + HeciRegMeCsrHaPtr = (VOID *) (UINTN) (HECI_BASE_ADDRESS + ME_CSR_HA); + + for (EopSendRetries = 0; EopSendRetries <= MAX_EOP_SEND_RETRIES; EopSendRetries++) { + + Status = HeciSendEndOfPostMessage (mHeciDrv); + if (Status == EFI_SUCCESS) { + break; + } + + MeReportError (MSG_EOP_ERROR); + + // + // Set H_RST and H_IG bits to reset HECI + // + HeciRegHCsr.ul = HeciRegHCsrPtr->ul; + HeciRegHCsr.r.H_RST = 1; + HeciRegHCsr.r.H_IG = 1; + HeciRegHCsrPtr->ul = HeciRegHCsr.ul; + + // + // Wait for ME_RDY + // + if (WaitForMEReady () != EFI_SUCCESS) { + Status = EFI_TIMEOUT; + break; + } + + // + // Clear H_RST, set H_RDY & H_IG bits + // + HeciRegHCsr.ul = HeciRegHCsrPtr->ul; + HeciRegHCsr.r.H_RST = 0; + HeciRegHCsr.r.H_IG = 1; + HeciRegHCsr.r.H_RDY = 1; + HeciRegHCsrPtr->ul = HeciRegHCsr.ul; + } + + if (EFI_ERROR(Status)) { + // + // Send HECI_BUS_DISABLE + // + for (EopSendRetries = 0; EopSendRetries <= MAX_EOP_SEND_RETRIES; EopSendRetries++) { + Status = HeciDisableHeciBusMsg(); + if (!EFI_ERROR(Status)) { + break; + } + } + + // + // Disable HECI function + // + HeciDisable(); + Heci2Disable(); + } + + } + } else if (ME_STATUS_ME_STATE_ONLY (MeStatus) == ME_DISABLE_WAIT) { + MeReportError (MSG_PLAT_DISABLE_WAIT); + } + + } + + return Status; +} + +/** + 1. Cf9Gr Lock Config + - PCH BIOS Spec Rev 0.9 Section 18.4 Additional Power Management Programming + Step 2 + Set "Power Management Initialization Register (PMIR) Field 1", D31:F0:ACh[31] = 1b + for production machine according to "RS - PCH Intel Management Engine + (Intel(r) ME) BIOS Writer's Guide". + 2. Function Disable SUS Well Lock + - PCH EDS 10.1.76 request that FDSW must be set when Intel Active Management Technology + is Enabled + + @param[in] None + + @retval Status. +**/ +EFI_STATUS +LockConfig ( + VOID + ) +{ + EFI_STATUS Status; + EFI_HECI_PROTOCOL *Heci; + UINT32 MeMode; + HECI_FWS_REGISTER MeFirmwareStatus; + UINTN Address; + UINT32 Data; + + Status = gBS->LocateProtocol ( + &gEfiHeciProtocolGuid, + NULL, + (VOID **) &Heci + ); + if (!EFI_ERROR (Status)) { + /// + /// Check ME Status + /// + Status = Heci->GetMeMode (&MeMode); + ASSERT_EFI_ERROR (Status); + + MeFirmwareStatus.ul = HeciPciRead32 (R_FWSTATE); + + /// + /// PCH BIOS Spec Rev 0.9 Section 18.4 Additional Power Management Programming + /// Step 2 + /// Set "Power Management Initialization Register (PMIR) Field 1", D31:F0:ACh[31] = 1b + /// for production machine according to "RS - PCH Intel Management Engine + /// (Intel(r) ME) BIOS Writer's Guide". + /// + /// PCH ME BWG section 4.5.1 + /// The IntelR FPT tool /GRST option uses CF9GR bit to trigger global reset. + /// Based on above reason, the BIOS should not lock down CF9GR bit during Manufacturing and + /// Re-manufacturing environment. + /// + Data = 0; + if ((((MeMode == ME_MODE_NORMAL) || (MeMode == ME_MODE_TEMP_DISABLED)) && !(MeFirmwareStatus.r.ManufacturingMode))) { + /// + /// PCH ME BWG section 4.4.1 + /// BIOS must also ensure that CF9GR is cleared and locked (via bit31 of the same register) before + /// handing control to the OS in order to prevent the host from issuing global resets and reseting + /// Intel Management Engine. + /// + Data |= B_PCH_LPC_PMIR_CF9LOCK; + } + + Address = PCI_LIB_ADDRESS ( + DEFAULT_PCI_BUS_NUMBER_PCH, + PCI_DEVICE_NUMBER_PCH_LPC, + PCI_FUNCTION_NUMBER_PCH_LPC, + R_PCH_LPC_PMIR + ); + PciAndThenOr32 ( + Address, + (UINT32) (~(B_PCH_LPC_PMIR_CF9LOCK | B_PCH_LPC_PMIR_CF9GR)), + (UINT32) Data + ); + + /// + /// Function Disable SUS Well lockdown + /// + if (MeMode == ME_MODE_NORMAL) { + if (mHeciContext->MeFwImageType == INTEL_ME_5MB_FW) { + DEBUG ((EFI_D_ERROR, "Function Disable SUS Well lockdown!\n")); + FunctionDisableWellLockdown (); + } + } + } + + return Status; +} + +/** + Halt Boot for up to 90 seconds if Bit 11 of FW Status Register (FW_UPD_IN_PROGRESS) is set + + @param[in] None + + @retval None +**/ +VOID +CheckFwUpdInProgress ( + VOID + ) +{ + HECI_FWS_REGISTER FwStatus; + UINT8 StallCount; + EFI_STATUS Status; + + StallCount = 0; + Status = mHeciContext->HeciCtlr.GetMeStatus (&FwStatus.ul); + if (!EFI_ERROR (Status)) { + if (FwStatus.ul & ME_FW_UPDATES_IN_PROGRESS) { + MeReportError (MSG_ME_FW_UPDATE_WAIT); + } + + while ((FwStatus.ul & ME_FW_UPDATES_IN_PROGRESS) && (StallCount < FWU_TIMEOUT)) { + gBS->Stall (ONE_SECOND_TIMEOUT); + StallCount = StallCount + 1; + Status = mHeciContext->HeciCtlr.GetMeStatus (&FwStatus.ul); + } + } + + return ; +} + +/** + Signal a event for Me ready to boot. + + @param[in] Event The event that triggered this notification function + @param[in] Context Pointer to the notification functions context + + @retval None +**/ +VOID +EFIAPI +MeReadyToBootEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + EFI_EVENT MePlatformReadyToBootEvent; + EFI_HANDLE *Handles; + UINTN Index; + UINTN Count; + AMT_READY_TO_BOOT_PROTOCOL *AmtReadyToBoot; + UINT32 MeMode; + UINT32 MeStatus; +#ifdef TCG_SUPPORT_FLAG + EFI_EVENT LegacyBootEvent; + EFI_EVENT ExitBootServicesEvent; + + Status = MeMeasurement (); + if (Status == EFI_NOT_READY) { + /// + /// Create a Legacy Boot event. + /// + Status = EfiCreateEventLegacyBootEx ( + EFI_TPL_CALLBACK, + MeMeasurementEvent, + NULL, + &LegacyBootEvent + ); + ASSERT_EFI_ERROR (Status); + + /// + /// Create a ExitBootService event. + /// + Status = gBS->CreateEvent ( + EVENT_SIGNAL_EXIT_BOOT_SERVICES, + EFI_TPL_CALLBACK, + MeMeasurementEvent, + NULL, + &ExitBootServicesEvent + ); + ASSERT_EFI_ERROR (Status); + } + +#endif //TCG_SUPPORT_FLAG + /// + /// PCH BIOS Spec Rev 0.8.0, Section 22.8.3.1 ASPM on DMI and the PCI Express Root Ports + /// Step g + /// Issue "WRITE_ICC_REGISTER" MEI message to program ICC register offset 0x4 with 0x000999999 + /// This is always needed for PCIE with hotplug on and off and PCIE RP enabled and disabled. + /// + if(GetPchSeries() == PchLp) { + Status = HeciWriteIccRegDword(0x0004, 0x00999999, ICC_RESPONSE_MODE_SKIP); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Heci writes to TMCSRCCLK failed. Status = %X\n", Status)); + } + } + + /// + /// We will trigger all events in order + /// + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gAmtReadyToBootProtocolGuid, + NULL, + &Count, + &Handles + ); + if (!EFI_ERROR (Status)) { + for (Index = 0; Index < Count; Index++) { + Status = gBS->HandleProtocol (Handles[Index], &gAmtReadyToBootProtocolGuid, (VOID **) &AmtReadyToBoot); + ASSERT_EFI_ERROR (Status); + AmtReadyToBoot->Signal (); + } + } + + Status = gBS->CreateEventEx ( + EFI_EVENT_NOTIFY_SIGNAL, + EFI_TPL_CALLBACK, + MeEmptyEvent, + NULL, + &gMePlatformReadyToBootGuid, + &MePlatformReadyToBootEvent + ); + ASSERT_EFI_ERROR (Status); + if (!EFI_ERROR (Status)) { + gBS->SignalEvent (MePlatformReadyToBootEvent); + gBS->CloseEvent (MePlatformReadyToBootEvent); + } + + HeciGetMeMode (&MeMode); + HeciGetMeStatus (&MeStatus); + if ((MeMode == ME_MODE_NORMAL) && + ((ME_STATUS_ME_STATE_ONLY (MeStatus) == ME_IN_RECOVERY_MODE) || (ME_STATUS_ME_STATE_ONLY (MeStatus) == ME_READY)) + ) { + + CheckFwUpdInProgress (); + + Status = MeWarningMessage (); + ASSERT_EFI_ERROR (Status); + + Status = MeEndOfPostEvent (); + ASSERT_EFI_ERROR (Status); + } + + /// + /// Set EndOfPostDone regardless whether the EOP msg was sent + /// + if (MeEndOfPostEnabled ()) { + mDxePlatformMePolicy->MeConfig.EndOfPostDone = 1; + } + + /// + /// PMIR Configuration & FDSW Lockdown + /// + Status = LockConfig (); + ASSERT_EFI_ERROR (Status); + + /// + /// Disable Heci2 if policy dictates + /// + Heci2Disable (); + + /// + /// If ME Mode is running in ME Temp Disable state, disable Heci1, HECI2, Ider and Sol + /// + HeciGetMeMode (&MeMode); + if (MeMode == ME_MODE_TEMP_DISABLED) { + DisableAllMEDevices (); + } + + gBS->CloseEvent (Event); + + return; +} + +/** + Signal a event to save Me relevant registers and this event must be run before ExitPmAuth. + + @param[in] Event The event that triggered this notification function + @param[in] ParentImageHandle Pointer to the notification functions context + + @retval None +**/ +VOID +EFIAPI +MeScriptSaveEvent ( + IN EFI_EVENT Event, + IN VOID *ParentImageHandle + ) +{ + EFI_STATUS Status; + VOID *ProtocolPointer; + EFI_HECI_PROTOCOL *Heci; + UINT32 MeMode; + HECI_FWS_REGISTER MeFirmwareStatus; + UINTN Address; + UINT32 Data; + UINT32 MebxSetupVariableAttributes; + UINTN MebxSetupVariableDataSize; + ME_BIOS_EXTENSION_SETUP MeBiosExtensionSetup; + const UINT8 Str5MBFw[sizeof (MEFW_5M_STRING)] = MEFW_5M_STRING; + EFI_MEBX_PROTOCOL *MebxProtocol; + + INITIALIZE_SCRIPT (ParentImageHandle, gST); + + /// + /// Check whether this is real ExitPmAuth notification, or just a SignalEvent + /// + Status = gBS->LocateProtocol (&gExitPmAuthProtocolGuid, NULL, &ProtocolPointer); + if (EFI_ERROR (Status)) { + return; + } + /// + /// PMIR Configuration Save + /// + Status = gBS->LocateProtocol ( + &gEfiHeciProtocolGuid, + NULL, + (VOID **) &Heci + ); + if (EFI_ERROR (Status)) { + return; + } + /// + /// Check ME Status + /// + Status = Heci->GetMeMode (&MeMode); + ASSERT_EFI_ERROR (Status); + + MeFirmwareStatus.ul = HeciPciRead32 (R_FWSTATE); + + /// + /// Init ME Policy Library + /// + Status = MePolicyLibInit (); + if (EFI_ERROR (Status)) { + return; + } + +#ifdef EFI_DEBUG + // + // Dump the ME platform policy + // + DxeMePolicyDebugDump (); +#endif + + /// + /// Report ME components version information to FVI + /// + InitFviDataHubCbContext ( + mDxePlatformMePolicy->MeMiscConfig.FviSmbiosType, + (UINT8) mMeFviElements, + &mMeFviVersionData + ); + + mMeFviElementsData[EnumMeFw].Element.Version.MajorVersion = (UINT8) mMbpData.MeBiosPayload.FwVersionName.MajorVersion; + mMeFviElementsData[EnumMeFw].Element.Version.MinorVersion = (UINT8) mMbpData.MeBiosPayload.FwVersionName.MinorVersion; + mMeFviElementsData[EnumMeFw].Element.Version.Revision = (UINT8) mMbpData.MeBiosPayload.FwVersionName.HotfixVersion; + mMeFviElementsData[EnumMeFw].Element.Version.BuildNum = (UINT16) mMbpData.MeBiosPayload.FwVersionName.BuildVersion; + if (mMbpData.MeBiosPayload.FwPlatType.RuleData.Fields.IntelMeFwImageType == INTEL_ME_5MB_FW) { + CopyMem (mMeFviElementsData[EnumMeFw].Element.VerString, Str5MBFw, sizeof (MEFW_5M_STRING)); + } + Status = gBS->LocateProtocol (&gEfiMebxProtocolGuid, NULL, (VOID **) &MebxProtocol); + if (!EFI_ERROR (Status)) { + mMeFviElementsData[EnumMebx].Element.Version.MajorVersion = (UINT8) MebxProtocol->MebxVersion.Major; + mMeFviElementsData[EnumMebx].Element.Version.MinorVersion = (UINT8) MebxProtocol->MebxVersion.Minor; + mMeFviElementsData[EnumMebx].Element.Version.Revision = (UINT8) MebxProtocol->MebxVersion.Hotfix; + mMeFviElementsData[EnumMebx].Element.Version.BuildNum = (UINT16) MebxProtocol->MebxVersion.Build; + } + + CreateRcFviDatahub (&mMeFviVersionData); + + /// + /// PCH BIOS Spec Rev 0.9 Section 18.4 Additional Power Management Programming + /// Step 2 + /// Set "Power Management Initialization Register (PMIR) Field 1", D31:F0:ACh[31] = 1b + /// for production machine according to "RS - PCH Intel Management Engine + /// (Intel(r) ME) BIOS Writer's Guide". + /// + /// PCH ME BWG section 4.5.1 + /// The IntelR FPT tool /GRST option uses CF9GR bit to trigger global reset. + /// Based on above reason, the BIOS should not lock down CF9GR bit during Manufacturing and + /// Re-manufacturing environment. + /// + Address = PCI_LIB_ADDRESS ( + DEFAULT_PCI_BUS_NUMBER_PCH, + PCI_DEVICE_NUMBER_PCH_LPC, + PCI_FUNCTION_NUMBER_PCH_LPC, + R_PCH_LPC_PMIR + ); + Data = PciRead32 (Address); + Data &= (UINT32) (~(B_PCH_LPC_PMIR_CF9LOCK | B_PCH_LPC_PMIR_CF9GR)); + + if ((((MeMode == ME_MODE_NORMAL) || (MeMode == ME_MODE_TEMP_DISABLED)) && !(MeFirmwareStatus.r.ManufacturingMode))) { + /// + /// PCH ME BWG section 4.4.1 + /// BIOS must also ensure that CF9GR is cleared and locked (via bit31 of the same register) before + /// handing control to the OS in order to prevent the host from issuing global resets and reseting + /// Intel Management Engine. + /// + Data |= (UINT32) (B_PCH_LPC_PMIR_CF9LOCK); + } +#ifdef SUS_WELL_RESTORE + /// + /// PMIR is a resume well register and has no script save for it. + /// System may go through S3 resume path from G3 if RapidStart is enabled, + /// that means all resume well registers will be reset to defaults. + /// Save boot script for PMIR register if RapidStart is enabled. + /// + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint32, + (UINTN) MmPciAddress (0x0, + DEFAULT_PCI_BUS_NUMBER_PCH, + PCI_DEVICE_NUMBER_PCH_LPC, + PCI_FUNCTION_NUMBER_PCH_LPC, + R_PCH_LPC_PMIR), + 1, + &Data + ); +#endif + /// + /// + /// Read RCBA register for saving + /// + Data = Mmio16 (PCH_RCRB_BASE, R_PCH_RCRB_FD2); + /// + /// Disable Heci2 if policy dictates + /// + Data |= (BIT0 << HECI2); + + /// + /// If ME Mode is running in ME Temp Disable state, disable Heci1, HECI2, Ider and Sol + /// + if ((MeMode == ME_MODE_TEMP_DISABLED) || (MeMode == ME_MODE_SECOVER)) { + Data |= ((BIT0 << HECI1) + (BIT0 << HECI2) + (BIT0 << IDER) + (BIT0 << SOL)); + } + + if (MeMode == ME_MODE_NORMAL) { + if (mHeciContext->MeFwImageType == INTEL_ME_1_5MB_FW) { + /// + /// We will disable HECI2, Ider and Sol in 1.5M SKU + /// + Data |= ((BIT0 << HECI2) + (BIT0 << IDER) + (BIT0 << SOL)); + } else if (mHeciContext->MeFwImageType == INTEL_ME_5MB_FW) { + MebxSetupVariableAttributes = EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS | + EFI_VARIABLE_NON_VOLATILE; + MebxSetupVariableDataSize = sizeof (ME_BIOS_EXTENSION_SETUP); + + Status = gST->RuntimeServices->GetVariable ( + gEfiMeBiosExtensionSetupName, + &gEfiMeBiosExtensionSetupGuid, + &MebxSetupVariableAttributes, + &MebxSetupVariableDataSize, + &MeBiosExtensionSetup + ); + if (!EFI_ERROR (Status)) { + if ((MeBiosExtensionSetup.AmtSolIder & SOL_ENABLE) == 0) { + Data |= (BIT0 << SOL); + } + + if ((MeBiosExtensionSetup.AmtSolIder & IDER_ENABLE) == 0) { + Data |= (BIT0 << IDER); + } + } + } + } + + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint16, + (UINTN) (PCH_RCRB_BASE + R_PCH_RCRB_FD2), + 1, + &Data + ); + /// + /// Function Disable SUS Well lockdown + /// + Data = Mmio16 (PCH_RCRB_BASE, R_PCH_RCRB_FDSW); + + if (MeMode == ME_MODE_NORMAL) { + if (mHeciContext->MeFwImageType == INTEL_ME_5MB_FW) { + Data |= B_PCH_RCRB_FDSW_FDSWL; + } + } + + SCRIPT_MEM_WRITE ( + EFI_ACPI_S3_RESUME_SCRIPT_TABLE, + EfiBootScriptWidthUint16, + (UINTN) (PCH_RCRB_BASE + R_PCH_RCRB_FDSW), + 1, + &Data + ); + + gBS->CloseEvent (Event); + return; +} + +/** + Send Get Firmware SKU Request to ME + + @param[out] FwCapsSku Return FwCapsSku mask for Get Firmware Capability SKU + + @exception EFI_UNSUPPORTED Current ME mode doesn't support this function + @retval EFI_SUCCESS Command succeeded + @retval EFI_DEVICE_ERROR HECI Device error, command aborts abnormally + @retval EFI_TIMEOUT HECI does not return the buffer before timeout + @retval EFI_BUFFER_TOO_SMALL Message Buffer is too smallfor the Acknowledge +**/ +EFI_STATUS +MbpGetFwCapsSkuThroughHeci ( + OUT MEFWCAPS_SKU *FwCapsSku + ) +{ + EFI_STATUS Status; + GEN_GET_FW_CAPS_SKU_BUFFER MsgGenGetFwCapsSku; + UINT32 Length; + UINT32 RespLength; + + MsgGenGetFwCapsSku.Request.MKHIHeader.Data = 0; + MsgGenGetFwCapsSku.Request.MKHIHeader.Fields.GroupId = MKHI_FWCAPS_GROUP_ID; + MsgGenGetFwCapsSku.Request.MKHIHeader.Fields.Command = FWCAPS_GET_RULE_CMD; + MsgGenGetFwCapsSku.Request.MKHIHeader.Fields.IsResponse = 0; + MsgGenGetFwCapsSku.Request.Data.RuleId = 0; + Length = sizeof (GEN_GET_FW_CAPSKU); + RespLength = sizeof(GEN_GET_FW_CAPS_SKU_ACK); + + /// + /// Send Get FW SKU Request to ME + /// + Status = HeciSendwACK ( + (UINT32 *) &MsgGenGetFwCapsSku, + Length, + &RespLength, + BIOS_FIXED_HOST_ADDR, + HECI_CORE_MESSAGE_ADDR + ); + + if (!EFI_ERROR(Status) && + ((MsgGenGetFwCapsSku.Response.MKHIHeader.Fields.Command) == FWCAPS_GET_RULE_CMD) && + ((MsgGenGetFwCapsSku.Response.MKHIHeader.Fields.IsResponse) == 1) && + (MsgGenGetFwCapsSku.Response.MKHIHeader.Fields.Result == 0) + ) { + *FwCapsSku = MsgGenGetFwCapsSku.Response.Data.FWCapSku; + return EFI_SUCCESS; + } + + return Status; +} + +/** + Send Get Platform Type Request to ME + + @param[in] RuleData PlatformBrand, + IntelMeFwImageType, + SuperSku, + PlatformTargetMarketType, + PlatformTargetUsageType + + @exception EFI_UNSUPPORTED Current ME mode doesn't support this function + @retval EFI_SUCCESS Command succeeded + @retval EFI_DEVICE_ERROR HECI Device error, command aborts abnormally + @retval EFI_TIMEOUT HECI does not return the buffer before timeout + @retval EFI_BUFFER_TOO_SMALL Message Buffer is too smallfor the Acknowledge +**/ +EFI_STATUS +MbpGetPlatformTypeThroughHeci ( + OUT PLATFORM_TYPE_RULE_DATA *RuleData + ) +{ + EFI_STATUS Status; + GEN_GET_PLATFORM_TYPE_BUFFER MsgGenGetPlatformType; + UINT32 Length; + UINT32 RespLength; + + MsgGenGetPlatformType.Request.MKHIHeader.Data = 0; + MsgGenGetPlatformType.Request.MKHIHeader.Fields.GroupId = MKHI_FWCAPS_GROUP_ID; + MsgGenGetPlatformType.Request.MKHIHeader.Fields.Command = FWCAPS_GET_RULE_CMD; + MsgGenGetPlatformType.Request.MKHIHeader.Fields.IsResponse = 0; + MsgGenGetPlatformType.Request.Data.RuleId = 0x1D; + Length = sizeof (GEN_GET_PLATFORM_TYPE); + RespLength = sizeof(GEN_GET_PLATFORM_TYPE_ACK); + + /// + /// Send Get FW SKU Request to ME + /// + Status = HeciSendwACK ( + (UINT32 *) &MsgGenGetPlatformType, + Length, + &RespLength, + BIOS_FIXED_HOST_ADDR, + HECI_CORE_MESSAGE_ADDR + ); + + if (!EFI_ERROR(Status) && + ((MsgGenGetPlatformType.Response.MKHIHeader.Fields.Command) == FWCAPS_GET_RULE_CMD) && + ((MsgGenGetPlatformType.Response.MKHIHeader.Fields.IsResponse) == 1) && + (MsgGenGetPlatformType.Response.MKHIHeader.Fields.Result == 0) + ) { + *RuleData = MsgGenGetPlatformType.Response.Data.RuleData; + return EFI_SUCCESS; + } + + return Status; +} + +/** + Send Get Firmware Features State Request to ME + + @param[out] FwFeaturesState Return FwFeaturesState mask for Get Firmware Features State + + @exception EFI_UNSUPPORTED Current ME mode doesn't support this function + @retval EFI_SUCCESS Command succeeded + @retval EFI_DEVICE_ERROR HECI Device error, command aborts abnormally + @retval EFI_TIMEOUT HECI does not return the buffer before timeout + @retval EFI_BUFFER_TOO_SMALL Message Buffer is too smallfor the Acknowledge +**/ +EFI_STATUS +MbpGetFwFeaturesStateThroughHeci ( + OUT MEFWCAPS_SKU *FwFeaturesState + ) +{ + EFI_STATUS Status; + GEN_GET_FW_CAPS_SKU_BUFFER MsgGenGetFwCapsSku; + UINT32 Length; + UINT32 RespLength; + + MsgGenGetFwCapsSku.Request.MKHIHeader.Data = 0; + MsgGenGetFwCapsSku.Request.MKHIHeader.Fields.GroupId = MKHI_FWCAPS_GROUP_ID; + MsgGenGetFwCapsSku.Request.MKHIHeader.Fields.Command = FWCAPS_GET_RULE_CMD; + MsgGenGetFwCapsSku.Request.MKHIHeader.Fields.IsResponse = 0; + MsgGenGetFwCapsSku.Request.Data.RuleId = 0x20; + Length = sizeof (GEN_GET_FW_CAPSKU); + RespLength = sizeof(GEN_GET_FW_CAPS_SKU_ACK); + + /// + /// Send Get FW SKU Request to ME + /// + Status = HeciSendwACK ( + (UINT32 *) &MsgGenGetFwCapsSku, + Length, + &RespLength, + BIOS_FIXED_HOST_ADDR, + HECI_CORE_MESSAGE_ADDR + ); + + if (!EFI_ERROR(Status) && + ((MsgGenGetFwCapsSku.Response.MKHIHeader.Fields.Command) == FWCAPS_GET_RULE_CMD) && + ((MsgGenGetFwCapsSku.Response.MKHIHeader.Fields.IsResponse) == 1) && + (MsgGenGetFwCapsSku.Response.MKHIHeader.Fields.Result == 0) + ) { + *FwFeaturesState = MsgGenGetFwCapsSku.Response.Data.FWCapSku; + return EFI_SUCCESS; + } + + return Status; +} + +/** + Install MbpData protocol. + + @param[in] None + + @retval None +**/ +VOID +InstallMbpDataProtocol ( + VOID + ) +{ + EFI_STATUS Status; + UINT32 MeMode; + UINT32 MeStatus; + MEFWCAPS_SKU FwCapsSku; + PLATFORM_TYPE_RULE_DATA RuleData; + + ZeroMem (&mMbpData, sizeof (DXE_MBP_DATA_PROTOCOL)); + + HeciGetMeMode (&MeMode); + + mMbpData.Revision = DXE_MBP_DATA_PROTOCOL_REVISION_2; + + PERF_START_EX (NULL, EVENT_REC_TOK, NULL, AsmReadTsc (), 0x8010); + Status = PrepareMeBiosPayload (&mMbpData.MeBiosPayload); + PERF_END_EX (NULL, EVENT_REC_TOK, NULL, AsmReadTsc (), 0x8011); + + if (!EFI_ERROR (Status)) { + HeciGetMeStatus (&MeStatus); + HeciGetMeMode (&MeMode); + + if (mMbpData.MeBiosPayload.FwCapsSku.Available == 0) { + if ((MeMode == ME_MODE_NORMAL) && + ( + (ME_STATUS_ME_STATE_ONLY (MeStatus) == ME_IN_RECOVERY_MODE) || + (ME_STATUS_ME_STATE_ONLY (MeStatus) == ME_READY) + ) + ) { + Status = MbpGetFwCapsSkuThroughHeci (&FwCapsSku); + if (!EFI_ERROR (Status)) { + mMbpData.MeBiosPayload.FwCapsSku.FwCapabilities.Data = FwCapsSku.Data; + mMbpData.MeBiosPayload.FwCapsSku.Available = TRUE; + } + } + } + + if (mMbpData.MeBiosPayload.FwPlatType.Available == 0) { + if ((MeMode == ME_MODE_NORMAL) && + ( + (ME_STATUS_ME_STATE_ONLY (MeStatus) == ME_IN_RECOVERY_MODE) || + (ME_STATUS_ME_STATE_ONLY (MeStatus) == ME_READY) + ) + ) { + Status = MbpGetPlatformTypeThroughHeci (&RuleData); + if (!EFI_ERROR (Status)) { + mMbpData.MeBiosPayload.FwPlatType.RuleData.Data = RuleData.Data; + mMbpData.MeBiosPayload.FwPlatType.Available = TRUE; + } + } + } + + if (mMbpData.MeBiosPayload.FwVersionName.MajorVersion == 10) { + // + // For ME 10 get the FW features state mask + // + if (mMbpData.MeBiosPayload.FwFeaturesState.Available == 0) { + if ((MeMode == ME_MODE_NORMAL) && + ( + (ME_STATUS_ME_STATE_ONLY (MeStatus) == ME_IN_RECOVERY_MODE) || + (ME_STATUS_ME_STATE_ONLY (MeStatus) == ME_READY) + ) + ) { + Status = MbpGetFwFeaturesStateThroughHeci ((MEFWCAPS_SKU*)&RuleData.Data); + if (!EFI_ERROR (Status)) { + mMbpData.MeBiosPayload.FwFeaturesState.FwFeatures.Data = RuleData.Data; + mMbpData.MeBiosPayload.FwFeaturesState.Available = TRUE; + } + } + } + } + +#ifdef EFI_DEBUG + // + // Dump the Mbp data + // + DxeMbpDebugDump (&mMbpData); +#endif + + /// + /// Install the MBP protocol + /// + mMbpData.Handle = NULL; + Status = gBS->InstallMultipleProtocolInterfaces ( + &mMbpData.Handle, + &gMeBiosPayloadDataProtocolGuid, + &mMbpData, + NULL + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "MBP data protocol install failed, Status is %r \n", Status)); + } + } +} + +/** + HECI driver entry point used to initialize support for the HECI device. + + @param[in] ImageHandle Standard entry point parameter. + @param[in] SystemTable Standard entry point parameter. + + @retval EFI_SUCCESS Always return EFI_SUCCESS +**/ +EFI_STATUS +InitializeHECI ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_EVENT ReadyToBootEvent; + VOID *Registration; + BOOLEAN HeciInitializeError; + UINT32 MeStatus; + UINT32 MeMode; + MEFWCAPS_SKU FwCapsSku; + PLATFORM_TYPE_RULE_DATA RuleData; + DXE_MBP_DATA_PROTOCOL *MbpData; + + INITIALIZE_SCRIPT (ImageHandle, SystemTable); + + mHeciDrv = ImageHandle; + HeciInitializeError = FALSE; + mHeciContext = AllocateZeroPool (sizeof (HECI_INSTANCE)); + /// + /// Initialize HECI protocol pointers + /// + if (mHeciContext != NULL) { + mHeciContext->HeciCtlr.ResetHeci = ResetHeciInterface; + mHeciContext->HeciCtlr.SendwACK = HeciSendwACK; + mHeciContext->HeciCtlr.ReadMsg = HeciReceive; + mHeciContext->HeciCtlr.SendMsg = HeciSend; + mHeciContext->HeciCtlr.InitHeci = HeciInitialize; + mHeciContext->HeciCtlr.ReInitHeci = HeciReInitialize; + mHeciContext->HeciCtlr.MeResetWait = MeResetWait; + mHeciContext->HeciCtlr.GetMeStatus = HeciGetMeStatus; + mHeciContext->HeciCtlr.GetMeMode = HeciGetMeMode; + } + /// + /// Initialize the HECI device + /// + Status = InitializeHeciPrivate (); + if ((EFI_ERROR (Status)) || (mHeciContext == NULL)) { + HeciInitializeError = TRUE; + } + /// + /// Install the MBP information + /// + InstallMbpDataProtocol (); + + if (HeciInitializeError) { + /// + /// Don't install on ERR + /// + if (Status != EFI_NOT_READY) { + DEBUG ((EFI_D_ERROR, "HECI not initialized - Removing devices from PCI space!\n")); + DisableAllMEDevices (); + /// + /// Store the current value of DEVEN for S3 resume path + /// + } + DeviceStatusSave (); + return EFI_SUCCESS; + } + /// + /// Install the HECI interface + /// + Status = gBS->InstallMultipleProtocolInterfaces ( + &mHeciContext->Handle, + &gEfiHeciProtocolGuid, + &mHeciContext->HeciCtlr, + NULL + ); + if (EFI_ERROR (Status)) { + return EFI_SUCCESS; + } + + HeciGetMeStatus (&MeStatus); + HeciGetMeMode (&MeMode); + + Status = gBS->LocateProtocol ( + &gMeBiosPayloadDataProtocolGuid, + NULL, + (VOID **) &MbpData + ); + if (!EFI_ERROR (Status)) { + if (MbpData->MeBiosPayload.FwCapsSku.Available == 0) { + if ((MeMode == ME_MODE_NORMAL) && + ( + (ME_STATUS_ME_STATE_ONLY (MeStatus) == ME_IN_RECOVERY_MODE) || + (ME_STATUS_ME_STATE_ONLY (MeStatus) == ME_READY) + ) + ) { + Status = HeciGetFwCapsSku (&FwCapsSku); + if (!EFI_ERROR (Status)) { + MbpData->MeBiosPayload.FwCapsSku.FwCapabilities.Data = FwCapsSku.Data; + } + } + } + + if (MbpData->MeBiosPayload.FwPlatType.Available == 0) { + if ((MeMode == ME_MODE_NORMAL) && + ( + (ME_STATUS_ME_STATE_ONLY (MeStatus) == ME_IN_RECOVERY_MODE) || + (ME_STATUS_ME_STATE_ONLY (MeStatus) == ME_READY) + ) + ) { + Status = HeciGetPlatformType (&RuleData); + if (!EFI_ERROR (Status)) { + MbpData->MeBiosPayload.FwPlatType.RuleData.Data = RuleData.Data; + } + } + } + /// + /// Dxe Mbp data is gone after ExitPmAuth, so we keep MeFwImageType for the inspection after ExitPmAuth + /// + mHeciContext->MeFwImageType = (UINT8) MbpData->MeBiosPayload.FwPlatType.RuleData.Fields.IntelMeFwImageType; + } + + + /// + /// Hide Me relevant Devices + /// + Status = MeDeviceConfigure (); + ASSERT_EFI_ERROR (Status); + + /// + /// Initialize the Me Reference Code Information + /// + mHeciContext->MeRcInfo.Revision = ME_RC_INFO_PROTOCOL_REVISION_1; + mHeciContext->MeRcInfo.RCVersion = ME_RC_VERSION; + + /// + /// Install the Me Reference Code Information + /// + Status = gBS->InstallMultipleProtocolInterfaces ( + &mHeciContext->Handle, + &gEfiMeRcInfoProtocolGuid, + &mHeciContext->MeRcInfo, + NULL + ); + if (EFI_ERROR (Status)) { + return EFI_SUCCESS; + } + + /// + /// Create an ExitPmAuth protocol call back event. + /// + EfiCreateProtocolNotifyEvent ( + &gExitPmAuthProtocolGuid, + EFI_TPL_CALLBACK, + MeScriptSaveEvent, + NULL, + &Registration + ); + + /// + /// Create a Ready to Boot event. + /// + Status = EfiCreateEventReadyToBootEx ( + EFI_TPL_CALLBACK, + MeReadyToBootEvent, + (VOID *) &ImageHandle, + &ReadyToBootEvent + ); + ASSERT_EFI_ERROR (Status); + + return Status; +} diff --git a/ReferenceCode/ME/Heci/Dxe/Hecidrv.dxs b/ReferenceCode/ME/Heci/Dxe/Hecidrv.dxs new file mode 100644 index 0000000..647c8e0 --- /dev/null +++ b/ReferenceCode/ME/Heci/Dxe/Hecidrv.dxs @@ -0,0 +1,43 @@ +/** @file + Dependency expression source file. + +@copyright + Copyright (c) 2010 - 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 a 'Sample Driver' and is licensed as such + under the terms of your license agreement with Intel or your + vendor. This file may be modified by the user, subject to + the additional terms of the license agreement + +**/ + + +// +// Common for R8 and R9 codebase +// +#include "AutoGen.h" +#include "DxeDepex.h" + +// +// BUILD_WITH_GLUELIB and BUILD_WITH_EDKII_GLUE_LIB are both "defined" in R8 codebase; +// BUILD_WITH_EDKII_GLUE_LIB is defined in Edk-Dev-Snapshot-20070228 and later version +// BUILD_WITH_GLUELIB and BUILD_WITH_EDKII_GLUE_LIB are "not defined" in R9 codebase. +// +#if defined (BUILD_WITH_GLUELIB) || defined (BUILD_WITH_EDKII_GLUE_LIB) +#include "EfiDepex.h" +#include EFI_PROTOCOL_DEFINITION (CpuIo) +#include EFI_PROTOCOL_DEFINITION (PciRootBridgeIo) +#endif + +DEPENDENCY_START + EFI_CPU_IO_PROTOCOL_GUID AND + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_GUID +DEPENDENCY_END + diff --git a/ReferenceCode/ME/Heci/Dxe/Hecidrv.h b/ReferenceCode/ME/Heci/Dxe/Hecidrv.h new file mode 100644 index 0000000..d3cea85 --- /dev/null +++ b/ReferenceCode/ME/Heci/Dxe/Hecidrv.h @@ -0,0 +1,70 @@ +/** @file + Definitions for HECI driver + +@copyright + Copyright (c) 2006 - 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 +**/ +#ifndef _HECI_DRV_H +#define _HECI_DRV_H + +#include "EdkIIGlueDxe.h" +#include "MeAccess.h" +#include "HeciRegs.h" +#include "Pci22.h" +#include "RcFviDxeLib.h" + +#include EFI_PROTOCOL_CONSUMER (PciRootBridgeIo) + +#define HECI_PRIVATE_DATA_SIGNATURE EFI_SIGNATURE_32 ('H', 'e', 'c', 'i') +#define HECI_ROUND_UP_BUFFER_LENGTH(Length) ((UINT32) ((((Length) + 3) / 4) * 4)) + +// +// Driver Produced Protocol Prototypes +// +#include EFI_PROTOCOL_PRODUCER (Heci) +#include EFI_PROTOCOL_PRODUCER (MeRcInfo) + +// +// Driver Consumed Protocol Prototypes +// +#include EFI_PROTOCOL_CONSUMER (MebxProtocol) + +extern FVI_ELEMENT_AND_FUNCTION mMeFviElementsData[]; +extern FVI_DATA_HUB_CALLBACK_CONTEXT mMeFviVersionData; +extern UINTN mMeFviElements; + +typedef union { + UINT32 Data32; + UINT16 Data16[2]; + UINT8 Data8[4]; +} DATA32_UNION; + +/// +/// HECI private data structure +/// +typedef struct { + UINTN Signature; + EFI_HANDLE Handle; + UINT64 HeciMBAR; + UINT16 DeviceInfo; + UINT32 RevisionInfo; + EFI_HECI_PROTOCOL HeciCtlr; + VOLATILE UINT32 *HpetTimer; + EFI_ME_RC_INFO_PROTOCOL MeRcInfo; + UINT8 MeFwImageType; +} HECI_INSTANCE; +#endif diff --git a/ReferenceCode/ME/Heci/Dxe/Hecidrv.inf b/ReferenceCode/ME/Heci/Dxe/Hecidrv.inf new file mode 100644 index 0000000..d82403e --- /dev/null +++ b/ReferenceCode/ME/Heci/Dxe/Hecidrv.inf @@ -0,0 +1,99 @@ +## @file +# Component description file for Heci DXE driver +# +#@copyright +# Copyright (c) 2007 - 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 a 'Sample Driver' and is licensed as such +# under the terms of your license agreement with Intel or your +# vendor. This file may be modified by the user, subject to +# the additional terms of the license agreement +# + +[defines] +BASE_NAME = Hecidrv +FILE_GUID = 55E76644-78A5-4a82-A900-7126A5798892 +COMPONENT_TYPE = BS_DRIVER + +[sources.common] + HeciDrv.c + Hecidrv.h + HeciCore.c + HeciCore.h + HeciHpet.c + HeciHpet.h + MeFvi.c + +# +# Edk II Glue Driver Entry Point +# + EdkIIGlueDxeDriverEntryPoint.c + +[includes.common] + $(EFI_SOURCE)/$(PROJECT_ME_ROOT) + $(EFI_SOURCE)/$(PROJECT_ME_ROOT)/Library/MeKernel/Dxe + $(EFI_SOURCE)/$(PROJECT_ME_ROOT)/Library/MeKernel/Include + $(EFI_SOURCE)/$(PROJECT_ME_ROOT)/Heci/Include + $(EFI_SOURCE)/$(PROJECT_PCH_ROOT) + $(EFI_SOURCE)/$(PROJECT_PCH_ROOT)/Include + $(EFI_SOURCE)/$(PROJECT_PCH_ROOT)/Include/Library + +# +# EDK II Glue Library utilizes some standard headers from EDK +# + $(EDK_SOURCE)/Foundation + $(EDK_SOURCE)/Foundation/Core/Dxe + $(EDK_SOURCE)/Foundation/Efi + $(EDK_SOURCE)/Foundation/Efi/Include + $(EDK_SOURCE)/Foundation/Framework + $(EDK_SOURCE)/Foundation/Framework/Include + $(EDK_SOURCE)/Foundation/Include + $(EDK_SOURCE)/Foundation/Include/IndustryStandard + $(EDK_SOURCE)/Foundation/Library/Dxe/Include + $(EDK_SOURCE)/Foundation/Library/EdkIIGlueLib/Include + +[libraries.common] + MeGuidLib + MeProtocolLib + MeLib + MeChipsetLib + IntelPchProtocolLib + $(PROJECT_PCH_FAMILY)ProtocolLib + RcFviDxeLib + EfiScriptLib + EfiProtocolLib + EdkProtocolLib + EdkFrameworkProtocolLib + EdkIIGlueBaseIoLibIntrinsic + EdkIIGlueDxeReportStatusCodeLib + EdkIIGlueDxeDebugLibReportStatusCode + EdkIIGlueUefiBootServicesTableLib + EdkIIGlueUefiLib + EdkIIGlueBasePciLibPciExpress + EdkIIGlueBasePciExpressLib + EdkIIGlueDxeServicesTableLib + EdkIIGlueBasePrintLib + +[nmake.common] + IMAGE_ENTRY_POINT=_ModuleEntryPoint + DPX_SOURCE=Hecidrv.dxs +# +# Module Entry Point +# + C_FLAGS = $(C_FLAGS) -D __EDKII_GLUE_MODULE_ENTRY_POINT__=InitializeHECI + C_FLAGS = $(C_FLAGS) -D __EDKII_GLUE_BASE_IO_LIB_INTRINSIC__ \ + -D __EDKII_GLUE_DXE_REPORT_STATUS_CODE_LIB__ \ + -D __EDKII_GLUE_DXE_DEBUG_LIB_REPORT_STATUS_CODE__ \ + -D __EDKII_GLUE_UEFI_BOOT_SERVICES_TABLE_LIB__ \ + -D __EDKII_GLUE_UEFI_LIB__ \ + -D __EDKII_GLUE_DXE_SERVICES_TABLE_LIB__ \ + -D __EDKII_GLUE_BASE_PCI_LIB_PCI_EXPRESS__ \ +# Uncomment the following line if RapidStart is supported +# C_FLAGS = $(C_FLAGS) -DRAPID_START_FLAG diff --git a/ReferenceCode/ME/Heci/Dxe/MeFvi.c b/ReferenceCode/ME/Heci/Dxe/MeFvi.c new file mode 100644 index 0000000..f41b616 --- /dev/null +++ b/ReferenceCode/ME/Heci/Dxe/MeFvi.c @@ -0,0 +1,49 @@ +/** @file + ME Firmware Version Info implementation. + +@copyright + Copyright (c) 2011 - 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 +**/ +#include "Hecidrv.h" + +FVI_ELEMENT_AND_FUNCTION mMeFviElementsData[] = { + { + DEFAULT_FVI_ELEMENT_DATA(ME), + NULL + }, + { + DEFAULT_FVI_ELEMENT_DATA(MEBX), + NULL + }, + { + { + 1, + 3, + MEFW_VERSION, + MEFW_FVI_STRING, + MEFW_1_5M_STRING, + }, + NULL + } +}; + +FVI_DATA_HUB_CALLBACK_CONTEXT mMeFviVersionData = { + MISC_SUBCLASS_FVI_HEADER_ENTRY(ME), + mMeFviElementsData, +}; + +UINTN mMeFviElements = sizeof (mMeFviElementsData) / sizeof (FVI_ELEMENT_AND_FUNCTION); diff --git a/ReferenceCode/ME/Heci/Include/HeciInclude.cif b/ReferenceCode/ME/Heci/Include/HeciInclude.cif new file mode 100644 index 0000000..4379006 --- /dev/null +++ b/ReferenceCode/ME/Heci/Include/HeciInclude.cif @@ -0,0 +1,9 @@ +<component> + name = "HeciInclude" + category = ModulePart + LocalRoot = "ReferenceCode\ME\Heci\Include\" + RefName = "HeciInclude" +[files] +"HeciInclude.sdl" +"HeciRegs.h" +<endComponent> diff --git a/ReferenceCode/ME/Heci/Include/HeciInclude.sdl b/ReferenceCode/ME/Heci/Include/HeciInclude.sdl new file mode 100644 index 0000000..9f9d6a7 --- /dev/null +++ b/ReferenceCode/ME/Heci/Include/HeciInclude.sdl @@ -0,0 +1,9 @@ +PATH + Name = "HeciInclude_DIR" +End + +ELINK + Name = "/I$(HeciInclude_DIR)" + Parent = "ME_INCLUDES" + InvokeOrder = AfterParent +End
\ No newline at end of file diff --git a/ReferenceCode/ME/Heci/Include/HeciRegs.h b/ReferenceCode/ME/Heci/Include/HeciRegs.h new file mode 100644 index 0000000..5bc0a09 --- /dev/null +++ b/ReferenceCode/ME/Heci/Include/HeciRegs.h @@ -0,0 +1,275 @@ +/** @file + Register Definitions for HECI + +@copyright + Copyright (c) 2010 - 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 +**/ +#ifndef _HECI_REGS_H +#define _HECI_REGS_H + +#define HECI_BUS ME_BUS +#define HECI_DEV ME_DEVICE_NUMBER +#define HECI_FUN HECI_FUNCTION_NUMBER +#define HECI_PCI_ADDR (HECI_BUS << 24) | (HECI_DEV << 16) | (HECI_FUN << 8) +#define REVID_MSK 0x000000FF + +#define BRNGUP_HMRFPO_DISABLE_CMD_MASK 0x0F +#define BRNGUP_HMRFPO_DISABLE_CMD 0x30 +#define BRNGUP_HMRFPO_DISABLE_OVR_MASK 0xF0000000 +#define BRNGUP_HMRFPO_DISABLE_OVR_RSP 0x30000000 + +// +// HECI PCI register definition +// +#define R_VENDORID 0x00 +#define R_DEVICEID 0x02 +#define R_COMMAND 0x04 +#define B_BME 0x04 +#define B_MSE 0x02 +#define R_REVID 0x08 +#define R_HECIMBAR 0x10 +#define R_FWSTATE 0x40 +#define R_GEN_STS 0x4C +#define R_HIDM 0xA0 + +// +// HECIMBAR register definition +// +#define H_CB_WW 0x00 +#define H_CSR 0x04 +#define ME_CB_RW 0x08 +#define ME_CSR_HA 0x0C + +/// +/// PCH related registers address +/// +#define PCH_ACPI_TIMER_MAX_VALUE 0x1000000 ///< The timer is 24 bit overflow +// +// HPET Information +// +#define HPET_ADDRESS_0 0xFED00000 +#define HPET_ADDRESS_1 0xFED01000 +#define HPET_ADDRESS_2 0xFED02000 +#define HPET_ADDRESS_3 0xFED03000 +// +// HPET Registers will be used as DWORD index +// +#define HPET_CAPS_REG_LOW 0x00 / 4 +#define HPET_CAPS_REG_HIGH 0x04 / 4 +#define HPET_GEN_CONFIG_LOW 0x10 / 4 +#define HPET_GEN_CONFIG_HIGH 0x14 / 4 +#define HPET_INT_STATUS_LOW 0x20 / 4 +#define HPET_INT_STATUS_HIGH 0x24 / 4 +#define HPET_MAIN_COUNTER_LOW 0xF0 / 4 +#define HPET_MAIN_COUNTER_HIGH 0xF4 / 4 + +#define HPET_START 0x01 +#define HPET_TICKS_PER_MICRO 14 ///< 70ns tick so 14.2 ticks per microsecond ish +// +// PEI Timeout values +// +#define PEI_HECI_WAIT_DELAY 50000 ///< 50ms timeout for IO delay +#define PEI_HECI_INIT_TIMEOUT 10000000 ///< 10 sec timeout in microseconds +#define PEI_HECI_READ_TIMEOUT 10000000 ///< 10sec timeout in microseconds +#define PEI_HECI_SEND_TIMEOUT 10000000 ///< 10sec timeout in microseconds +// +// DXE Timeout values based on HPET +// +#define HECI_WAIT_DELAY 1000 ///< 1ms timeout for IO delay +#define HECI_INIT_TIMEOUT 15000000 ///< 15sec timeout in microseconds +#define HECI_READ_TIMEOUT 5000000 ///< 5sec timeout in microseconds +#define HECI_SEND_TIMEOUT 5000000 ///< 5sec timeout in microseconds +#define HECI_MAX_RETRY 3 ///< Value based off HECI HPS +#define HECI_MSG_DELAY 2000000 ///< show warning msg and stay for 2 seconds. +#define HECI_MBP_RDY_TIMEOUT 50000 ///< 50ms timeout +#define HECI_MBP_CLR_TIMEOUT 1000000 ///< 1s timeout +#define HECI_MBP_READ_MAX_RETRIES 2 ///< MBP read will be retried twice +#pragma pack(1) +// +// REGISTER EQUATES +// + +/// +/// ME_CSR_HA - ME Control Status Host Access +/// +typedef union { + UINT32 ul; + struct { + UINT32 ME_IE_HRA : 1; ///< 0 - ME Interrupt Enable (Host Read Access) + UINT32 ME_IS_HRA : 1; ///< 1 - ME Interrupt Status (Host Read Access) + UINT32 ME_IG_HRA : 1; ///< 2 - ME Interrupt Generate (Host Read Access) + UINT32 ME_RDY_HRA : 1; ///< 3 - ME Ready (Host Read Access) + UINT32 ME_RST_HRA : 1; ///< 4 - ME Reset (Host Read Access) + UINT32 Reserved : 3; ///< 7:5 + UINT32 ME_CBRP_HRA : 8; ///< 15:8 - ME CB Read Pointer (Host Read Access) + UINT32 ME_CBWP_HRA : 8; ///< 23:16 - ME CB Write Pointer (Host Read Access) + UINT32 ME_CBD_HRA : 8; ///< 31:24 - ME Circular Buffer Depth (Host Read Access) + } r; +} HECI_ME_CONTROL_REGISTER; + +/// +/// H_CSR - Host Control Status +/// +typedef union { + UINT32 ul; + struct { + UINT32 H_IE : 1; ///< 0 - Host Interrupt Enable ME + UINT32 H_IS : 1; ///< 1 - Host Interrupt Status ME + UINT32 H_IG : 1; ///< 2 - Host Interrupt Generate + UINT32 H_RDY : 1; ///< 3 - Host Ready + UINT32 H_RST : 1; ///< 4 - Host Reset + UINT32 Reserved : 3; ///< 7:5 + UINT32 H_CBRP : 8; ///< 15:8 - Host CB Read Pointer + UINT32 H_CBWP : 8; ///< 23:16 - Host CB Write Pointer + UINT32 H_CBD : 8; ///< 31:24 - Host Circular Buffer Depth + } r; +} HECI_HOST_CONTROL_REGISTER; + +/// +/// FWS +/// +typedef union { + UINT32 ul; + struct { + UINT32 CurrentState : 4; ///< 0:3 - Current State + UINT32 ManufacturingMode : 1; ///< 4 Manufacturing Mode + UINT32 FptBad : 1; ///< 5 FPT(Flash Partition Table ) Bad + UINT32 MeOperationState : 3; ///< 6:8 - ME Operation State + UINT32 FwInitComplete : 1; ///< 9 + UINT32 FtBupLdFlr : 1; ///< 10 - This bit is set when firmware is not able to load BRINGUP from the fault tolerant (FT) code. + UINT32 FwUpdateInprogress : 1; ///< 11 + UINT32 ErrorCode : 4; ///< 12:15 - Error Code + UINT32 MeOperationMode : 4; ///< 16:19 - Management Engine Current Operation Mode + UINT32 Reserved2 : 4; ///< 20:23 + UINT32 MeBootOptionsPresent : 1; ///< 24 - If this bit is set, an Boot Options is present + UINT32 AckData : 3; ///< 25:27 Ack Data + UINT32 BiosMessageAck : 4; ///< 28:31 BIOS Message Ack + } r; +} HECI_FWS_REGISTER; + +/// +/// MISC_SHDW +/// +typedef union { + UINT32 ul; + struct { + UINT32 MUSZ : 6; ///< 0:5 - ME UMA Size + UINT32 Reserved : 8; ///< 6:13 - Reserved + UINT32 Reserved2 : 2; ///< 14:15 - Reserved + UINT32 MUSZV : 1; ///< 16:16 - ME UMA Size Valid + UINT32 Reserved3 : 8; ///< 17:24 - Reserved + UINT32 Reserved4 : 6; ///< 25:30 - Reserved + UINT32 MSVLD : 1; ///< 31:31 - Miscellaneous Shadow Valid + } r; +} HECI_MISC_SHDW_REGISTER; + +/// +/// GS_SHDW +/// +typedef union { + UINT32 ul; + struct { + UINT32 BistInProg : 1; ///< 0 - BIST in progress + UINT32 IccProgSts : 2; ///< 1:2 - ICC Prog STS + UINT32 InvokeMEBx : 1; ///< 3 - Invoke MEBX + UINT32 CpuReplacedSts : 1; ///< 4 - CPU Replaced STS + UINT32 MbpRdy : 1; ///< 5 - MBP RDY + UINT32 MfsFailure : 1; ///< 6 - MFS Failure + UINT32 WarmRstReqForDF : 1; ///< 7 - Warm Reset Required for Dynamic Fusing + UINT32 CpuReplacedValid : 1; ///< 8 - CPU Replaced Valid + UINT32 Reserved : 2; ///< 9:10 - Reserved + UINT32 FwUpdIpu : 1; ///< 11 - FW UPD IPU Needed + UINT32 Reserved2 : 1; ///< 12 - Reserved + UINT32 MbpCleared : 1; ///< 13 - MBP Cleared + UINT32 Reserved3 : 2; ///< 14:15 - Reserved + UINT32 ExtStatCode1 : 8; ///< 16:23 - EXT Status Code 1 + UINT32 ExtStatCode2 : 4; ///< 24:27 - EXT Status Code 2 + UINT32 InfPhaseCode : 4; ///< 31:28 - Infra. Phase code + } r; +} HECI_GS_SHDW_REGISTER; + +/// +/// HECI_GS2 +/// +typedef union { + UINT32 ul; + struct { + UINT32 MbpGiveUp : 1; ///< 0 - MBP Give Up + UINT32 Reserved :31; ///< 1-31 - Reserved + } r; +} HECI_GS2_REGISTER; + +// +// ME Current State Values +// +#define ME_STATE_RESET 0x00 +#define ME_STATE_INIT 0x01 +#define ME_STATE_RECOVERY 0x02 +#define ME_STATE_NORMAL 0x05 +#define ME_STATE_DISABLE_WAIT 0x06 +#define ME_STATE_TRANSITION 0x07 +#define ME_STATE_INVALID_CPU 0x08 + +// +// DRAM Initiailization Response Codes. +// +#define CBM_DIR_NON_PCR 0x01 +#define CBM_DIR_PCR 0x02 +#define CBM_DIR_GLOBAL_RESET 0x06 +#define CBM_DIR_CONTINUE_POST 0x07 +// +// ME Firmware FwInitComplete +// +#define ME_FIRMWARE_COMPLETED 0x01 +#define ME_FIRMWARE_INCOMPLETED 0x00 + +// +// ME Boot Options Present +// +#define ME_BOOT_OPTIONS_PRESENT 0x01 +#define ME_BOOT_OPTIONS_NOT_PRESENT 0x00 + +// +// ME Operation State Values +// +#define ME_OPERATION_STATE_PREBOOT 0x00 +#define ME_OPERATION_STATE_M0_UMA 0x01 +#define ME_OPERATION_STATE_M3 0x04 +#define ME_OPERATION_STATE_M0 0x05 +#define ME_OPERATION_STATE_BRINGUP 0x06 +#define ME_OPERATION_STATE_M0_ERROR 0x07 + +// +// ME Error Code Values +// +#define ME_ERROR_CODE_NO_ERROR 0x00 +#define ME_ERROR_CODE_UNKNOWN 0x01 +#define ME_ERROR_CODE_IMAGE_FAILURE 0x03 +#define ME_ERROR_CODE_DEBUG_FAILURE 0x04 + +// +// Management Engine Current Operation Mode +// +#define ME_OPERATION_MODE_NORMAL 0x00 + +#define ME_OPERATION_MODE_DEBUG 0x02 +#define ME_OPERATION_MODE_SOFT_TEMP_DISABLE 0x03 +#define ME_OPERATION_MODE_SECOVR_JMPR 0x04 +#define ME_OPERATION_MODE_SECOVR_HECI_MSG 0x05 +#pragma pack() + +#endif // HECI_REGS_H diff --git a/ReferenceCode/ME/Heci/MeHeci.cif b/ReferenceCode/ME/Heci/MeHeci.cif new file mode 100644 index 0000000..73fdc6d --- /dev/null +++ b/ReferenceCode/ME/Heci/MeHeci.cif @@ -0,0 +1,13 @@ +<component> + name = "MeHeci" + category = ModulePart + LocalRoot = "ReferenceCode\ME\Heci\" + RefName = "MeHeci" +[files] +"MeHeci.sdl" +[parts] +"HeciDxe" +"HeciPei" +"HeciInclude" +"HeciSmm" +<endComponent> diff --git a/ReferenceCode/ME/Heci/MeHeci.sdl b/ReferenceCode/ME/Heci/MeHeci.sdl new file mode 100644 index 0000000..8755bf8 --- /dev/null +++ b/ReferenceCode/ME/Heci/MeHeci.sdl @@ -0,0 +1,19 @@ +TOKEN + Name = "MeHeci_SUPPORT" + Value = "1" + TokenType = Boolean + TargetEQU = Yes + TargetMAK = Yes + Master = Yes + Help = "Main switch to enable MeHeci support in Project" +End + +PATH + Name = "MeHeci_DIR" + Help = "Me Heci Driver files source directory" +End +ELINK + Name = "/I$(MeHeci_DIR)\Include" + Parent = "ME_INCLUDES" + InvokeOrder = AfterParent +End
\ No newline at end of file diff --git a/ReferenceCode/ME/Heci/Pei/HeciCore.c b/ReferenceCode/ME/Heci/Pei/HeciCore.c new file mode 100644 index 0000000..e248118 --- /dev/null +++ b/ReferenceCode/ME/Heci/Pei/HeciCore.c @@ -0,0 +1,1247 @@ +/** @file + Heci driver core. For PEI Phase, determines the HECI device and initializes it. + +@copyright + Copyright (c) 2008 - 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 + +**/ +#include "HeciInit.h" +/** + Delay for at least the request number of microseconds + + @param[in] PeiServices General purpose services available to every PEIM. + @param[in] Microseconds Number of microseconds to delay. + + @retval EFI_SUCCESS The function completed successfully. +**/ +EFI_STATUS +EFIAPI +Stall ( + IN EFI_PEI_SERVICES **PeiServices, + IN UINTN Microseconds + ) +{ + UINTN Ticks; + UINTN Counts; + UINT32 CurrentTick; + UINT32 OriginalTick; + UINT32 RemainingTick; + UINT32 AcpiPm1TimerBar; + + if (Microseconds == 0) { + return EFI_SUCCESS; + } + + AcpiPm1TimerBar = ( + PciRead32 (PCI_LIB_ADDRESS (DEFAULT_PCI_BUS_NUMBER_PCH, PCI_DEVICE_NUMBER_PCH_LPC, 0, R_PCH_LPC_ACPI_BASE)) & B_PCH_LPC_ACPI_BASE_BAR + ) + + R_PCH_ACPI_PM1_TMR; + + OriginalTick = IoRead32 ((UINTN) (UINT64) AcpiPm1TimerBar); + OriginalTick &= (PCH_ACPI_TIMER_MAX_VALUE - 1); + CurrentTick = OriginalTick; + + /// + /// The timer frequency is 3.579545MHz, so 1 ms corresponds to 3.58 clocks + /// + Ticks = Microseconds * 358 / 100 + OriginalTick + 1; + + /// + /// The loops needed for timer overflow + /// + Counts = Ticks / PCH_ACPI_TIMER_MAX_VALUE; + + /// + /// Remaining clocks within one loop + /// + RemainingTick = Ticks % PCH_ACPI_TIMER_MAX_VALUE; + + /// + /// Do not intend to use TMROF_STS bit of register PM1_STS, because this add extra + /// one I/O operation, and may generate SMI + /// + while (Counts != 0) { + CurrentTick = IoRead32 ((UINTN) (UINT64) AcpiPm1TimerBar); + CurrentTick &= (PCH_ACPI_TIMER_MAX_VALUE - 1); + if (CurrentTick <= OriginalTick) { + Counts--; + } + + OriginalTick = CurrentTick; + } + + while ((RemainingTick > CurrentTick) && (OriginalTick <= CurrentTick)) { + OriginalTick = CurrentTick; + CurrentTick = IoRead32 ((UINTN) (UINT64) AcpiPm1TimerBar); + CurrentTick &= (PCH_ACPI_TIMER_MAX_VALUE - 1); + } + + return EFI_SUCCESS; +} + +/** + Enable Hpet function. + + @param[in] PeiServices General purpose services available to every PEIM. + + @retval UINT32 Return the High Precision Event Timer base address +**/ +VOLATILE +UINT32 * +EnableHpet ( + IN EFI_PEI_SERVICES **PeiServices + ) +{ + VOLATILE UINT32 *HpetConfigReg; + VOLATILE UINT32 *HpetTimer; + UINT32 Temp32; + HpetConfigReg = NULL; + /// + /// Get the High Precision Event Timer base address and enable the memory range + /// + HpetConfigReg = (UINT32 *) (PCH_RCRB_BASE + R_PCH_RCRB_HPTC); + switch (*HpetConfigReg & B_PCH_RCRB_HPTC_AS) { + case 0: + HpetTimer = (VOID *) (HPET_ADDRESS_0); + break; + + case 1: + HpetTimer = (VOID *) (HPET_ADDRESS_1); + break; + + case 2: + HpetTimer = (VOID *) (HPET_ADDRESS_2); + break; + + case 3: + HpetTimer = (VOID *) (HPET_ADDRESS_3); + break; + + default: + HpetTimer = NULL; + break; + } + + *HpetConfigReg = *HpetConfigReg | B_PCH_RCRB_HPTC_AE; + /// + /// Read back from RCBA area. + /// + Temp32 = *HpetConfigReg; + + /// + /// Start the timer so it is up and running + /// + HpetTimer[HPET_GEN_CONFIG_LOW] = HPET_START; + + return HpetTimer; +} + +/** + This function provides a standard way to verify the HECI cmd and MBAR regs + in its PCI cfg space are setup properly and that the local mHeciContext + variable matches this info. + + @param[in] PeiServices General purpose services available to every PEIM. + @param[in] This The address of HECI PPI + @param[in][out] HeciMemBar HECI Memory BAR + + @retval None +**/ +VOID +CheckAndFixHeciForAccess ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_HECI_PPI *This, + IN OUT UINT32 *HeciMemBar + ) +{ + UINT32 Buffer; + + /// + /// Check if HECI_MBAR has changed + /// + Buffer = HeciPciRead32 (R_HECIMBAR) & 0xFFFFFFF0; + if (*HeciMemBar != Buffer) { + /// + /// If it did change update the mHeciContext variable so we use the proper address for acceses + /// + *HeciMemBar = Buffer; + } + /// + /// Enable HECI BME and MSE + /// + HeciPciOr8 ( + PCI_COMMAND_OFFSET, + EFI_PCI_COMMAND_MEMORY_SPACE | EFI_PCI_COMMAND_BUS_MASTER + ); + return ; +} + +#ifdef EFI_DEBUG + +/** + For EFI debug used, will show the message of buffer to terminal. + + @param[in] PeiServices General purpose services available to every PEIM. + @param[in] Message The address of message. + @param[in] Length The length of message. +**/ +VOID +ShowBuffer ( + IN EFI_PEI_SERVICES **PeiServices, + IN UINT8 *Message, + IN UINT32 Length + ) +{ + UINT32 LineBreak; + UINT32 Index; + LineBreak = 0; + Index = 0; + + while (Length-- > 0) { + if (LineBreak == 0) { + DEBUG ((EFI_D_ERROR, "%02x: ", (Index & 0xF0))); + } + + DEBUG ((EFI_D_ERROR, "%02x ", Message[Index++])); + LineBreak++; + if (LineBreak == 16) { + DEBUG ((EFI_D_ERROR, "\n")); + LineBreak = 0; + } + + if (LineBreak == 8) { + DEBUG ((EFI_D_ERROR, "- ")); + } + } + + DEBUG ((EFI_D_ERROR, "\n")); + return ; +} +#endif // End Of EFI_DEBUG + +/** + Determines if the HECI device is present and, if present, initializes it for + use by the BIOS. + + @param[in] PeiServices General purpose services available to every PEIM. + @param[in] This The address of HECI PPI + @param[in][out] HeciMemBar HECI Memory BAR + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_DEVICE_ERROR No HECI device + @retval EFI_TIMEOUT HECI does not return the buffer before timeout + @exception EFI_UNSUPPORTED HECI MSG is unsupported +**/ +EFI_STATUS +EFIAPI +InitializeHeci ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_HECI_PPI *This, + IN OUT UINT32 *HeciMemBar + ) +{ + HECI_HOST_CONTROL_REGISTER HeciRegHCsr; + VOLATILE HECI_HOST_CONTROL_REGISTER *HeciRegHCsrPtr; + VOLATILE HECI_ME_CONTROL_REGISTER *HeciRegMeCsrHaPtr; + UINT32 HeciMBar; + UINT32 MeMode; + + HeciRegHCsrPtr = NULL; + HeciRegMeCsrHaPtr = NULL; + + /// + /// Check for HECI-1 PCI device availability + /// + if (HeciPciRead16 (PCI_DEVICE_ID_OFFSET) == 0xFFFF) { + return EFI_DEVICE_ERROR; + } + /// + /// Check for ME error status + /// + if ((HeciPciRead32 (R_FWSTATE) & 0xF000) != 0) { + /// + /// ME failed to start so no HECI + /// + return EFI_DEVICE_ERROR; + } + /// + /// HECI MSG is unsupported if ME MODE is in Security Override + /// + HeciGetMeMode (PeiServices, &MeMode); + if (MeMode == ME_MODE_SECOVER) { + return EFI_UNSUPPORTED; + } + /// + /// Get HECI_MBAR and see if it is programmed + /// to a useable value + /// + HeciMBar = HeciPciRead32 (R_HECIMBAR) & 0xFFFFFFF0; + + /// + /// Load temporary address for HECI_MBAR if one is not assigned + /// + if (HeciMBar == 0) { + DEBUG ((EFI_D_ERROR, "Heci MMIO Bar not programmed in PEI phase\n")); + } + + *HeciMemBar = HeciMBar; + + /// + /// Enable HECI BME and MSE + /// + HeciPciOr8 ( + PCI_COMMAND_OFFSET, + EFI_PCI_COMMAND_MEMORY_SPACE | EFI_PCI_COMMAND_BUS_MASTER + ); + + /// + /// Set HECI interrupt delivery mode. + /// HECI-1 using legacy/MSI interrupt + /// + HeciPciAnd8 (R_HIDM, 0xFC); + + /// + /// 2) setup H_CSR reg as follows: + /// a) Make sure H_RST is clear + /// b) Set H_RDY + /// c) Set H_IG + /// + HeciRegHCsrPtr = (VOID *) (HeciMBar + H_CSR); + HeciRegHCsr.ul = HeciRegHCsrPtr->ul; + if (HeciRegHCsrPtr->r.H_RDY == 0) { + HeciRegHCsr.r.H_RST = 0; + HeciRegHCsr.r.H_RDY = 1; + HeciRegHCsr.r.H_IG = 1; + HeciRegHCsrPtr->ul = HeciRegHCsr.ul; + } + + return EFI_SUCCESS; +} + +/** + Waits for the ME to report that it is ready for communication over the HECI + interface. + + @param[in] PeiServices General purpose services available to every PEIM. + @param[in] This The address of HECI PPI. + @param[in] HeciMemBar HECI Memory BAR. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_TIMEOUT If 5 second timeout has expired, return fail. +**/ +EFI_STATUS +WaitForMEReady ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_HECI_PPI *This, + IN UINT32 HeciMemBar + ) +{ + UINT32 TimerStart; + UINT32 TimerEnd; + VOLATILE HECI_ME_CONTROL_REGISTER *HeciRegMeCsrHaPtr; + VOLATILE UINT32 *HpetTimer; + + HeciRegMeCsrHaPtr = (VOID *) (HeciMemBar + ME_CSR_HA); + /// + /// Wait for ME ready + /// + /// + /// Check for ME ready status + /// + HpetTimer = StartTimer (PeiServices, &TimerStart, &TimerEnd, PEI_HECI_INIT_TIMEOUT); + while (HeciRegMeCsrHaPtr->r.ME_RDY_HRA == 0) { + /// + /// If 5 second timeout has expired, return fail + /// + if (Timeout (TimerStart, TimerEnd, HpetTimer) != EFI_SUCCESS) { + return EFI_TIMEOUT; + } + /// + /// Perform IO delay + /// + Stall (PeiServices, PEI_HECI_WAIT_DELAY); + } + /// + /// ME ready!!! + /// + return EFI_SUCCESS; +} + +/** + Read the HECI Message from Intel ME with size in Length into + buffer Message. Set Blocking to BLOCKING and code will wait + until one message packet is received. When set to + NON_BLOCKING, if the circular buffer is empty at the time, the + code not wait for the message packet read. + + @param[in] PeiServices General purpose services available to every PEIM. + @param[in] This The address of HECI PPI. + @param[in] HeciMemBar HECI Memory BAR. + @param[in] Blocking Used to determine if the read is BLOCKING or NON_BLOCKING. + @param[in] MessageBody Pointer to a buffer used to receive a message. + @param[in][out] Length Pointer to the length of the buffer on input and the length + of the message on return. (in bytes) + + @exception EFI_UNSUPPORTED Current ME mode doesn't support this function + @retval EFI_SUCCESS One message packet read + @retval EFI_TIMEOUT HECI is not ready for communication + @retval EFI_DEVICE_ERROR Zero-length message packet read + @retval EFI_BUFFER_TOO_SMALL The caller's buffer was not large enough +**/ +EFI_STATUS +EFIAPI +HeciReadMsg ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_HECI_PPI *This, + IN UINT32 Blocking, + IN UINT32 HeciMemBar, + IN UINT32 *MessageBody, + IN OUT UINT32 *Length + ) +{ + HECI_MESSAGE_HEADER PacketHeader; + UINT32 CurrentLength; + UINT32 MessageComplete; + EFI_STATUS ReadError; + UINT32 PacketBuffer; + UINT32 timer_start; + UINT32 timer_end; + VOLATILE UINT32 *HpetTimer; + UINT32 MeMode; + + CurrentLength = 0; + MessageComplete = 0; + + HeciGetMeMode (PeiServices, &MeMode); + if (MeMode == ME_MODE_SECOVER) { + return EFI_UNSUPPORTED; + } + /// + /// Make sure that HECI device BAR is correct and device is enabled. + /// + /// CheckAndFixHeciForAccess (PeiServices, This); + /// + /// Make sure that HECI is ready for communication. + /// + if (WaitForMEReady (PeiServices, This, HeciMemBar) != EFI_SUCCESS) { + return EFI_TIMEOUT; + } + /// + /// Set up timer for BIOS timeout. + /// + HpetTimer = StartTimer (PeiServices, &timer_start, &timer_end, PEI_HECI_READ_TIMEOUT); + while ((CurrentLength < *Length) && (MessageComplete == 0)) { + /// + /// If 1 second timeout has expired, return fail as we have not yet received a full message + /// + if (Timeout (timer_start, timer_end, HpetTimer) != EFI_SUCCESS) { + return EFI_TIMEOUT; + } + + PacketBuffer = *Length - CurrentLength; + ReadError = HeciPacketRead ( + PeiServices, + Blocking, + HeciMemBar, + &PacketHeader, + (UINT32 *) &MessageBody[CurrentLength / 4], + &PacketBuffer + ); + + /// + /// Check for error condition on read + /// + if (EFI_ERROR (ReadError)) { + *Length = 0; + return ReadError; + } + /// + /// Get completion status from the packet header + /// + MessageComplete = PacketHeader.Fields.MessageComplete; + + /// + /// Check for zero length messages + /// + if (PacketBuffer == 0) { + /// + /// If we are not in the middle of a message, and we see Message Complete, + /// this is a valid zero-length message. + /// + if ((CurrentLength == 0) && (MessageComplete == 1)) { + *Length = 0; + return EFI_SUCCESS; + } else { + /// + /// We should not expect a zero-length message packet except as described above. + /// + *Length = 0; + return EFI_DEVICE_ERROR; + } + } + /// + /// Track the length of what we have read so far + /// + CurrentLength += PacketBuffer; + + } + /// + /// If we get here the message should be complete, if it is not + /// the caller's buffer was not large enough. + /// + if (MessageComplete == 0) { + *Length = 0; + return EFI_BUFFER_TOO_SMALL; + } + + *Length = CurrentLength; + + DEBUG ((EFI_D_ERROR, "HECI ReadMsg:\n")); +#ifdef EFI_DEBUG + DEBUG_CODE ( + ShowBuffer (PeiServices, (UINT8 *) MessageBody, *Length); + ); +#endif // End Of EFI_DEBUG + return EFI_SUCCESS; +} + +/** + Function to pull one messsage packet off the HECI circular buffer. + Corresponds to HECI HPS (part of) section 4.2.4 + + @param[in] PeiServices General purpose services available to every PEIM. + @param[in] HeciMemBar HECI Memory BAR. + @param[in] Blocking Used to determine if the read is BLOCKING or NON_BLOCKING. + @param[out] MessageHeader Pointer to a buffer for the message header. + @param[out] MessageData Pointer to a buffer to recieve the message in. + @param[in][out] Length On input is the size of the callers buffer in bytes. On + output this is the size of the packet in bytes. + + @retval EFI_SUCCESS One message packet read. + @retval EFI_DEVICE_ERROR The circular buffer is overflowed. + @retval EFI_NO_RESPONSE The circular buffer is empty + @retval EFI_TIMEOUT Failed to receive a full message + @retval EFI_BUFFER_TOO_SMALL Message packet is larger than caller's buffer +**/ +EFI_STATUS +HeciPacketRead ( + IN EFI_PEI_SERVICES **PeiServices, + IN UINT32 Blocking, + IN UINT32 HeciMemBar, + OUT HECI_MESSAGE_HEADER *MessageHeader, + OUT UINT32 *MessageData, + IN OUT UINT32 *Length + ) +{ + BOOLEAN GotMessage; + UINT32 TimerStart; + UINT32 TimerEnd; + UINT32 TimerStart1; + UINT32 TimerEnd1; + UINT32 i; + UINT32 LengthInDwords; + HECI_ME_CONTROL_REGISTER HeciRegMeCsrHa; + VOLATILE UINT32 *HpetTimer; + /// + /// Initialize memory mapped register pointers + /// + VOLATILE HECI_HOST_CONTROL_REGISTER *HeciRegHCsrPtr; + VOLATILE HECI_ME_CONTROL_REGISTER *HeciRegMeCsrHaPtr; + VOLATILE UINT32 *HeciRegMeCbrwPtr; + + HeciRegHCsrPtr = (VOID *) (HeciMemBar + H_CSR); + HeciRegMeCsrHaPtr = (VOID *) (HeciMemBar + ME_CSR_HA); + HeciRegMeCbrwPtr = (VOID *) (HeciMemBar + ME_CB_RW); + + GotMessage = FALSE; + + /// + /// clear Interrupt Status bit + /// + HeciRegHCsrPtr->r.H_IS = 1; + + /// + /// test for circular buffer overflow + /// + HeciRegMeCsrHa.ul = HeciRegMeCsrHaPtr->ul; + if (OverflowCB ( + HeciRegMeCsrHa.r.ME_CBRP_HRA, + HeciRegMeCsrHa.r.ME_CBWP_HRA, + HeciRegMeCsrHa.r.ME_CBD_HRA + ) != EFI_SUCCESS) { + /// + /// if we get here, the circular buffer is overflowed + /// + *Length = 0; + return EFI_DEVICE_ERROR; + } + /// + /// If NON_BLOCKING, exit if the circular buffer is empty + /// + HeciRegMeCsrHa.ul = HeciRegMeCsrHaPtr->ul; + if ((FilledSlots (HeciRegMeCsrHa.r.ME_CBRP_HRA, HeciRegMeCsrHa.r.ME_CBWP_HRA) == 0) && (Blocking == NON_BLOCKING)) { + *Length = 0; + return EFI_NO_RESPONSE; + } + /// + /// Start timeout counter + /// + HpetTimer = StartTimer (PeiServices, &TimerStart, &TimerEnd, PEI_HECI_READ_TIMEOUT); + + /// + /// loop until we get a message packet + /// + while (!GotMessage) { + /// + /// If 1 second timeout has expired, return fail as we have not yet received a full message. + /// + if (Timeout (TimerStart, TimerEnd, HpetTimer) != EFI_SUCCESS) { + *Length = 0; + return EFI_TIMEOUT; + } + /// + /// Read one message from HECI buffer and advance read pointer. Make sure + /// that we do not pass the write pointer. + /// + HeciRegMeCsrHa.ul = HeciRegMeCsrHaPtr->ul; + if (FilledSlots (HeciRegMeCsrHa.r.ME_CBRP_HRA, HeciRegMeCsrHa.r.ME_CBWP_HRA) > 0) { + /// + /// Eat the HECI Message header + /// + MessageHeader->Data = *HeciRegMeCbrwPtr; + + /// + /// Compute required message length in DWORDS + /// + LengthInDwords = ((MessageHeader->Fields.Length + 3) / 4); + + /// + /// Just return success if Length is 0 + /// + if (MessageHeader->Fields.Length == 0) { + /// + /// Set Interrupt Generate bit and return + /// + HeciRegHCsrPtr->r.H_IG = 1; + *Length = 0; + return EFI_SUCCESS; + } + /// + /// Make sure that the message does not overflow the circular buffer. + /// + if ((MessageHeader->Fields.Length + sizeof (HECI_MESSAGE_HEADER)) > (HeciRegMeCsrHaPtr->r.ME_CBD_HRA * 4)) { + *Length = 0; + return EFI_DEVICE_ERROR; + } + /// + /// Make sure that the callers buffer can hold the correct number of DWORDS + /// + if ((MessageHeader->Fields.Length) <= *Length) { + /// + /// Start timeout counter for inner loop + /// + HpetTimer = StartTimer (PeiServices, &TimerStart1, &TimerEnd1, PEI_HECI_READ_TIMEOUT); + + /// + /// Wait here until entire message is present in circular buffer + /// + HeciRegMeCsrHa.ul = HeciRegMeCsrHaPtr->ul; + while (LengthInDwords > FilledSlots (HeciRegMeCsrHa.r.ME_CBRP_HRA, HeciRegMeCsrHa.r.ME_CBWP_HRA)) { + /// + /// If 1 second timeout has expired, return fail as we have not yet received a full message + /// + if (Timeout (TimerStart1, TimerEnd1, HpetTimer) != EFI_SUCCESS) { + *Length = 0; + return EFI_TIMEOUT; + } + /// + /// Wait before we read the register again + /// + Stall (PeiServices, PEI_HECI_WAIT_DELAY); + + /// + /// Read the register again + /// + HeciRegMeCsrHa.ul = HeciRegMeCsrHaPtr->ul; + } + /// + /// copy rest of message + /// + for (i = 0; i < LengthInDwords; i++) { + MessageData[i] = *HeciRegMeCbrwPtr; + } + /// + /// Update status and length + /// + GotMessage = TRUE; + *Length = MessageHeader->Fields.Length; + + } else { + /// + /// Message packet is larger than caller's buffer + /// + *Length = 0; + return EFI_BUFFER_TOO_SMALL; + } + } + /// + /// Wait before we try to get a message again + /// + Stall (PeiServices, PEI_HECI_WAIT_DELAY); + } + /// + /// Read ME_CSR_HA. If the ME_RDY bit is 0, then an ME reset occurred during the + /// transaction and the message should be discarded as bad data may have been retrieved + /// from the host's circular buffer + /// + if (HeciRegMeCsrHaPtr->r.ME_RDY_HRA == 0) { + *Length = 0; + return EFI_DEVICE_ERROR; + } + /// + /// Set Interrupt Generate bit + /// + HeciRegHCsrPtr->r.H_IG = 1; + + return EFI_SUCCESS; +} + +/** + Function sends one messsage (of any length) through the HECI circular buffer. + + @param[in] PeiServices General purpose services available to every PEIM. + @param[in] This The address of HECI PPI. + @param[in] HeciMemBar HECI Memory BAR. + @param[in] Message Pointer to the message data to be sent. + @param[in] Length Length of the message in bytes. + @param[in] HostAddress The address of the host processor. + @param[in] MeAddress Address of the ME subsystem the message is being sent to. + + @retval EFI_SUCCESS One message packet sent. + @retval EFI_DEVICE_ERROR Failed to initialize HECI + @retval EFI_TIMEOUT HECI is not ready for communication + @exception EFI_UNSUPPORTED Current ME mode doesn't support send message through HEC +**/ +EFI_STATUS +HeciSendMsg ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_HECI_PPI *This, + IN UINT32 *Message, + IN UINT32 HeciMemBar, + IN UINT32 Length, + IN UINT8 HostAddress, + IN UINT8 MeAddress + ) +{ + UINT32 CBLength; + UINT32 SendLength; + UINT32 CurrentLength; + HECI_MESSAGE_HEADER MessageHeader; + EFI_STATUS WriteStatus; + VOLATILE HECI_HOST_CONTROL_REGISTER *HeciRegHCsrPtr; + UINT32 MeMode; + + CurrentLength = 0; + HeciRegHCsrPtr = NULL; + + HeciGetMeMode (PeiServices, &MeMode); + if (MeMode == ME_MODE_SECOVER) { + return EFI_UNSUPPORTED; + } + + DEBUG ((EFI_D_ERROR, "HECI SendMsg:\n")); +#ifdef EFI_DEBUG + DEBUG_CODE ( + ShowBuffer (PeiServices, (UINT8 *) Message, Length); + ); +#endif // End Of EFI_DEBUG + /// + /// Make sure that HECI device BAR is correct and device is enabled. + /// + /// CheckAndFixHeciForAccess (PeiServices, This); + /// + /// Make sure that HECI is ready for communication. + /// + if (WaitForMEReady (PeiServices, This, HeciMemBar) != EFI_SUCCESS) { + return EFI_TIMEOUT; + } + /// + /// Set up memory mapped registers + /// + HeciRegHCsrPtr = (VOID *) (HeciMemBar + H_CSR); + + /// + /// Grab Circular Buffer length + /// + CBLength = HeciRegHCsrPtr->r.H_CBD; + + /// + /// Prepare message header + /// + MessageHeader.Data = 0; + MessageHeader.Fields.MeAddress = MeAddress; + MessageHeader.Fields.HostAddress = HostAddress; + + /// + /// Break message up into CB-sized packets and loop until completely sent + /// + while (Length > CurrentLength) { + /// + /// Set the Message Complete bit if this is our last packet in the message. + /// Needs to be 'less than' to account for the header. + /// + if ((((Length - CurrentLength) + 3) / 4) < CBLength) { + MessageHeader.Fields.MessageComplete = 1; + } + /// + /// Calculate length for Message Header + /// header length == smaller of circular buffer or remaining message (both account for the size of the header) + /// + SendLength = ((CBLength < (((Length - CurrentLength) + 3) / 4)) ? ((CBLength - 1) * 4) : (Length - CurrentLength)); + MessageHeader.Fields.Length = SendLength; + + DEBUG ((EFI_D_ERROR, "HECI Header: %08x\n", MessageHeader.Data)); + /// + /// send the current packet (CurrentLength can be treated as the index into the message buffer) + /// + WriteStatus = HeciPacketWrite ( + PeiServices, + This, + HeciMemBar, + &MessageHeader, + (UINT32 *) ((UINT32) Message + CurrentLength) + ); + if (EFI_ERROR (WriteStatus)) { + return WriteStatus; + } + /// + /// Update the length information + /// + CurrentLength += SendLength; + } + + return EFI_SUCCESS; +} + +/** + Function sends one messsage packet through the HECI circular buffer + Corresponds to HECI HPS (part of) section 4.2.3 + + @param[in] PeiServices General purpose services available to every PEIM. + @param[in] This The address of HECI PPI. + @param[in] HeciMemBar HECI Memory BAR. + @param[in] MessageHeader Pointer to the message header. + @param[in] MessageData Pointer to the actual message data. + + @retval EFI_SUCCESS One message packet sent + @retval EFI_DEVICE_ERROR ME is not ready + @retval EFI_TIMEOUT HECI is not ready for communication +**/ +EFI_STATUS +HeciPacketWrite ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_HECI_PPI *This, + IN UINT32 HeciMemBar, + IN HECI_MESSAGE_HEADER *MessageHeader, + IN UINT32 *MessageData + ) +{ + UINT32 timer_start; + UINT32 timer_end; + UINT32 i; + UINT32 LengthInDwords; + HECI_HOST_CONTROL_REGISTER HeciRegHCsr; + VOLATILE UINT32 *HpetTimer; + VOLATILE HECI_HOST_CONTROL_REGISTER *HeciRegHCsrPtr; + VOLATILE HECI_ME_CONTROL_REGISTER *HeciRegMeCsrHaPtr; + VOLATILE UINT32 *HeciRegHCbwwPtr; + + HeciRegHCsrPtr = (VOID *) (HeciMemBar + H_CSR); + HeciRegMeCsrHaPtr = (VOID *) (HeciMemBar + ME_CSR_HA); + HeciRegHCbwwPtr = (VOID *) (HeciMemBar + H_CB_WW); + /// + /// Make sure that HECI is ready for communication. + /// + if (WaitForMEReady (PeiServices, This, HeciMemBar) != EFI_SUCCESS) { + return EFI_TIMEOUT; + } + /// + /// Start timeout counter + /// + HpetTimer = StartTimer (PeiServices, &timer_start, &timer_end, PEI_HECI_SEND_TIMEOUT); + + /// + /// Compute message length in DWORDS + /// + LengthInDwords = ((MessageHeader->Fields.Length + 3) / 4); + + /// + /// Wait until there is sufficient room in the circular buffer + /// Must have room for message and message header + /// + HeciRegHCsr.ul = HeciRegHCsrPtr->ul; + while ((LengthInDwords + 1) > (HeciRegHCsr.r.H_CBD - FilledSlots (HeciRegHCsr.r.H_CBRP, HeciRegHCsr.r.H_CBWP))) { + /// + /// If 1 second timeout has expired, return fail as the circular buffer never emptied + /// + if (Timeout (timer_start, timer_end, HpetTimer) != EFI_SUCCESS) { + return EFI_TIMEOUT; + } + /// + /// Wait before we read the register again + /// + Stall (PeiServices, PEI_HECI_WAIT_DELAY); + + /// + /// Read Host CSR for next iteration + /// + HeciRegHCsr.ul = HeciRegHCsrPtr->ul; + } + /// + /// Write Message Header + /// + *HeciRegHCbwwPtr = MessageHeader->Data; + + /// + /// Write Message Body + /// + for (i = 0; i < LengthInDwords; i++) { + *HeciRegHCbwwPtr = MessageData[i]; + } + /// + /// Set Interrupt Generate bit + /// + HeciRegHCsrPtr->r.H_IG = 1; + + /// + /// Test if ME Ready bit is set to 1, if set to 0 a fatal error occured during + /// the transmission of this message. + /// + if (HeciRegMeCsrHaPtr->r.ME_RDY_HRA == 0) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +/** + Function sends one messsage through the HECI circular buffer and waits + for the corresponding ACK message. + + @param[in] PeiServices General purpose services available to every PEIM. + @param[in] This The address of HECI PPI. + @param[in][out] Message Pointer to the message buffer. + @param[in] HeciMemBar HECI Memory BAR. + @param[in][out] Length Length of the message in bytes. + @param[in] HostAddress Address of the sending entity. + @param[in] MeAddress Address of the ME entity that should receive the message. + + @retval EFI_SUCCESS Command succeeded + @retval EFI_DEVICE_ERROR HECI Device error, command aborts abnormally + @retval EFI_TIMEOUT HECI does not return the bufferbefore timeout + @retval EFI_BUFFER_TOO_SMALL Message Buffer is too small for the Acknowledge + @exception EFI_UNSUPPORTED Current ME mode doesn't support send message through HECI +**/ +EFI_STATUS +HeciSendwAck ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_HECI_PPI *This, + IN OUT UINT32 *Message, + IN UINT32 HeciMemBar, + IN OUT UINT32 *Length, + IN UINT8 HostAddress, + IN UINT8 MeAddress + ) +{ + EFI_STATUS Status; + UINT32 MeMode; + + HeciGetMeMode (PeiServices, &MeMode); + if (MeMode == ME_MODE_SECOVER) { + return EFI_UNSUPPORTED; + } + /// + /// Send the message + /// + Status = HeciSendMsg (PeiServices, This, Message, HeciMemBar, *Length, HostAddress, MeAddress); + if (EFI_ERROR (Status)) { + return Status; + } + /// + /// Wait for ACK message + /// + return HeciReadMsg (PeiServices, This, BLOCKING, HeciMemBar, Message, Length); +} + +/** + Calculate if the circular buffer has overflowed. + Corresponds to HECI HPS (part of) section 4.2.1 + + @param[in] ReadPointer Location of the read pointer. + @param[in] WritePointer Location of the write pointer. + + @retval UINT8 Number of filled slots. +**/ +UINT8 +FilledSlots ( + IN UINT32 ReadPointer, + IN UINT32 WritePointer + ) +{ + UINT8 FilledSlots; + + /// + /// Calculation documented in HECI HPS 0.68 section 4.2.1 + /// + FilledSlots = (((INT8) WritePointer) - ((INT8) ReadPointer)); + + return FilledSlots; +} + +/** + Calculate if the circular buffer has overflowed + Corresponds to HECI HPS (part of) section 4.2.1 + + @param[in] ReadPointer Value read from host/me read pointer + @param[in] WritePointer Value read from host/me write pointer + @param[in] BufferDepth Value read from buffer depth register + + @retval EFI_DEVICE_ERROR The circular buffer has overflowed + @retval EFI_SUCCESS The circular buffer does not overflowed +**/ +EFI_STATUS +OverflowCB ( + IN UINT32 ReadPointer, + IN UINT32 WritePointer, + IN UINT32 BufferDepth + ) +{ + UINT8 FilledSlots; + + /// + /// Calculation documented in HECI HPS 0.68 section 4.2.1 + /// + FilledSlots = (((INT8) WritePointer) - ((INT8) ReadPointer)); + + /// + /// test for overflow + /// + if (FilledSlots > ((UINT8) BufferDepth)) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +/** + Used for calculating timeouts + + @param[in] PeiServices General purpose services available to every PEIM. + @param[in] Start Snapshot of the HPET timer + @param[in] End Calculated time when timeout period will be done + @param[in] Time Timeout period in microseconds + + @retval None +**/ +VOLATILE +UINT32 * +StartTimer ( + IN EFI_PEI_SERVICES **PeiServices, + OUT UINT32 *Start, + OUT UINT32 *End, + IN UINT32 Time + ) +{ + UINT32 Ticks; + VOLATILE UINT32 *HpetTimer; + /// + /// Make sure that HPET is enabled and running + /// + HpetTimer = EnableHpet (PeiServices); + + /// + /// Read current timer value into start time from HPET + /// + *Start = HpetTimer[HPET_MAIN_COUNTER_LOW]; + + /// + /// Convert microseconds into 70ns timer ticks + /// + Ticks = Time * HPET_TICKS_PER_MICRO; + + /// + /// Compute end time + /// + *End = *Start + Ticks; + + return HpetTimer; +} + +/** + Used to determine if a timeout has occured. + + @param[in] Start Snapshot of the HPET timer when the timeout period started. + @param[in] End Calculated time when timeout period will be done. + @param[in] HpetTimer The value of High Precision Event Timer + + @retval EFI_TIMEOUT Timeout occured. + @retval EFI_SUCCESS Not yet timed out +**/ +EFI_STATUS +Timeout ( + IN UINT32 Start, + IN UINT32 End, + IN VOLATILE UINT32 *HpetTimer + ) +{ + UINT32 Current; + + /// + /// Read HPET and assign the value as the current time. + /// + Current = HpetTimer[HPET_MAIN_COUNTER_LOW]; + + /// + /// If no timeout, current timer always is +1 to Start timer + /// + /// if(This->HeciTimeout == 0){ + /// Current = Start + 1; + /// } + /// + /// Test basic case (no overflow) + /// + if ((Start < End) && (End <= Current)) { + return EFI_TIMEOUT; + } + /// + /// Test basic start/end conditions with overflowed timer + /// + if ((Start < End) && (Current < Start)) { + return EFI_TIMEOUT; + } + /// + /// Test for overflowed start/end condition + /// + if ((Start > End) && ((Current < Start) && (Current > End))) { + return EFI_TIMEOUT; + } + /// + /// Catch corner case of broken arguments + /// + if (Start == End) { + return EFI_TIMEOUT; + } + /// + /// Else, we have not yet timed out + /// + return EFI_SUCCESS; +} + +/** + Get an abstract Intel ME Status from Firmware Status Register. + This is used to control BIOS flow for different Intel ME + functions. + + @param[in] PeiServices General purpose services available to every PEIM. + @param[in] MeStatus Pointer for status report, + see MeState.h - Abstract ME status definitions. + + @retval EFI_SUCCESS MeStatus copied + @retval EFI_INVALID_PARAMETER Pointer of MeStatus is invalid +**/ +EFI_STATUS +EFIAPI +HeciGetMeStatus ( + IN EFI_PEI_SERVICES **PeiServices, + IN UINT32 *MeStatus + ) +{ + HECI_FWS_REGISTER MeFirmwareStatus; + + if (MeStatus == NULL) { + return EFI_INVALID_PARAMETER; + } + + MeFirmwareStatus.ul = HeciPciRead32 (R_FWSTATE); + if (MeFirmwareStatus.r.CurrentState == ME_STATE_NORMAL && MeFirmwareStatus.r.ErrorCode == ME_ERROR_CODE_NO_ERROR) { + *MeStatus = ME_READY; + } else if (MeFirmwareStatus.r.CurrentState == ME_STATE_RECOVERY) { + *MeStatus = ME_IN_RECOVERY_MODE; + } else { + *MeStatus = ME_NOT_READY; + } + + if (MeFirmwareStatus.r.FwInitComplete == ME_FIRMWARE_COMPLETED) { + *MeStatus |= ME_FW_INIT_COMPLETE; + } + + DEBUG ((EFI_D_ERROR, "HECI MeStatus %X\n", MeFirmwareStatus.ul)); + + return EFI_SUCCESS; +} + +/** + Get an abstract ME operation mode from firmware status + register. This is used to control BIOS flow for different + Intel ME functions. + + @param[in] PeiServices General purpose services available to every PEIM. + @param[in] MeMode Pointer for ME Mode report, + see MeState.h - Abstract ME Mode definitions. + + @retval EFI_SUCCESS MeMode copied + @retval EFI_INVALID_PARAMETER Pointer of MeMode is invalid +**/ +EFI_STATUS +EFIAPI +HeciGetMeMode ( + IN EFI_PEI_SERVICES **PeiServices, + IN UINT32 *MeMode + ) +{ + HECI_FWS_REGISTER MeFirmwareStatus; + + if (MeMode == NULL) { + return EFI_INVALID_PARAMETER; + } + + MeFirmwareStatus.ul = HeciPciRead32 (R_FWSTATE); + + switch (MeFirmwareStatus.r.MeOperationMode) { + case ME_OPERATION_MODE_NORMAL: + *MeMode = ME_MODE_NORMAL; + break; + + case ME_OPERATION_MODE_DEBUG: + *MeMode = ME_MODE_DEBUG; + break; + + case ME_OPERATION_MODE_SOFT_TEMP_DISABLE: + *MeMode = ME_MODE_TEMP_DISABLED; + break; + + case ME_OPERATION_MODE_SECOVR_JMPR: + case ME_OPERATION_MODE_SECOVR_HECI_MSG: + *MeMode = ME_MODE_SECOVER; + break; + + default: + *MeMode = ME_MODE_FAILED; + } + DEBUG ((EFI_D_ERROR, "HECI MeMode %X\n", MeFirmwareStatus.r.MeOperationMode)); + return EFI_SUCCESS; +} diff --git a/ReferenceCode/ME/Heci/Pei/HeciInit.c b/ReferenceCode/ME/Heci/Pei/HeciInit.c new file mode 100644 index 0000000..0375bd7 --- /dev/null +++ b/ReferenceCode/ME/Heci/Pei/HeciInit.c @@ -0,0 +1,182 @@ +/** @file + Framework PEIM to HECI. + +@copyright + Copyright (c) 2008 - 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) +// +// Statements that include other files +// +#include "HeciInit.h" +#endif +// +// Function Declarations +// +static PEI_HECI_PPI mHeciPpi = { + HeciSendwAck, + HeciReadMsg, + HeciSendMsg, + InitializeHeci, + HeciGetMeStatus, + HeciGetMeMode +}; + +static EFI_PEI_PPI_DESCRIPTOR mInstallHeciPpi = { + EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, + &gPeiHeciPpiGuid, + &mHeciPpi +}; + +// +// Function Implementations +// + +/** + Internal function performing Heci platform PPIs init needed in PEI phase + + @param[in] PeiServices General purpose services available to every PEIM. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_DEVICE_ERROR ME FPT is bad +**/ +EFI_STATUS +EFIAPI +PeiInstallHeciPpi ( + IN EFI_PEI_SERVICES **PeiServices + ) +{ + EFI_STATUS Status; + + /// + /// Check for ME FPT Bad + /// + if ((HeciPciRead32 (R_FWSTATE) & 0x0020) != 0) { + + return EFI_DEVICE_ERROR; + } + /// + /// Initialize Heci platform PPIs + /// Do not use EdkIIGlueLib here because PeiService pointer used in GlueLib + /// is not updated after memory installed. + /// + Status = (**PeiServices).InstallPpi (PeiServices, &mInstallHeciPpi); + ASSERT_EFI_ERROR (Status); + + DEBUG ((EFI_D_ERROR, "Install Heci Ppi Complete.\n")); + return Status; +} + +/** + Internal function performing PM register initialization for Me + + @param[in] PeiServices General purpose services available to every PEIM. + + @retval EFI_SUCCESS Always return EFI_SUCCESS +**/ +EFI_STATUS +EFIAPI +MePmInit ( + IN EFI_PEI_SERVICES **PeiServices + ) +{ + UINT16 PmBase; + UINT16 Pm1Cnt; + + /// + /// Before system memory initialization, BIOS should check the WAK_STS bit in PM1_STS[15] (PCH register PMBASE+00h) + /// to determine if Intel Management Engine has reset the system while the host was in a sleep state. If WAK_STS is + /// not set, BIOS should ensure a non-sleep exit path is taken. One way to accomplish this is by overwriting + /// PM1_CNT[12:10] (PCH register PMBASE+04h) to 111b to force an S5 exit path by the BIOS. + /// + PmBase = PciRead16 ( + PCI_LIB_ADDRESS (DEFAULT_PCI_BUS_NUMBER_PCH, + PCI_DEVICE_NUMBER_PCH_LPC, + 0, + R_PCH_LPC_ACPI_BASE) + ) & B_PCH_LPC_ACPI_BASE_BAR; + + ASSERT (PmBase != 0); + + if (PmBase != 0) { + if ((IoRead16 (PmBase + R_PCH_ACPI_PM1_STS) & B_PCH_ACPI_PM1_STS_WAK) == 0) { + Pm1Cnt = IoRead16 (PmBase + R_PCH_ACPI_PM1_CNT) | V_PCH_ACPI_PM1_CNT_S5; + IoWrite16 (PmBase + R_PCH_ACPI_PM1_CNT, Pm1Cnt); + DEBUG ((EFI_D_ERROR, "Force an S5 exit path.\n")); + } + } + + return EFI_SUCCESS; +} + +/** + Internal function performing Me initialization. + + @param[in] PeiServices General purpose services available to every PEIM. + + @retval EFI_SUCCESS Heci initialization completed successfully. + @retval All other error conditions encountered result in an ASSERT. +**/ +EFI_STATUS +EFIAPI +MeInit ( + IN EFI_PEI_SERVICES **PeiServices + ) +{ + EFI_STATUS Status; + + Status = MePmInit (PeiServices); + return Status; +} + +/** + Initialize ME after reset + + @param[in] FfsHeader Not used. + @param[in] PeiServices General purpose services available to every PEIM. + + @retval EFI_SUCCESS Heci initialization completed successfully. + @retval All other error conditions encountered result in an ASSERT. +**/ +EFI_STATUS +PeimHeciInit ( + IN EFI_FFS_FILE_HEADER *FfsHeader, + IN EFI_PEI_SERVICES **PeiServices + ) +{ + EFI_STATUS Status; + + /// + /// Performing Me initialization + /// + Status = MeInit (PeiServices); + ASSERT_EFI_ERROR (Status); + + Status = PeiInstallHeciPpi (PeiServices); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "(ICC) Failed to PeiInstallHeciPpi! Status = %r\n", Status)); + } else { + DEBUG ((EFI_D_INFO, "HeciInit Complete.\n")); + } + + return Status; +} diff --git a/ReferenceCode/ME/Heci/Pei/HeciInit.dxs b/ReferenceCode/ME/Heci/Pei/HeciInit.dxs new file mode 100644 index 0000000..2db83cd --- /dev/null +++ b/ReferenceCode/ME/Heci/Pei/HeciInit.dxs @@ -0,0 +1,45 @@ +/** @file + Dependency expression file for Heci Init PEIM. + +@copyright + Copyright (c) 2010 - 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 a 'Sample Driver' and is licensed as such + under the terms of your license agreement with Intel or your + vendor. This file may be modified by the user, subject to + the additional terms of the license agreement + +**/ + +// +// Common for R8 and R9 codebase +// +#include "AutoGen.h" +#include "PeimDepex.h" + +// +// BUILD_WITH_GLUELIB and BUILD_WITH_EDKII_GLUE_LIB are both "defined" in R8 codebase; +// BUILD_WITH_EDKII_GLUE_LIB is defined in Edk-Dev-Snapshot-20070228 and later version +// BUILD_WITH_GLUELIB and BUILD_WITH_EDKII_GLUE_LIB are "not defined" in R9 codebase. +// +#if defined (BUILD_WITH_GLUELIB) || defined (BUILD_WITH_EDKII_GLUE_LIB) +#include "EfiDepex.h" + +#endif + + +DEPENDENCY_START + + TRUE +DEPENDENCY_END + + + + diff --git a/ReferenceCode/ME/Heci/Pei/HeciInit.h b/ReferenceCode/ME/Heci/Pei/HeciInit.h new file mode 100644 index 0000000..a8dab69 --- /dev/null +++ b/ReferenceCode/ME/Heci/Pei/HeciInit.h @@ -0,0 +1,390 @@ +/** @file + Framework PEIM to provide Heci. + +@copyright + Copyright (c) 2008 - 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 + +**/ +#ifndef _HECI_INIT_H_ +#define _HECI_INIT_H_ + +#include "EdkIIGluePeim.h" +#include "MeAccess.h" +#include "HeciRegs.h" +#include "MeState.h" +#include "CoreBiosMsg.h" +#include "Pci22.h" + +// +// Driver Consumed PPI Prototypes +// +#include EFI_PPI_DEPENDENCY (CpuIo) +#include EFI_PPI_DEPENDENCY (PciCfg) +#include EFI_PPI_DEPENDENCY (Heci) +#include EFI_PPI_DEPENDENCY (MemoryDiscovered) + +// +// Prototypes +// + +/** + Enable Hpet function. + + @param[in] PeiServices General purpose services available to every PEIM. + + @retval UINT32 Return the High Precision Event Timer base address +**/ +VOLATILE +UINT32 * +EnableHpet ( + IN EFI_PEI_SERVICES **PeiServices + ) +; + +/** + This function provides a standard way to verify the HECI cmd and MBAR regs + in its PCI cfg space are setup properly and that the local mHeciContext + variable matches this info. + + @param[in] PeiServices General purpose services available to every PEIM. + @param[in] This The address of HECI PPI + @param[in][out] HeciMemBar HECI Memory BAR + + @retval None +**/ +VOID +CheckAndFixHeciForAccess ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_HECI_PPI *This, + IN OUT UINT32 *HeciMemBar + ) +; + +/** + Determines if the HECI device is present and, if present, initializes it for + use by the BIOS. + + @param[in] PeiServices General purpose services available to every PEIM. + @param[in] This The address of HECI PPI + @param[in][out] HeciMemBar HECI Memory BAR + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_DEVICE_ERROR No HECI device + @retval EFI_TIMEOUT HECI does not return the buffer before timeout + @exception EFI_UNSUPPORTED HECI MSG is unsupported +**/ +EFI_STATUS +EFIAPI +InitializeHeci ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_HECI_PPI *This, + IN OUT UINT32 *HeciMemBar + ) +; + +/** + Waits for the ME to report that it is ready for communication over the HECI + interface. + + @param[in] PeiServices General purpose services available to every PEIM. + @param[in] This The address of HECI PPI. + @param[in] HeciMemBar HECI Memory BAR. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_TIMEOUT If 5 second timeout has expired, return fail. +**/ +EFI_STATUS +WaitForMEReady ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_HECI_PPI *This, + IN UINT32 HeciMemBar + ) +; + +/** + Read the HECI Message from Intel ME with size in Length into + buffer Message. Set Blocking to BLOCKING and code will wait + until one message packet is received. When set to + NON_BLOCKING, if the circular buffer is empty at the time, the + code not wait for the message packet read. + + @param[in] PeiServices General purpose services available to every PEIM. + @param[in] This The address of HECI PPI. + @param[in] HeciMemBar HECI Memory BAR. + @param[in] Blocking Used to determine if the read is BLOCKING or NON_BLOCKING. + @param[in] MessageBody Pointer to a buffer used to receive a message. + @param[in][out] Length Pointer to the length of the buffer on input and the length + of the message on return. (in bytes) + + @exception EFI_UNSUPPORTED Current ME mode doesn't support this function + @retval EFI_SUCCESS One message packet read + @retval EFI_TIMEOUT HECI is not ready for communication + @retval EFI_DEVICE_ERROR Zero-length message packet read + @retval EFI_BUFFER_TOO_SMALL The caller's buffer was not large enough +**/ +EFI_STATUS +EFIAPI +HeciReadMsg ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_HECI_PPI *This, + IN UINT32 Blocking, + IN UINT32 HeciMemBar, + IN UINT32 *MessageBody, + IN OUT UINT32 *Length + ) +; + +/** + Function to pull one messsage packet off the HECI circular buffer. + Corresponds to HECI HPS (part of) section 4.2.4 + + @param[in] PeiServices General purpose services available to every PEIM. + @param[in] HeciMemBar HECI Memory BAR. + @param[in] Blocking Used to determine if the read is BLOCKING or NON_BLOCKING. + @param[out] MessageHeader Pointer to a buffer for the message header. + @param[out] MessageData Pointer to a buffer to recieve the message in. + @param[in][out] Length On input is the size of the callers buffer in bytes. On + output this is the size of the packet in bytes. + + @retval EFI_SUCCESS One message packet read. + @retval EFI_DEVICE_ERROR The circular buffer is overflowed. + @retval EFI_NO_RESPONSE The circular buffer is empty + @retval EFI_TIMEOUT Failed to receive a full message + @retval EFI_BUFFER_TOO_SMALL Message packet is larger than caller's buffer +**/ +EFI_STATUS +HeciPacketRead ( + IN EFI_PEI_SERVICES **PeiServices, + IN UINT32 Blocking, + IN UINT32 HeciMemBar, + OUT HECI_MESSAGE_HEADER *MessageHeader, + OUT UINT32 *MessageData, + IN OUT UINT32 *Length + ) +; + +/** + Function sends one messsage (of any length) through the HECI circular buffer. + + @param[in] PeiServices General purpose services available to every PEIM. + @param[in] This The address of HECI PPI. + @param[in] HeciMemBar HECI Memory BAR. + @param[in] Message Pointer to the message data to be sent. + @param[in] Length Length of the message in bytes. + @param[in] HostAddress The address of the host processor. + @param[in] MeAddress Address of the ME subsystem the message is being sent to. + + @retval EFI_SUCCESS One message packet sent. + @retval EFI_DEVICE_ERROR Failed to initialize HECI + @retval EFI_TIMEOUT HECI is not ready for communication + @exception EFI_UNSUPPORTED Current ME mode doesn't support send message through HEC +**/ +EFI_STATUS +HeciSendMsg ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_HECI_PPI *This, + IN UINT32 *Message, + IN UINT32 HeciMemBar, + IN UINT32 Length, + IN UINT8 HostAddress, + IN UINT8 MeAddress + ) +; + +/** + Function sends one messsage packet through the HECI circular buffer + Corresponds to HECI HPS (part of) section 4.2.3 + + @param[in] PeiServices General purpose services available to every PEIM. + @param[in] This The address of HECI PPI. + @param[in] HeciMemBar HECI Memory BAR. + @param[in] MessageHeader Pointer to the message header. + @param[in] MessageData Pointer to the actual message data. + + @retval EFI_SUCCESS One message packet sent + @retval EFI_DEVICE_ERROR ME is not ready + @retval EFI_TIMEOUT HECI is not ready for communication +**/ +EFI_STATUS +HeciPacketWrite ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_HECI_PPI *This, + IN UINT32 HeciMemBar, + IN HECI_MESSAGE_HEADER *MessageHeader, + IN UINT32 *MessageData + ) +; + +/** + Function sends one messsage through the HECI circular buffer and waits + for the corresponding ACK message. + + @param[in] PeiServices General purpose services available to every PEIM. + @param[in] This The address of HECI PPI. + @param[in][out] Message Pointer to the message buffer. + @param[in] HeciMemBar HECI Memory BAR. + @param[in][out] Length Length of the message in bytes. + @param[in] HostAddress Address of the sending entity. + @param[in] MeAddress Address of the ME entity that should receive the message. + + @retval EFI_SUCCESS Command succeeded + @retval EFI_DEVICE_ERROR HECI Device error, command aborts abnormally + @retval EFI_TIMEOUT HECI does not return the bufferbefore timeout + @retval EFI_BUFFER_TOO_SMALL Message Buffer is too small for the Acknowledge + @exception EFI_UNSUPPORTED Current ME mode doesn't support send message through HECI +**/ +EFI_STATUS +HeciSendwAck ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_HECI_PPI *This, + IN OUT UINT32 *Message, + IN UINT32 HeciMemBar, + IN OUT UINT32 *Length, + IN UINT8 HostAddress, + IN UINT8 MeAddress + ) +; + +/** + Calculate if the circular buffer has overflowed + Corresponds to HECI HPS (part of) section 4.2.1 + + @param[in] ReadPointer Value read from host/me read pointer + @param[in] WritePointer Value read from host/me write pointer + @param[in] BufferDepth Value read from buffer depth register + + @retval EFI_DEVICE_ERROR The circular buffer has overflowed + @retval EFI_SUCCESS The circular buffer does not overflowed +**/ +EFI_STATUS +OverflowCB ( + IN UINT32 ReadPointer, + IN UINT32 WritePointer, + IN UINT32 BufferDepth + ) +; + +/** + Used for calculating timeouts + + @param[in] PeiServices General purpose services available to every PEIM. + @param[in] Start Snapshot of the HPET timer + @param[in] End Calculated time when timeout period will be done + @param[in] Time Timeout period in microseconds + + @retval None +**/ +VOLATILE +UINT32 * +StartTimer ( + IN EFI_PEI_SERVICES **PeiServices, + OUT UINT32 *Start, + OUT UINT32 *End, + IN UINT32 Time + ) +; + +/** + Used to determine if a timeout has occured. + + @param[in] Start Snapshot of the HPET timer when the timeout period started. + @param[in] End Calculated time when timeout period will be done. + @param[in] HpetTimer The value of High Precision Event Timer + + @retval EFI_TIMEOUT Timeout occured. + @retval EFI_SUCCESS Not yet timed out +**/ +EFI_STATUS +Timeout ( + IN UINT32 Start, + IN UINT32 End, + IN VOLATILE UINT32 *HpetTimer + ) +; + +/** + Get an abstract Intel ME Status from Firmware Status Register. + This is used to control BIOS flow for different Intel ME + functions. + + @param[in] PeiServices General purpose services available to every PEIM. + @param[in] MeStatus Pointer for status report, + see MeState.h - Abstract ME status definitions. + + @retval EFI_SUCCESS MeStatus copied + @retval EFI_INVALID_PARAMETER Pointer of MeStatus is invalid +**/ +EFI_STATUS +EFIAPI +HeciGetMeStatus ( + IN EFI_PEI_SERVICES **PeiServices, + IN UINT32 *MeStatus + ) +; + +/** + Get an abstract ME operation mode from firmware status + register. This is used to control BIOS flow for different + Intel ME functions. + + @param[in] PeiServices General purpose services available to every PEIM. + @param[in] MeMode Pointer for ME Mode report, + see MeState.h - Abstract ME Mode definitions. + + @retval EFI_SUCCESS MeMode copied + @retval EFI_INVALID_PARAMETER Pointer of MeMode is invalid +**/ +EFI_STATUS +EFIAPI +HeciGetMeMode ( + IN EFI_PEI_SERVICES **PeiServices, + IN UINT32 *MeMode + ) +; + +/** + Initialize ME after reset + + @param[in] FfsHeader Not used. + @param[in] PeiServices General purpose services available to every PEIM. + + @retval EFI_SUCCESS Heci initialization completed successfully. + @retval All other error conditions encountered result in an ASSERT. +**/ +EFI_STATUS +PeimHeciInit ( + IN EFI_FFS_FILE_HEADER *FfsHeader, + IN EFI_PEI_SERVICES **PeiServices + ) +; + +/** + Calculate if the circular buffer has overflowed. + Corresponds to HECI HPS (part of) section 4.2.1 + + @param[in] ReadPointer Location of the read pointer. + @param[in] WritePointer Location of the write pointer. + + @retval UINT8 Number of filled slots. +**/ +UINT8 +FilledSlots ( + IN UINT32 ReadPointer, + IN UINT32 WritePointer + ) +; +#endif // _HECI_INIT_H_ diff --git a/ReferenceCode/ME/Heci/Pei/HeciInit.inf b/ReferenceCode/ME/Heci/Pei/HeciInit.inf new file mode 100644 index 0000000..2181282 --- /dev/null +++ b/ReferenceCode/ME/Heci/Pei/HeciInit.inf @@ -0,0 +1,82 @@ +## @file +# Component description file for HeciInit module +# +#@copyright +# Copyright (c) 2010 - 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 a 'Sample Driver' and is licensed as such +# under the terms of your license agreement with Intel or your +# vendor. This file may be modified by the user, subject to +# the additional terms of the license agreement +# + +[defines] +BASE_NAME = HeciInit +FILE_GUID = 4862aff3-667c-5458-b274-a1c62df8ba80 +COMPONENT_TYPE = PE32_PEIM + +[sources.common] + HeciInit.c + HeciInit.h + HeciCore.c + ../Include/HeciRegs.h + +# +# Edk II Glue Driver Entry Point +# + EdkIIGluePeimEntryPoint.c + +[includes.common] + $(EFI_SOURCE)/$(PROJECT_ME_ROOT) + $(EFI_SOURCE)/$(PROJECT_ME_ROOT)/Library/MeKernel/Dxe + $(EFI_SOURCE)/$(PROJECT_ME_ROOT)/Library/MeKernel/Include + $(EFI_SOURCE)/$(PROJECT_ME_ROOT)/Heci/Include + $(EFI_SOURCE)/$(PROJECT_PCH_ROOT)/Include + +# +# EDK II Glue Library utilizes some standard headers from EDK +# + $(EDK_SOURCE)/Foundation + $(EDK_SOURCE)/Foundation/Core/Dxe + $(EDK_SOURCE)/Foundation/Efi + $(EDK_SOURCE)/Foundation/Efi/Include + $(EDK_SOURCE)/Foundation/Framework + $(EDK_SOURCE)/Foundation/Framework/Include + $(EDK_SOURCE)/Foundation/Include + $(EDK_SOURCE)/Foundation/Include/IndustryStandard + $(EDK_SOURCE)/Foundation/Include/Pei + $(EDK_SOURCE)/Foundation/Library/Dxe/Include + $(EDK_SOURCE)/Foundation/Library/EdkIIGlueLib/Include + + + +[libraries.common] + EdkFrameworkPpiLib + MeLibPpi + EdkIIGlueBaseIoLibIntrinsic + EdkIIGluePeiDebugLibReportStatusCode + EdkIIGluePeiReportStatusCodeLib + EdkIIGluePeiServicesLib + EdkIIGlueBasePciLibPciExpress + EdkIIGlueBasePciExpressLib + EdkPpiLib + +[nmake.common] + IMAGE_ENTRY_POINT = _ModuleEntryPoint + DPX_SOURCE = HeciInit.dxs +# +# Module Entry Point +# + C_FLAGS = $(C_FLAGS) -D __EDKII_GLUE_MODULE_ENTRY_POINT__=PeimHeciInit + C_FLAGS = $(C_FLAGS) -D __EDKII_GLUE_BASE_IO_LIB_INTRINSIC__ \ + -D __EDKII_GLUE_PEI_DEBUG_LIB_REPORT_STATUS_CODE__ \ + -D __EDKII_GLUE_PEI_REPORT_STATUS_CODE_LIB__ \ + -D __EDKII_GLUE_PEI_SERVICES_LIB__ \ + -D __EDKII_GLUE_BASE_PCI_LIB_PCI_EXPRESS__ diff --git a/ReferenceCode/ME/Heci/Pei/HeciPei.cif b/ReferenceCode/ME/Heci/Pei/HeciPei.cif new file mode 100644 index 0000000..c009607 --- /dev/null +++ b/ReferenceCode/ME/Heci/Pei/HeciPei.cif @@ -0,0 +1,14 @@ +<component> + name = "HeciPei" + category = ModulePart + LocalRoot = "ReferenceCode\ME\Heci\Pei\" + RefName = "HeciPei" +[files] +"HeciPei.sdl" +"HeciPei.mak" +"HeciCore.c" +"HeciInit.c" +"HeciInit.dxs" +"HeciInit.h" +"HeciInit.inf" +<endComponent> diff --git a/ReferenceCode/ME/Heci/Pei/HeciPei.mak b/ReferenceCode/ME/Heci/Pei/HeciPei.mak new file mode 100644 index 0000000..990bcf1 --- /dev/null +++ b/ReferenceCode/ME/Heci/Pei/HeciPei.mak @@ -0,0 +1,48 @@ +# MAK file for the ModulePart:HeciPei + +all: HeciPei + +$(BUILD_DIR)\HeciPei.mak : $(HeciPei_DIR)\HeciPei.cif $(BUILD_RULES) + $(CIF2MAK) $(HeciPei_DIR)\HeciPei.cif $(CIF2MAK_DEFAULTS) + +HeciPei: $(BUILD_DIR)\HeciPei.mak HeciPeiBin + +HeciPei_INCLUDES=\ + $(EDK_INCLUDES)\ + $(EdkIIGlueLib_INCLUDES)\ + $(ME_INCLUDES)\ + $(INTEL_PCH_INCLUDES) + + +HeciPei_DEFINES=$(MY_DEFINES)\ + /D"__EDKII_GLUE_MODULE_ENTRY_POINT__=PeimHeciInit"\ + /D __EDKII_GLUE_BASE_IO_LIB_INTRINSIC__ \ + /D __EDKII_GLUE_PEI_DEBUG_LIB_REPORT_STATUS_CODE__ \ + /D __EDKII_GLUE_PEI_REPORT_STATUS_CODE_LIB__\ + /D __EDKII_GLUE_PEI_SERVICES_LIB__ \ + /D __EDKII_GLUE_BASE_PCI_LIB_PCI_EXPRESS__ \ + +HeciPei_LIBS =\ + $(EDKPROTOCOLLIB)\ + $(EdkIIGlueBaseLib_LIB)\ + $(EdkIIGlueBaseLibIA32_LIB)\ + $(EdkIIGlueBaseIoLibIntrinsic_LIB)\ + $(EdkIIGluePeiDebugLibReportStatusCode_LIB)\ + $(EdkIIGluePeiReportStatusCodeLib_LIB)\ + $(EdkIIGluePeiServicesLib_LIB)\ + $(EdkIIGlueBasePciLibPciExpress_LIB)\ + + +HeciPeiBin : $(EDKFRAMEWORKPPILIB) $(MeLibPpi_LIB) $(HeciPei_LIBS) + $(MAKE) /$(MAKEFLAGS) $(EDKIIGLUE_DEFAULTS)\ + /f $(BUILD_DIR)\HeciPei.mak all\ + NAME=HeciPei\ + MAKEFILE=$(BUILD_DIR)\HeciPei.mak \ + GUID=9cf30325-dc5c-4556-a8b0-74215c5f7fc4\ + "MY_INCLUDES=$(HeciPei_INCLUDES)" \ + "MY_DEFINES=$(HeciPei_DEFINES)"\ + ENTRY_POINT=_ModuleEntryPoint \ + TYPE=PEIM \ + EDKIIModule=PEIM\ + DEPEX1=$(HeciPei_DIR)\HeciInit.dxs DEPEX1_TYPE=EFI_SECTION_PEI_DEPEX \ + COMPRESS=0 diff --git a/ReferenceCode/ME/Heci/Pei/HeciPei.sdl b/ReferenceCode/ME/Heci/Pei/HeciPei.sdl new file mode 100644 index 0000000..e193446 --- /dev/null +++ b/ReferenceCode/ME/Heci/Pei/HeciPei.sdl @@ -0,0 +1,24 @@ +TOKEN + Name = HeciPei_SUPPORT + Value = "1" + TokenType = Boolean + TargetEQU = Yes + TargetMAK = Yes + Master = Yes + Help = "Main switch to enable HeciPei support in Project" +End +MODULE + Help = "Includes HeciPei.mak to Project" + File = "HeciPei.mak" +End + +PATH + Name = "HeciPei_DIR" + Help = "Me Heci Pei file source directory" +End + +ELINK + Name = "$(BUILD_DIR)\HeciPei.ffs" + Parent = "FV_BB" + InvokeOrder = AfterParent +End
\ No newline at end of file diff --git a/ReferenceCode/ME/Heci/Smm/HeciHpet.c b/ReferenceCode/ME/Heci/Smm/HeciHpet.c new file mode 100644 index 0000000..2f75571 --- /dev/null +++ b/ReferenceCode/ME/Heci/Smm/HeciHpet.c @@ -0,0 +1,282 @@ +/*++ + 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 +--*/ +/*++ + +Copyright (c) 2006 - 2010 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. + +Module Name: + + HeciHpet.c + +Abstract: + + Definitions for HECI driver + +--*/ +#include "HeciHpet.h" +#include "HeciRegs.h" +#include "HeciCore.h" + +// +// Extern for shared HECI data and protocols +// +extern HECI_INSTANCE_SMM *mHeciContext; +VOLATILE UINT32 mSaveHpetConfigReg; + +VOID +SaveHpet ( + VOID + ) +/*++ + +Routine Description: + + Store the value of High Performance Timer + +Arguments: + + None + +Returns: + + None + +--*/ +{ + mSaveHpetConfigReg = MmioRead32 (PCH_RCRB_BASE + R_PCH_RCRB_HPTC); +} + +VOID +RestoreHpet ( + VOID + ) +/*++ + +Routine Description: + + Restore the value of High Performance Timer + +Arguments: + + None + +Returns: + + None + +--*/ +{ + MmioWrite32 (PCH_RCRB_BASE + R_PCH_RCRB_HPTC, mSaveHpetConfigReg); +} + +VOID +StartTimer ( + OUT UINT32 *Start, + OUT UINT32 *End, + IN UINT32 Time + ) +/*++ + + Routine Description: + + Used for calculating timeouts + + Arguments: + + Start - Snapshot of the HPET timer + End - Calculated time when timeout period will be done + Time - Timeout period in microseconds + + Returns: + + VOID + +--*/ +{ + UINT32 Ticks; + + // + // Make sure that HPET is enabled and running + // + EnableHpet (); + + // + // Read current timer value into start time from HPET + // + *Start = mHeciContext->HpetTimer[HPET_MAIN_COUNTER_LOW]; + + // + // Convert microseconds into 70ns timer ticks + // + Ticks = Time * HPET_TICKS_PER_MICRO; + + // + // Compute end time + // + *End = *Start + Ticks; + + return ; +} + +EFI_STATUS +Timeout ( + IN UINT32 Start, + IN UINT32 End + ) +/*++ + + Routine Description: + Used to determine if a timeout has occured. + + Arguments: + Start - Snapshot of the HPET timer when the timeout period started. + End - Calculated time when timeout period will be done. + + Returns: + EFI_STATUS + +--*/ +{ + UINT32 Current; + + // + // Read HPET and assign the value as the current time. + // + Current = mHeciContext->HpetTimer[HPET_MAIN_COUNTER_LOW]; + + // + // Test basic case (no overflow) + // + if ((Start < End) && (End <= Current)) { + return EFI_TIMEOUT; + } + // + // Test basic start/end conditions with overflowed timer + // + if ((Start < End) && (Current < Start)) { + return EFI_TIMEOUT; + } + // + // Test for overflowed start/end condition + // + if ((Start > End) && ((Current < Start) && (Current > End))) { + return EFI_TIMEOUT; + } + // + // Catch corner case of broken arguments + // + if (Start == End) { + return EFI_TIMEOUT; + } + // + // Else, we have not yet timed out + // + return EFI_SUCCESS; +} + +VOID +IoDelay ( + UINT32 delayTime + ) +/*++ + +Routine Description: + + Delay for at least the request number of microseconds + +Arguments: + + delayTime - Number of microseconds to delay. + +Returns: + + None. + +--*/ +{ + SmmStall (delayTime); +} + +VOID +SmmStall ( + IN UINTN Microseconds + ) +/*++ + +Routine Description: + + Delay for at least the request number of microseconds. + Timer used is DMA refresh timer, which has 15us granularity. + You can call with any number of microseconds, but this + implementation cannot support 1us granularity. + +Arguments: + + Microseconds - Number of microseconds to delay. + +Returns: + + None + +--*/ +{ + UINT8 Data; + UINT8 InitialState; + UINTN CycleIterations; + + CycleIterations = 0; + Data = 0; + InitialState = 0; + + // + // The time-source is 15 us granular, so calibrate the timing loop + // based on this baseline + // Error is possible 15us. + // + CycleIterations = (Microseconds / 15) + 1; + + // + // Use the DMA Refresh timer in port 0x61. Cheap but effective. + // The only issue is that the granularity is 15us, and we want to + // guarantee "at least" one full transition to avoid races. + // + // + // _____________/----------\__________/-------- + // + // |<--15us-->| + // + // --------------------------------------------------> Time (us) + // + while (CycleIterations--) { + Data = IoRead8 (0x61); + InitialState = Data; + + // + // Capture first transition (strictly less than one period) + // + while (InitialState == Data) { + Data = IoRead8 (0x61); + } + + InitialState = Data; + // + // Capture next transition (guarantee at least one full pulse) + // + while (InitialState == Data) { + Data = IoRead8 (0x61); + } + } +} diff --git a/ReferenceCode/ME/Heci/Smm/HeciHpet.h b/ReferenceCode/ME/Heci/Smm/HeciHpet.h new file mode 100644 index 0000000..8624445 --- /dev/null +++ b/ReferenceCode/ME/Heci/Smm/HeciHpet.h @@ -0,0 +1,197 @@ +/*++ + 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 +--*/ +/*++ + +Copyright (c) 2006 - 2010 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. + +Module Name: + + HeciHpet.h + +Abstract: + + Definitions for HECI driver + +--*/ +#ifndef _HECI_HPET_H +#define _HECI_HPET_H + +#include "EdkIIGlueDxe.h" +#include "MeAccess.h" +#include "HeciRegs.h" +#include "Pci22.h" + +#define HECI_PRIVATE_DATA_SIGNATURE EFI_SIGNATURE_32 ('H', 'e', 'c', 'i') +#define HECI_ROUND_UP_BUFFER_LENGTH(Length) ((UINT32) ((((Length) + 3) / 4) * 4)) + +// +// Driver Produced Protocol Prototypes +// +#include EFI_PROTOCOL_PRODUCER (HeciSmm) + +VOID +SaveHpet ( + VOID + ) +/*++ + +Routine Description: + + Store the value of High Performance Timer + +Arguments: + + None + +Returns: + + None + +--*/ +; + +VOID +RestoreHpet ( + VOID + ) +/*++ + +Routine Description: + + Restore the value of High Performance Timer + +Arguments: + + None + +Returns: + + None + +--*/ +; + +VOID +StartTimer ( + OUT UINT32 *Start, + OUT UINT32 *End, + IN UINT32 Time + ) +/*++ + + Routine Description: + + Used for calculating timeouts + + Arguments: + + Start - Snapshot of the HPET timer + End - Calculated time when timeout period will be done + Time - Timeout period in microseconds + + Returns: + + VOID + +--*/ +; + +EFI_STATUS +Timeout ( + IN UINT32 Start, + IN UINT32 End + ) +/*++ + + Routine Description: + Used to determine if a timeout has occured. + + Arguments: + Start - Snapshot of the HPET timer when the timeout period started. + End - Calculated time when timeout period will be done. + + Returns: + EFI_STATUS + +--*/ +; + +VOID +EnableHpet ( + VOID + ) +/*++ + +Routine Description: + + Enable Hpet function. + +Arguments: + + None. + +Returns: + + None. + +--*/ +; + +VOID +IoDelay ( + UINT32 delayTime + ) +/*++ + +Routine Description: + + Delay for at least the request number of microseconds + +Arguments: + + delayTime - Number of microseconds to delay. + +Returns: + + None. + +--*/ +; + +VOID +SmmStall ( + IN UINTN Microseconds + ) +/*++ + +Routine Description: + + Delay for at least the request number of microseconds. + Timer used is DMA refresh timer, which has 15us granularity. + You can call with any number of microseconds, but this + implementation cannot support 1us granularity. + +Arguments: + + Microseconds - Number of microseconds to delay. + +Returns: + + None + +--*/ +; +#endif // _HECI_HPET_H diff --git a/ReferenceCode/ME/Heci/Smm/HeciSmm.c b/ReferenceCode/ME/Heci/Smm/HeciSmm.c new file mode 100644 index 0000000..df1f165 --- /dev/null +++ b/ReferenceCode/ME/Heci/Smm/HeciSmm.c @@ -0,0 +1,228 @@ +/*++ + 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 +--*/ +/*++ + +Copyright (c) 2008 - 2010 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. + +Module Name: + + HeciSmm.c + +Abstract: + + SMM HECI driver + +--*/ + +// +// External include files do NOT need to be explicitly specified in real EDKII +// environment +// +#if !defined(EDK_RELEASE_VERSION) || (EDK_RELEASE_VERSION < 0x00020000) +#include "HeciHpet.h" +#include "HeciCore.h" +#endif // EDK_RELEASE_VERSION +// +// Global driver data +// +EFI_SMM_BASE_PROTOCOL *mSmmBase; +HECI_INSTANCE_SMM *mHeciContext; + +UINT32 +CheckAndFixHeciForAccess ( + VOID + ) +/*++ + +Routine Description: + This function provides a standard way to verify the HECI cmd and MBAR regs + in its PCI cfg space are setup properly and that the local mHeciContext + variable matches this info. + +Arguments: + None. + +Returns: + VOID + +--*/ +{ + UINTN HeciPciAddressBase; + + HeciPciAddressBase = mHeciContext->PciAddressBase; + + // + // Read HECI_MBAR in case it has changed + // + mHeciContext->HeciMBAR = PciRead32 (HeciPciAddressBase + R_HECIMBAR) & 0xFFFFFFF0; + + // + // Check if HECI_MBAR is disabled + // + if (( + PciRead8 (HeciPciAddressBase + PCI_COMMAND_OFFSET) & (EFI_PCI_COMMAND_MEMORY_SPACE | EFI_PCI_COMMAND_BUS_MASTER) + ) != (EFI_PCI_COMMAND_MEMORY_SPACE | EFI_PCI_COMMAND_BUS_MASTER) + ) { + // + // If cmd reg in pci cfg space is not turned on turn it on. + // + PciOr8 ( + HeciPciAddressBase + PCI_COMMAND_OFFSET, + EFI_PCI_COMMAND_MEMORY_SPACE | EFI_PCI_COMMAND_BUS_MASTER + ); + } + + return mHeciContext->HeciMBAR; +} + +VOID +EnableHpet ( + VOID + ) +/*++ + +Routine Description: + + Enable Hpet function. + +Arguments: + + None. + +Returns: + + None. + +--*/ +{ + VOLATILE UINT32 *HpetConfigReg; + + HpetConfigReg = NULL; + // + // Get the High Precision Event Timer base address and enable the memory range + // + HpetConfigReg = (UINT32 *) (UINTN) (PCH_RCRB_BASE + R_PCH_RCRB_HPTC); + switch (*HpetConfigReg & B_PCH_RCRB_HPTC_AS) { + case 0: + mHeciContext->HpetTimer = (VOID *) (UINTN) (HPET_ADDRESS_0); + break; + + case 1: + mHeciContext->HpetTimer = (VOID *) (UINTN) (HPET_ADDRESS_1); + break; + + case 2: + mHeciContext->HpetTimer = (VOID *) (UINTN) (HPET_ADDRESS_2); + break; + + case 3: + mHeciContext->HpetTimer = (VOID *) (UINTN) (HPET_ADDRESS_3); + break; + + default: + mHeciContext->HpetTimer = NULL; + break; + } + // + // Read this back to force the write-back. + // + *HpetConfigReg = *HpetConfigReg | B_PCH_RCRB_HPTC_AE; + + // + // Start the timer so it is up and running + // + mHeciContext->HpetTimer[HPET_GEN_CONFIG_LOW] = HPET_START; + mHeciContext->HpetTimer[HPET_GEN_CONFIG_LOW] = HPET_START; + + return ; +} + +EFI_STATUS +InitializeHECI ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + HECI driver entry point used to initialize support for the HECI device. + +Arguments: + ImageHandle - Standard entry point parameter. + SystemTable - Standard entry point parameter. + +Returns: + EFI_STATUS + +--*/ +{ + EFI_STATUS Status; + + Status = gBS->LocateProtocol (&gEfiSmmBaseProtocolGuid, NULL, &mSmmBase); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Create database record and add to database + // + Status = mSmmBase->SmmAllocatePool ( + mSmmBase, + EfiRuntimeServicesData, + sizeof (HECI_INSTANCE_SMM), + &mHeciContext + ); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + return Status; + } + + mHeciContext->Handle = ImageHandle; + + // + // Initialize HECI protocol pointers + // + mHeciContext->HeciCtlr.ResetHeci = ResetHeciInterface; + mHeciContext->HeciCtlr.SendwACK = HeciSendwACK; + mHeciContext->HeciCtlr.ReadMsg = HeciReceive; + mHeciContext->HeciCtlr.SendMsg = HeciSend; + mHeciContext->HeciCtlr.InitHeci = HeciInitialize; + mHeciContext->HeciCtlr.ReInitHeci = HeciReInitialize; + mHeciContext->HeciCtlr.MeResetWait = MeResetWait; + mHeciContext->HeciCtlr.GetMeStatus = HeciGetMeStatus; + mHeciContext->HeciCtlr.GetMeMode = HeciGetMeMode; + // + // Initialize the HECI device + // + Status = InitializeHeciPrivate (); + if (EFI_ERROR (Status)) { + return EFI_SUCCESS; + } + // + // Install the HECI interface + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &mHeciContext->Handle, + &gSmmHeciProtocolGuid, + &mHeciContext->HeciCtlr, + NULL + ); + if (EFI_ERROR (Status)) { + return EFI_SUCCESS; + } + + return EFI_SUCCESS; +} diff --git a/ReferenceCode/ME/Heci/Smm/HeciSmm.cif b/ReferenceCode/ME/Heci/Smm/HeciSmm.cif new file mode 100644 index 0000000..3ddcf24 --- /dev/null +++ b/ReferenceCode/ME/Heci/Smm/HeciSmm.cif @@ -0,0 +1,16 @@ +<component> + name = "HeciSmm" + category = ModulePart + LocalRoot = "ReferenceCode\ME\Heci\Smm\" + RefName = "HeciSmm" +[files] +"HeciSmm.sdl" +"HeciSmm.mak" +"Hecicore.c" +"Hecicore.h" +"HeciSmm.c" +"HeciSmm.dxs" +"HeciHpet.c" +"HeciHpet.h" +"HeciSmm.inf" +<endComponent> diff --git a/ReferenceCode/ME/Heci/Smm/HeciSmm.dxs b/ReferenceCode/ME/Heci/Smm/HeciSmm.dxs new file mode 100644 index 0000000..9c3676a --- /dev/null +++ b/ReferenceCode/ME/Heci/Smm/HeciSmm.dxs @@ -0,0 +1,51 @@ +/*++ + This file contains a 'Sample Driver' and is licensed as such + under the terms of your license agreement with Intel or your + vendor. This file may be modified by the user, subject to + the additional terms of the license agreement +--*/ +/*++ + +Copyright (c) 2010 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. + +Module Name: + + HeciSmm.dxs + +Abstract: + + Dependency expression source file. + +--*/ + +// +// Common for R8 and R9 codebase +// +#include "AutoGen.h" +#include "DxeDepex.h" + +// +// BUILD_WITH_GLUELIB and BUILD_WITH_EDKII_GLUE_LIB are both "defined" in R8 codebase; +// BUILD_WITH_EDKII_GLUE_LIB is defined in Edk-Dev-Snapshot-20070228 and later version +// BUILD_WITH_GLUELIB and BUILD_WITH_EDKII_GLUE_LIB are "not defined" in R9 codebase. +// +#if defined (BUILD_WITH_GLUELIB) || defined (BUILD_WITH_EDKII_GLUE_LIB) +#include "EfiDepex.h" +#include EFI_PROTOCOL_DEFINITION (SmmBase) +#include EFI_PROTOCOL_DEFINITION (CpuIo) +#include EFI_PROTOCOL_DEFINITION (PciRootBridgeIo) +#endif + +DEPENDENCY_START + EFI_CPU_IO_PROTOCOL_GUID AND + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_GUID AND + EFI_SMM_BASE_PROTOCOL_GUID +DEPENDENCY_END + diff --git a/ReferenceCode/ME/Heci/Smm/HeciSmm.inf b/ReferenceCode/ME/Heci/Smm/HeciSmm.inf new file mode 100644 index 0000000..600e1f2 --- /dev/null +++ b/ReferenceCode/ME/Heci/Smm/HeciSmm.inf @@ -0,0 +1,102 @@ +#/*++ +# This file contains a 'Sample Driver' and is licensed as such +# under the terms of your license agreement with Intel or your +# vendor. This file may be modified by the user, subject to +# the additional terms of the license agreement +#--*/ +#/*++ +# +# Copyright (c) 2007 - 2010 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. +# +# Module Name: +# +# HeciSmm.inf +# +# Abstract: +# +# Component description file for Heci SMM driver +# +#--*/ + +[defines] +BASE_NAME = HeciSmm +FILE_GUID = 921CD783-3E22-4579-A71F-00D74197FCC8 +COMPONENT_TYPE = BS_DRIVER + +[sources.common] + HeciSmm.c + Hecicore.c + HeciCore.h + HeciHpet.c + HeciHpet.h + +# +# Edk II Glue Driver Entry Point +# + EdkIIGlueSmmDriverEntryPoint.c + +[includes.common] + $(EDK_SOURCE)\Foundation + $(EDK_SOURCE)\Foundation\Framework + $(EDK_SOURCE)\Foundation\Efi + $(EDK_SOURCE)\Foundation\Include + $(EDK_SOURCE)\Foundation\Efi\Include + $(EDK_SOURCE)\Foundation\Framework\Include + $(EDK_SOURCE)\Foundation\Library\Dxe\Include + $(EDK_SOURCE)\Foundation\Include\IndustryStandard + $(EDK_SOURCE)\Foundation\Cpu\Pentium\Include + $(EFI_SOURCE)\$(PROJECT_ME_ROOT) + $(EFI_SOURCE)\$(PROJECT_ME_ROOT)\Library\MeKernel\Dxe + $(EFI_SOURCE)\$(PROJECT_ME_ROOT)\Library\MeKernel\Include + $(EFI_SOURCE)\$(PROJECT_ME_ROOT)\Heci\Include + +# +# Edk II Glue Library, some hearder are included by R9 header so have to include +# + $(EFI_SOURCE) + $(EFI_SOURCE)\Framework + $(EDK_SOURCE)\Foundation + $(EDK_SOURCE)\Foundation\Framework + $(EDK_SOURCE)\Foundation\Include\IndustryStandard + $(EDK_SOURCE)\Foundation\Core\Dxe + $(EDK_SOURCE)\Foundation\Include\Pei + $(EDK_SOURCE)\Foundation\Library\Dxe\Include + $(EDK_SOURCE)\Foundation\Library\EdkIIGlueLib\Include + +[libraries.common] + MeProtocolLib + MeLib + MeChipsetLib + EdkProtocolLib + EdkFrameworkProtocolLib + EdkIIGlueBaseLib + EdkIIGlueBasePciLibPciExpress + EdkIIGlueDxeMemoryAllocationLib + EdkIIGlueDxeServicesTableLib + EdkIIGluePeiDxeDebugLibReportStatusCode + EdkIIGlueSmmRuntimeDxeReportStatusCodeLib + EdkIIGlueUefiBootServicesTableLib + EdkIIGlueUefiDevicePathLib + +[nmake.common] + IMAGE_ENTRY_POINT=_ModuleEntryPoint + DPX_SOURCE=HeciSmm.dxs +# +# Module Entry Point +# + C_FLAGS = $(C_FLAGS) /D__EDKII_GLUE_MODULE_ENTRY_POINT__=InitializeHECI + C_FLAGS = $(C_FLAGS) /D __EDKII_GLUE_BASE_LIB__ \ + /D __EDKII_GLUE_BASE_PCI_LIB_PCI_EXPRESS__ \ + /D __EDKII_GLUE_DXE_MEMORY_ALLOCATION_LIB__ \ + /D __EDKII_GLUE_DXE_SERVICES_TABLE_LIB__ \ + /D __EDKII_GLUE_PEI_DXE_DEBUG_LIB_REPORT_STATUS_CODE__\ + /D __EDKII_GLUE_SMM_RUNTIME_DXE_REPORT_STATUS_CODE_LIB__ \ + /D __EDKII_GLUE_UEFI_BOOT_SERVICES_TABLE_LIB__\ + /D __EDKII_GLUE_UEFI_DEVICE_PATH_LIB__ diff --git a/ReferenceCode/ME/Heci/Smm/HeciSmm.mak b/ReferenceCode/ME/Heci/Smm/HeciSmm.mak new file mode 100644 index 0000000..31006bc --- /dev/null +++ b/ReferenceCode/ME/Heci/Smm/HeciSmm.mak @@ -0,0 +1,64 @@ +# MAK file for the ModulePart:HeciSmm +all : HeciSmm + +HeciSmm : $(BUILD_DIR)\HeciSmm.mak HeciSmmBin + +$(BUILD_DIR)\HeciSmm.mak : $(HeciSmm_DIR)\$(@B).cif $(HeciSmm_DIR)\$(@B).mak $(CP_BUILD_RULES) + $(CIF2MAK) $(HeciSmm_DIR)\$(@B).cif $(CIF2MAK_DEFAULTS) + +HeciSmm_INCLUDES= \ + $(EDK_INCLUDES)\ + $(EdkIIGlueLib_INCLUDES)\ + $(ME_INCLUDES)\ + /I$(INTEL_COUGAR_POINT_INCLUDE_DIR) + + +HeciSmm_LIBS=\ + $(EDKPROTOCOLLIB)\ + $(MeProtocolLib_LIB)\ + $(MeLibDxe_LIB)\ + $(MeChipsetDxeLib_LIB)\ + $(MeGuidLib_LIB)\ + $(EFISCRIPTLIB)\ + $(EDKFRAMEWORKPROTOCOLLIB)\ + $(EFIGUIDLIB)\ + $(EdkIIGlueBaseLib_LIB)\ +!IF "$(x64_BUILD)"=="1" + $(EdkIIGlueBaseLibX64_LIB)\ +!ELSE + $(EdkIIGlueBaseLibIA32_LIB)\ +!ENDIF + $(EdkIIGlueBaseIoLibIntrinsic_LIB)\ + $(EdkIIGlueDxeReportStatusCodeLib_LIB)\ + $(EdkIIGlueDxeDebugLibReportStatusCode_LIB)\ + $(EdkIIGlueUefiBootServicesTableLib_LIB)\ + $(EdkIIGlueUefiLib_LIB)\ + $(EdkIIGlueBasePciLibPciExpress_LIB)\ + $(EdkIIGlueDxeServicesTableLib_LIB)\ + $(EFIDRIVERLIB)\ + $(RcFviDxeLib_LIB)\ + $(PchPlatformDxeLib_LIB) + +HeciSmm_DEFINES=$(MY_DEFINES)\ + /D"__EDKII_GLUE_MODULE_ENTRY_POINT__=InitializeHECI"\ + /D __EDKII_GLUE_BASE_IO_LIB_INTRINSIC__ \ + /D __EDKII_GLUE_DXE_REPORT_STATUS_CODE_LIB__ \ + /D __EDKII_GLUE_DXE_DEBUG_LIB_REPORT_STATUS_CODE__ \ + /D __EDKII_GLUE_UEFI_BOOT_SERVICES_TABLE_LIB__ \ + /D __EDKII_GLUE_UEFI_LIB__\ + /D __EDKII_GLUE_BASE_PCI_LIB_PCI_EXPRESS__ \ + /D __EDKII_GLUE_DXE_SERVICES_TABLE_LIB__ \ + +HeciSmmBin : $(HeciSmm_LIBS) + $(MAKE) /$(MAKEFLAGS) $(EDKIIGLUE_DEFAULTS)\ + /f $(BUILD_DIR)\HeciSmm.mak all\ + MAKEFILE=$(BUILD_DIR)\HeciSmm.mak\ + "MY_INCLUDES=$(HeciSmm_INCLUDES)"\ + "MY_DEFINES=$(HeciSmm_DEFINES)"\ + GUID=921CD783-3E22-4579-A71F-00D74197FCC8\ + DEPEX1=$(HeciSmm_DIR)\HeciSmm.dxs\ + DEPEX1_TYPE=EFI_SECTION_DXE_DEPEX \ + ENTRY_POINT=_ModuleEntryPoint \ + TYPE=RT_DRIVER\ + EDKIIModule=SMMDRIVER\ + COMPRESS=1 diff --git a/ReferenceCode/ME/Heci/Smm/HeciSmm.sdl b/ReferenceCode/ME/Heci/Smm/HeciSmm.sdl new file mode 100644 index 0000000..3165eee --- /dev/null +++ b/ReferenceCode/ME/Heci/Smm/HeciSmm.sdl @@ -0,0 +1,25 @@ +TOKEN + Name = "HeciSmm_SUPPORT" + Value = "1" + TokenType = Boolean + TargetEQU = Yes + TargetMAK = Yes + Master = Yes + Help = "Main switch to enable HeciSmm Suppport in Project" +End + +MODULE + Help = "Includes HeciSmm.mak to Project" + File = "HeciSmm.mak" +End + +ELINK + Name = "$(BUILD_DIR)\HeciSmm.ffs" + Parent = "FV_MAIN" + InvokeOrder = AfterParent +End + +PATH + Name = "HeciSmm_DIR" + Help = "iAMT Hec SMM Driver files source directory" +End
\ No newline at end of file diff --git a/ReferenceCode/ME/Heci/Smm/Hecicore.c b/ReferenceCode/ME/Heci/Smm/Hecicore.c new file mode 100644 index 0000000..612f2f6 --- /dev/null +++ b/ReferenceCode/ME/Heci/Smm/Hecicore.c @@ -0,0 +1,1585 @@ +/*++ + 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 +--*/ +/*++ + +Copyright (c) 2008 - 2010 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. + +Module Name: + + Hecicore.c + +Abstract: + + Heci driver core. For Dxe Phase, determines the HECI device and initializes it. + +--*/ +#include "HeciHpet.h" +#include "HeciCore.h" +#include "HeciRegs.h" +#include "MeState.h" + +// +// ////////////////////////////////////////////////////////////////////////////////// +// Globals used in Heci driver +//////////////////////////////////////////////////////////////////////////////////// +// +UINT16 HECICtlrBDF; +static UINT32 HeciMBAR = 0; + +// +// ////////////////////////////////////////////////////////////////////////////////// +// Macro definition for function used in Heci driver +//////////////////////////////////////////////////////////////////////////////////// +// +#define R_PCH_RCRB_FUNC_DIS2 0x3428 + +UINT32 +MmIoReadDword ( + UINTN a + ) +/*++ + +Routine Description: + + The routing of MmIo Read Dword + +Arguments: + + a - The address of Mmio + +Returns: + + Return the valut of MmIo Read + +--*/ +{ + volatile HECI_HOST_CONTROL_REGISTER *HeciRegHCsrPtr; + + HeciRegHCsrPtr = (HECI_HOST_CONTROL_REGISTER *) a; + return HeciRegHCsrPtr->ul; +} + +VOID +MmIoWriteDword ( + UINTN a, + UINT32 b + ) +/*++ + +Routine Description: + + The routing of MmIo Write Dword + +Arguments: + + a - The address of Mmio + b - Value revised + +Returns: + + None + +--*/ +{ + volatile HECI_HOST_CONTROL_REGISTER *HeciRegHCsrPtr; + + HeciRegHCsrPtr = (HECI_HOST_CONTROL_REGISTER *) a; + + HeciRegHCsrPtr->ul = b; +} + +#define MMIOREADDWORD(a) MmIoReadDword (a) +#define MMIOWRITEDWORD(a, b) MmIoWriteDword (a, b) + +// +// Extern for shared HECI data and protocols +// +extern HECI_INSTANCE_SMM *mHeciContext; + +// +// ////////////////////////////////////////////////////////////////////////////////// +// Forward declaration +//////////////////////////////////////////////////////////////////////////////////// +// +UINT8 +FilledSlots ( + IN UINT32 ReadPointer, + IN UINT32 WritePointer + ); + +EFI_STATUS +OverflowCB ( + IN UINT32 ReadPointer, + IN UINT32 WritePointer, + IN UINT32 BufferDepth + ); + +EFI_STATUS +WaitForMEReady ( + VOID + ); + +// +// Heci driver function definitions +// +EFI_STATUS +InitializeHeciPrivate ( + VOID + ) +/*++ + + Routine Description: + Determines if the HECI device is present and, if present, initializes it for + use by the BIOS. + + Arguments: + None. + + Returns: + EFI_STATUS + +--*/ +{ + HECI_HOST_CONTROL_REGISTER HeciRegHCsr; + VOLATILE HECI_HOST_CONTROL_REGISTER *HeciRegHCsrPtr; + UINT32 MeMode; + EFI_STATUS Status; + UINTN HeciPciAddressBase; + + Status = EFI_SUCCESS; + + SaveHpet (); + + do { + // + // Check for ME FPT Bad + // + if ((HeciPciRead32 (R_FWSTATE) & 0x0020) != 0) { + Status = EFI_DEVICE_ERROR; + break; + } + // + // Check for ME error status + // + if ((HeciPciRead32 (R_FWSTATE) & 0xF000) != 0) { + // + // ME failed to start so no HECI + // + Status = EFI_DEVICE_ERROR; + break; + } + // + // Check ME Operation Mode to decice which HECI to use in SMM mode + // + Status = HeciGetMeMode (&MeMode); + ASSERT_EFI_ERROR (Status); + + // + // HECI MSG is unsupported if ME MODE is in Security Override + // + mHeciContext->MeMode = MeMode; + if (mHeciContext->MeMode == ME_MODE_DEBUG) { + Status = EFI_UNSUPPORTED; + break; + } + + HeciPciAddressBase = PCI_LIB_ADDRESS ( + ME_BUS, + ME_DEVICE_NUMBER, + HECI_FUNCTION_NUMBER, + 0 + ); + mHeciContext->HeciDevSaveEnable = Heci2DevSaveEnable; + mHeciContext->PciAddressBase = HeciPciAddressBase; + + // + // Store HECI vendor and device information away + // + mHeciContext->DeviceInfo = PciRead16 (HeciPciAddressBase + PCI_DEVICE_ID_OFFSET); + + // + // Check for HECI-2 PCI device availability + // + if (mHeciContext->DeviceInfo == 0xFFFF) { + Status = EFI_DEVICE_ERROR; + break; + } + // + // Store HECI revision ID + // + mHeciContext->RevisionInfo = PciRead8 (HeciPciAddressBase + PCI_REVISION_ID_OFFSET); + + // + // Get HECI_MBAR and see if it is programmed + // to a useable value + // + mHeciContext->HeciMBAR = PciRead32 (HeciPciAddressBase + R_HECIMBAR) & 0xFFFFFFF0; + HeciMBAR = mHeciContext->HeciMBAR; + + // + // Load temporary address for HECI_MBAR if one is not assigned + // + if (mHeciContext->HeciMBAR == 0) { + // + // mHeciContext->HeciMBAR = mHeciContext->DefaultHeciBar; + // PciWrite32 (HeciPciAddressBase + R_HECIMBAR, mHeciContext->HeciMBAR); + // HeciMBAR = mHeciContext->HeciMBAR; + // + DEBUG ((EFI_D_ERROR, "Heci MMIO Bar not programmed in SMM phase\n")); + } + // + // Enable HECI BME and MSE + // + PciOr8 ( + HeciPciAddressBase + PCI_COMMAND_OFFSET, + EFI_PCI_COMMAND_MEMORY_SPACE | EFI_PCI_COMMAND_BUS_MASTER + ); + + // + // Set HECI interrupt delivery mode. + // HECI-2 using legacy/MSI interrupt + // + PciAnd8 (HeciPciAddressBase + R_HIDM, 0xFC); + + // + // Need to do following on ME init: + // + // 1) wait for ME_CSR_HA reg ME_RDY bit set + // + if (WaitForMEReady () != EFI_SUCCESS) { + Status = EFI_TIMEOUT; + break; + } + // + // 2) setup H_CSR reg as follows: + // a) Make sure H_RST is clear + // b) Set H_RDY + // c) Set H_IG + // + HeciRegHCsrPtr = (VOID *) (UINTN) (mHeciContext->HeciMBAR + H_CSR); + HeciRegHCsr.ul = HeciRegHCsrPtr->ul; + if (HeciRegHCsrPtr->r.H_RDY == 0) { + HeciRegHCsr.r.H_RST = 0; + HeciRegHCsr.r.H_RDY = 1; + HeciRegHCsr.r.H_IG = 1; + HeciRegHCsrPtr->ul = HeciRegHCsr.ul; + } + + } while (EFI_ERROR (Status)); + + RestoreHpet (); + + return Status; +} + +EFI_STATUS +WaitForMEReady ( + VOID + ) +/*++ + + Routine Description: + Waits for the ME to report that it is ready for communication over the HECI + interface. + + Arguments: + None. + + Returns: + EFI_STATUS + +--*/ +{ + UINT32 TimerStart; + UINT32 TimerEnd; + HECI_ME_CONTROL_REGISTER HeciRegMeCsrHa; + + // + // Wait for ME ready + // + // + // Check for ME ready status + // + StartTimer (&TimerStart, &TimerEnd, HECI_INIT_TIMEOUT); + HeciRegMeCsrHa.ul = MMIOREADDWORD (HeciMBAR + ME_CSR_HA); + while (HeciRegMeCsrHa.r.ME_RDY_HRA == 0) { + // + // If 5 second timeout has expired, return fail + // + if (Timeout (TimerStart, TimerEnd) != EFI_SUCCESS) { + return EFI_TIMEOUT; + } + // + // Perform IO delay + // + IoDelay (HECI_WAIT_DELAY); + + HeciRegMeCsrHa.ul = MMIOREADDWORD (HeciMBAR + ME_CSR_HA); + } + // + // ME ready!!! + // + return EFI_SUCCESS; +} + +BOOLEAN +CheckForHeciReset ( + VOID + ) +/*++ + + Routine Description: + Checks if HECI reset has occured. + + Arguments: + None. + + Returns: + TRUE - HECI reset occurred + FALSE - No HECI reset occurred + +--*/ +{ + HECI_HOST_CONTROL_REGISTER HeciRegHCsr; + HECI_ME_CONTROL_REGISTER HeciRegMeCsrHa; + + // + // Init Host & ME CSR + // + HeciRegHCsr.ul = MMIOREADDWORD (HeciMBAR + H_CSR); + HeciRegMeCsrHa.ul = MMIOREADDWORD (HeciMBAR + ME_CSR_HA); + + if ((HeciRegMeCsrHa.r.ME_RDY_HRA == 0) || (HeciRegHCsr.r.H_RDY == 0)) { + return TRUE; + } + + return FALSE; +} + +EFI_STATUS +HeciInitialize ( + VOID + ) +/*++ + + Routine Description: + Determines if the HECI device is present and, if present, initializes it for + use by the BIOS. + + Arguments: + None. + + Returns: + EFI_STATUS + +--*/ +{ + HECI_HOST_CONTROL_REGISTER HeciRegHCsr; + + // + // Make sure that HECI device BAR is correct and device is enabled. + // + HeciMBAR = CheckAndFixHeciForAccess (); + + // + // Need to do following on ME init: + // + // 1) wait for ME_CSR_HA reg ME_RDY bit set + // + if (WaitForMEReady () != EFI_SUCCESS) { + return EFI_TIMEOUT; + } + // + // 2) setup H_CSR reg as follows: + // a) Make sure H_RST is clear + // b) Set H_RDY + // c) Set H_IG + // + HeciRegHCsr.ul = MMIOREADDWORD (HeciMBAR + H_CSR); + if (HeciRegHCsr.r.H_RDY == 0) { + HeciRegHCsr.r.H_RST = 0; + HeciRegHCsr.r.H_RDY = 1; + HeciRegHCsr.r.H_IG = 1; + MMIOWRITEDWORD (HeciMBAR + H_CSR, HeciRegHCsr.ul); + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +HeciReInitialize ( + VOID + ) +/*++ + + Routine Description: + Heci Re-initializes it for Host + + Arguments: + None. + + Returns: + EFI_STATUS + +--*/ +{ + HECI_HOST_CONTROL_REGISTER HeciRegHCsr; + EFI_STATUS Status; + + Status = EFI_SUCCESS; + // + // Need to do following on ME init: + // + // 1) wait for HOST_CSR_HA reg H_RDY bit set + // + // if (WaitForHostReady() != EFI_SUCCESS) { + // + if (MeResetWait (HECI_INIT_TIMEOUT) != EFI_SUCCESS) { + return EFI_TIMEOUT; + } + + HeciRegHCsr.ul = MMIOREADDWORD (HeciMBAR + H_CSR); + if (HeciRegHCsr.r.H_RDY == 0) { + Status = ResetHeciInterface (); + + } + + return Status; +} + +EFI_STATUS +EFIAPI +HeciReInitialize2 ( + VOID + ) +/*++ + + Routine Description: + Heci Re-initializes it for Me + + Arguments: + None. + + Returns: + EFI_STATUS + +--*/ +{ + HECI_ME_CONTROL_REGISTER HeciRegMeCsrHa; + EFI_STATUS Status; + UINT32 TimerStart; + UINT32 TimerEnd; + Status = EFI_SUCCESS; + // + // Need to do following on ME init: + // + // 1) wait for HOST_CSR_HA reg H_RDY bit set + // + // if (WaitForHostReady() != EFI_SUCCESS) { + // + StartTimer (&TimerStart, &TimerEnd, HECI_INIT_TIMEOUT); + HeciRegMeCsrHa.ul = MMIOREADDWORD (HeciMBAR + ME_CSR_HA); + while (HeciRegMeCsrHa.r.ME_RDY_HRA == 1) { + // + // If 5 second timeout has expired, return fail + // + if (Timeout (TimerStart, TimerEnd) != EFI_SUCCESS) { + return EFI_TIMEOUT; + } + + IoDelay (HECI_WAIT_DELAY); + + HeciRegMeCsrHa.ul = MMIOREADDWORD (HeciMBAR + ME_CSR_HA); + } + + if (WaitForMEReady () != EFI_SUCCESS) { + return EFI_TIMEOUT; + } + + return Status; +} + +EFI_STATUS +HECIPacketRead ( + IN UINT32 Blocking, + OUT HECI_MESSAGE_HEADER *MessageHeader, + OUT UINT32 *MessageData, + IN OUT UINT32 *Length + ) +/*++ + + Routine Description: + Function to pull one messsage packet off the HECI circular buffer. + Corresponds to HECI HPS (part of) section 4.2.4 + + + Arguments: + Blocking - Used to determine if the read is BLOCKING or NON_BLOCKING. + MessageHeader - Pointer to a buffer for the message header. + MessageData - Pointer to a buffer to recieve the message in. + Length - On input is the size of the callers buffer in bytes. On + output this is the size of the packet in bytes. + + Returns: + EFI_STATUS + +--*/ +{ + BOOLEAN GotMessage; + UINT32 TimerStart; + UINT32 TimerEnd; + UINT32 TimerStart1; + UINT32 TimerEnd1; + UINT32 i; + UINT32 LengthInDwords; + HECI_ME_CONTROL_REGISTER HeciRegMeCsrHa; + HECI_HOST_CONTROL_REGISTER HeciRegHCsr; + + GotMessage = FALSE; + // + // Initialize memory mapped register pointers + // + // VOLATILE HECI_HOST_CONTROL_REGISTER *HeciRegHCsrPtr = (VOID*)(mHeciContext->HeciMBAR + H_CSR); + // VOLATILE HECI_ME_CONTROL_REGISTER *HeciRegMeCsrHaPtr = (VOID*)(mHeciContext->HeciMBAR + ME_CSR_HA); + // VOLATILE UINT32 *HeciRegMeCbrwPtr = (VOID*)(mHeciContext->HeciMBAR + ME_CB_RW); + // + // clear Interrupt Status bit + // + HeciRegHCsr.ul = MMIOREADDWORD (HeciMBAR + H_CSR); + HeciRegHCsr.r.H_IS = 1; + + // + // test for circular buffer overflow + // + HeciRegMeCsrHa.ul = MMIOREADDWORD (HeciMBAR + ME_CSR_HA); + if (OverflowCB ( + HeciRegMeCsrHa.r.ME_CBRP_HRA, + HeciRegMeCsrHa.r.ME_CBWP_HRA, + HeciRegMeCsrHa.r.ME_CBD_HRA + ) != EFI_SUCCESS) { + // + // if we get here, the circular buffer is overflowed + // + *Length = 0; + return EFI_DEVICE_ERROR; + } + // + // If NON_BLOCKING, exit if the circular buffer is empty + // + HeciRegMeCsrHa.ul = MMIOREADDWORD (HeciMBAR + ME_CSR_HA);; + if ((FilledSlots (HeciRegMeCsrHa.r.ME_CBRP_HRA, HeciRegMeCsrHa.r.ME_CBWP_HRA) == 0) && (Blocking == NON_BLOCKING)) { + *Length = 0; + return EFI_NO_RESPONSE; + } + // + // Start timeout counter + // + StartTimer (&TimerStart, &TimerEnd, HECI_READ_TIMEOUT); + + // + // loop until we get a message packet + // + while (!GotMessage) { + // + // If 1 second timeout has expired, return fail as we have not yet received a full message. + // + if (Timeout (TimerStart, TimerEnd) != EFI_SUCCESS) { + *Length = 0; + return EFI_TIMEOUT; + } + // + // Read one message from HECI buffer and advance read pointer. Make sure + // that we do not pass the write pointer. + // + HeciRegMeCsrHa.ul = MMIOREADDWORD (HeciMBAR + ME_CSR_HA);; + if (FilledSlots (HeciRegMeCsrHa.r.ME_CBRP_HRA, HeciRegMeCsrHa.r.ME_CBWP_HRA) > 0) { + // + // Eat the HECI Message header + // + MessageHeader->Data = MMIOREADDWORD (HeciMBAR + ME_CB_RW); + + // + // Compute required message length in DWORDS + // + LengthInDwords = ((MessageHeader->Fields.Length + 3) / 4); + + // + // Just return success if Length is 0 + // + if (MessageHeader->Fields.Length == 0) { + // + // Set Interrupt Generate bit and return + // + MMIOREADDWORD (HeciMBAR + H_CSR); + HeciRegHCsr.r.H_IG = 1; + MMIOWRITEDWORD (HeciMBAR + H_CSR, HeciRegHCsr.ul); + *Length = 0; + return EFI_SUCCESS; + } + // + // Make sure that the message does not overflow the circular buffer. + // + HeciRegMeCsrHa.ul = MMIOREADDWORD (HeciMBAR + ME_CSR_HA); + if ((MessageHeader->Fields.Length + sizeof (HECI_MESSAGE_HEADER)) > (HeciRegMeCsrHa.r.ME_CBD_HRA * 4)) { + *Length = 0; + return EFI_DEVICE_ERROR; + } + // + // Make sure that the callers buffer can hold the correct number of DWORDS + // + if ((MessageHeader->Fields.Length) <= *Length) { + // + // Start timeout counter for inner loop + // + StartTimer (&TimerStart1, &TimerEnd1, HECI_READ_TIMEOUT); + + // + // Wait here until entire message is present in circular buffer + // + HeciRegMeCsrHa.ul = MMIOREADDWORD (HeciMBAR + ME_CSR_HA); + while (LengthInDwords > FilledSlots (HeciRegMeCsrHa.r.ME_CBRP_HRA, HeciRegMeCsrHa.r.ME_CBWP_HRA)) { + // + // If 1 second timeout has expired, return fail as we have not yet received a full message + // + if (Timeout (TimerStart1, TimerEnd1) != EFI_SUCCESS) { + *Length = 0; + return EFI_TIMEOUT; + } + // + // Wait before we read the register again + // + IoDelay (HECI_WAIT_DELAY); + + // + // Read the register again + // + HeciRegMeCsrHa.ul = MMIOREADDWORD (HeciMBAR + ME_CSR_HA); + } + // + // copy rest of message + // + for (i = 0; i < LengthInDwords; i++) { + MessageData[i] = MMIOREADDWORD (HeciMBAR + ME_CB_RW); + } + // + // Update status and length + // + GotMessage = TRUE; + *Length = MessageHeader->Fields.Length; + + } else { + // + // Message packet is larger than caller's buffer + // + *Length = 0; + return EFI_BUFFER_TOO_SMALL; + } + } + // + // Wait before we try to get a message again + // + IoDelay (HECI_WAIT_DELAY); + } + // + // Read ME_CSR_HA. If the ME_RDY bit is 0, then an ME reset occurred during the + // transaction and the message should be discarded as bad data may have been retrieved + // from the host's circular buffer + // + HeciRegMeCsrHa.ul = MMIOREADDWORD (HeciMBAR + ME_CSR_HA); + if (HeciRegMeCsrHa.r.ME_RDY_HRA == 0) { + *Length = 0; + return EFI_DEVICE_ERROR; + } + // + // Set Interrupt Generate bit + // + HeciRegHCsr.ul = MMIOREADDWORD (HeciMBAR + H_CSR); + HeciRegHCsr.r.H_IG = 1; + MMIOWRITEDWORD (HeciMBAR + H_CSR, HeciRegHCsr.ul); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +HeciReceive ( + IN UINT32 Blocking, + IN OUT UINT32 *MessageBody, + IN OUT UINT32 *Length + ) +/*++ + + Routine Description: + Reads a message from the ME across HECI. + + Arguments: + Blocking - Used to determine if the read is BLOCKING or NON_BLOCKING. + MessageBody - Pointer to a buffer used to receive a message. + Length - Pointer to the length of the buffer on input and the length + of the message on return. (in bytes) + + Returns: + EFI_STATUS + +--*/ +{ + HECI_MESSAGE_HEADER PacketHeader; + UINT32 CurrentLength; + UINT32 MessageComplete; + EFI_STATUS Status; + UINT32 PacketBuffer; + UINT32 timer_start; + UINT32 timer_end; + UINT32 MeDeviceState; + BOOLEAN QuitFlag; + + Status = EFI_SUCCESS; + CurrentLength = 0; + MessageComplete = 0; + QuitFlag = FALSE; + + SaveHpet (); + + do { + if (mHeciContext->MeMode == ME_MODE_SECOVER) { + Status = EFI_UNSUPPORTED; + break; + } + // + // Enable HECI and Save the Device State + // + mHeciContext->HeciDevSaveEnable (&MeDeviceState); + + // + // Make sure that HECI device BAR is correct and device is enabled. + // + HeciMBAR = CheckAndFixHeciForAccess (); + + // + // Make sure we do not have a HECI reset + // + if (CheckForHeciReset ()) { + // + // if HECI reset than try to re-init HECI + // + Status = HeciInitialize (); + + if (EFI_ERROR (Status)) { + HeciDevRestore (MeDeviceState); + Status = EFI_DEVICE_ERROR; + break; + } + } + // + // Make sure that HECI is ready for communication. + // + if (WaitForMEReady () != EFI_SUCCESS) { + HeciDevRestore (MeDeviceState); + Status = EFI_TIMEOUT; + break; + } + // + // Set up timer for BIOS timeout. + // + StartTimer (&timer_start, &timer_end, HECI_READ_TIMEOUT); + while ((CurrentLength < *Length) && (MessageComplete == 0)) { + // + // If 1 second timeout has expired, return fail as we have not yet received a full message + // + if (Timeout (timer_start, timer_end) != EFI_SUCCESS) { + Status = EFI_TIMEOUT; + QuitFlag = TRUE; + break; + } + + PacketBuffer = *Length - CurrentLength; + Status = HECIPacketRead ( + Blocking, + &PacketHeader, + (UINT32 *) &MessageBody[CurrentLength / 4], + &PacketBuffer + ); + + // + // Check for error condition on read + // + if (EFI_ERROR (Status)) { + *Length = 0; + QuitFlag = TRUE; + break; + } + // + // Get completion status from the packet header + // + MessageComplete = PacketHeader.Fields.MessageComplete; + + // + // Check for zero length messages + // + if (PacketBuffer == 0) { + // + // If we are not in the middle of a message, and we see Message Complete, + // this is a valid zero-length message. + // + if ((CurrentLength == 0) && (MessageComplete == 1)) { + *Length = 0; + QuitFlag = TRUE; + break; + } else { + // + // We should not expect a zero-length message packet except as described above. + // + *Length = 0; + Status = EFI_DEVICE_ERROR; + QuitFlag = TRUE; + break; + } + } + // + // Track the length of what we have read so far + // + CurrentLength += PacketBuffer; + + } + + if (QuitFlag == TRUE) { + break; + } + // + // If we get here the message should be complete, if it is not + // the caller's buffer was not large enough. + // + if (MessageComplete == 0) { + *Length = 0; + Status = EFI_BUFFER_TOO_SMALL; + } + + if (*Length != 0) { + *Length = CurrentLength; + } + // + // Restore HECI Device State + // + HeciDevRestore (MeDeviceState); + + } while (EFI_ERROR (Status) && (Status != EFI_BUFFER_TOO_SMALL)); + RestoreHpet (); + + return Status; +} + +EFI_STATUS +EFIAPI +HeciSend ( + IN UINT32 *Message, + IN UINT32 Length, + IN UINT8 HostAddress, + IN UINT8 MeAddress + ) +/*++ + + Routine Description: + Function sends one messsage (of any length) through the HECI circular buffer. + + Arguments: + Message - Pointer to the message data to be sent. + Length - Length of the message in bytes. + HostAddress - The address of the host processor. + MeAddress - Address of the ME subsystem the message is being sent to. + + Returns: + EFI_STATUS + +--*/ +{ + UINT32 CBLength; + UINT32 SendLength; + UINT32 CurrentLength; + HECI_MESSAGE_HEADER MessageHeader; + EFI_STATUS Status; + HECI_HOST_CONTROL_REGISTER HeciRegHCsr; + UINT32 MeDeviceState; + + Status = EFI_SUCCESS; + CurrentLength = 0; + + SaveHpet (); + + do { + if (mHeciContext->MeMode == ME_MODE_SECOVER) { + Status = EFI_UNSUPPORTED; + break; + } + // + // Enable HECI and Save the Device State + // + mHeciContext->HeciDevSaveEnable (&MeDeviceState); + + // + // Make sure that HECI device BAR is correct and device is enabled. + // + HeciMBAR = CheckAndFixHeciForAccess (); + + // + // Make sure we do not have a HECI reset + // + if (CheckForHeciReset ()) { + // + // if HECI reset than try to re-init HECI + // + Status = HeciInitialize (); + + if (EFI_ERROR (Status)) { + HeciDevRestore (MeDeviceState); + Status = EFI_DEVICE_ERROR; + break; + } + } + // + // Make sure that HECI is ready for communication. + // + if (WaitForMEReady () != EFI_SUCCESS) { + HeciDevRestore (MeDeviceState); + Status = EFI_TIMEOUT; + break; + } + // + // Set up memory mapped registers + // + HeciRegHCsr.ul = MMIOREADDWORD (HeciMBAR + H_CSR); + + // + // Grab Circular Buffer length + // + CBLength = HeciRegHCsr.r.H_CBD; + + // + // Prepare message header + // + MessageHeader.Data = 0; + MessageHeader.Fields.MeAddress = MeAddress; + MessageHeader.Fields.HostAddress = HostAddress; + + // + // Break message up into CB-sized packets and loop until completely sent + // + while (Length > CurrentLength) { + // + // Set the Message Complete bit if this is our last packet in the message. + // Needs to be 'less than' to account for the header. + // + if ((((Length - CurrentLength) + 3) / 4) < CBLength) { + MessageHeader.Fields.MessageComplete = 1; + } + // + // Calculate length for Message Header + // header length == smaller of circular buffer or remaining message (both account for the size of the header) + // + SendLength = ((CBLength < (((Length - CurrentLength) + 3) / 4)) ? ((CBLength - 1) * 4) : (Length - CurrentLength)); + MessageHeader.Fields.Length = SendLength; + + // + // send the current packet (CurrentLength can be treated as the index into the message buffer) + // + Status = HeciPacketWrite (&MessageHeader, (UINT32 *) ((UINTN) Message + CurrentLength)); + if (EFI_ERROR (Status)) { + break; + } + // + // Update the length information + // + CurrentLength += SendLength; + } + + if (EFI_ERROR (Status)) { + break; + } + // + // Restore HECI Device State + // + HeciDevRestore (MeDeviceState); + + } while (EFI_ERROR (Status)); + + RestoreHpet (); + + return Status; +} + +EFI_STATUS +HeciPacketWrite ( + IN HECI_MESSAGE_HEADER *MessageHeader, + IN UINT32 *MessageData + ) +/*++ + + Routine Description: + Function sends one messsage packet through the HECI circular buffer + Corresponds to HECI HPS (part of) section 4.2.3 + + Arguments: + MessageHeader - Pointer to the message header. + MessageData - Pointer to the actual message data. + + Returns: + EFI_STATUS + +--*/ +{ + UINT32 timer_start; + UINT32 timer_end; + UINT32 i; + UINT32 LengthInDwords; + HECI_HOST_CONTROL_REGISTER HeciRegHCsr; + HECI_ME_CONTROL_REGISTER HeciRegMeCsrHa; + + // + // VOLATILE HECI_HOST_CONTROL_REGISTER *HeciRegHCsrPtr = (VOID*)(mHeciContext->HeciMBAR + H_CSR); + // VOLATILE HECI_ME_CONTROL_REGISTER *HeciRegMeCsrHaPtr = (VOID*)(mHeciContext->HeciMBAR + ME_CSR_HA); + // VOLATILE UINT32 *HeciRegHCbwwPtr = (VOID*)(mHeciContext->HeciMBAR + H_CB_WW); + // + // Make sure that HECI is ready for communication. + // + if (WaitForMEReady () != EFI_SUCCESS) { + return EFI_TIMEOUT; + } + // + // Start timeout counter + // + StartTimer (&timer_start, &timer_end, HECI_SEND_TIMEOUT); + + // + // Compute message length in DWORDS + // + LengthInDwords = ((MessageHeader->Fields.Length + 3) / 4); + + // + // Wait until there is sufficient room in the circular buffer + // Must have room for message and message header + // + HeciRegHCsr.ul = MMIOREADDWORD (HeciMBAR + H_CSR); + while ((LengthInDwords + 1) > (HeciRegHCsr.r.H_CBD - FilledSlots (HeciRegHCsr.r.H_CBRP, HeciRegHCsr.r.H_CBWP))) { + // + // If 1 second timeout has expired, return fail as the circular buffer never emptied + // + if (Timeout (timer_start, timer_end) != EFI_SUCCESS) { + return EFI_TIMEOUT; + } + // + // Wait before we read the register again + // + IoDelay (HECI_WAIT_DELAY); + + // + // Read Host CSR for next iteration + // + HeciRegHCsr.ul = MMIOREADDWORD (HeciMBAR + H_CSR); + } + // + // Write Message Header + // + MMIOWRITEDWORD (HeciMBAR + H_CB_WW, MessageHeader->Data); + + // + // Write Message Body + // + for (i = 0; i < LengthInDwords; i++) { + MMIOWRITEDWORD (HeciMBAR + H_CB_WW, MessageData[i]); + } + // + // Set Interrupt Generate bit + // + HeciRegHCsr.ul = MMIOREADDWORD (HeciMBAR + H_CSR); + HeciRegHCsr.r.H_IG = 1; + MMIOWRITEDWORD (HeciMBAR + H_CSR, HeciRegHCsr.ul); + + // + // Test if ME Ready bit is set to 1, if set to 0 a fatal error occured during + // the transmission of this message. + // + HeciRegMeCsrHa.ul = MMIOREADDWORD (HeciMBAR + ME_CSR_HA); + if (HeciRegMeCsrHa.r.ME_RDY_HRA == 0) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +HeciSendwACK ( + IN OUT UINT32 *Message, + IN UINT32 Length, + IN OUT UINT32 *RecLength, + IN UINT8 HostAddress, + IN UINT8 MeAddress + ) +/*++ + + Routine Description: + Function sends one messsage through the HECI circular buffer and waits + for the corresponding ACK message. + + Arguments: + Message - Pointer to the message buffer. + SendLength - Length of the message in bytes. + RecLength - Length of the message response in bytes. + HostAddress - Address of the sending entity. + MeAddress - Address of the ME entity that should receive the message. + + Returns: + EFI_STATUS + +--*/ +{ + EFI_STATUS Status; + UINT16 RetryCount; + UINT32 TempRecLength; + + if (mHeciContext->MeMode == ME_MODE_SECOVER) { + return EFI_UNSUPPORTED; + } + // + // Send the message + // + Status = HeciSend (Message, Length, HostAddress, MeAddress); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Wait for ACK message + // + TempRecLength = *RecLength; + for (RetryCount = 0; RetryCount < HECI_MAX_RETRY; RetryCount++) { + // + // Read Message + // + Status = HeciReceive (BLOCKING, Message, &TempRecLength); + if (!EFI_ERROR (Status)) { + break; + } + // + // Reload receive length as it has been modified by the read function + // + TempRecLength = *RecLength; + } + // + // Return read length and status + // + *RecLength = TempRecLength; + return Status; +} + +EFI_STATUS +EFIAPI +MeResetWait ( + IN UINT32 Delay + ) +/*++ + +Routine Description: + + Me reset and waiting for ready + +Arguments: + + Delay - The biggest waiting time + +Returns: + + EFI_TIMEOUT - Time out + EFI_SUCCESS - Me ready + +--*/ +{ + HECI_HOST_CONTROL_REGISTER HeciRegHCsr; + UINT32 TimerStart; + UINT32 TimerEnd; + + // + // Make sure that HECI device BAR is correct and device is enabled. + // + HeciMBAR = CheckAndFixHeciForAccess (); + + // + // Wait for the HOST Ready bit to be cleared to signal a reset + // + StartTimer (&TimerStart, &TimerEnd, Delay); + HeciRegHCsr.ul = MMIOREADDWORD (HeciMBAR + H_CSR); + while (HeciRegHCsr.r.H_RDY == 1) { + // + // If timeout has expired, return fail + // + if (Timeout (TimerStart, TimerEnd) != EFI_SUCCESS) { + return EFI_TIMEOUT; + } + + HeciRegHCsr.ul = MMIOREADDWORD (HeciMBAR + H_CSR); + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +ResetHeciInterface ( + VOID + ) +/*++ + + Routine Description: + Function forces a reinit of the heci interface by following the reset heci interface via host algorithm + in HPS 0.90 doc 4-17-06 njy + + Arguments: + none + + Returns: + EFI_STATUS + +--*/ +{ + HECI_HOST_CONTROL_REGISTER HeciRegHCsr; + HECI_ME_CONTROL_REGISTER HeciRegMeCsrHa; + UINT32 TimerStart; + UINT32 TimerEnd; + + // + // Make sure that HECI device BAR is correct and device is enabled. + // + HeciMBAR = CheckAndFixHeciForAccess (); + + // + // Enable Reset + // + HeciRegHCsr.ul = MMIOREADDWORD (HeciMBAR + H_CSR); + HeciRegHCsr.r.H_RST = 1; + HeciRegHCsr.r.H_IG = 1; + MMIOWRITEDWORD (HeciMBAR + H_CSR, HeciRegHCsr.ul); + + // + // Make sure that the reset started + // + // HeciRegHCsr.ul = MMIOREADDWORD(HeciMBAR + H_CSR); + // + StartTimer (&TimerStart, &TimerEnd, HECI_INIT_TIMEOUT); + do { + // + // If 5 second timeout has expired, return fail + // + if (Timeout (TimerStart, TimerEnd) != EFI_SUCCESS) { + return EFI_TIMEOUT; + } + // + // Read the ME CSR + // + HeciRegHCsr.ul = MMIOREADDWORD (HeciMBAR + H_CSR); + } while (HeciRegHCsr.r.H_RDY == 1); + + // + // Wait for ME to perform reset + // + // HeciRegMeCsrHa.ul = MMIOREADDWORD(HeciMBAR + ME_CSR_HA); + // + StartTimer (&TimerStart, &TimerEnd, HECI_INIT_TIMEOUT); + do { + // + // If 5 second timeout has expired, return fail + // + if (Timeout (TimerStart, TimerEnd) != EFI_SUCCESS) { + return EFI_TIMEOUT; + } + // + // Read the ME CSR + // + HeciRegMeCsrHa.ul = MMIOREADDWORD (HeciMBAR + ME_CSR_HA); + } while (HeciRegMeCsrHa.r.ME_RDY_HRA == 0); + + // + // Make sure IS has been signaled on the HOST side + // + // HeciRegHCsr.ul = MMIOREADDWORD(HeciMBAR + H_CSR); + // + StartTimer (&TimerStart, &TimerEnd, HECI_INIT_TIMEOUT); + do { + // + // If 5 second timeout has expired, return fail + // + if (Timeout (TimerStart, TimerEnd) != EFI_SUCCESS) { + return EFI_TIMEOUT; + } + // + // Read the ME CSR + // + HeciRegHCsr.ul = MMIOREADDWORD (HeciMBAR + H_CSR); + } while (HeciRegHCsr.r.H_IS == 0); + + // + // Enable host side interface + // + HeciRegHCsr.ul = MMIOREADDWORD (HeciMBAR + H_CSR);; + HeciRegHCsr.r.H_RST = 0; + HeciRegHCsr.r.H_IG = 1; + HeciRegHCsr.r.H_RDY = 1; + MMIOWRITEDWORD (HeciMBAR + H_CSR, HeciRegHCsr.ul); + + return EFI_SUCCESS; +} + +UINT8 +FilledSlots ( + IN UINT32 ReadPointer, + IN UINT32 WritePointer + ) +/*++ + + Routine Description: + Calculate if the circular buffer has overflowed. + Corresponds to HECI HPS (part of) section 4.2.1 + + Arguments: + ReadPointer - Location of the read pointer. + WritePointer - Location of the write pointer. + + Returns: + Number of filled slots. + +--*/ +{ + UINT8 FilledSlots; + + // + // Calculation documented in HECI HPS 0.68 section 4.2.1 + // + FilledSlots = (((INT8) WritePointer) - ((INT8) ReadPointer)); + + return FilledSlots; +} + +EFI_STATUS +OverflowCB ( + IN UINT32 ReadPointer, + IN UINT32 WritePointer, + IN UINT32 BufferDepth + ) +/*++ + + Routine Description: + Calculate if the circular buffer has overflowed + Corresponds to HECI HPS (part of) section 4.2.1 + + Arguments: + ReadPointer - Value read from host/me read pointer + WritePointer - Value read from host/me write pointer + BufferDepth - Value read from buffer depth register + + Returns: + EFI_STATUS + +--*/ +{ + UINT8 FilledSlots; + + // + // Calculation documented in HECI HPS 0.68 section 4.2.1 + // + FilledSlots = (((INT8) WritePointer) - ((INT8) ReadPointer)); + + // + // test for overflow + // + if (FilledSlots > ((UINT8) BufferDepth)) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +HeciGetMeStatus ( + IN UINT32 *MeStatus + ) +/*++ + + Routine Description: + Return ME Status + + Arguments: + MeStatus pointer for status report + + Returns: + EFI_STATUS + +--*/ +{ + HECI_FWS_REGISTER MeFirmwareStatus; + UINT32 MeDeviceState; + + if (MeStatus == NULL) { + return EFI_INVALID_PARAMETER; + } + // + // Save HECI1 Device State and Enable it + // + Heci1DevSaveEnable (&MeDeviceState); + + MeFirmwareStatus.ul = HeciPciRead32 (R_FWSTATE); + + if (MeFirmwareStatus.r.CurrentState == ME_STATE_NORMAL && MeFirmwareStatus.r.ErrorCode == ME_ERROR_CODE_NO_ERROR) { + *MeStatus = ME_READY; + } else if (MeFirmwareStatus.r.CurrentState == ME_STATE_RECOVERY) { + *MeStatus = ME_IN_RECOVERY_MODE; + } else { + *MeStatus = ME_NOT_READY; + } + + if (MeFirmwareStatus.r.FwInitComplete == ME_FIRMWARE_COMPLETED) { + *MeStatus |= ME_FW_INIT_COMPLETE; + } + // + // Save HECI Device State and Enable it + // + HeciDevRestore (MeDeviceState); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +HeciGetMeMode ( + IN UINT32 *MeMode + ) +/*++ + + Routine Description: + Return ME Mode + + Arguments: + MeMode pointer for ME Mode report + + Returns: + EFI_STATUS + +--*/ +{ + HECI_FWS_REGISTER MeFirmwareStatus; + UINT32 MeDeviceState; + + if (MeMode == NULL) { + return EFI_INVALID_PARAMETER; + } + // + // Save HECI1 Device State and Enable it + // + Heci1DevSaveEnable (&MeDeviceState); + + MeFirmwareStatus.ul = HeciPciRead32 (R_FWSTATE); + switch (MeFirmwareStatus.r.MeOperationMode) { + case ME_OPERATION_MODE_NORMAL: + *MeMode = ME_MODE_NORMAL; + break; + + case ME_OPERATION_MODE_DEBUG: + *MeMode = ME_MODE_DEBUG; + break; + + case ME_OPERATION_MODE_SOFT_TEMP_DISABLE: + *MeMode = ME_MODE_TEMP_DISABLED; + break; + + case ME_OPERATION_MODE_SECOVR_JMPR: + case ME_OPERATION_MODE_SECOVR_HECI_MSG: + *MeMode = ME_MODE_SECOVER; + break; + + default: + *MeMode = ME_MODE_FAILED; + } + // + // Save HECI Device State and Enable it + // + HeciDevRestore (MeDeviceState); + + return EFI_SUCCESS; +} + +EFI_STATUS +Heci1DevSaveEnable ( + IN OUT UINT32 *DevState + ) +/*++ + + Routine Description: + Save HECI1 State and Enable it + + Arguments: + DevState - Device State Save Buffer + + Returns: + EFI_STATUS + +--*/ +{ + *DevState = MMIOREADDWORD (PCH_RCRB_BASE + R_PCH_RCRB_FUNC_DIS2); + HeciEnable (); + return EFI_SUCCESS; +} + +EFI_STATUS +Heci2DevSaveEnable ( + IN OUT UINT32 *DevState + ) +/*++ + + Routine Description: + Save HECI2 State and Enable it + + Arguments: + DevState - Device State Save Buffer + + Returns: + EFI_STATUS + +--*/ +{ + *DevState = MMIOREADDWORD (PCH_RCRB_BASE + R_PCH_RCRB_FUNC_DIS2); + Heci2Enable (); + return EFI_SUCCESS; +} + +EFI_STATUS +HeciDevRestore ( + IN UINT32 DevState + ) +/*++ + + Routine Description: + Restore HECI1&HECI2 State + + Arguments: + DevState - Device State Save Buffer + + Returns: + EFI_STATUS + +--*/ +{ + MMIOWRITEDWORD (PCH_RCRB_BASE + R_PCH_RCRB_FUNC_DIS2, DevState); + MMIOREADDWORD (PCH_RCRB_BASE + R_PCH_RCRB_FUNC_DIS2); + return EFI_SUCCESS; +} diff --git a/ReferenceCode/ME/Heci/Smm/Hecicore.h b/ReferenceCode/ME/Heci/Smm/Hecicore.h new file mode 100644 index 0000000..5f05c10 --- /dev/null +++ b/ReferenceCode/ME/Heci/Smm/Hecicore.h @@ -0,0 +1,512 @@ +/*++ + 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 +--*/ +/*++ + +Copyright (c) 2006 - 2010 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. + +Module Name: + + HeciCore.h + +Abstract: + + Definitions for HECI driver + +--*/ +#ifndef _HECI_CORE_H +#define _HECI_CORE_H + +#include "CpuIa32.h" +#include "CoreBiosMsg.h" + +// +// HECI bus function version +// +#define HBM_MINOR_VERSION 0 +#define HBM_MAJOR_VERSION 1 + +// +// HECI save/restore Function +// +typedef +EFI_STATUS +(EFIAPI *HECI_DEV_SAVE_ENABLE) ( + IN OUT UINT32 *DevState + ); + +// +// HECI private data structure +// +typedef struct { + UINTN Signature; + EFI_HANDLE Handle; + UINT32 HeciMBAR; + UINT16 DeviceInfo; + UINT32 RevisionInfo; + SMM_HECI_PROTOCOL HeciCtlr; + VOLATILE UINT32 *HpetTimer; + UINTN PciAddressBase; + UINT32 DefaultHeciBar; + HECI_DEV_SAVE_ENABLE HeciDevSaveEnable; + UINT32 MeMode; +} HECI_INSTANCE_SMM; + +// +// Prototypes +// +EFI_STATUS +EFIAPI +HeciInitialize ( + VOID + ) +/*++ + + Routine Description: + Determines if the HECI device is present and, if present, initializes it for + use by the BIOS. + + Arguments: + None. + + Returns: + EFI_STATUS + +--*/ +; + +EFI_STATUS +EFIAPI +HeciReInitialize ( + VOID + ) +/*++ + + Routine Description: + Heci Re-initializes it for Host + + Arguments: + None. + + Returns: + EFI_STATUS + +--*/ +; + +EFI_STATUS +EFIAPI +HeciReInitialize2 ( + VOID + ) +/*++ + + Routine Description: + Heci Re-initializes it for Me + + Arguments: + None. + + Returns: + EFI_STATUS + +--*/ +; + +EFI_STATUS +EFIAPI +HeciReceive ( + IN UINT32 Blocking, + OUT UINT32 *MessageData, + IN OUT UINT32 *Length + ) +/*++ + + Routine Description: + Reads a message from the ME across HECI. + + Arguments: + Blocking - Used to determine if the read is BLOCKING or NON_BLOCKING. + MessageData - Pointer to a buffer used to receive a message. + Length - Pointer to the length of the buffer on input and the length + of the message on return. (in bytes) + + Returns: + EFI_STATUS + +--*/ +; + +EFI_STATUS +EFIAPI +HeciSend ( + IN UINT32 *Message, + IN UINT32 Length, + IN UINT8 HostAddress, + IN UINT8 MeAddress + ) +/*++ + + Routine Description: + Function sends one messsage (of any length) through the HECI circular buffer. + + Arguments: + Message - Pointer to the message data to be sent. + Length - Length of the message in bytes. + HostAddress - The address of the host processor. + MeAddress - Address of the ME subsystem the message is being sent to. + + Returns: + EFI_STATUS + +--*/ +; + +EFI_STATUS +EFIAPI +HeciSendwACK ( + IN OUT UINT32 *Message, + IN UINT32 Length, + IN OUT UINT32 *RecLength, + IN UINT8 HostAddress, + IN UINT8 MeAddress + ) +/*++ + + Routine Description: + Function sends one messsage through the HECI circular buffer and waits + for the corresponding ACK message. + + Arguments: + Message - Pointer to the message buffer. + SendLength - Length of the message in bytes. + RecLength - Length of the message response in bytes. + HostAddress - Address of the sending entity. + MeAddress - Address of the ME entity that should receive the message. + + Returns: + EFI_STATUS + +--*/ +; + +EFI_STATUS +EFIAPI +MeResetWait ( + IN UINT32 Delay + ) +/*++ + +Routine Description: + + Me reset and waiting for ready + +Arguments: + + Delay - The biggest waiting time + +Returns: + + EFI_TIMEOUT - Time out + EFI_SUCCESS - Me ready + +--*/ +; + +EFI_STATUS +EFIAPI +ResetHeciInterface ( + VOID + ) +/*++ + + Routine Description: + Function forces a reinit of the heci interface by following the reset heci interface via host algorithm + in HPS 0.90 doc 4-17-06 njy + + Arguments: + none + + Returns: + EFI_STATUS + +--*/ +; + +EFI_STATUS +EFIAPI +HeciGetMeStatus ( + IN UINT32 *MeStatus + ) +/*++ + + Routine Description: + Return ME Status + + Arguments: + MeStatus pointer for status report + + Returns: + EFI_STATUS + +--*/ +; + +EFI_STATUS +EFIAPI +HeciGetMeMode ( + IN UINT32 *MeMode + ) +/*++ + + Routine Description: + Return ME Mode + + Arguments: + MeMode pointer for ME Mode report + + Returns: + EFI_STATUS + +--*/ +; + +// +// Local/Private functions not part of EFIAPI for HECI +// +EFI_STATUS +InitializeHECI ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + HECI driver entry point used to initialize support for the HECI device. + +Arguments: + ImageHandle - Standard entry point parameter. + SystemTable - Standard entry point parameter. + +Returns: + EFI_STATUS + +--*/ +; + +EFI_STATUS +InitializeHeciPrivate ( + VOID + ) +/*++ + + Routine Description: + Determines if the HECI device is present and, if present, initializes it for + use by the BIOS. + + Arguments: + None. + + Returns: + EFI_STATUS + +--*/ +; + +UINT32 +CheckAndFixHeciForAccess ( + VOID + ) +/*++ + +Routine Description: + This function provides a standard way to verify the HECI cmd and MBAR regs + in its PCI cfg space are setup properly and that the local mHeciContext + variable matches this info. + +Arguments: + None. + +Returns: + VOID + +--*/ +; + +EFI_STATUS +WaitForMEReady ( + VOID + ) +/*++ + + Routine Description: + Waits for the ME to report that it is ready for communication over the HECI + interface. + + Arguments: + None. + + Returns: + EFI_STATUS + +--*/ +; + +UINT8 +FilledSlots ( + IN UINT32 ReadPointer, + IN UINT32 WritePointer + ) +/*++ + + Routine Description: + Calculate if the circular buffer has overflowed. + Corresponds to HECI HPS (part of) section 4.2.1 + + Arguments: + ReadPointer - Location of the read pointer. + WritePointer - Location of the write pointer. + + Returns: + Number of filled slots. + +--*/ +; + +EFI_STATUS +OverflowCB ( + IN UINT32 ReadPointer, + IN UINT32 WritePointer, + IN UINT32 BufferDepth + ) +/*++ + + Routine Description: + Calculate if the circular buffer has overflowed + Corresponds to HECI HPS (part of) section 4.2.1 + + Arguments: + ReadPointer - Value read from host/me read pointer + WritePointer - Value read from host/me write pointer + BufferDepth - Value read from buffer depth register + + Returns: + EFI_STATUS + +--*/ +; + +EFI_STATUS +HeciPacketRead ( + IN UINT32 Blocking, + OUT HECI_MESSAGE_HEADER *MessageHeader, + OUT UINT32 *MessageData, + IN OUT UINT32 *Length + ) +/*++ + + Routine Description: + Function to pull one messsage packet off the HECI circular buffer. + Corresponds to HECI HPS (part of) section 4.2.4 + + + Arguments: + Blocking - Used to determine if the read is BLOCKING or NON_BLOCKING. + MessageHeader - Pointer to a buffer for the message header. + MessageData - Pointer to a buffer to recieve the message in. + Length - On input is the size of the callers buffer in bytes. On + output this is the size of the packet in bytes. + + Returns: + EFI_STATUS + +--*/ +; + +EFI_STATUS +HeciPacketWrite ( + IN HECI_MESSAGE_HEADER *MessageHeader, + IN UINT32 *MessageData + ) +/*++ + + Routine Description: + Function sends one messsage packet through the HECI circular buffer + Corresponds to HECI HPS (part of) section 4.2.3 + + Arguments: + MessageHeader - Pointer to the message header. + MessageData - Pointer to the actual message data. + + Returns: + EFI_STATUS + +--*/ +; + +EFI_STATUS +Heci1DevSaveEnable ( + IN OUT UINT32 *DevState + ) +/*++ + + Routine Description: + Save HECI1 State and Enable it + + Arguments: + DevState - Device State Save Buffer + + Returns: + EFI_STATUS + +--*/ +; + +EFI_STATUS +Heci2DevSaveEnable ( + IN OUT UINT32 *DevState + ) +/*++ + + Routine Description: + Save HECI2 State and Enable it + + Arguments: + DevState - Device State Save Buffer + + Returns: + EFI_STATUS + +--*/ +; + +EFI_STATUS +HeciDevRestore ( + IN UINT32 DevState + ) +/*++ + + Routine Description: + Restore HECI1 State + + Arguments: + DevState - Device State Save Buffer + + Returns: + EFI_STATUS + +--*/ +; +#endif // _HECI_CORE_H |