diff options
author | raywu <raywu0301@gmail.com> | 2018-06-15 00:00:50 +0800 |
---|---|---|
committer | raywu <raywu0301@gmail.com> | 2018-06-15 00:00:50 +0800 |
commit | b7c51c9cf4864df6aabb99a1ae843becd577237c (patch) | |
tree | eebe9b0d0ca03062955223097e57da84dd618b9a /ReferenceCode/ME/Heci/Dxe | |
download | zprj-b7c51c9cf4864df6aabb99a1ae843becd577237c.tar.xz |
Diffstat (limited to 'ReferenceCode/ME/Heci/Dxe')
-rw-r--r-- | ReferenceCode/ME/Heci/Dxe/HeciDxe.cif | 18 | ||||
-rw-r--r-- | ReferenceCode/ME/Heci/Dxe/HeciDxe.mak | 65 | ||||
-rw-r--r-- | ReferenceCode/ME/Heci/Dxe/HeciDxe.sdl | 24 | ||||
-rw-r--r-- | ReferenceCode/ME/Heci/Dxe/HeciHpet.c | 168 | ||||
-rw-r--r-- | ReferenceCode/ME/Heci/Dxe/HeciHpet.h | 115 | ||||
-rw-r--r-- | ReferenceCode/ME/Heci/Dxe/Hecicore.c | 1461 | ||||
-rw-r--r-- | ReferenceCode/ME/Heci/Dxe/Hecicore.h | 342 | ||||
-rw-r--r-- | ReferenceCode/ME/Heci/Dxe/Hecidrv.c | 1540 | ||||
-rw-r--r-- | ReferenceCode/ME/Heci/Dxe/Hecidrv.dxs | 43 | ||||
-rw-r--r-- | ReferenceCode/ME/Heci/Dxe/Hecidrv.h | 70 | ||||
-rw-r--r-- | ReferenceCode/ME/Heci/Dxe/Hecidrv.inf | 99 | ||||
-rw-r--r-- | ReferenceCode/ME/Heci/Dxe/MeFvi.c | 49 |
12 files changed, 3994 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); |