summaryrefslogtreecommitdiff
path: root/ReferenceCode/ME/Heci
diff options
context:
space:
mode:
Diffstat (limited to 'ReferenceCode/ME/Heci')
-rw-r--r--ReferenceCode/ME/Heci/Dxe/HeciDxe.cif18
-rw-r--r--ReferenceCode/ME/Heci/Dxe/HeciDxe.mak65
-rw-r--r--ReferenceCode/ME/Heci/Dxe/HeciDxe.sdl24
-rw-r--r--ReferenceCode/ME/Heci/Dxe/HeciHpet.c168
-rw-r--r--ReferenceCode/ME/Heci/Dxe/HeciHpet.h115
-rw-r--r--ReferenceCode/ME/Heci/Dxe/Hecicore.c1461
-rw-r--r--ReferenceCode/ME/Heci/Dxe/Hecicore.h342
-rw-r--r--ReferenceCode/ME/Heci/Dxe/Hecidrv.c1540
-rw-r--r--ReferenceCode/ME/Heci/Dxe/Hecidrv.dxs43
-rw-r--r--ReferenceCode/ME/Heci/Dxe/Hecidrv.h70
-rw-r--r--ReferenceCode/ME/Heci/Dxe/Hecidrv.inf99
-rw-r--r--ReferenceCode/ME/Heci/Dxe/MeFvi.c49
-rw-r--r--ReferenceCode/ME/Heci/Include/HeciInclude.cif9
-rw-r--r--ReferenceCode/ME/Heci/Include/HeciInclude.sdl9
-rw-r--r--ReferenceCode/ME/Heci/Include/HeciRegs.h275
-rw-r--r--ReferenceCode/ME/Heci/MeHeci.cif13
-rw-r--r--ReferenceCode/ME/Heci/MeHeci.sdl19
-rw-r--r--ReferenceCode/ME/Heci/Pei/HeciCore.c1247
-rw-r--r--ReferenceCode/ME/Heci/Pei/HeciInit.c182
-rw-r--r--ReferenceCode/ME/Heci/Pei/HeciInit.dxs45
-rw-r--r--ReferenceCode/ME/Heci/Pei/HeciInit.h390
-rw-r--r--ReferenceCode/ME/Heci/Pei/HeciInit.inf82
-rw-r--r--ReferenceCode/ME/Heci/Pei/HeciPei.cif14
-rw-r--r--ReferenceCode/ME/Heci/Pei/HeciPei.mak48
-rw-r--r--ReferenceCode/ME/Heci/Pei/HeciPei.sdl24
-rw-r--r--ReferenceCode/ME/Heci/Smm/HeciHpet.c282
-rw-r--r--ReferenceCode/ME/Heci/Smm/HeciHpet.h197
-rw-r--r--ReferenceCode/ME/Heci/Smm/HeciSmm.c228
-rw-r--r--ReferenceCode/ME/Heci/Smm/HeciSmm.cif16
-rw-r--r--ReferenceCode/ME/Heci/Smm/HeciSmm.dxs51
-rw-r--r--ReferenceCode/ME/Heci/Smm/HeciSmm.inf102
-rw-r--r--ReferenceCode/ME/Heci/Smm/HeciSmm.mak64
-rw-r--r--ReferenceCode/ME/Heci/Smm/HeciSmm.sdl25
-rw-r--r--ReferenceCode/ME/Heci/Smm/Hecicore.c1585
-rw-r--r--ReferenceCode/ME/Heci/Smm/Hecicore.h512
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