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/Smm | |
download | zprj-master.tar.xz |
Diffstat (limited to 'ReferenceCode/ME/Heci/Smm')
-rw-r--r-- | ReferenceCode/ME/Heci/Smm/HeciHpet.c | 282 | ||||
-rw-r--r-- | ReferenceCode/ME/Heci/Smm/HeciHpet.h | 197 | ||||
-rw-r--r-- | ReferenceCode/ME/Heci/Smm/HeciSmm.c | 228 | ||||
-rw-r--r-- | ReferenceCode/ME/Heci/Smm/HeciSmm.cif | 16 | ||||
-rw-r--r-- | ReferenceCode/ME/Heci/Smm/HeciSmm.dxs | 51 | ||||
-rw-r--r-- | ReferenceCode/ME/Heci/Smm/HeciSmm.inf | 102 | ||||
-rw-r--r-- | ReferenceCode/ME/Heci/Smm/HeciSmm.mak | 64 | ||||
-rw-r--r-- | ReferenceCode/ME/Heci/Smm/HeciSmm.sdl | 25 | ||||
-rw-r--r-- | ReferenceCode/ME/Heci/Smm/Hecicore.c | 1585 | ||||
-rw-r--r-- | ReferenceCode/ME/Heci/Smm/Hecicore.h | 512 |
10 files changed, 3062 insertions, 0 deletions
diff --git a/ReferenceCode/ME/Heci/Smm/HeciHpet.c b/ReferenceCode/ME/Heci/Smm/HeciHpet.c new file mode 100644 index 0000000..2f75571 --- /dev/null +++ b/ReferenceCode/ME/Heci/Smm/HeciHpet.c @@ -0,0 +1,282 @@ +/*++ + This file contains an 'Intel Peripheral Driver' and uniquely + identified as "Intel Reference Module" and is + licensed for Intel CPUs and chipsets under the terms of your + license agreement with Intel or your vendor. This file may + be modified by the user, subject to additional terms of the + license agreement +--*/ +/*++ + +Copyright (c) 2006 - 2010 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +Module Name: + + HeciHpet.c + +Abstract: + + Definitions for HECI driver + +--*/ +#include "HeciHpet.h" +#include "HeciRegs.h" +#include "HeciCore.h" + +// +// Extern for shared HECI data and protocols +// +extern HECI_INSTANCE_SMM *mHeciContext; +VOLATILE UINT32 mSaveHpetConfigReg; + +VOID +SaveHpet ( + VOID + ) +/*++ + +Routine Description: + + Store the value of High Performance Timer + +Arguments: + + None + +Returns: + + None + +--*/ +{ + mSaveHpetConfigReg = MmioRead32 (PCH_RCRB_BASE + R_PCH_RCRB_HPTC); +} + +VOID +RestoreHpet ( + VOID + ) +/*++ + +Routine Description: + + Restore the value of High Performance Timer + +Arguments: + + None + +Returns: + + None + +--*/ +{ + MmioWrite32 (PCH_RCRB_BASE + R_PCH_RCRB_HPTC, mSaveHpetConfigReg); +} + +VOID +StartTimer ( + OUT UINT32 *Start, + OUT UINT32 *End, + IN UINT32 Time + ) +/*++ + + Routine Description: + + Used for calculating timeouts + + Arguments: + + Start - Snapshot of the HPET timer + End - Calculated time when timeout period will be done + Time - Timeout period in microseconds + + Returns: + + VOID + +--*/ +{ + UINT32 Ticks; + + // + // Make sure that HPET is enabled and running + // + EnableHpet (); + + // + // Read current timer value into start time from HPET + // + *Start = mHeciContext->HpetTimer[HPET_MAIN_COUNTER_LOW]; + + // + // Convert microseconds into 70ns timer ticks + // + Ticks = Time * HPET_TICKS_PER_MICRO; + + // + // Compute end time + // + *End = *Start + Ticks; + + return ; +} + +EFI_STATUS +Timeout ( + IN UINT32 Start, + IN UINT32 End + ) +/*++ + + Routine Description: + Used to determine if a timeout has occured. + + Arguments: + Start - Snapshot of the HPET timer when the timeout period started. + End - Calculated time when timeout period will be done. + + Returns: + EFI_STATUS + +--*/ +{ + UINT32 Current; + + // + // Read HPET and assign the value as the current time. + // + Current = mHeciContext->HpetTimer[HPET_MAIN_COUNTER_LOW]; + + // + // Test basic case (no overflow) + // + if ((Start < End) && (End <= Current)) { + return EFI_TIMEOUT; + } + // + // Test basic start/end conditions with overflowed timer + // + if ((Start < End) && (Current < Start)) { + return EFI_TIMEOUT; + } + // + // Test for overflowed start/end condition + // + if ((Start > End) && ((Current < Start) && (Current > End))) { + return EFI_TIMEOUT; + } + // + // Catch corner case of broken arguments + // + if (Start == End) { + return EFI_TIMEOUT; + } + // + // Else, we have not yet timed out + // + return EFI_SUCCESS; +} + +VOID +IoDelay ( + UINT32 delayTime + ) +/*++ + +Routine Description: + + Delay for at least the request number of microseconds + +Arguments: + + delayTime - Number of microseconds to delay. + +Returns: + + None. + +--*/ +{ + SmmStall (delayTime); +} + +VOID +SmmStall ( + IN UINTN Microseconds + ) +/*++ + +Routine Description: + + Delay for at least the request number of microseconds. + Timer used is DMA refresh timer, which has 15us granularity. + You can call with any number of microseconds, but this + implementation cannot support 1us granularity. + +Arguments: + + Microseconds - Number of microseconds to delay. + +Returns: + + None + +--*/ +{ + UINT8 Data; + UINT8 InitialState; + UINTN CycleIterations; + + CycleIterations = 0; + Data = 0; + InitialState = 0; + + // + // The time-source is 15 us granular, so calibrate the timing loop + // based on this baseline + // Error is possible 15us. + // + CycleIterations = (Microseconds / 15) + 1; + + // + // Use the DMA Refresh timer in port 0x61. Cheap but effective. + // The only issue is that the granularity is 15us, and we want to + // guarantee "at least" one full transition to avoid races. + // + // + // _____________/----------\__________/-------- + // + // |<--15us-->| + // + // --------------------------------------------------> Time (us) + // + while (CycleIterations--) { + Data = IoRead8 (0x61); + InitialState = Data; + + // + // Capture first transition (strictly less than one period) + // + while (InitialState == Data) { + Data = IoRead8 (0x61); + } + + InitialState = Data; + // + // Capture next transition (guarantee at least one full pulse) + // + while (InitialState == Data) { + Data = IoRead8 (0x61); + } + } +} diff --git a/ReferenceCode/ME/Heci/Smm/HeciHpet.h b/ReferenceCode/ME/Heci/Smm/HeciHpet.h new file mode 100644 index 0000000..8624445 --- /dev/null +++ b/ReferenceCode/ME/Heci/Smm/HeciHpet.h @@ -0,0 +1,197 @@ +/*++ + This file contains an 'Intel Peripheral Driver' and uniquely + identified as "Intel Reference Module" and is + licensed for Intel CPUs and chipsets under the terms of your + license agreement with Intel or your vendor. This file may + be modified by the user, subject to additional terms of the + license agreement +--*/ +/*++ + +Copyright (c) 2006 - 2010 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +Module Name: + + HeciHpet.h + +Abstract: + + Definitions for HECI driver + +--*/ +#ifndef _HECI_HPET_H +#define _HECI_HPET_H + +#include "EdkIIGlueDxe.h" +#include "MeAccess.h" +#include "HeciRegs.h" +#include "Pci22.h" + +#define HECI_PRIVATE_DATA_SIGNATURE EFI_SIGNATURE_32 ('H', 'e', 'c', 'i') +#define HECI_ROUND_UP_BUFFER_LENGTH(Length) ((UINT32) ((((Length) + 3) / 4) * 4)) + +// +// Driver Produced Protocol Prototypes +// +#include EFI_PROTOCOL_PRODUCER (HeciSmm) + +VOID +SaveHpet ( + VOID + ) +/*++ + +Routine Description: + + Store the value of High Performance Timer + +Arguments: + + None + +Returns: + + None + +--*/ +; + +VOID +RestoreHpet ( + VOID + ) +/*++ + +Routine Description: + + Restore the value of High Performance Timer + +Arguments: + + None + +Returns: + + None + +--*/ +; + +VOID +StartTimer ( + OUT UINT32 *Start, + OUT UINT32 *End, + IN UINT32 Time + ) +/*++ + + Routine Description: + + Used for calculating timeouts + + Arguments: + + Start - Snapshot of the HPET timer + End - Calculated time when timeout period will be done + Time - Timeout period in microseconds + + Returns: + + VOID + +--*/ +; + +EFI_STATUS +Timeout ( + IN UINT32 Start, + IN UINT32 End + ) +/*++ + + Routine Description: + Used to determine if a timeout has occured. + + Arguments: + Start - Snapshot of the HPET timer when the timeout period started. + End - Calculated time when timeout period will be done. + + Returns: + EFI_STATUS + +--*/ +; + +VOID +EnableHpet ( + VOID + ) +/*++ + +Routine Description: + + Enable Hpet function. + +Arguments: + + None. + +Returns: + + None. + +--*/ +; + +VOID +IoDelay ( + UINT32 delayTime + ) +/*++ + +Routine Description: + + Delay for at least the request number of microseconds + +Arguments: + + delayTime - Number of microseconds to delay. + +Returns: + + None. + +--*/ +; + +VOID +SmmStall ( + IN UINTN Microseconds + ) +/*++ + +Routine Description: + + Delay for at least the request number of microseconds. + Timer used is DMA refresh timer, which has 15us granularity. + You can call with any number of microseconds, but this + implementation cannot support 1us granularity. + +Arguments: + + Microseconds - Number of microseconds to delay. + +Returns: + + None + +--*/ +; +#endif // _HECI_HPET_H diff --git a/ReferenceCode/ME/Heci/Smm/HeciSmm.c b/ReferenceCode/ME/Heci/Smm/HeciSmm.c new file mode 100644 index 0000000..df1f165 --- /dev/null +++ b/ReferenceCode/ME/Heci/Smm/HeciSmm.c @@ -0,0 +1,228 @@ +/*++ + This file contains an 'Intel Peripheral Driver' and uniquely + identified as "Intel Reference Module" and is + licensed for Intel CPUs and chipsets under the terms of your + license agreement with Intel or your vendor. This file may + be modified by the user, subject to additional terms of the + license agreement +--*/ +/*++ + +Copyright (c) 2008 - 2010 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +Module Name: + + HeciSmm.c + +Abstract: + + SMM HECI driver + +--*/ + +// +// External include files do NOT need to be explicitly specified in real EDKII +// environment +// +#if !defined(EDK_RELEASE_VERSION) || (EDK_RELEASE_VERSION < 0x00020000) +#include "HeciHpet.h" +#include "HeciCore.h" +#endif // EDK_RELEASE_VERSION +// +// Global driver data +// +EFI_SMM_BASE_PROTOCOL *mSmmBase; +HECI_INSTANCE_SMM *mHeciContext; + +UINT32 +CheckAndFixHeciForAccess ( + VOID + ) +/*++ + +Routine Description: + This function provides a standard way to verify the HECI cmd and MBAR regs + in its PCI cfg space are setup properly and that the local mHeciContext + variable matches this info. + +Arguments: + None. + +Returns: + VOID + +--*/ +{ + UINTN HeciPciAddressBase; + + HeciPciAddressBase = mHeciContext->PciAddressBase; + + // + // Read HECI_MBAR in case it has changed + // + mHeciContext->HeciMBAR = PciRead32 (HeciPciAddressBase + R_HECIMBAR) & 0xFFFFFFF0; + + // + // Check if HECI_MBAR is disabled + // + if (( + PciRead8 (HeciPciAddressBase + PCI_COMMAND_OFFSET) & (EFI_PCI_COMMAND_MEMORY_SPACE | EFI_PCI_COMMAND_BUS_MASTER) + ) != (EFI_PCI_COMMAND_MEMORY_SPACE | EFI_PCI_COMMAND_BUS_MASTER) + ) { + // + // If cmd reg in pci cfg space is not turned on turn it on. + // + PciOr8 ( + HeciPciAddressBase + PCI_COMMAND_OFFSET, + EFI_PCI_COMMAND_MEMORY_SPACE | EFI_PCI_COMMAND_BUS_MASTER + ); + } + + return mHeciContext->HeciMBAR; +} + +VOID +EnableHpet ( + VOID + ) +/*++ + +Routine Description: + + Enable Hpet function. + +Arguments: + + None. + +Returns: + + None. + +--*/ +{ + VOLATILE UINT32 *HpetConfigReg; + + HpetConfigReg = NULL; + // + // Get the High Precision Event Timer base address and enable the memory range + // + HpetConfigReg = (UINT32 *) (UINTN) (PCH_RCRB_BASE + R_PCH_RCRB_HPTC); + switch (*HpetConfigReg & B_PCH_RCRB_HPTC_AS) { + case 0: + mHeciContext->HpetTimer = (VOID *) (UINTN) (HPET_ADDRESS_0); + break; + + case 1: + mHeciContext->HpetTimer = (VOID *) (UINTN) (HPET_ADDRESS_1); + break; + + case 2: + mHeciContext->HpetTimer = (VOID *) (UINTN) (HPET_ADDRESS_2); + break; + + case 3: + mHeciContext->HpetTimer = (VOID *) (UINTN) (HPET_ADDRESS_3); + break; + + default: + mHeciContext->HpetTimer = NULL; + break; + } + // + // Read this back to force the write-back. + // + *HpetConfigReg = *HpetConfigReg | B_PCH_RCRB_HPTC_AE; + + // + // Start the timer so it is up and running + // + mHeciContext->HpetTimer[HPET_GEN_CONFIG_LOW] = HPET_START; + mHeciContext->HpetTimer[HPET_GEN_CONFIG_LOW] = HPET_START; + + return ; +} + +EFI_STATUS +InitializeHECI ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + HECI driver entry point used to initialize support for the HECI device. + +Arguments: + ImageHandle - Standard entry point parameter. + SystemTable - Standard entry point parameter. + +Returns: + EFI_STATUS + +--*/ +{ + EFI_STATUS Status; + + Status = gBS->LocateProtocol (&gEfiSmmBaseProtocolGuid, NULL, &mSmmBase); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Create database record and add to database + // + Status = mSmmBase->SmmAllocatePool ( + mSmmBase, + EfiRuntimeServicesData, + sizeof (HECI_INSTANCE_SMM), + &mHeciContext + ); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + return Status; + } + + mHeciContext->Handle = ImageHandle; + + // + // Initialize HECI protocol pointers + // + mHeciContext->HeciCtlr.ResetHeci = ResetHeciInterface; + mHeciContext->HeciCtlr.SendwACK = HeciSendwACK; + mHeciContext->HeciCtlr.ReadMsg = HeciReceive; + mHeciContext->HeciCtlr.SendMsg = HeciSend; + mHeciContext->HeciCtlr.InitHeci = HeciInitialize; + mHeciContext->HeciCtlr.ReInitHeci = HeciReInitialize; + mHeciContext->HeciCtlr.MeResetWait = MeResetWait; + mHeciContext->HeciCtlr.GetMeStatus = HeciGetMeStatus; + mHeciContext->HeciCtlr.GetMeMode = HeciGetMeMode; + // + // Initialize the HECI device + // + Status = InitializeHeciPrivate (); + if (EFI_ERROR (Status)) { + return EFI_SUCCESS; + } + // + // Install the HECI interface + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &mHeciContext->Handle, + &gSmmHeciProtocolGuid, + &mHeciContext->HeciCtlr, + NULL + ); + if (EFI_ERROR (Status)) { + return EFI_SUCCESS; + } + + return EFI_SUCCESS; +} diff --git a/ReferenceCode/ME/Heci/Smm/HeciSmm.cif b/ReferenceCode/ME/Heci/Smm/HeciSmm.cif new file mode 100644 index 0000000..3ddcf24 --- /dev/null +++ b/ReferenceCode/ME/Heci/Smm/HeciSmm.cif @@ -0,0 +1,16 @@ +<component> + name = "HeciSmm" + category = ModulePart + LocalRoot = "ReferenceCode\ME\Heci\Smm\" + RefName = "HeciSmm" +[files] +"HeciSmm.sdl" +"HeciSmm.mak" +"Hecicore.c" +"Hecicore.h" +"HeciSmm.c" +"HeciSmm.dxs" +"HeciHpet.c" +"HeciHpet.h" +"HeciSmm.inf" +<endComponent> diff --git a/ReferenceCode/ME/Heci/Smm/HeciSmm.dxs b/ReferenceCode/ME/Heci/Smm/HeciSmm.dxs new file mode 100644 index 0000000..9c3676a --- /dev/null +++ b/ReferenceCode/ME/Heci/Smm/HeciSmm.dxs @@ -0,0 +1,51 @@ +/*++ + This file contains a 'Sample Driver' and is licensed as such + under the terms of your license agreement with Intel or your + vendor. This file may be modified by the user, subject to + the additional terms of the license agreement +--*/ +/*++ + +Copyright (c) 2010 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +Module Name: + + HeciSmm.dxs + +Abstract: + + Dependency expression source file. + +--*/ + +// +// Common for R8 and R9 codebase +// +#include "AutoGen.h" +#include "DxeDepex.h" + +// +// BUILD_WITH_GLUELIB and BUILD_WITH_EDKII_GLUE_LIB are both "defined" in R8 codebase; +// BUILD_WITH_EDKII_GLUE_LIB is defined in Edk-Dev-Snapshot-20070228 and later version +// BUILD_WITH_GLUELIB and BUILD_WITH_EDKII_GLUE_LIB are "not defined" in R9 codebase. +// +#if defined (BUILD_WITH_GLUELIB) || defined (BUILD_WITH_EDKII_GLUE_LIB) +#include "EfiDepex.h" +#include EFI_PROTOCOL_DEFINITION (SmmBase) +#include EFI_PROTOCOL_DEFINITION (CpuIo) +#include EFI_PROTOCOL_DEFINITION (PciRootBridgeIo) +#endif + +DEPENDENCY_START + EFI_CPU_IO_PROTOCOL_GUID AND + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_GUID AND + EFI_SMM_BASE_PROTOCOL_GUID +DEPENDENCY_END + diff --git a/ReferenceCode/ME/Heci/Smm/HeciSmm.inf b/ReferenceCode/ME/Heci/Smm/HeciSmm.inf new file mode 100644 index 0000000..600e1f2 --- /dev/null +++ b/ReferenceCode/ME/Heci/Smm/HeciSmm.inf @@ -0,0 +1,102 @@ +#/*++ +# This file contains a 'Sample Driver' and is licensed as such +# under the terms of your license agreement with Intel or your +# vendor. This file may be modified by the user, subject to +# the additional terms of the license agreement +#--*/ +#/*++ +# +# Copyright (c) 2007 - 2010 Intel Corporation. All rights reserved +# This software and associated documentation (if any) is furnished +# under a license and may only be used or copied in accordance +# with the terms of the license. Except as permitted by such +# license, no part of this software or documentation may be +# reproduced, stored in a retrieval system, or transmitted in any +# form or by any means without the express written consent of +# Intel Corporation. +# +# Module Name: +# +# HeciSmm.inf +# +# Abstract: +# +# Component description file for Heci SMM driver +# +#--*/ + +[defines] +BASE_NAME = HeciSmm +FILE_GUID = 921CD783-3E22-4579-A71F-00D74197FCC8 +COMPONENT_TYPE = BS_DRIVER + +[sources.common] + HeciSmm.c + Hecicore.c + HeciCore.h + HeciHpet.c + HeciHpet.h + +# +# Edk II Glue Driver Entry Point +# + EdkIIGlueSmmDriverEntryPoint.c + +[includes.common] + $(EDK_SOURCE)\Foundation + $(EDK_SOURCE)\Foundation\Framework + $(EDK_SOURCE)\Foundation\Efi + $(EDK_SOURCE)\Foundation\Include + $(EDK_SOURCE)\Foundation\Efi\Include + $(EDK_SOURCE)\Foundation\Framework\Include + $(EDK_SOURCE)\Foundation\Library\Dxe\Include + $(EDK_SOURCE)\Foundation\Include\IndustryStandard + $(EDK_SOURCE)\Foundation\Cpu\Pentium\Include + $(EFI_SOURCE)\$(PROJECT_ME_ROOT) + $(EFI_SOURCE)\$(PROJECT_ME_ROOT)\Library\MeKernel\Dxe + $(EFI_SOURCE)\$(PROJECT_ME_ROOT)\Library\MeKernel\Include + $(EFI_SOURCE)\$(PROJECT_ME_ROOT)\Heci\Include + +# +# Edk II Glue Library, some hearder are included by R9 header so have to include +# + $(EFI_SOURCE) + $(EFI_SOURCE)\Framework + $(EDK_SOURCE)\Foundation + $(EDK_SOURCE)\Foundation\Framework + $(EDK_SOURCE)\Foundation\Include\IndustryStandard + $(EDK_SOURCE)\Foundation\Core\Dxe + $(EDK_SOURCE)\Foundation\Include\Pei + $(EDK_SOURCE)\Foundation\Library\Dxe\Include + $(EDK_SOURCE)\Foundation\Library\EdkIIGlueLib\Include + +[libraries.common] + MeProtocolLib + MeLib + MeChipsetLib + EdkProtocolLib + EdkFrameworkProtocolLib + EdkIIGlueBaseLib + EdkIIGlueBasePciLibPciExpress + EdkIIGlueDxeMemoryAllocationLib + EdkIIGlueDxeServicesTableLib + EdkIIGluePeiDxeDebugLibReportStatusCode + EdkIIGlueSmmRuntimeDxeReportStatusCodeLib + EdkIIGlueUefiBootServicesTableLib + EdkIIGlueUefiDevicePathLib + +[nmake.common] + IMAGE_ENTRY_POINT=_ModuleEntryPoint + DPX_SOURCE=HeciSmm.dxs +# +# Module Entry Point +# + C_FLAGS = $(C_FLAGS) /D__EDKII_GLUE_MODULE_ENTRY_POINT__=InitializeHECI + C_FLAGS = $(C_FLAGS) /D __EDKII_GLUE_BASE_LIB__ \ + /D __EDKII_GLUE_BASE_PCI_LIB_PCI_EXPRESS__ \ + /D __EDKII_GLUE_DXE_MEMORY_ALLOCATION_LIB__ \ + /D __EDKII_GLUE_DXE_SERVICES_TABLE_LIB__ \ + /D __EDKII_GLUE_PEI_DXE_DEBUG_LIB_REPORT_STATUS_CODE__\ + /D __EDKII_GLUE_SMM_RUNTIME_DXE_REPORT_STATUS_CODE_LIB__ \ + /D __EDKII_GLUE_UEFI_BOOT_SERVICES_TABLE_LIB__\ + /D __EDKII_GLUE_UEFI_DEVICE_PATH_LIB__ diff --git a/ReferenceCode/ME/Heci/Smm/HeciSmm.mak b/ReferenceCode/ME/Heci/Smm/HeciSmm.mak new file mode 100644 index 0000000..31006bc --- /dev/null +++ b/ReferenceCode/ME/Heci/Smm/HeciSmm.mak @@ -0,0 +1,64 @@ +# MAK file for the ModulePart:HeciSmm +all : HeciSmm + +HeciSmm : $(BUILD_DIR)\HeciSmm.mak HeciSmmBin + +$(BUILD_DIR)\HeciSmm.mak : $(HeciSmm_DIR)\$(@B).cif $(HeciSmm_DIR)\$(@B).mak $(CP_BUILD_RULES) + $(CIF2MAK) $(HeciSmm_DIR)\$(@B).cif $(CIF2MAK_DEFAULTS) + +HeciSmm_INCLUDES= \ + $(EDK_INCLUDES)\ + $(EdkIIGlueLib_INCLUDES)\ + $(ME_INCLUDES)\ + /I$(INTEL_COUGAR_POINT_INCLUDE_DIR) + + +HeciSmm_LIBS=\ + $(EDKPROTOCOLLIB)\ + $(MeProtocolLib_LIB)\ + $(MeLibDxe_LIB)\ + $(MeChipsetDxeLib_LIB)\ + $(MeGuidLib_LIB)\ + $(EFISCRIPTLIB)\ + $(EDKFRAMEWORKPROTOCOLLIB)\ + $(EFIGUIDLIB)\ + $(EdkIIGlueBaseLib_LIB)\ +!IF "$(x64_BUILD)"=="1" + $(EdkIIGlueBaseLibX64_LIB)\ +!ELSE + $(EdkIIGlueBaseLibIA32_LIB)\ +!ENDIF + $(EdkIIGlueBaseIoLibIntrinsic_LIB)\ + $(EdkIIGlueDxeReportStatusCodeLib_LIB)\ + $(EdkIIGlueDxeDebugLibReportStatusCode_LIB)\ + $(EdkIIGlueUefiBootServicesTableLib_LIB)\ + $(EdkIIGlueUefiLib_LIB)\ + $(EdkIIGlueBasePciLibPciExpress_LIB)\ + $(EdkIIGlueDxeServicesTableLib_LIB)\ + $(EFIDRIVERLIB)\ + $(RcFviDxeLib_LIB)\ + $(PchPlatformDxeLib_LIB) + +HeciSmm_DEFINES=$(MY_DEFINES)\ + /D"__EDKII_GLUE_MODULE_ENTRY_POINT__=InitializeHECI"\ + /D __EDKII_GLUE_BASE_IO_LIB_INTRINSIC__ \ + /D __EDKII_GLUE_DXE_REPORT_STATUS_CODE_LIB__ \ + /D __EDKII_GLUE_DXE_DEBUG_LIB_REPORT_STATUS_CODE__ \ + /D __EDKII_GLUE_UEFI_BOOT_SERVICES_TABLE_LIB__ \ + /D __EDKII_GLUE_UEFI_LIB__\ + /D __EDKII_GLUE_BASE_PCI_LIB_PCI_EXPRESS__ \ + /D __EDKII_GLUE_DXE_SERVICES_TABLE_LIB__ \ + +HeciSmmBin : $(HeciSmm_LIBS) + $(MAKE) /$(MAKEFLAGS) $(EDKIIGLUE_DEFAULTS)\ + /f $(BUILD_DIR)\HeciSmm.mak all\ + MAKEFILE=$(BUILD_DIR)\HeciSmm.mak\ + "MY_INCLUDES=$(HeciSmm_INCLUDES)"\ + "MY_DEFINES=$(HeciSmm_DEFINES)"\ + GUID=921CD783-3E22-4579-A71F-00D74197FCC8\ + DEPEX1=$(HeciSmm_DIR)\HeciSmm.dxs\ + DEPEX1_TYPE=EFI_SECTION_DXE_DEPEX \ + ENTRY_POINT=_ModuleEntryPoint \ + TYPE=RT_DRIVER\ + EDKIIModule=SMMDRIVER\ + COMPRESS=1 diff --git a/ReferenceCode/ME/Heci/Smm/HeciSmm.sdl b/ReferenceCode/ME/Heci/Smm/HeciSmm.sdl new file mode 100644 index 0000000..3165eee --- /dev/null +++ b/ReferenceCode/ME/Heci/Smm/HeciSmm.sdl @@ -0,0 +1,25 @@ +TOKEN + Name = "HeciSmm_SUPPORT" + Value = "1" + TokenType = Boolean + TargetEQU = Yes + TargetMAK = Yes + Master = Yes + Help = "Main switch to enable HeciSmm Suppport in Project" +End + +MODULE + Help = "Includes HeciSmm.mak to Project" + File = "HeciSmm.mak" +End + +ELINK + Name = "$(BUILD_DIR)\HeciSmm.ffs" + Parent = "FV_MAIN" + InvokeOrder = AfterParent +End + +PATH + Name = "HeciSmm_DIR" + Help = "iAMT Hec SMM Driver files source directory" +End
\ No newline at end of file diff --git a/ReferenceCode/ME/Heci/Smm/Hecicore.c b/ReferenceCode/ME/Heci/Smm/Hecicore.c new file mode 100644 index 0000000..612f2f6 --- /dev/null +++ b/ReferenceCode/ME/Heci/Smm/Hecicore.c @@ -0,0 +1,1585 @@ +/*++ + This file contains an 'Intel Peripheral Driver' and uniquely + identified as "Intel Reference Module" and is + licensed for Intel CPUs and chipsets under the terms of your + license agreement with Intel or your vendor. This file may + be modified by the user, subject to additional terms of the + license agreement +--*/ +/*++ + +Copyright (c) 2008 - 2010 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +Module Name: + + Hecicore.c + +Abstract: + + Heci driver core. For Dxe Phase, determines the HECI device and initializes it. + +--*/ +#include "HeciHpet.h" +#include "HeciCore.h" +#include "HeciRegs.h" +#include "MeState.h" + +// +// ////////////////////////////////////////////////////////////////////////////////// +// Globals used in Heci driver +//////////////////////////////////////////////////////////////////////////////////// +// +UINT16 HECICtlrBDF; +static UINT32 HeciMBAR = 0; + +// +// ////////////////////////////////////////////////////////////////////////////////// +// Macro definition for function used in Heci driver +//////////////////////////////////////////////////////////////////////////////////// +// +#define R_PCH_RCRB_FUNC_DIS2 0x3428 + +UINT32 +MmIoReadDword ( + UINTN a + ) +/*++ + +Routine Description: + + The routing of MmIo Read Dword + +Arguments: + + a - The address of Mmio + +Returns: + + Return the valut of MmIo Read + +--*/ +{ + volatile HECI_HOST_CONTROL_REGISTER *HeciRegHCsrPtr; + + HeciRegHCsrPtr = (HECI_HOST_CONTROL_REGISTER *) a; + return HeciRegHCsrPtr->ul; +} + +VOID +MmIoWriteDword ( + UINTN a, + UINT32 b + ) +/*++ + +Routine Description: + + The routing of MmIo Write Dword + +Arguments: + + a - The address of Mmio + b - Value revised + +Returns: + + None + +--*/ +{ + volatile HECI_HOST_CONTROL_REGISTER *HeciRegHCsrPtr; + + HeciRegHCsrPtr = (HECI_HOST_CONTROL_REGISTER *) a; + + HeciRegHCsrPtr->ul = b; +} + +#define MMIOREADDWORD(a) MmIoReadDword (a) +#define MMIOWRITEDWORD(a, b) MmIoWriteDword (a, b) + +// +// Extern for shared HECI data and protocols +// +extern HECI_INSTANCE_SMM *mHeciContext; + +// +// ////////////////////////////////////////////////////////////////////////////////// +// Forward declaration +//////////////////////////////////////////////////////////////////////////////////// +// +UINT8 +FilledSlots ( + IN UINT32 ReadPointer, + IN UINT32 WritePointer + ); + +EFI_STATUS +OverflowCB ( + IN UINT32 ReadPointer, + IN UINT32 WritePointer, + IN UINT32 BufferDepth + ); + +EFI_STATUS +WaitForMEReady ( + VOID + ); + +// +// Heci driver function definitions +// +EFI_STATUS +InitializeHeciPrivate ( + VOID + ) +/*++ + + Routine Description: + Determines if the HECI device is present and, if present, initializes it for + use by the BIOS. + + Arguments: + None. + + Returns: + EFI_STATUS + +--*/ +{ + HECI_HOST_CONTROL_REGISTER HeciRegHCsr; + VOLATILE HECI_HOST_CONTROL_REGISTER *HeciRegHCsrPtr; + UINT32 MeMode; + EFI_STATUS Status; + UINTN HeciPciAddressBase; + + Status = EFI_SUCCESS; + + SaveHpet (); + + do { + // + // Check for ME FPT Bad + // + if ((HeciPciRead32 (R_FWSTATE) & 0x0020) != 0) { + Status = EFI_DEVICE_ERROR; + break; + } + // + // Check for ME error status + // + if ((HeciPciRead32 (R_FWSTATE) & 0xF000) != 0) { + // + // ME failed to start so no HECI + // + Status = EFI_DEVICE_ERROR; + break; + } + // + // Check ME Operation Mode to decice which HECI to use in SMM mode + // + Status = HeciGetMeMode (&MeMode); + ASSERT_EFI_ERROR (Status); + + // + // HECI MSG is unsupported if ME MODE is in Security Override + // + mHeciContext->MeMode = MeMode; + if (mHeciContext->MeMode == ME_MODE_DEBUG) { + Status = EFI_UNSUPPORTED; + break; + } + + HeciPciAddressBase = PCI_LIB_ADDRESS ( + ME_BUS, + ME_DEVICE_NUMBER, + HECI_FUNCTION_NUMBER, + 0 + ); + mHeciContext->HeciDevSaveEnable = Heci2DevSaveEnable; + mHeciContext->PciAddressBase = HeciPciAddressBase; + + // + // Store HECI vendor and device information away + // + mHeciContext->DeviceInfo = PciRead16 (HeciPciAddressBase + PCI_DEVICE_ID_OFFSET); + + // + // Check for HECI-2 PCI device availability + // + if (mHeciContext->DeviceInfo == 0xFFFF) { + Status = EFI_DEVICE_ERROR; + break; + } + // + // Store HECI revision ID + // + mHeciContext->RevisionInfo = PciRead8 (HeciPciAddressBase + PCI_REVISION_ID_OFFSET); + + // + // Get HECI_MBAR and see if it is programmed + // to a useable value + // + mHeciContext->HeciMBAR = PciRead32 (HeciPciAddressBase + R_HECIMBAR) & 0xFFFFFFF0; + HeciMBAR = mHeciContext->HeciMBAR; + + // + // Load temporary address for HECI_MBAR if one is not assigned + // + if (mHeciContext->HeciMBAR == 0) { + // + // mHeciContext->HeciMBAR = mHeciContext->DefaultHeciBar; + // PciWrite32 (HeciPciAddressBase + R_HECIMBAR, mHeciContext->HeciMBAR); + // HeciMBAR = mHeciContext->HeciMBAR; + // + DEBUG ((EFI_D_ERROR, "Heci MMIO Bar not programmed in SMM phase\n")); + } + // + // Enable HECI BME and MSE + // + PciOr8 ( + HeciPciAddressBase + PCI_COMMAND_OFFSET, + EFI_PCI_COMMAND_MEMORY_SPACE | EFI_PCI_COMMAND_BUS_MASTER + ); + + // + // Set HECI interrupt delivery mode. + // HECI-2 using legacy/MSI interrupt + // + PciAnd8 (HeciPciAddressBase + R_HIDM, 0xFC); + + // + // Need to do following on ME init: + // + // 1) wait for ME_CSR_HA reg ME_RDY bit set + // + if (WaitForMEReady () != EFI_SUCCESS) { + Status = EFI_TIMEOUT; + break; + } + // + // 2) setup H_CSR reg as follows: + // a) Make sure H_RST is clear + // b) Set H_RDY + // c) Set H_IG + // + HeciRegHCsrPtr = (VOID *) (UINTN) (mHeciContext->HeciMBAR + H_CSR); + HeciRegHCsr.ul = HeciRegHCsrPtr->ul; + if (HeciRegHCsrPtr->r.H_RDY == 0) { + HeciRegHCsr.r.H_RST = 0; + HeciRegHCsr.r.H_RDY = 1; + HeciRegHCsr.r.H_IG = 1; + HeciRegHCsrPtr->ul = HeciRegHCsr.ul; + } + + } while (EFI_ERROR (Status)); + + RestoreHpet (); + + return Status; +} + +EFI_STATUS +WaitForMEReady ( + VOID + ) +/*++ + + Routine Description: + Waits for the ME to report that it is ready for communication over the HECI + interface. + + Arguments: + None. + + Returns: + EFI_STATUS + +--*/ +{ + UINT32 TimerStart; + UINT32 TimerEnd; + HECI_ME_CONTROL_REGISTER HeciRegMeCsrHa; + + // + // Wait for ME ready + // + // + // Check for ME ready status + // + StartTimer (&TimerStart, &TimerEnd, HECI_INIT_TIMEOUT); + HeciRegMeCsrHa.ul = MMIOREADDWORD (HeciMBAR + ME_CSR_HA); + while (HeciRegMeCsrHa.r.ME_RDY_HRA == 0) { + // + // If 5 second timeout has expired, return fail + // + if (Timeout (TimerStart, TimerEnd) != EFI_SUCCESS) { + return EFI_TIMEOUT; + } + // + // Perform IO delay + // + IoDelay (HECI_WAIT_DELAY); + + HeciRegMeCsrHa.ul = MMIOREADDWORD (HeciMBAR + ME_CSR_HA); + } + // + // ME ready!!! + // + return EFI_SUCCESS; +} + +BOOLEAN +CheckForHeciReset ( + VOID + ) +/*++ + + Routine Description: + Checks if HECI reset has occured. + + Arguments: + None. + + Returns: + TRUE - HECI reset occurred + FALSE - No HECI reset occurred + +--*/ +{ + HECI_HOST_CONTROL_REGISTER HeciRegHCsr; + HECI_ME_CONTROL_REGISTER HeciRegMeCsrHa; + + // + // Init Host & ME CSR + // + HeciRegHCsr.ul = MMIOREADDWORD (HeciMBAR + H_CSR); + HeciRegMeCsrHa.ul = MMIOREADDWORD (HeciMBAR + ME_CSR_HA); + + if ((HeciRegMeCsrHa.r.ME_RDY_HRA == 0) || (HeciRegHCsr.r.H_RDY == 0)) { + return TRUE; + } + + return FALSE; +} + +EFI_STATUS +HeciInitialize ( + VOID + ) +/*++ + + Routine Description: + Determines if the HECI device is present and, if present, initializes it for + use by the BIOS. + + Arguments: + None. + + Returns: + EFI_STATUS + +--*/ +{ + HECI_HOST_CONTROL_REGISTER HeciRegHCsr; + + // + // Make sure that HECI device BAR is correct and device is enabled. + // + HeciMBAR = CheckAndFixHeciForAccess (); + + // + // Need to do following on ME init: + // + // 1) wait for ME_CSR_HA reg ME_RDY bit set + // + if (WaitForMEReady () != EFI_SUCCESS) { + return EFI_TIMEOUT; + } + // + // 2) setup H_CSR reg as follows: + // a) Make sure H_RST is clear + // b) Set H_RDY + // c) Set H_IG + // + HeciRegHCsr.ul = MMIOREADDWORD (HeciMBAR + H_CSR); + if (HeciRegHCsr.r.H_RDY == 0) { + HeciRegHCsr.r.H_RST = 0; + HeciRegHCsr.r.H_RDY = 1; + HeciRegHCsr.r.H_IG = 1; + MMIOWRITEDWORD (HeciMBAR + H_CSR, HeciRegHCsr.ul); + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +HeciReInitialize ( + VOID + ) +/*++ + + Routine Description: + Heci Re-initializes it for Host + + Arguments: + None. + + Returns: + EFI_STATUS + +--*/ +{ + HECI_HOST_CONTROL_REGISTER HeciRegHCsr; + EFI_STATUS Status; + + Status = EFI_SUCCESS; + // + // Need to do following on ME init: + // + // 1) wait for HOST_CSR_HA reg H_RDY bit set + // + // if (WaitForHostReady() != EFI_SUCCESS) { + // + if (MeResetWait (HECI_INIT_TIMEOUT) != EFI_SUCCESS) { + return EFI_TIMEOUT; + } + + HeciRegHCsr.ul = MMIOREADDWORD (HeciMBAR + H_CSR); + if (HeciRegHCsr.r.H_RDY == 0) { + Status = ResetHeciInterface (); + + } + + return Status; +} + +EFI_STATUS +EFIAPI +HeciReInitialize2 ( + VOID + ) +/*++ + + Routine Description: + Heci Re-initializes it for Me + + Arguments: + None. + + Returns: + EFI_STATUS + +--*/ +{ + HECI_ME_CONTROL_REGISTER HeciRegMeCsrHa; + EFI_STATUS Status; + UINT32 TimerStart; + UINT32 TimerEnd; + Status = EFI_SUCCESS; + // + // Need to do following on ME init: + // + // 1) wait for HOST_CSR_HA reg H_RDY bit set + // + // if (WaitForHostReady() != EFI_SUCCESS) { + // + StartTimer (&TimerStart, &TimerEnd, HECI_INIT_TIMEOUT); + HeciRegMeCsrHa.ul = MMIOREADDWORD (HeciMBAR + ME_CSR_HA); + while (HeciRegMeCsrHa.r.ME_RDY_HRA == 1) { + // + // If 5 second timeout has expired, return fail + // + if (Timeout (TimerStart, TimerEnd) != EFI_SUCCESS) { + return EFI_TIMEOUT; + } + + IoDelay (HECI_WAIT_DELAY); + + HeciRegMeCsrHa.ul = MMIOREADDWORD (HeciMBAR + ME_CSR_HA); + } + + if (WaitForMEReady () != EFI_SUCCESS) { + return EFI_TIMEOUT; + } + + return Status; +} + +EFI_STATUS +HECIPacketRead ( + IN UINT32 Blocking, + OUT HECI_MESSAGE_HEADER *MessageHeader, + OUT UINT32 *MessageData, + IN OUT UINT32 *Length + ) +/*++ + + Routine Description: + Function to pull one messsage packet off the HECI circular buffer. + Corresponds to HECI HPS (part of) section 4.2.4 + + + Arguments: + Blocking - Used to determine if the read is BLOCKING or NON_BLOCKING. + MessageHeader - Pointer to a buffer for the message header. + MessageData - Pointer to a buffer to recieve the message in. + Length - On input is the size of the callers buffer in bytes. On + output this is the size of the packet in bytes. + + Returns: + EFI_STATUS + +--*/ +{ + BOOLEAN GotMessage; + UINT32 TimerStart; + UINT32 TimerEnd; + UINT32 TimerStart1; + UINT32 TimerEnd1; + UINT32 i; + UINT32 LengthInDwords; + HECI_ME_CONTROL_REGISTER HeciRegMeCsrHa; + HECI_HOST_CONTROL_REGISTER HeciRegHCsr; + + GotMessage = FALSE; + // + // Initialize memory mapped register pointers + // + // VOLATILE HECI_HOST_CONTROL_REGISTER *HeciRegHCsrPtr = (VOID*)(mHeciContext->HeciMBAR + H_CSR); + // VOLATILE HECI_ME_CONTROL_REGISTER *HeciRegMeCsrHaPtr = (VOID*)(mHeciContext->HeciMBAR + ME_CSR_HA); + // VOLATILE UINT32 *HeciRegMeCbrwPtr = (VOID*)(mHeciContext->HeciMBAR + ME_CB_RW); + // + // clear Interrupt Status bit + // + HeciRegHCsr.ul = MMIOREADDWORD (HeciMBAR + H_CSR); + HeciRegHCsr.r.H_IS = 1; + + // + // test for circular buffer overflow + // + HeciRegMeCsrHa.ul = MMIOREADDWORD (HeciMBAR + ME_CSR_HA); + if (OverflowCB ( + HeciRegMeCsrHa.r.ME_CBRP_HRA, + HeciRegMeCsrHa.r.ME_CBWP_HRA, + HeciRegMeCsrHa.r.ME_CBD_HRA + ) != EFI_SUCCESS) { + // + // if we get here, the circular buffer is overflowed + // + *Length = 0; + return EFI_DEVICE_ERROR; + } + // + // If NON_BLOCKING, exit if the circular buffer is empty + // + HeciRegMeCsrHa.ul = MMIOREADDWORD (HeciMBAR + ME_CSR_HA);; + if ((FilledSlots (HeciRegMeCsrHa.r.ME_CBRP_HRA, HeciRegMeCsrHa.r.ME_CBWP_HRA) == 0) && (Blocking == NON_BLOCKING)) { + *Length = 0; + return EFI_NO_RESPONSE; + } + // + // Start timeout counter + // + StartTimer (&TimerStart, &TimerEnd, HECI_READ_TIMEOUT); + + // + // loop until we get a message packet + // + while (!GotMessage) { + // + // If 1 second timeout has expired, return fail as we have not yet received a full message. + // + if (Timeout (TimerStart, TimerEnd) != EFI_SUCCESS) { + *Length = 0; + return EFI_TIMEOUT; + } + // + // Read one message from HECI buffer and advance read pointer. Make sure + // that we do not pass the write pointer. + // + HeciRegMeCsrHa.ul = MMIOREADDWORD (HeciMBAR + ME_CSR_HA);; + if (FilledSlots (HeciRegMeCsrHa.r.ME_CBRP_HRA, HeciRegMeCsrHa.r.ME_CBWP_HRA) > 0) { + // + // Eat the HECI Message header + // + MessageHeader->Data = MMIOREADDWORD (HeciMBAR + ME_CB_RW); + + // + // Compute required message length in DWORDS + // + LengthInDwords = ((MessageHeader->Fields.Length + 3) / 4); + + // + // Just return success if Length is 0 + // + if (MessageHeader->Fields.Length == 0) { + // + // Set Interrupt Generate bit and return + // + MMIOREADDWORD (HeciMBAR + H_CSR); + HeciRegHCsr.r.H_IG = 1; + MMIOWRITEDWORD (HeciMBAR + H_CSR, HeciRegHCsr.ul); + *Length = 0; + return EFI_SUCCESS; + } + // + // Make sure that the message does not overflow the circular buffer. + // + HeciRegMeCsrHa.ul = MMIOREADDWORD (HeciMBAR + ME_CSR_HA); + if ((MessageHeader->Fields.Length + sizeof (HECI_MESSAGE_HEADER)) > (HeciRegMeCsrHa.r.ME_CBD_HRA * 4)) { + *Length = 0; + return EFI_DEVICE_ERROR; + } + // + // Make sure that the callers buffer can hold the correct number of DWORDS + // + if ((MessageHeader->Fields.Length) <= *Length) { + // + // Start timeout counter for inner loop + // + StartTimer (&TimerStart1, &TimerEnd1, HECI_READ_TIMEOUT); + + // + // Wait here until entire message is present in circular buffer + // + HeciRegMeCsrHa.ul = MMIOREADDWORD (HeciMBAR + ME_CSR_HA); + while (LengthInDwords > FilledSlots (HeciRegMeCsrHa.r.ME_CBRP_HRA, HeciRegMeCsrHa.r.ME_CBWP_HRA)) { + // + // If 1 second timeout has expired, return fail as we have not yet received a full message + // + if (Timeout (TimerStart1, TimerEnd1) != EFI_SUCCESS) { + *Length = 0; + return EFI_TIMEOUT; + } + // + // Wait before we read the register again + // + IoDelay (HECI_WAIT_DELAY); + + // + // Read the register again + // + HeciRegMeCsrHa.ul = MMIOREADDWORD (HeciMBAR + ME_CSR_HA); + } + // + // copy rest of message + // + for (i = 0; i < LengthInDwords; i++) { + MessageData[i] = MMIOREADDWORD (HeciMBAR + ME_CB_RW); + } + // + // Update status and length + // + GotMessage = TRUE; + *Length = MessageHeader->Fields.Length; + + } else { + // + // Message packet is larger than caller's buffer + // + *Length = 0; + return EFI_BUFFER_TOO_SMALL; + } + } + // + // Wait before we try to get a message again + // + IoDelay (HECI_WAIT_DELAY); + } + // + // Read ME_CSR_HA. If the ME_RDY bit is 0, then an ME reset occurred during the + // transaction and the message should be discarded as bad data may have been retrieved + // from the host's circular buffer + // + HeciRegMeCsrHa.ul = MMIOREADDWORD (HeciMBAR + ME_CSR_HA); + if (HeciRegMeCsrHa.r.ME_RDY_HRA == 0) { + *Length = 0; + return EFI_DEVICE_ERROR; + } + // + // Set Interrupt Generate bit + // + HeciRegHCsr.ul = MMIOREADDWORD (HeciMBAR + H_CSR); + HeciRegHCsr.r.H_IG = 1; + MMIOWRITEDWORD (HeciMBAR + H_CSR, HeciRegHCsr.ul); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +HeciReceive ( + IN UINT32 Blocking, + IN OUT UINT32 *MessageBody, + IN OUT UINT32 *Length + ) +/*++ + + Routine Description: + Reads a message from the ME across HECI. + + Arguments: + Blocking - Used to determine if the read is BLOCKING or NON_BLOCKING. + MessageBody - Pointer to a buffer used to receive a message. + Length - Pointer to the length of the buffer on input and the length + of the message on return. (in bytes) + + Returns: + EFI_STATUS + +--*/ +{ + HECI_MESSAGE_HEADER PacketHeader; + UINT32 CurrentLength; + UINT32 MessageComplete; + EFI_STATUS Status; + UINT32 PacketBuffer; + UINT32 timer_start; + UINT32 timer_end; + UINT32 MeDeviceState; + BOOLEAN QuitFlag; + + Status = EFI_SUCCESS; + CurrentLength = 0; + MessageComplete = 0; + QuitFlag = FALSE; + + SaveHpet (); + + do { + if (mHeciContext->MeMode == ME_MODE_SECOVER) { + Status = EFI_UNSUPPORTED; + break; + } + // + // Enable HECI and Save the Device State + // + mHeciContext->HeciDevSaveEnable (&MeDeviceState); + + // + // Make sure that HECI device BAR is correct and device is enabled. + // + HeciMBAR = CheckAndFixHeciForAccess (); + + // + // Make sure we do not have a HECI reset + // + if (CheckForHeciReset ()) { + // + // if HECI reset than try to re-init HECI + // + Status = HeciInitialize (); + + if (EFI_ERROR (Status)) { + HeciDevRestore (MeDeviceState); + Status = EFI_DEVICE_ERROR; + break; + } + } + // + // Make sure that HECI is ready for communication. + // + if (WaitForMEReady () != EFI_SUCCESS) { + HeciDevRestore (MeDeviceState); + Status = EFI_TIMEOUT; + break; + } + // + // Set up timer for BIOS timeout. + // + StartTimer (&timer_start, &timer_end, HECI_READ_TIMEOUT); + while ((CurrentLength < *Length) && (MessageComplete == 0)) { + // + // If 1 second timeout has expired, return fail as we have not yet received a full message + // + if (Timeout (timer_start, timer_end) != EFI_SUCCESS) { + Status = EFI_TIMEOUT; + QuitFlag = TRUE; + break; + } + + PacketBuffer = *Length - CurrentLength; + Status = HECIPacketRead ( + Blocking, + &PacketHeader, + (UINT32 *) &MessageBody[CurrentLength / 4], + &PacketBuffer + ); + + // + // Check for error condition on read + // + if (EFI_ERROR (Status)) { + *Length = 0; + QuitFlag = TRUE; + break; + } + // + // Get completion status from the packet header + // + MessageComplete = PacketHeader.Fields.MessageComplete; + + // + // Check for zero length messages + // + if (PacketBuffer == 0) { + // + // If we are not in the middle of a message, and we see Message Complete, + // this is a valid zero-length message. + // + if ((CurrentLength == 0) && (MessageComplete == 1)) { + *Length = 0; + QuitFlag = TRUE; + break; + } else { + // + // We should not expect a zero-length message packet except as described above. + // + *Length = 0; + Status = EFI_DEVICE_ERROR; + QuitFlag = TRUE; + break; + } + } + // + // Track the length of what we have read so far + // + CurrentLength += PacketBuffer; + + } + + if (QuitFlag == TRUE) { + break; + } + // + // If we get here the message should be complete, if it is not + // the caller's buffer was not large enough. + // + if (MessageComplete == 0) { + *Length = 0; + Status = EFI_BUFFER_TOO_SMALL; + } + + if (*Length != 0) { + *Length = CurrentLength; + } + // + // Restore HECI Device State + // + HeciDevRestore (MeDeviceState); + + } while (EFI_ERROR (Status) && (Status != EFI_BUFFER_TOO_SMALL)); + RestoreHpet (); + + return Status; +} + +EFI_STATUS +EFIAPI +HeciSend ( + IN UINT32 *Message, + IN UINT32 Length, + IN UINT8 HostAddress, + IN UINT8 MeAddress + ) +/*++ + + Routine Description: + Function sends one messsage (of any length) through the HECI circular buffer. + + Arguments: + Message - Pointer to the message data to be sent. + Length - Length of the message in bytes. + HostAddress - The address of the host processor. + MeAddress - Address of the ME subsystem the message is being sent to. + + Returns: + EFI_STATUS + +--*/ +{ + UINT32 CBLength; + UINT32 SendLength; + UINT32 CurrentLength; + HECI_MESSAGE_HEADER MessageHeader; + EFI_STATUS Status; + HECI_HOST_CONTROL_REGISTER HeciRegHCsr; + UINT32 MeDeviceState; + + Status = EFI_SUCCESS; + CurrentLength = 0; + + SaveHpet (); + + do { + if (mHeciContext->MeMode == ME_MODE_SECOVER) { + Status = EFI_UNSUPPORTED; + break; + } + // + // Enable HECI and Save the Device State + // + mHeciContext->HeciDevSaveEnable (&MeDeviceState); + + // + // Make sure that HECI device BAR is correct and device is enabled. + // + HeciMBAR = CheckAndFixHeciForAccess (); + + // + // Make sure we do not have a HECI reset + // + if (CheckForHeciReset ()) { + // + // if HECI reset than try to re-init HECI + // + Status = HeciInitialize (); + + if (EFI_ERROR (Status)) { + HeciDevRestore (MeDeviceState); + Status = EFI_DEVICE_ERROR; + break; + } + } + // + // Make sure that HECI is ready for communication. + // + if (WaitForMEReady () != EFI_SUCCESS) { + HeciDevRestore (MeDeviceState); + Status = EFI_TIMEOUT; + break; + } + // + // Set up memory mapped registers + // + HeciRegHCsr.ul = MMIOREADDWORD (HeciMBAR + H_CSR); + + // + // Grab Circular Buffer length + // + CBLength = HeciRegHCsr.r.H_CBD; + + // + // Prepare message header + // + MessageHeader.Data = 0; + MessageHeader.Fields.MeAddress = MeAddress; + MessageHeader.Fields.HostAddress = HostAddress; + + // + // Break message up into CB-sized packets and loop until completely sent + // + while (Length > CurrentLength) { + // + // Set the Message Complete bit if this is our last packet in the message. + // Needs to be 'less than' to account for the header. + // + if ((((Length - CurrentLength) + 3) / 4) < CBLength) { + MessageHeader.Fields.MessageComplete = 1; + } + // + // Calculate length for Message Header + // header length == smaller of circular buffer or remaining message (both account for the size of the header) + // + SendLength = ((CBLength < (((Length - CurrentLength) + 3) / 4)) ? ((CBLength - 1) * 4) : (Length - CurrentLength)); + MessageHeader.Fields.Length = SendLength; + + // + // send the current packet (CurrentLength can be treated as the index into the message buffer) + // + Status = HeciPacketWrite (&MessageHeader, (UINT32 *) ((UINTN) Message + CurrentLength)); + if (EFI_ERROR (Status)) { + break; + } + // + // Update the length information + // + CurrentLength += SendLength; + } + + if (EFI_ERROR (Status)) { + break; + } + // + // Restore HECI Device State + // + HeciDevRestore (MeDeviceState); + + } while (EFI_ERROR (Status)); + + RestoreHpet (); + + return Status; +} + +EFI_STATUS +HeciPacketWrite ( + IN HECI_MESSAGE_HEADER *MessageHeader, + IN UINT32 *MessageData + ) +/*++ + + Routine Description: + Function sends one messsage packet through the HECI circular buffer + Corresponds to HECI HPS (part of) section 4.2.3 + + Arguments: + MessageHeader - Pointer to the message header. + MessageData - Pointer to the actual message data. + + Returns: + EFI_STATUS + +--*/ +{ + UINT32 timer_start; + UINT32 timer_end; + UINT32 i; + UINT32 LengthInDwords; + HECI_HOST_CONTROL_REGISTER HeciRegHCsr; + HECI_ME_CONTROL_REGISTER HeciRegMeCsrHa; + + // + // VOLATILE HECI_HOST_CONTROL_REGISTER *HeciRegHCsrPtr = (VOID*)(mHeciContext->HeciMBAR + H_CSR); + // VOLATILE HECI_ME_CONTROL_REGISTER *HeciRegMeCsrHaPtr = (VOID*)(mHeciContext->HeciMBAR + ME_CSR_HA); + // VOLATILE UINT32 *HeciRegHCbwwPtr = (VOID*)(mHeciContext->HeciMBAR + H_CB_WW); + // + // Make sure that HECI is ready for communication. + // + if (WaitForMEReady () != EFI_SUCCESS) { + return EFI_TIMEOUT; + } + // + // Start timeout counter + // + StartTimer (&timer_start, &timer_end, HECI_SEND_TIMEOUT); + + // + // Compute message length in DWORDS + // + LengthInDwords = ((MessageHeader->Fields.Length + 3) / 4); + + // + // Wait until there is sufficient room in the circular buffer + // Must have room for message and message header + // + HeciRegHCsr.ul = MMIOREADDWORD (HeciMBAR + H_CSR); + while ((LengthInDwords + 1) > (HeciRegHCsr.r.H_CBD - FilledSlots (HeciRegHCsr.r.H_CBRP, HeciRegHCsr.r.H_CBWP))) { + // + // If 1 second timeout has expired, return fail as the circular buffer never emptied + // + if (Timeout (timer_start, timer_end) != EFI_SUCCESS) { + return EFI_TIMEOUT; + } + // + // Wait before we read the register again + // + IoDelay (HECI_WAIT_DELAY); + + // + // Read Host CSR for next iteration + // + HeciRegHCsr.ul = MMIOREADDWORD (HeciMBAR + H_CSR); + } + // + // Write Message Header + // + MMIOWRITEDWORD (HeciMBAR + H_CB_WW, MessageHeader->Data); + + // + // Write Message Body + // + for (i = 0; i < LengthInDwords; i++) { + MMIOWRITEDWORD (HeciMBAR + H_CB_WW, MessageData[i]); + } + // + // Set Interrupt Generate bit + // + HeciRegHCsr.ul = MMIOREADDWORD (HeciMBAR + H_CSR); + HeciRegHCsr.r.H_IG = 1; + MMIOWRITEDWORD (HeciMBAR + H_CSR, HeciRegHCsr.ul); + + // + // Test if ME Ready bit is set to 1, if set to 0 a fatal error occured during + // the transmission of this message. + // + HeciRegMeCsrHa.ul = MMIOREADDWORD (HeciMBAR + ME_CSR_HA); + if (HeciRegMeCsrHa.r.ME_RDY_HRA == 0) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +HeciSendwACK ( + IN OUT UINT32 *Message, + IN UINT32 Length, + IN OUT UINT32 *RecLength, + IN UINT8 HostAddress, + IN UINT8 MeAddress + ) +/*++ + + Routine Description: + Function sends one messsage through the HECI circular buffer and waits + for the corresponding ACK message. + + Arguments: + Message - Pointer to the message buffer. + SendLength - Length of the message in bytes. + RecLength - Length of the message response in bytes. + HostAddress - Address of the sending entity. + MeAddress - Address of the ME entity that should receive the message. + + Returns: + EFI_STATUS + +--*/ +{ + EFI_STATUS Status; + UINT16 RetryCount; + UINT32 TempRecLength; + + if (mHeciContext->MeMode == ME_MODE_SECOVER) { + return EFI_UNSUPPORTED; + } + // + // Send the message + // + Status = HeciSend (Message, Length, HostAddress, MeAddress); + if (EFI_ERROR (Status)) { + return Status; + } + // + // Wait for ACK message + // + TempRecLength = *RecLength; + for (RetryCount = 0; RetryCount < HECI_MAX_RETRY; RetryCount++) { + // + // Read Message + // + Status = HeciReceive (BLOCKING, Message, &TempRecLength); + if (!EFI_ERROR (Status)) { + break; + } + // + // Reload receive length as it has been modified by the read function + // + TempRecLength = *RecLength; + } + // + // Return read length and status + // + *RecLength = TempRecLength; + return Status; +} + +EFI_STATUS +EFIAPI +MeResetWait ( + IN UINT32 Delay + ) +/*++ + +Routine Description: + + Me reset and waiting for ready + +Arguments: + + Delay - The biggest waiting time + +Returns: + + EFI_TIMEOUT - Time out + EFI_SUCCESS - Me ready + +--*/ +{ + HECI_HOST_CONTROL_REGISTER HeciRegHCsr; + UINT32 TimerStart; + UINT32 TimerEnd; + + // + // Make sure that HECI device BAR is correct and device is enabled. + // + HeciMBAR = CheckAndFixHeciForAccess (); + + // + // Wait for the HOST Ready bit to be cleared to signal a reset + // + StartTimer (&TimerStart, &TimerEnd, Delay); + HeciRegHCsr.ul = MMIOREADDWORD (HeciMBAR + H_CSR); + while (HeciRegHCsr.r.H_RDY == 1) { + // + // If timeout has expired, return fail + // + if (Timeout (TimerStart, TimerEnd) != EFI_SUCCESS) { + return EFI_TIMEOUT; + } + + HeciRegHCsr.ul = MMIOREADDWORD (HeciMBAR + H_CSR); + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +ResetHeciInterface ( + VOID + ) +/*++ + + Routine Description: + Function forces a reinit of the heci interface by following the reset heci interface via host algorithm + in HPS 0.90 doc 4-17-06 njy + + Arguments: + none + + Returns: + EFI_STATUS + +--*/ +{ + HECI_HOST_CONTROL_REGISTER HeciRegHCsr; + HECI_ME_CONTROL_REGISTER HeciRegMeCsrHa; + UINT32 TimerStart; + UINT32 TimerEnd; + + // + // Make sure that HECI device BAR is correct and device is enabled. + // + HeciMBAR = CheckAndFixHeciForAccess (); + + // + // Enable Reset + // + HeciRegHCsr.ul = MMIOREADDWORD (HeciMBAR + H_CSR); + HeciRegHCsr.r.H_RST = 1; + HeciRegHCsr.r.H_IG = 1; + MMIOWRITEDWORD (HeciMBAR + H_CSR, HeciRegHCsr.ul); + + // + // Make sure that the reset started + // + // HeciRegHCsr.ul = MMIOREADDWORD(HeciMBAR + H_CSR); + // + StartTimer (&TimerStart, &TimerEnd, HECI_INIT_TIMEOUT); + do { + // + // If 5 second timeout has expired, return fail + // + if (Timeout (TimerStart, TimerEnd) != EFI_SUCCESS) { + return EFI_TIMEOUT; + } + // + // Read the ME CSR + // + HeciRegHCsr.ul = MMIOREADDWORD (HeciMBAR + H_CSR); + } while (HeciRegHCsr.r.H_RDY == 1); + + // + // Wait for ME to perform reset + // + // HeciRegMeCsrHa.ul = MMIOREADDWORD(HeciMBAR + ME_CSR_HA); + // + StartTimer (&TimerStart, &TimerEnd, HECI_INIT_TIMEOUT); + do { + // + // If 5 second timeout has expired, return fail + // + if (Timeout (TimerStart, TimerEnd) != EFI_SUCCESS) { + return EFI_TIMEOUT; + } + // + // Read the ME CSR + // + HeciRegMeCsrHa.ul = MMIOREADDWORD (HeciMBAR + ME_CSR_HA); + } while (HeciRegMeCsrHa.r.ME_RDY_HRA == 0); + + // + // Make sure IS has been signaled on the HOST side + // + // HeciRegHCsr.ul = MMIOREADDWORD(HeciMBAR + H_CSR); + // + StartTimer (&TimerStart, &TimerEnd, HECI_INIT_TIMEOUT); + do { + // + // If 5 second timeout has expired, return fail + // + if (Timeout (TimerStart, TimerEnd) != EFI_SUCCESS) { + return EFI_TIMEOUT; + } + // + // Read the ME CSR + // + HeciRegHCsr.ul = MMIOREADDWORD (HeciMBAR + H_CSR); + } while (HeciRegHCsr.r.H_IS == 0); + + // + // Enable host side interface + // + HeciRegHCsr.ul = MMIOREADDWORD (HeciMBAR + H_CSR);; + HeciRegHCsr.r.H_RST = 0; + HeciRegHCsr.r.H_IG = 1; + HeciRegHCsr.r.H_RDY = 1; + MMIOWRITEDWORD (HeciMBAR + H_CSR, HeciRegHCsr.ul); + + return EFI_SUCCESS; +} + +UINT8 +FilledSlots ( + IN UINT32 ReadPointer, + IN UINT32 WritePointer + ) +/*++ + + Routine Description: + Calculate if the circular buffer has overflowed. + Corresponds to HECI HPS (part of) section 4.2.1 + + Arguments: + ReadPointer - Location of the read pointer. + WritePointer - Location of the write pointer. + + Returns: + Number of filled slots. + +--*/ +{ + UINT8 FilledSlots; + + // + // Calculation documented in HECI HPS 0.68 section 4.2.1 + // + FilledSlots = (((INT8) WritePointer) - ((INT8) ReadPointer)); + + return FilledSlots; +} + +EFI_STATUS +OverflowCB ( + IN UINT32 ReadPointer, + IN UINT32 WritePointer, + IN UINT32 BufferDepth + ) +/*++ + + Routine Description: + Calculate if the circular buffer has overflowed + Corresponds to HECI HPS (part of) section 4.2.1 + + Arguments: + ReadPointer - Value read from host/me read pointer + WritePointer - Value read from host/me write pointer + BufferDepth - Value read from buffer depth register + + Returns: + EFI_STATUS + +--*/ +{ + UINT8 FilledSlots; + + // + // Calculation documented in HECI HPS 0.68 section 4.2.1 + // + FilledSlots = (((INT8) WritePointer) - ((INT8) ReadPointer)); + + // + // test for overflow + // + if (FilledSlots > ((UINT8) BufferDepth)) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +HeciGetMeStatus ( + IN UINT32 *MeStatus + ) +/*++ + + Routine Description: + Return ME Status + + Arguments: + MeStatus pointer for status report + + Returns: + EFI_STATUS + +--*/ +{ + HECI_FWS_REGISTER MeFirmwareStatus; + UINT32 MeDeviceState; + + if (MeStatus == NULL) { + return EFI_INVALID_PARAMETER; + } + // + // Save HECI1 Device State and Enable it + // + Heci1DevSaveEnable (&MeDeviceState); + + MeFirmwareStatus.ul = HeciPciRead32 (R_FWSTATE); + + if (MeFirmwareStatus.r.CurrentState == ME_STATE_NORMAL && MeFirmwareStatus.r.ErrorCode == ME_ERROR_CODE_NO_ERROR) { + *MeStatus = ME_READY; + } else if (MeFirmwareStatus.r.CurrentState == ME_STATE_RECOVERY) { + *MeStatus = ME_IN_RECOVERY_MODE; + } else { + *MeStatus = ME_NOT_READY; + } + + if (MeFirmwareStatus.r.FwInitComplete == ME_FIRMWARE_COMPLETED) { + *MeStatus |= ME_FW_INIT_COMPLETE; + } + // + // Save HECI Device State and Enable it + // + HeciDevRestore (MeDeviceState); + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +HeciGetMeMode ( + IN UINT32 *MeMode + ) +/*++ + + Routine Description: + Return ME Mode + + Arguments: + MeMode pointer for ME Mode report + + Returns: + EFI_STATUS + +--*/ +{ + HECI_FWS_REGISTER MeFirmwareStatus; + UINT32 MeDeviceState; + + if (MeMode == NULL) { + return EFI_INVALID_PARAMETER; + } + // + // Save HECI1 Device State and Enable it + // + Heci1DevSaveEnable (&MeDeviceState); + + MeFirmwareStatus.ul = HeciPciRead32 (R_FWSTATE); + switch (MeFirmwareStatus.r.MeOperationMode) { + case ME_OPERATION_MODE_NORMAL: + *MeMode = ME_MODE_NORMAL; + break; + + case ME_OPERATION_MODE_DEBUG: + *MeMode = ME_MODE_DEBUG; + break; + + case ME_OPERATION_MODE_SOFT_TEMP_DISABLE: + *MeMode = ME_MODE_TEMP_DISABLED; + break; + + case ME_OPERATION_MODE_SECOVR_JMPR: + case ME_OPERATION_MODE_SECOVR_HECI_MSG: + *MeMode = ME_MODE_SECOVER; + break; + + default: + *MeMode = ME_MODE_FAILED; + } + // + // Save HECI Device State and Enable it + // + HeciDevRestore (MeDeviceState); + + return EFI_SUCCESS; +} + +EFI_STATUS +Heci1DevSaveEnable ( + IN OUT UINT32 *DevState + ) +/*++ + + Routine Description: + Save HECI1 State and Enable it + + Arguments: + DevState - Device State Save Buffer + + Returns: + EFI_STATUS + +--*/ +{ + *DevState = MMIOREADDWORD (PCH_RCRB_BASE + R_PCH_RCRB_FUNC_DIS2); + HeciEnable (); + return EFI_SUCCESS; +} + +EFI_STATUS +Heci2DevSaveEnable ( + IN OUT UINT32 *DevState + ) +/*++ + + Routine Description: + Save HECI2 State and Enable it + + Arguments: + DevState - Device State Save Buffer + + Returns: + EFI_STATUS + +--*/ +{ + *DevState = MMIOREADDWORD (PCH_RCRB_BASE + R_PCH_RCRB_FUNC_DIS2); + Heci2Enable (); + return EFI_SUCCESS; +} + +EFI_STATUS +HeciDevRestore ( + IN UINT32 DevState + ) +/*++ + + Routine Description: + Restore HECI1&HECI2 State + + Arguments: + DevState - Device State Save Buffer + + Returns: + EFI_STATUS + +--*/ +{ + MMIOWRITEDWORD (PCH_RCRB_BASE + R_PCH_RCRB_FUNC_DIS2, DevState); + MMIOREADDWORD (PCH_RCRB_BASE + R_PCH_RCRB_FUNC_DIS2); + return EFI_SUCCESS; +} diff --git a/ReferenceCode/ME/Heci/Smm/Hecicore.h b/ReferenceCode/ME/Heci/Smm/Hecicore.h new file mode 100644 index 0000000..5f05c10 --- /dev/null +++ b/ReferenceCode/ME/Heci/Smm/Hecicore.h @@ -0,0 +1,512 @@ +/*++ + This file contains an 'Intel Peripheral Driver' and uniquely + identified as "Intel Reference Module" and is + licensed for Intel CPUs and chipsets under the terms of your + license agreement with Intel or your vendor. This file may + be modified by the user, subject to additional terms of the + license agreement +--*/ +/*++ + +Copyright (c) 2006 - 2010 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +Module Name: + + HeciCore.h + +Abstract: + + Definitions for HECI driver + +--*/ +#ifndef _HECI_CORE_H +#define _HECI_CORE_H + +#include "CpuIa32.h" +#include "CoreBiosMsg.h" + +// +// HECI bus function version +// +#define HBM_MINOR_VERSION 0 +#define HBM_MAJOR_VERSION 1 + +// +// HECI save/restore Function +// +typedef +EFI_STATUS +(EFIAPI *HECI_DEV_SAVE_ENABLE) ( + IN OUT UINT32 *DevState + ); + +// +// HECI private data structure +// +typedef struct { + UINTN Signature; + EFI_HANDLE Handle; + UINT32 HeciMBAR; + UINT16 DeviceInfo; + UINT32 RevisionInfo; + SMM_HECI_PROTOCOL HeciCtlr; + VOLATILE UINT32 *HpetTimer; + UINTN PciAddressBase; + UINT32 DefaultHeciBar; + HECI_DEV_SAVE_ENABLE HeciDevSaveEnable; + UINT32 MeMode; +} HECI_INSTANCE_SMM; + +// +// Prototypes +// +EFI_STATUS +EFIAPI +HeciInitialize ( + VOID + ) +/*++ + + Routine Description: + Determines if the HECI device is present and, if present, initializes it for + use by the BIOS. + + Arguments: + None. + + Returns: + EFI_STATUS + +--*/ +; + +EFI_STATUS +EFIAPI +HeciReInitialize ( + VOID + ) +/*++ + + Routine Description: + Heci Re-initializes it for Host + + Arguments: + None. + + Returns: + EFI_STATUS + +--*/ +; + +EFI_STATUS +EFIAPI +HeciReInitialize2 ( + VOID + ) +/*++ + + Routine Description: + Heci Re-initializes it for Me + + Arguments: + None. + + Returns: + EFI_STATUS + +--*/ +; + +EFI_STATUS +EFIAPI +HeciReceive ( + IN UINT32 Blocking, + OUT UINT32 *MessageData, + IN OUT UINT32 *Length + ) +/*++ + + Routine Description: + Reads a message from the ME across HECI. + + Arguments: + Blocking - Used to determine if the read is BLOCKING or NON_BLOCKING. + MessageData - Pointer to a buffer used to receive a message. + Length - Pointer to the length of the buffer on input and the length + of the message on return. (in bytes) + + Returns: + EFI_STATUS + +--*/ +; + +EFI_STATUS +EFIAPI +HeciSend ( + IN UINT32 *Message, + IN UINT32 Length, + IN UINT8 HostAddress, + IN UINT8 MeAddress + ) +/*++ + + Routine Description: + Function sends one messsage (of any length) through the HECI circular buffer. + + Arguments: + Message - Pointer to the message data to be sent. + Length - Length of the message in bytes. + HostAddress - The address of the host processor. + MeAddress - Address of the ME subsystem the message is being sent to. + + Returns: + EFI_STATUS + +--*/ +; + +EFI_STATUS +EFIAPI +HeciSendwACK ( + IN OUT UINT32 *Message, + IN UINT32 Length, + IN OUT UINT32 *RecLength, + IN UINT8 HostAddress, + IN UINT8 MeAddress + ) +/*++ + + Routine Description: + Function sends one messsage through the HECI circular buffer and waits + for the corresponding ACK message. + + Arguments: + Message - Pointer to the message buffer. + SendLength - Length of the message in bytes. + RecLength - Length of the message response in bytes. + HostAddress - Address of the sending entity. + MeAddress - Address of the ME entity that should receive the message. + + Returns: + EFI_STATUS + +--*/ +; + +EFI_STATUS +EFIAPI +MeResetWait ( + IN UINT32 Delay + ) +/*++ + +Routine Description: + + Me reset and waiting for ready + +Arguments: + + Delay - The biggest waiting time + +Returns: + + EFI_TIMEOUT - Time out + EFI_SUCCESS - Me ready + +--*/ +; + +EFI_STATUS +EFIAPI +ResetHeciInterface ( + VOID + ) +/*++ + + Routine Description: + Function forces a reinit of the heci interface by following the reset heci interface via host algorithm + in HPS 0.90 doc 4-17-06 njy + + Arguments: + none + + Returns: + EFI_STATUS + +--*/ +; + +EFI_STATUS +EFIAPI +HeciGetMeStatus ( + IN UINT32 *MeStatus + ) +/*++ + + Routine Description: + Return ME Status + + Arguments: + MeStatus pointer for status report + + Returns: + EFI_STATUS + +--*/ +; + +EFI_STATUS +EFIAPI +HeciGetMeMode ( + IN UINT32 *MeMode + ) +/*++ + + Routine Description: + Return ME Mode + + Arguments: + MeMode pointer for ME Mode report + + Returns: + EFI_STATUS + +--*/ +; + +// +// Local/Private functions not part of EFIAPI for HECI +// +EFI_STATUS +InitializeHECI ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +/*++ + +Routine Description: + HECI driver entry point used to initialize support for the HECI device. + +Arguments: + ImageHandle - Standard entry point parameter. + SystemTable - Standard entry point parameter. + +Returns: + EFI_STATUS + +--*/ +; + +EFI_STATUS +InitializeHeciPrivate ( + VOID + ) +/*++ + + Routine Description: + Determines if the HECI device is present and, if present, initializes it for + use by the BIOS. + + Arguments: + None. + + Returns: + EFI_STATUS + +--*/ +; + +UINT32 +CheckAndFixHeciForAccess ( + VOID + ) +/*++ + +Routine Description: + This function provides a standard way to verify the HECI cmd and MBAR regs + in its PCI cfg space are setup properly and that the local mHeciContext + variable matches this info. + +Arguments: + None. + +Returns: + VOID + +--*/ +; + +EFI_STATUS +WaitForMEReady ( + VOID + ) +/*++ + + Routine Description: + Waits for the ME to report that it is ready for communication over the HECI + interface. + + Arguments: + None. + + Returns: + EFI_STATUS + +--*/ +; + +UINT8 +FilledSlots ( + IN UINT32 ReadPointer, + IN UINT32 WritePointer + ) +/*++ + + Routine Description: + Calculate if the circular buffer has overflowed. + Corresponds to HECI HPS (part of) section 4.2.1 + + Arguments: + ReadPointer - Location of the read pointer. + WritePointer - Location of the write pointer. + + Returns: + Number of filled slots. + +--*/ +; + +EFI_STATUS +OverflowCB ( + IN UINT32 ReadPointer, + IN UINT32 WritePointer, + IN UINT32 BufferDepth + ) +/*++ + + Routine Description: + Calculate if the circular buffer has overflowed + Corresponds to HECI HPS (part of) section 4.2.1 + + Arguments: + ReadPointer - Value read from host/me read pointer + WritePointer - Value read from host/me write pointer + BufferDepth - Value read from buffer depth register + + Returns: + EFI_STATUS + +--*/ +; + +EFI_STATUS +HeciPacketRead ( + IN UINT32 Blocking, + OUT HECI_MESSAGE_HEADER *MessageHeader, + OUT UINT32 *MessageData, + IN OUT UINT32 *Length + ) +/*++ + + Routine Description: + Function to pull one messsage packet off the HECI circular buffer. + Corresponds to HECI HPS (part of) section 4.2.4 + + + Arguments: + Blocking - Used to determine if the read is BLOCKING or NON_BLOCKING. + MessageHeader - Pointer to a buffer for the message header. + MessageData - Pointer to a buffer to recieve the message in. + Length - On input is the size of the callers buffer in bytes. On + output this is the size of the packet in bytes. + + Returns: + EFI_STATUS + +--*/ +; + +EFI_STATUS +HeciPacketWrite ( + IN HECI_MESSAGE_HEADER *MessageHeader, + IN UINT32 *MessageData + ) +/*++ + + Routine Description: + Function sends one messsage packet through the HECI circular buffer + Corresponds to HECI HPS (part of) section 4.2.3 + + Arguments: + MessageHeader - Pointer to the message header. + MessageData - Pointer to the actual message data. + + Returns: + EFI_STATUS + +--*/ +; + +EFI_STATUS +Heci1DevSaveEnable ( + IN OUT UINT32 *DevState + ) +/*++ + + Routine Description: + Save HECI1 State and Enable it + + Arguments: + DevState - Device State Save Buffer + + Returns: + EFI_STATUS + +--*/ +; + +EFI_STATUS +Heci2DevSaveEnable ( + IN OUT UINT32 *DevState + ) +/*++ + + Routine Description: + Save HECI2 State and Enable it + + Arguments: + DevState - Device State Save Buffer + + Returns: + EFI_STATUS + +--*/ +; + +EFI_STATUS +HeciDevRestore ( + IN UINT32 DevState + ) +/*++ + + Routine Description: + Restore HECI1 State + + Arguments: + DevState - Device State Save Buffer + + Returns: + EFI_STATUS + +--*/ +; +#endif // _HECI_CORE_H |